Permissions
Karma ships with a flexible built-in permission system that allows you to define, who can perform certain actions within Karma.
Permission system is based on rules, that can be defined in a configuration file called rules.js within the configuration directory.
This document describes:
- the used terminology for the permission system
- how rules can be defined
- what the default rules are (if not explicitly defined)
- how to configure which attributes should be available
Terminology
permission
A permission defines, if a logged-in user is authorized to perform a certain task. It is represented by string, for example: can assign and revoke roles. In this example, if the user has this permission, he will be able to manage roles for a specific user.
rule
A rule is a Javascript function returning true (the user will be assigned the permission) or false (the user won't be assigned the permission).
viewer
A viewer is the currently logged-in Karma user who wants to perform a certain action.
subject
The subject is the object under evaluation. For example, if you want to assign roles to or revoke roles from a user, the user is the subject.
owner
The owner is an object (for example a user or role) that holds the subject which shall be changed. It allows to define permissions in a more granular manner by not only evaluating the subject but also the object that the subject is assigned to.
For example, it enables you to define for which particular user (= owner) the viewer is authorized to revoke a role (= subject).
principal
$principals is an array of DNs associated with a viewer, subject or owner. There are the following principals:
- on any object type: all parent containers of the object
- on a user:
groupMembership nrfDynamicGroupMembership nrfMemberOf - on a role:
nrfChildRoles nrfExternalChildRoles
How to define rules
Rules are defined in the file rules.js within the configuration directory.
Permissions are divided into two sections:
user: for all operations where thesubjectis a user; thesubjectis aliased asuserin the parameter objectrole: for all operations where thesubjectis a role; thesubjectis aliased asrolein the parameter object
Each section may contain several rule functions which accept as a single parameter. This parameter object is a sandbox with the following additional properties:
subject: object- likeviewerexcept foris(dn)owner: object- likeviewerexcept foris(dn);nullif there is no owner in the current evaluation contextrequest: object- only available for request-based rules such ascan startandcan trigger action. Relevant properties of that object are:entryDN: helps you to write a custom rule for a specific requestauthz: can contain a Karma role (admin,user,guest) as well as a DN of a user, role, group or container that is allowed to trigger the action. This value can be defined in the configuration file.(local.yaml) for each action withinuser,account, orrole
The function must return true, to activate the permission, otherwise false.
Currently, there are two permissions that can be configured (more will be implemented):
for users (subject.$type === 'user'):
can assign and revoke roles: authorizes theviewerto request role assignment / revokation for a specific user (subject)
for roles (subject.$type === 'role'):
is revokable: authorizes theviewerto request role (subject) revokation for a specific user (owner)can assign and revoke users: authorizes theviewerto request user assignment / revokation for a specific role (subject)
The following is an example for a rules configuration.
'use strict'
const always = value => () => value
const isSame = (a, b) => (
!!(a && b) &&
(
a === b ||
(
a.$type === b.$type &&
a.$id === b.$id
)
)
)
const invokeWith = (ctx) => fn => fn(ctx)
const and = (...conditions) => ctx => conditions.all(invokeWith(ctx))
const or = (...conditions) => ctx => conditions.some(invokeWith(ctx))
const is = role => ({ viewer }) => viewer.is(role)
const everybody = always(true)
const nobody = always(false)
const isAdmin = is('admin')
const isUser = is('user')
const isGuest = is('guest')
const viewerIsSubject = ({ viewer, subject }) => isSame(viewer, subject)
const viewerIsOwner = ({ viewer, owner }) => isSame(viewer, owner)
exports.permissions = {
// subject.$type === 'user'
user: {
'can edit attributes': or(isAdmin, viewerIsSubject),
'can view inherited roles': isAdmin,
'can view groups': or(isAdmin, viewerIsSubject),
'can view resources': isAdmin,
// is the viewer allowed to request role assignments and revocations for this user
'can assign and revoke roles': or(isAdmin, viewerIsSubject),
'can view child objects on dashboard': everybody,
'can view tiles on dashboard': everybody,
'can view provisioning requests on dashboard': everybody,
// panels and rows
'can view password status': isAdmin
// tabs
'can view details tab': everybody,
'can view tasks tab': everybody,
'can view requests tab': everybody,
'can view history tab': everybody,
'can view process history tab': everybody,
},
// subject.$type === 'account'
account: {
'can edit attributes': isAdmin,
// is the viewer allowed to request role assignments and revocations for this account
'can assign and revoke roles': isAdmin,
'can view groups': isUser,
'can view resources': isAdmin,
'can view inherited roles': isUser,
// tabs
'can view details tab': everybody,
'can view tasks tab': everybody,
'can view requests tab': everybody,
'can view history tab': everybody,
'can view process history tab': everybody,
},
// subject.$type === 'role'
role: {
// is the viewer allowed to request revocation of this role
'is revokable': or(isAdmin, viewerIsOwner),
'can edit attributes': isAdmin,
'can assign and revoke users': isAdmin
},
// subject.$type === 'request'
request: {
'can start': everybody,
// owner is the user/role for whom to trigger the action
'can trigger action': ({ viewer, request }) => viewer.is(request.authz || 'admin')
}
}
Default rules
The following are the default rules in case no custom rules are defined. Basically, only users that are assigned to the Karma admin role are authorized to perform the defined actions.
'use strict'
exports.permissions = {
// subject.$type === 'user'
user: {
'can edit attributes': isAdmin,
// is the viewer allowed to request role assignments and revokations for this user
'can assign and revoke roles': isAdmin,
'can view groups': isUser,
'can view resources': isUser,
'can view inherited roles': isUser,
'can view child objects on dashboard': everybody,
'can view details tab': everybody,
// special property access
'can view $parentObjects': everybody,
'can view $childObjects': everybody,
},
// subject.$type === 'account'
account: {
'can edit attributes': isAdmin,
// is the viewer allowed to request role assignments and revokations for this account
'can assign and revoke roles': isAdmin,
'can view groups': isUser,
'can view resources': isUser,
'can view inherited roles': isUser,
'can view details tab': everybody,
// special property access
'can view $parentObjects': everybody,
'can view $childObjects': everybody,
}
// subject.$type === 'role'
role: {
'can edit attributes': isAdmin,
// is the viewer allowed to request revokation of this role
'is revokable': isAdmin,
// is the viewer allowed to request users assignments and revokations for this role
'can assign and revoke users': isAdmin,
// special property access
'can view $parentObjects': everybody,
'can view $childObjects': everybody,
'can view $externalChildRoles': everybody,
'can view $externalParentRoles': everybody,
'can view $implicitGroups': everybody,
'can view $implicitContainers': everybody,
'can view $owners': everybody,
},
// subject.$type === 'request'
request: {
'can start': everybody,
// owner is the user/role for whom to trigger the action
'can trigger action': ({ viewer, request }) => viewer.is(request.authz || 'admin'),
},
// subject.$ype === 'group'
group: {
// special property access
'can view $associatedRoles': everybody,
'can view $owners': everybody,
}
}