:toc: macro toc::[] = Access-Control Access-Control is a central and important aspect of link:guide-security[Security]. It consists of two major aspects: * xref:Authentication[] (Who tries to access?) * xref:Authorization[] (Is the one accessing allowed to do what he wants to do?) == Authentication Definition: > Authentication is the verification that somebody interacting with the system is the actual subject for whom he claims to be. The one authenticated is properly called _subject_ or http://docs.oracle.com/javase/7/docs/api/java/security/Principal.html[_principal_]. There are two forms of principals you need to distinguish while designing your authentication: `human users` and `autonomous systems`. While e.g. a Kerberos/SPNEGO Single-Sign-On makes sense for human users, it is pointless for authenticating autonomous systems. For simplicity, we use the common term _user_ to refer to any principal even though it may not be a human (e.g. in case of a service call from an external system). To prove the authenticity, the user provides some secret called _credentials_. The most simple form of credentials is a password. === Implementations NOTE: Please never implement your own authentication mechanism or credential store. You have to be aware of implicit demands such as salting and hashing credentials, password life-cycle with recovery, expiry, and renewal including email notification confirmation tokens, central password policies, etc. This is the domain of identity and access management (IAM). There are various existing products for IAM that already solve the problems better than you could ever implement it yourselve. In a business context you will typically already find a system for this purpose that you have to integrate (e.g. via JWT and OAuth). In case you have the freedom of choice, we recommend using http://keycloak.org[keycloak]. We recommend using link:guide-jwt[JWT] when possible. For KISS, also try to avoid combining multiple authentication mechanisms (form based, basic-auth, SAMLv2, OAuth, etc.) within the same application (for different URLs). Please note that inside an identity and access management (IAM) you have many different options for authentication. In case you are in charge of making decisions considere the following options according to your requirements and demands (esp. security): * Consider if a second factor (e.g. via https://en.wikipedia.org/wiki/Time-based_one-time_password[TOTP] and according free mobile apps) should be used for advanced security * Consider if https://fidoalliance.org/fido2/[Fido2] is an option to get rid of passwords and increase security. For link:spring[spring], check the link:spring/guide-authentication-spring[Spring Security] For link:quarkus[quarkus], check the link:quarkus/guide-authentication-quarkus[Quarkus Authentication] == Authorization **Definition:** > Authorization is the verification that an authenticated user is allowed to perform the operation he intends to invoke. === Clarification of terms For clarification we also want to give a common understanding of related terms that have no unique definition and consistent usage in the wild. .Security terms related to authorization [options="header", cols="15%,85%"] |======================= |*Term*|*Meaning and comment* |Permission|A permission is an object that allows a principal to perform an operation in the system. This permission can be _granted_ (give) or _revoked_ (taken away). Sometimes people also use the term _right_ what is actually wrong as a right (such as the right to be free) can not be revoked. |Group|We use the term group in this context for an object that contains permissions. A group may also contain other groups. Then the group represents the set of all recursively contained permissions. |Role|We consider a role as a specific form of group that also contains permissions. A role identifies a specific function of a principal. A user can act in a role. For simple scenarios a principal has a single role associated. In more complex situations a principal can have multiple roles but has only one active role at a time that he can choose out of his assigned roles. For KISS it is sometimes sufficient to avoid this by creating multiple accounts for the few users with multiple roles. Otherwise at least avoid switching roles at run-time in clients as this may cause problems with related states. Simply restart the client with the new role as parameter in case the user wants to switch his role. | Access Control | Any permission, group, role, etc., which declares a control for access management. |======================= === Suggestions on the access model For the access model we give the following suggestions: * Each Access Control (permission, group, role, ...) is uniquely identified by a human readable string. * We create a unique permission for each use-case. * We define groups that combine permissions to typical and useful sets for the users. * We define roles as specific groups as required by our business demands. * We allow to associate users with a list of Access Controls. * For authorization of an implemented use case we determine the required permission. Furthermore, we determine the current user and verify that the required permission is contained in the tree spanned by all his associated Access Controls. If the user does not have the permission we throw a security exception and thus abort the operation and transaction. * We avoid negative permissions, that is a user has no permission by default and only those granted to him explicitly give him additional permission for specific things. Permissions granted can not be reduced by other permissions. * Technically we consider permissions as a secret of the application. Administrators shall not fiddle with individual permissions but grant them via groups. So the access management provides a list of strings identifying the Access Controls of a user. The individual application itself contains these Access Controls in a structured way, whereas each group forms a permission tree. === Naming conventions As stated above each Access Control is uniquely identified by a human readable string. This string should follow the naming convention: ``` «app-id».«local-name» ``` For Access Control Permissions the `«local-name»` again follows the convention: ``` «verb»«object» ``` The segments are defined by the following table: .Segments of Access Control Permission ID [options="header"] |============================================= |*Segment* | *Description* | *Example* |«app-id»|Is a unique technical but human readable string of the application (or microservice). It shall not contain special characters and especially no dot or whitespace. We recommend to use `lower-train-case-ascii-syntax`. The identity and access management should be organized on enterprise level rather than application level. Therefore permissions of different apps might easily clash (e.g. two apps might both define a group `ReadMasterData` but some user shall get this group for only one of these two apps). Using the `«app-id».` prefix is a simple but powerful namespacing concept that allows you to scale and grow. You may also reserve specific «app-id»s for cross-cutting concerns that do not actually reflect a single app e.g to grant access to a geographic region. |`shop` |«verb»|The action that is to be performed on «object». We use `Find` for searching and reading data. `Save` shall be used both for create and update. Only if you really have demands to separate these two you may use `Create` in addition to `Save`. Finally, `Delete` is used for deletions. For non CRUD actions you are free to use additional verbs such as `Approve` or `Reject`.|`Find` |«object»|The affected object or entity. Shall be named according to your data-model|`Product` |============================================= So as an example `shop.FindProduct` will reflect the permission to search and retrieve a `Product` in the `shop` application. The group `shop.ReadMasterData` may combine all permissions to read master-data from the `shop`. However, also a group `shop.Admin` may exist for the `Admin` role of the `shop` application. Here the `«local-name»` is `Admin` that does not follow the `«verb»«object»` schema. === devon4j-security The module `devon4j-security` provides ready-to-use code based on http://projects.spring.io/spring-security/[spring-security] that makes your life a lot easier. .devon4j Security Model image::images/Security-AccessControl.png["access-control",scaledwidth="80%",align="center",link="images/Security-AccessControl.png"] The diagram shows the model of `devon4j-security` that separates two different aspects: * The _Identity- and Access-Management_ is provided by according products and typically already available in the enterprise landscape (e.g. an active directory). It provides a hierarchy of _primary access control objects_ (roles and groups) of a user. An administrator can grant and revoke permissions (indirectly) via this way. * The application security defines a hierarchy of _secondary access control objects_ (groups and permissions). This is done by configuration owned by the application (see following section). The "API" is defined by the IDs of the primary access control objects that will be referenced from the _Identity- and Access-Management_. === Access Control Config In your application simply extend `AccessControlConfig` to configure your access control objects as code and reference it from your use-cases. An example config may look like this: [source,java] ---- @Named public class ApplicationAccessControlConfig extends AccessControlConfig { public static final String APP_ID = "MyApp"; private static final String PREFIX = APP_ID + "."; public static final String PERMISSION_FIND_OFFER = PREFIX + "FindOffer"; public static final String PERMISSION_SAVE_OFFER = PREFIX + "SaveOffer"; public static final String PERMISSION_DELETE_OFFER = PREFIX + "DeleteOffer"; public static final String PERMISSION_FIND_PRODUCT = PREFIX + "FindProduct"; public static final String PERMISSION_SAVE_PRODUCT = PREFIX + "SaveProduct"; public static final String PERMISSION_DELETE_PRODUCT = PREFIX + "DeleteProduct"; public static final String GROUP_READ_MASTER_DATA = PREFIX + "ReadMasterData"; public static final String GROUP_MANAGER = PREFIX + "Manager"; public static final String GROUP_ADMIN = PREFIX + "Admin"; public ApplicationAccessControlConfig() { super(); AccessControlGroup readMasterData = group(GROUP_READ_MASTER_DATA, PERMISSION_FIND_OFFER, PERMISSION_FIND_PRODUCT); AccessControlGroup manager = group(GROUP_MANAGER, readMasterData, PERMISSION_SAVE_OFFER, PERMISSION_SAVE_PRODUCT); AccessControlGroup admin = group(GROUP_ADMIN, manager, PERMISSION_DELETE_OFFER, PERMISSION_DELETE_PRODUCT); } } ---- === Configuration on Java Method level In your use-case you can now reference a permission like this: [source,java] ---- @Named public class UcSafeOfferImpl extends ApplicationUc implements UcSafeOffer { @Override @RolesAllowed(ApplicationAccessControlConfig.PERMISSION_SAVE_OFFER) public OfferEto save(OfferEto offer) { ... } ... } ---- === JEE Standard https://en.wikipedia.org/wiki/Role-based_access_control[Role-based Access Control (RBAC)] is commonly used for authorization. JSR 250 defines a number of common annotations to secure your application. * `javax.annotation.security.PermitAll` specifies that no access control is required to invoke the specified method(s). * `javax.annotation.security.DenyAll` specifies that no access controls are allowed to invoke the specified method(s). * `javax.annotation.security.RolesAllowed` specifies that only a list of access controls are allowed to invoke the specified method(s). * `javax.annotation.security.DeclareRoles` defines roles for security checking. * `javax.annotation.security.RunAs` specifies the RunAs role for the given components. `@PermitAll`, `@Denyall`, and `@RolesAllowed` annotations can be applied to both class and method. A method-level annotation will override the behaviour of class-level annotation. Using multiple annotations of those 3 is not valid. ```java // invalid @PermitAll @DenyAll public String foo() // invalid and compilation fails @RolesAllowed("admin") @RolesAllowed("user") public String bar() // OK @RolesAllowed("admin", "user") public String bar() ``` Please note that when specifying multiple arguments to `@RolesAllowed` those are combined with OR (and not with AND). So if the user has any of the specified access controls, he will be able to access the method. As a best practice avoid specifying string literals to `@RolesAllowed`. Instead define a class with all access controls as constants and reference them from there. This class is typically called `ApplicationAccessControlConfig` in devonfw. In many complicated cases where `@PermitAll` `@DenyAll` `@RolesAllowed` are insufficient e.g. a method should be accessed by a user in role A and not in role B at the same time, you have to verify the user role directly in the method. You can use `SecurityContext` class to get further needed information. ==== Spring Spring Security also supports authorization on method level. To use it, you need to add the `spring-security-config` dependency. If you use Spring Boot, the dependency `spring-boot-starter-security` already includes `spring-security-config`. Then you can configure as follows: * `prePostEnabled` property enables Spring Security pre/post annotations. `@PreAuthorize` and `@PostAuthorize` annotations provide expression-based access control. See more https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/el-access.html[here] * `securedEnabled` property determines if the `@Secured` annotation should be enabled. `@Secured` can be used similarly as `@RollesAllowed`. * `jsr250Enabled` property allows us to use the JSR-250 annotations such as `@RolesAllowed`. ```java @Configuration @EnableGlobalMethodSecurity( prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { } ``` A further read about the whole concept of Spring Security Authorization can be found https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-authorization[here]. ==== Quarkus Quarkus comes with built-in security to allow for RBAC based on the common security annotations `@RolesAllowed`, `@DenyAll`, `@PermitAll` on REST endpoints and CDI beans. Quarkus also provides the `io.quarkus.security.Authenticated` annotation that will permit any authenticated user to access the resource (equivalent to @RolesAllowed("**")). === Data-based Permissions See link:guide-data-permission[data permissions] === Access Control Schema (deprecated) The `access-control-schema.xml` approach is deprecated. The documentation can still be found in link:guide-access-control-schema[access control schema].