7.3:dev:security:authorization

Authorization policies

An authorization policy determines which permissions a user in CzechIdM has.

A policy is assigned to a role and everyone with this role gains the permissions determined by the policy as well.

  • assigning permissions in CzechIdM via ordinary roles enables managing permissions for CzechIdM by a standard mechanism

The default role "User" gives implicit permissions, which all the users in CzechIdM have. This role is not assigned explicitly, it is simply default and is always applied (see the following chapter).

A new agenda of authorization policies = permissions for data and agendas has been tied to a role. Assigning permissions makes available both agendas on the front-end (or rather REST endpoints on the back-end) and permissions for data (make records in these agendas available) to the logged in user. Permissions for agendas (REST endpoints) are assessed according to the set permissions.

The main idea is that if an agenda supports a permission for data, then we cannot see any data in the default state. To see some data we need to get / comply with a configured policy, which we get based on our assigned roles.
How permissions for agendas and permissions for data work together:
  • To see some data, we need to have at least one role with a policy assigning the permissions.

Real life example:

Let there be an agenda of roles. To be able to select from the roles dial (e.g. when requesting roles) we need to be assigned a permission for an agenda of autocomplete for roles Role - AUTOCOMPLETE or Displaying in autocomplete, selections for instance with the evaluation type BasePermissionEvaluator.

  • BasePermission - a base permission; can be added in modules; basic permissions for the IdM core, which are identical for both permissions for access into agendas and for permissions for data:
    • ADMIN - administration - includes all operations ⇒ wildcard - there is no need to list all the operations (see IdmAuthorityHierarchy)
    • AUTOCOMPLETE - displaying of data in the autocomplete. We do not have to have permissions for reading a log but we need to select it somewhere from a menu (e.g. when requesting a role we can select it but if we had only this permission, we would not see the role in the role agenda). This permission enables reading a "trimmed" log (we might limit this).
    • READ - a permission for reading the whole log - the log is displayed in the agenda.
    • CREATE - creating of new logs in the agenda
    • UPDATE - log updating
    • DELETE - log deleting
  • GroupPermission - a group (target) permission (e.g. USER, ROLE …). A group of base permissions. This group is assigned specific domain classes (e.g. IdMRole) and determines which base permissions it contains ⇒ what can be done with the given type.
    By linking a group with a base permission we get an authority - for example ROLEREAD, IDENTITYWRITE.
    A Special group is APP, which is meant for the application administrators - the authority APP_ADMIN is created by linking a group with a base permission. The authority owns all the permissions in the application.
  • AuthorizationPolicy - a policy according to which the permissions for a specific agenda (attribute groupPermission) and specific domain type (attribute authorizableType) are evaluated. It determines an evaluator (AuthorizationEvaluator) with specific settings (attribute ConfigurationMap) and which base permissions (attribute basePermissions) can be acquired if the evaluation passes.
    Policies are assigned to individual roles and thanks to that the logged in user also gets them (relation identity - IR - role - policy).
  • AuthorizationEvaluator - authorization "evaluator" - it is basically an implementation of the individual types of the rule described above. Each evaluator carries information about which domain type and which setting it supports. Some can also be universal for more domain types (e.g. children ofBaseEntity). In order to simplify the implementation of a rule, the class AbstractAuthorizationEvaluator has been created, which can be simply inherited when adding another rule. The main evaluators will be described below. The main evaluator methods, which must be implemented (or overloaded from AbstractAuthorizationEvaluator):
    • supports(authorizableType) - which doamin type is supported by the evaluator
    • supportsPermissions() - returns true if the assigned permissions are supported. False - it defines them itself internally (e.g. AbstractTransitiveEvaluator).
    • getAuthorities(policy) - returns a set of operations (the setBasePermission), which the currently logged in identity could perform according to the given policy (e.g. READ, UPDATE).
      • getPermissions(policy, authorizable) - returns a set of operations (the set BasePermission), which the currently logged in identity can perform with a given domain object according to the given policy (e.g. READ, UPDATE)
      • evaluate(policy, authorizable, permission) - this is just sort of a shortcut - it returns true if the currently logged in identity can perform the given operation according to the given policy (in practice - contains to the set above)
      • getPredicate(…) - returns a jpa criteria predicate, which can be "stuck" onto a where clause ⇒ the query then returns a result which can be paged and ordered. The result contains data, which we have permissions for according to the given policy. It is recommended to write the predicates as subqueries with exists, to prevent problems with joining tables (if, of course, it is not something simple).
      • AuthorizableService - an interface for labeling a service working with entities that it supports evaluating of policies for permissions for data. This has been added mainly because of backward compatibility - permissions for data are linked to individual agendas one by one. The policies can thus be configured only for domain types with services supporting this interface.
      • AuthorizationManager - loads and evaluates the set policies for the logged in identity throughout the application:
      • loads all the active policies according to the assigned user roles
      • connects predicates according to the policies into the where clause when searching or auto-completing data (AuthorizableService.findSecured(…))
      • evaluates available operations over the given domain objects on the level of REST controllers.

Adds the default implementation of the AuthorizationEvaluator methods. It is used as a parent for the other evaluators.

Serves as a parent for evaluating permissions according to the derived objects - for example, I have a permission for the assigned role if I have a permission for the identity, etc. See the children of this abstract class below (IdentityContractByIdentityEvaluator).

Serves for assigning the configured permission for the configured domain type - for all the data of the given type. It can be used when we want to give an access to an agenda including the access to all data. It is used, for example, for an admin with the configuration - any type (permissions for all the Identifiable children) + BasePermission.ADMIN. It can also be used for assigning the base permission for displaying data during autocomplete (see BasePermission.AUTOCOMPLETE above).

BasePermissionEvaluator is also used for simple sharing of an agenda which does not support permissions for data yet. Agendas which do not support permissions for data yet are not linked to the domain object, which can be see on the front-end as well. No other evaluator can be selected for these agendas

"Shares" the object with the given uuid. It is suitable when we are not able to configure another, more general rule - simply put - when somebody needs to see only one log from the whole agenda, it can be "shared" via the identifier (it would be nice not to enter the uuid directly in the configuration but to use autocomplete … coming soon).

"Shares" the object with the given identifier so that it is possible to enter uuid of the code of the given entity. For this evaluator, it is necessary to choose the entity type for which it is intended - does not work across entities.

A permission for identities which are my subordinates. Overloadable filters are used for evaluating subordinates or managers.

Gives a permission for industrial relations according to the permission for identity ⇒ e.g. if I have a permission to read an identity, I have a permission to read its IR. AbstractTransitiveEvaluator is used here.

Gives a permission for guarantees of a industrial relation (setting a guarantee "directly") according to the permission for a industrial relation ⇒ e.g. If I have a permission to read IR, I have a permission to read its guarantees. AbstractTransitiveEvaluator is used here. If I have a permission to edit IR, I have a permission to edit (add or delete) its assigned guarantees.

Gives a permission for assigned roles according to the permission for the identity ⇒ e.g. If I have a permission to read an identity, I have a permission to read its assigned roles. AbstractTransitiveEvaluator is used here. If I have a permission to edit the identity, I have a permission to edit (add or delete) its assigned roles.

Gives a permission to work with roles which I guarantee.

Gives a permission for authorization policies according to the permission for a role ⇒ e.g. if I have a permission to read a role, I have permission the authorization policies assigned to it. If I have a permission to edit a role, I have a permission to edit (add or delete) authorization policies assigned to it.

Gives a permission for automatic roles according to the permission for a role ⇒ e.g. if I have a permission to read a role, I have a permission to read the automatic roles assigned to it. if I have a permission to edit a role, I have a permission to edit (add or delete) the automatic roles assigned to it.

Gives a permission for application configuration (read, set…). If we want to get permissions for the secured configuration items, we need to set the parameter secured to true.

Assigns permissions for a role according to the role attribute "canBeRequested". This means that if I have a role with this evaluator, I will get permissions only for those roles the attribute of which "canBeRequested" is set to true.

Gives a permission for accounts in system according to the permission for the role ⇒ e.g. If I have a permission to read a role, I have a permission to read its accounts in system. AbstractTransitiveEvaluator is used here.

The configuration of default permissions for agendas and data for all logged in users is carried out through the default role according to the application configuration. The default role can have, similarly to other roles, configured permissions for agendas and data. After logging in, these permissions will be filled in the context of the logged-in user (authorities and authorization policies) - the role itself does not figure in the assigned roles of the user. The default role can be used mainly for adding base permissions for the autocomplete (of roles, identities) and the like.

The subordinate roles are not dealt with within the default role ⇒ the user will get what is set for the role, nothing more

If we want to read an identity profile including its assigned roles and IR, to enable password change and to request roles, it is possible to set the default role authorization policies as follows:

  • Permission to read one's own identity: Users (IdmIdentity) | Displaying in autocomplete, selections, reading, change password | SelfIdentityEvaluator
  • Permission to real the assigned identity roles: Roles assigned to users (IdmIdentityRole)| - | IdentityRoleByIdentityEvaluator
  • Permission to read IR accoding to identity: industrial relations (IdmIdentityContract) | - | IdentityContractByIdentityEvaluator
  • Permission to read guarantees of IR: industrial relation guarantees (IdmContractGuarantee) | - | ContractGuaranteeByIdentityContractEvaluator
  • Enabling the autocomplete for entities:
    • Users (IdmIdentity) | Displaying in autocomplete, selections | BasePermissionEvaluator
    • Role (IdmRole) | Displaying in autocomplete, selections | BasePermissionEvaluator
    • industrial relations (IdmIdentityContract) | Displaying in autocomplete, selections | BasePermissionEvaluator

If we want to read and edit roles where we are a guarantee, including the assigned permissions, automatic roles and accounts on target system, the authorization policies can be set as follows:

  • Permission to read guaranteed roles: Role (IdmRole) | Reading, Editing| RoleGuaranteeEvaluator
  • Permission to read automatic roles by role: Automatic roles (IdmRoleTreeNode) | - | RoleTreeNodeByRoleEvaluator
  • Permission to read permissions by role: Permission (IdmAuthorizationPolicy) | - | AuthorizationPolicyByRoleEvaluator
  • Permission to read accounts: Accounts in system | Read | BasePermissionEvaluator
  • Permission to read permissions by role: Role accounts (AccRoleAccount) | - | RoleAccountByRoleEvaluator

To employ permissions for data for a new domain type it is necessary: * to implement the interface AuthorizableService for the service working with entities. This requires the repository not to search for log via hql queries but via jpa criteria api (this is the main adjustment for the existing services where all the filters need to be rewritten). An example can be found in DefaultIdmAuthorizationPolicyService. * To implement a new rule if the universal ones (see above) do not suffice. In order to simplify the implementation of a new rule, the class AbstractAuthorizationEvaluator has been created, which can be simply inherited when adding another rule. Example:

/**
 * Adds permission for create new role only
 *
 */
@Component
@Description("Adds permission for create new role")
public class RoleWriteNewOnlyEvaluator extends AbstractAuthorizationEvaluator<IdmRole> {	
 
	@Override
	public Set<String> getPermissions(AuthorizationPolicy policy, IdmRole entity) {
		Set<String> permissions = super.getPermissions(policy, entity);	
		permissions.add(IdmBasePermission.CREATE.getName());
		return permissions;
	}
}
  • the rest is taken care of by AuthenticationManager, which finds all implementations of the rules according to the application context, offers supported types and so on.