cap-ams-support
Authorization Management Service Support for CAP Java Applications
A general description of Authorization Management Service (AMS) and its functionality can be found here. Integrating AMS into applications that use the Cloud Application Programming Model (CAP) is already possible. This can be done by using, for example, the API provided by jakarta-ams
and calling it in all required CAP event handlers. This support module tries to make the integration of AMS into CAP more convenient.
There is a previous, deprecated approach to integrating AMS into CAP Java applications using the cds2dcl
tool. The deprecated implementation still works, but we recommend to use the new approach, which is described in this document. A guide for a transition to the new approach can be found [here][1].
Disclaimer on API Usage
This documentation provides information that might be useful in using AMS. We try to ensure that future versions of the APIs are backwards compatible with the immediately preceding version. This is also true for the API that is exposed with com.sap.cloud.security.ams.dcl.client
package and its subpackages.
Please check the release notes for updates about new features and API modifications.
Integration Process
When using this module, the usage of AMS in a CAP Java application works as follows:
- The application defines its authorization model concerning roles (for example,
Admin
,Specialist
, etc.) and attributes relevant for instance based authorizations. - The application developer creates role policies and a schema with authorization attributes for AMS.
- In the CDS model the application developer annotates the service entities with privileges for the defined roles.
- The customer assigns the predefined or customized role-policies in which the
RESTRICTED
attributes of the base-policies can be redefined.
AMS schema and role policies
SCHEMA {
//defining attributes
@valueHelp { ... } //configure application endpoint for value help
CompanyId : String,
@valueHelp { ... }
BusinessSystemType : String,
}
This schema defines two attributes, CompanyId
and BusinessSystemType,
that can be used in role policies. The schema.dcl
must be located on the root level of your DCL folder (common practice src/main/resources/ams
). Additional documentation for the value help annotation can be found here. The following is a set of role policies that offers you examples for both unrestricted and restricted role assignments. The latter contain a template condition with schema attributes that can be customized by customers for instance-based access by creating admin policies that restrict those attributes.
//grant role with additional filter condition
POLICY BusinessConfigurationExpert {
ASSIGN ROLE BusinessConfigurationExpert WHERE CompanyId IS NOT RESTRICTED AND BusinessSystemType IS NOT RESTRICTED;
}
POLICY TechnicalConfigurationExpert {
ASSIGN ROLE TechnicalConfigurationExpert;
}
POLICY CarbonAccountant {
ASSIGN ROLE CarbonAccountant WHERE CompanyId IS NOT RESTRICTED AND BusinessSystemType IS NOT RESTRICTED;
}
//AMS example admin policy
POLICY BusinessConfigurationExpert001 {
USE BusinessConfigurationExpert RESTRICT CompanyId = '001' AND BusinessSystemType = 'DEV';
}
AMS annotations in CDS
CAP provides a standard annotation syntax for several use cases. The following example demonstrates the required CDS annotations for AMS:
// link the fields of the entity to the schema attributes for AMS
annotate Account with @ams.attributes: {
CompanyId: (companyId),
BusinessSystemType: (businessSystemType),
};
annotate ChartOfAccounts with @ams.attributes: {
BusinessSystemType: {
element: (businessSystemType),
attribute: 'BusinessSystemType'
}
};
// annotate the entities with privileges for the roles
annotate Account with @restrict: [
{
grant: 'DRAFT',
to: 'BusinessConfigurationExpert'
},
{
grant: [ 'CREATE', 'READ', 'UPDATE', 'DELETE' ],
to: 'BusinessConfigurationExpert',
// where: additional filter condition is generated by AMS runtime: 'and companyId = '001' and businessSystemType = 'DEV''
},
{
grant: [ 'READ' ],
to: 'CarbonAccountant',
// where: additional filter condition is generated by AMS runtime
},
];
annotate ChartOfAccounts with @restrict: [
{
grant: ['READ'],
to: [ 'BusinessConfigurationExpert', 'CarbonAccountant' ]
// where: additional filter condition is generated by AMS runtime: 'businessSystemType = 'DEV'
}
];
The example is taken from the documentation linked above.
Enforcing AMS Policies
By declaring a dependency to the module in the pom.xml
of the service
<dependency>
<groupId>com.sap.cloud.security.ams.client</groupId>
<artifactId>cap-ams-support</artifactId>
<version>...</version>
</dependency>
two extensions are integrated into the CAP runtime. The AmsUserInfoProvider
adds CAP roles to the user assigned via particular grant statements in authorization policies (...ASSIGN ROLE <roles>...
). The AmsAuthorzationHandler
is a regular CAP event handler called whenever CAP performs an authorization check. For entities annotated for AMS, this handler enforces the assigned authorization policies by attaching conditions to the database query of the current request. If the CAP entity is not annotated for AMS, nothing is executed.
If you're transitioning from the previous approach, you activate the new implementation by deleting the _dcl_.cap
metadata file which was generated by the cds2dcl
tool.
Handling of entities where not all AMS attributes are applicable
One of the main ideas for the CAP integration of AMS is that the attributes defined in AMS have an equivalent in most entities of the CDS model. However, there might be cases where not all attributes are applicable. For correct, consistent, and reasonable filter conditions, we need a way to distinguish the cases and the conditions, for example with one of the following options.
Context Attribute
The first option is to add an attribute that indicates if the entity is system-only and add the attribute to the conditions. For example:
SCHEMA {
hasSystemOnly : Boolean,
BusinessSystemId : String,
CompanyId : String
}
POLICY p1 {
ASSIGN ROLE CarbonAccountant WHERE CompanyId IS NOT RESTRICTED AND BusinessSystemId IS NOT RESTRICTED AND hasSystemOnly=false;
ASSIGN ROLE CarbonAccountant WHERE BusinessSystemId IS NOT RESTRICTED AND hasSystemOnly=true;
}
For entities with only the BusinessSystemId
attribute, the hasSystemOnly
attribute is set to true
. Using the given context, the correct value can be set in an AttributesProcessor
implementation.
Contextual Role Names
The second option is to use different role names. For example:
SCHEMA {
BusinessSystemId : String,
CompanyId : String
}
POLICY p1 {
ASSIGN ROLE CarbonAccountant WHERE CompanyId IS NOT RESTRICTED AND BusinessSystemId IS NOT RESTRICTED;
ASSIGN ROLE CarbonAccountantForSystemOnly WHERE BusinessSystemId IS NOT RESTRICTED;
}
Entities that have both attributes use the CarbonAccountant
role; entities that have only the BusinessSystemId
use the CarbonAccountantForSystemOnly
role in the @restrict
annotation.
Customize Attributes object
The AmsUserInfoProvider
and AmsAuthorizationHandler
also support the request customization going to the PolicyDecisionPoint
(PDP) by providing an AttributeProvider
implementation. The interface and configuration are described here. The two integration points require different context information. This is provided by a set of dynamic arguments available via the method Principal.getDynamicAttributes()
. Constants for the dynamic arguments are defined in the AmsConstants
class.
Toggles and configuration
Here is a list of features and functionalities that can be switched on/off via configuration. The default of the configuration might change over time, or a toggle is deleted.
Generate exists
predicate
By setting the property cds.security.authorization.ams.features.generateExists
to true
, the AMS runtime checks annotated paths for 1..*
associations. If such an association is found in a path, the runtime generates the 'where' clause using the CAP exists predicate.
Help and Support
See the SAP Cloud Identity Services Developer Guide documentation or the documentation of the other AMS client library modules for example jakarta-ams for more information. The sample application could also be useful.
If you have an issue of type "My user has assigned policy X and I expect Y but get Z", please follow these steps:
Activate log
Activate the debug log for com.sap.cloud.security.ams
in your application.yaml
:
logging:
level:
com.sap.cloud.security.ams: DEBUG
com.sap.cloud.security.ams.dcl.capsupport: DEBUG
Make sure to add it to all relevant profiles (for example cloud
, default
). You should now see log entries like:
2025-03-18T14:31:05.926+01:00 WARN 64495 --- [nio-8080-exec-4] c.s.c.s.a.l.PolicyEvaluationSlf4jLogger : Policy evaluation result: {"operation":"dcr._default_.allowPartial","kind":"FILTER","ignores":"[$env, $app]","unknowns":"[$dcl.action]","$dcl.resource":"$SCOPES","$dcl.principal2policies":"[null, mock/admin]","$dcl.tenant":"null","access":"deny","accessResult":"false"}.
- You can check the startup log for:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.4.0)
...
2025-03-18T14:14:24.022+01:00 INFO 64495 --- [ restartedMain] c.s.c.s.impl.runtime.CdsRuntimeImpl : Registered handler class com.sap.cloud.security.ams.capsupport.AmsAuthorizationHandler
...
- Make sure the policy assignments are not overwritten in an
AttributesProcessor
implementation. An indication for this is a log entry like this:
2025-03-18T14:31:05.926+01:00 WARN 64495 --- [nio-8080-exec-4] c.s.c.s.a.l.PolicyEvaluationSlf4jLogger : Policy evaluation result: {"operation":"dcr._default_.allowPartial",...,"$dcl.policies":"["local..."]",...,"access":"deny","accessResult":"false"}.
- If the entity hasn't all attributes, check the Handling of entities where not all AMS attributes are applicable section for possible solutions.