Authentication
This guide is available for Node.js and Java.
Use the toggle in the title bar or press v to switch.
This guide explains how to authenticate CAP services to resolve CAP users.
Pluggable Authentication
In essence, authentication verifies the user's identity and validates the presented claims, such as granted roles and tenant membership. Briefly, authentication ensures who is going to use the service which is technically reflected in a resulting user. In contrast, authorization determines how the user can interact with the application's resources according to the defined access rules. As access control relies on verified claims, authentication is a mandatory prerequisite for authorization.
According to key concept Pluggable Building Blocks, the authentication method can be configured freely. CAP leverages platform services to provide proper authentication strategies to cover all relevant scenarios:
For local development and unit testing, Mock User Authentication is an appropriate built-in authentication feature.
For cloud deployments, in particular deployments for production, CAP provides integration of several identity services out of the box:
- Identity Authentication Service (IAS) provides a full-fledged OpenId Connect compliant, cross-landscape identity management as first choice for applications.
- XS User Authentication and Authorization Service (XSUAA) is an OAuth 2.0-based authorization server to support existing applications and services in the scope of individual BTP landscapes.
- CAP applications can run IAS and XSUAA in hybrid mode to support a smooth migration from XSUAA to IAS.
Mock User Authentication
In non-production profile, by default, CAP creates a security configuration which accepts mock users. As this authentication strategy is a built-in feature which does not require any platform service, it is perfect for unit testing and local development scenarios.
Setup and start a simple sample application:
cds init bookshop --java --add sample && cd ./bookshop
mvn spring-boot:runTip
CAP Java requires certain Maven dependencies to enable authentication middleware support. Platform starter bundles cds-starter-cf and cds-starter-k8s ensure all required dependencies out of the box.
cds init bookshop --nodejs --add sample && cd ./bookshop
cds watchIn the application startup trace you can find a log message indicating mock user configuration is active:
MockUsersSecurityConfig : * Security configuration based on mock users found in active profile. *[cds] - using auth strategy {
kind: 'mocked',
…
}Also notice that the application log contains information about all registered mock users:
MockUsersSecurityConfig : Added mock user {"name":"admin","password":"admin", ...}You should not manually configure authentication for endpoints. As the mock user authentication is active, all (CAP) endpoints are authenticated automatically.
Tip
To simplify the development scenario, you can set cds.security.authentication.mode = "model-relaxed" to deactivate authentication of endpoints derived from unrestricted CDS services.
If you stay with the standard authentication mode, sending the OData request results in a 401 error response from the server, indicating that the anonymous user has been rejected due to missing authentication.
curl http://localhost:8080/odata/v4/CatalogService/Books --verboseThis is the case for all endpoints including the web application page at /index.html.
Mock users require basic authentication, hence sending the same request on behalf of mock user admin (password: admin) returns successfully (HTTP response 200).
curl http://admin:admin@localhost:8080/odata/v4/CatalogService/BooksTip
In non-production profile, endpoints derived from unrestricted CDS services are not authenticated to simplify the development scenario.
Send an OData request through the restricted AdminService as follows:
curl http://localhost:4004/odata/v4/admin/Books --verboseThis results in a 401 error response from the server indicating that the anonymous user has been rejected due to missing authentication. This is true for all endpoints including the web application page at /index.html.
Mock users require basic authentication, hence sending the same request on behalf of mock user alice (no password) returns successfully (HTTP response 200).
curl http://alice:@localhost:4004/odata/v4/admin/BooksInfo
Mock users are deactivated in production profile by default ❗
Preconfigured Mock Users
For convenience, the runtime creates default mock users to cover typical test scenarios, such as privileged users passing all security checks or users that pass authentication but don't have additional claims. The runtime adds the predefined users to custom mock users you define in the application.
You can opt out the preconfigured mock users by setting cds.security.mock.defaultUsers = false.
Customization
You can define custom mock users to simulate any type of end users that will interact with your application at production time. Internally, mock users are represented as CAP users as well. Hence, you can use the mock users, to test your authorization settings or custom handlers, fully decoupled from the actual execution environment.
spring:
config.activate.on-profile: default
cds:
security:
mock:
users:
viewer-user:
tenant: CrazyCars
roles:
- Viewer
attributes:
Country: [GER, FR]
features:
- park"cds": {
"requires": {
"auth": {
"[development]": {
"kind": "mocked",
"users": {
"viewer-user": {
"password": "pass",
"tenant": "CrazyCars",
"roles": ["Viewer"],
"attr": { ... }
}
},
"tenants": {
"name" : "CrazyCars",
"features": [ "cruise", "park" ]
}
}
}
}
}In the mock user configuration you can specify:
- name (mandatory) and tenant
- CAP roles (including pseudo-roles) and attributes affecting authorization
- additional attributes
- feature toggles which influence request processing.
Tip
Define the mock users in development profile only.
To verify the user properties, activate user tracing and send a request using the mock user (such as viewer-user). In the application log you will find information about the resolved user after successful authentication:
MockedUserInfoProvider: Resolved MockedUserInfo [id='mock/viewer-user', name='viewer-user', roles='[Viewer]', attributes='{Country=[GER, FR], tenant=[CrazyCars]}'[basic] - authenticated: { user: 'viewer-user', tenant: 'CrazyCars', features: [ 'cruise', 'park' ] }Automated Testing
Mock users provide an excellent foundation for automated unit tests, which are essential for ensuring application security. The flexibility in defining various types of mock users and the seamless integration into testing code significantly reduces the burden of covering all relevant test combinations.
How to leverage Spring-MVC to use CAP mock users
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class BookServiceOrdersTest {
String BOOKS_URL = "/odata/v4/CatalogService/Books";
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "viewer-user")
public void testViewer() throws Exception {
mockMvc.perform(get(BOOKS_URL)).andExpect(status().isOk());
}
@Test
public void testUnauthorized() throws Exception {
mockMvc.perform(get(BOOKS_URL)).andExpect(status().isUnauthorized());
}
}Tip
Integration tests running in production profile should verify that unauthenticated users cannot access any application endpoints❗
IAS Authentication
Tip
Start new projects with IAS to take advantage of the best integration options. IAS offers a cross-consumption mode that allows IAS users to consume legacy XSUAA services.
SAP Identity Authentication Service (IAS) is the preferred platform service for identity management providing the following features:
- best of breed authentication mechanisms (single sign-on, multi-factor enforcement)
- federation of corporate identity providers (multiple user stores)
- cross-landscape user propagation (including on-premise)
- streamlined SAP and non-SAP system integration (due to OpenId Connect compliance)
You can best configure and test IAS authentication in the Cloud, so let's enhance the previously started bookshop sample application with a deployment descriptor for SAP BTP, Cloud Foundry Runtime (CF).
Get Ready with IAS
Before working with IAS on CF, you need to do all of the following:
Prepare an IAS (test) tenant. If not available yet, you need to create it now.
Establish trust towards your IAS tenant to use it as identity provider for applications in your subaccount.
Ensure your development environment is prepared for deploying on CF, in particular you require a
cfCLI session targeting a CF space in the test subaccount (test withcf target).
You can continue with the sample already created. In the project root folder, execute the following command to make your application ready for deployment to CF.
cds add mtaInfo
Command add mta will enhance the project with cds-starter-cloudfoundry and therefore all dependencies required for security are added transitively.
You also need to configure database support:
cds add hanaAdding IAS
Now the application is ready to be enhanced with IAS-support:
cds add iasThis command automatically adds a service instance named bookshop-ias of type identity (plan: application) and binds the CAP application to it in the mta.yaml.
Generated deployment descriptor for IAS instance and binding
modules:
- name: bookshop-srv
# [...]
requires:
- name: bookshop-ias
parameters:
config:
credential-type: X509_GENERATED
app-identifier: srv
resources:
- name: bookshop-ias
type: org.cloudfoundry.managed-service
parameters:
service: identity
service-name: bookshop-ias
service-plan: application
config:
display-name: bookshopInfo
The binding to service instance of type identity is the trigger to automatically enforce IAS authentication at runtime ❗
The binding provides access to the identity services on behalf of a concrete client. CAP applications can have at most one binding to an IAS instance. Conversely, multiple CAP applications can share the same IAS instance.
Service instance and binding offer the following crucial configuration properties:
| Property | Artifact | Description |
|---|---|---|
name | instance | Name for the IAS application - unique in the tenant |
display-name | instance | Human-readable name for the IAS application as it appears in the Console UI for IAS administrators |
multi-tenant | instance | Specifies application mode: false for single tenant (default), true for multiple subscriber tenants (SAAS) |
credential-type | binding | X509_GENERATED generates a private-key and a signed certificate which is added to IAS application |
app-identifier | binding | Ensures stable subject in generated certificate (required for credential rotation) |
Learn more about IAS service instance and binding configuration.
Now let's pack and deploy the application:
cds upYou can test the status with cf apps on CLI level or in BTP Cockpit, alternatively.
The startup log should confirm the activated IAS authentication:
... : Loaded feature 'IdentityUserInfoProvider' (IAS: bookshop-ias, XSUAA: <none>)[cds] - using auth strategy {
kind: 'ias',
impl: 'node_modules/@sap/cds/lib/srv/middlewares/auth/ias-auth.js'
}Tip
The local setup is still runnable on basis of mock users as there is no IAS binding in the environment.
For mTLS support which is mandatory for IAS, the CAP application has a second route configured with the cert.* domain:
modules:
- name: bookshop-srv
# [...]
parameters:
routes:
- route: "${default-url}"
- route: "${default-host}.cert.${default-domain}"Info
Platform-level TLS termination is provided on CF out of the box via cert.*-domains. By default, the validated certificate is forwarded via HTTP header X-Forwarded-Client-Cert to the CAP endpoint.
Warning
On SAP BTP Kyma Runtime, you might need to adapt configuration parameter cds.security.authentication.clientCertificateHeader to match the header used by the component terminating TLS you configured.
Administrative Console for IAS
In the Administrative Console for Cloud Identity Services you can see and manage the deployed IAS application. You need a user with administrative privileges in the IAS tenant to access the services at <ias-tenant>.accounts400.ondemand.com/admin.
In the Console you can manage the IAS tenant and IAS applications, for example:
- Create (test) users in
Users & Authorizations->User Management. - Deactivate users.
- Configure the authentication strategy (password policies, multifactor authentication, and similar) in
Applications & Resources->Applications(IAS instances listed with their display-name). - Inspect logs in
Monitoring & Reporting->Troubleshooting.
Tip
In BTP Cockpit, service instance bookshop-ias appears as a link that allows direct navigation to the IAS application in the Administrative Console for IAS.
CLI Level Testing
Due to CAP's autoconfiguration, all CAP endpoints are authenticated and expect valid OAuth tokens created for the IAS application.
The following request as anonymous user without a token results in a 401 Unauthorized:
curl https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/CatalogService/Books --verbosecurl https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/catalog/Books --verboseThis is expected. Now let's fetch a token as basis for a fully authenticated test request. For doing so, you need to interact with IAS service which requires an authenticated client itself.
The overall setup with CLI client and the Cloud services is sketched in the diagram:
As IAS requires mTLS-protected channels, client certificates are mandatory for all of the following requests:
- Token request to IAS to fetch a valid IAS token (1)
- Business request to the CAP application presenting the token (2)
- Initial proof token request to IAS - not required for all business requests (3)
As first step add a new client for the IAS application by creating an appropriate service key:
cf create-service-key bookshop-ias bookshop-ias-key \
-c '{"credential-type": "X509_GENERATED"}'The client certificates are presented in the IAS binding and hence can be examined via a service key accordingly.
How to create and retrieve service key credentials
cf service-key bookshop-ias bookshop-ias-key
{
"credentials": {
[...]
"certificate": "-----BEGIN CERTIFICATE----- [...] -----END CERTIFICATE-----",
"clientid": "2a92c297-8603-4157-9aa9-ca758582abcd",
"credential-type": "X509_GENERATED",
"key": "-----BEGIN RSA PRIVATE KEY----- [...] -----END RSA PRIVATE KEY-----",
"url": "https://<tenant-id>.accounts400.ondemand.com",
[...]
}
}Warning
❗ Never share service keys or tokens ❗
From the credentials, you can prepare local files containing the certificate used to initiate the HTTP request.
How to prepare client X.509 certificate files
Copy the public X.509-certificate in property certificate into a file cert-raw.pem and key into a file key-raw.pem, accordingly. Both files need to be post-processed to transform the single-line representation into a standard multi-line representation:
awk '{gsub(/\\n/,"\n")}1' <file-raw>.pem > <file>.pemFinally, ensure correct format of both files with
openssl x509 -in <file>.pem -text -nooutAll the steps can be executed in a single script as shown in the example.
To fetch a token - either as technical or as named user - the request needs to provide the client certificate being send to /oauth2/token endpoint of IAS service with URI given in url property of the binding:
curl --cert cert.pem --key key.pem \
-d "grant_type=client_credentials"\
-d "client_id=<clientid>" \
https://<url>/oauth2/tokencurl --cert cert.pem --key key.pem \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=<clientid>" \
-d "username=<user>" \
-d "password=<URL-encoded pwd>" \
-X POST https://<url>/oauth2/tokenThe request returns with a valid IAS token which is suitable for authentication in the CAP application:
{"access_token":"[...]","token_type":"Bearer","expires_in":3600}The final test request needs to provide the client certificate and the token being send to the application's route with cert.*-domain:
curl --cert cert.pem --key key.pem -H "Authorization: Bearer <access_token>" \
https://<org>-<space>-bookshop-srv.cert.<landscape-domain> \
/odata/v4/CatalogService/Bookscurl --cert cert.pem --key key.pem -H "Authorization: Bearer <access_token>" \
https://<org>-<space>-bookshop-srv.cert.<landscape-domain> \
/odata/v4/catalog/BooksThe response should contain the queried books accordingly (HTTP response code 200).
Don't forget to delete the service key after your tests:
cf delete-service-key bookshop-ias bookshop-ias-keyUI Level Testing
In the UI scenario, adding an Application Router as an ingress proxy to the deployment simplifies testing significantly. It fetches the required IAS tokens when forwarding requests to the backend service.
Enhancing the project with SAP Cloud Portal configuration adds an Application Router component as well as HTML5 Application Repository:
cds add portalThe resulting setup is sketched in the diagram:
To be able to fetch the token, the AppRouter needs a binding to the IAS instance as well. In addition, property forwardAuthCertificates needs to be true to support the mTLS connection with the service backend which is called by the route with the cert-domain.
AppRouter component with IAS binding
- name: bookshop
[...]
requires:
- name: srv-api
group: destinations
properties:
name: srv-api
url: ~{srv-cert-url}
forwardAuthToken: true
forwardAuthCertificates: true
- name: bookshop-ias
parameters:
config:
credential-type: X509_GENERATED
app-identifier: approuterAs the login flow is based on an HTTP redirect between the CAP application and IAS login page, IAS needs to know a valid callback URI that the AppRouter offers out of the box. The same is true for the logout flow.
Redirect URIs for login and logout
- name: bookshop-ias
[...]
parameters:
[...]
config:
[...]
oauth2-configuration:
redirect-uris:
- ~{app-api/app-protocol}://~{app-api/app-uri}/login/callback
post-logout-redirect-uris:
- ~{app-api/app-protocol}://~{app-api/app-uri}/*/logout.htmlNow re-deploy the solution:
cds upTest the application using the URL provided in the Cockpit.
The Application Router should redirect to a login flow where you can enter the credentials of a test user you created before in the Administration Console for IAS.
XSUAA Authentication
Warning
Start new projects with IAS to take advantage of the best integration options. IAS offers a cross-consumption mode that allows IAS users to consume legacy XSUAA services.
SAP Authorization and Trust Management Service (XSUAA) is a platform service for identity and access management which provides:
- authentication mechanisms (single sign-on, multi-factor enforcement)
- federation of corporate identity providers (multiple user stores)
- create and assign access roles
Tip
In contrast to IAS, XSUAA does not allow cross-landscape user propagation out of the box.
You can best configure and test XSUAA authentication in the Cloud, so let's enhance the sample with a deployment descriptor for SAP BTP, Cloud Foundry Runtime (CF).
Get Ready with XSUAA
Before working with XSUAA on CF, you need to ensure your development environment is prepared for deploying to CF. In particular, you require a cf CLI session targeting a CF space in the test subaccount (test with cf target).
If you haven't prepared a sample yet...
You can create a bookshop sample as described in Mock User Authentication.
Execute the following two commands in the project root folder, only if you haven't prepared your sample for IAS in the previous section already.
If there is no deployment descriptor yet, execute the following in the project root folder:
cds add mtaYou also need to configure database support:
cds add hanaFor Java
Command add mta enhances the project with cds-starter-cloudfoundry and therefore adds all dependencies required for security transitively.
Adding XSUAA
Enhance your sample application with XSUAA-support:
cds add xsuaacds add xsuaa --for productionThe command automatically adds a service instance named bookshop-auth of type xsuaa (plan: application) and binds the CAP application to it:
modules:
- name: bookshop-srv
# [...]
requires:
- name: bookshop-auth
resources:
- name: bookshop-auth
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json
config:
xsappname: bookshop-${org}-${space}
tenant-mode: dedicated
role-collections:
- name: 'admin (bookshop ${org}-${space})'
description: 'generated'
role-template-references:
- '$XSAPPNAME.admin'Info
Command cds add xsuaa enhances the project with required binding to service instance identity and therefore activates XSUAA authentication automatically.
CAP applications should have at most one binding to an XSUAA instance. Conversely, multiple CAP applications can share the same XSUAA instance.
Tip
In case your application has multiple XSUAA bindings you need to pin the binding.
There are some mandatory configuration parameters:
| Property | Description |
|---|---|
service-plan | The plan type reflecting various application scenarios. UI applications without API access use plan application. All others should use plan broker. |
path | File system path to the application security descriptor. |
xsappname | A unique application name within the subaccount. All XSUAA artifacts are prefixed with it (wildcard $XSAPPNAME). |
tenant-mode | dedicated is suitable for a single-tenant application. Mode shared is mandatory for a multitenant application. |
Warning
Upgrading the service-plan from type application to broker is not supported. Start with plan broker if you want to provide technical APIs in future.
Learn more about XSUAA application security descriptor configuration syntax.
Security Descriptor
The security descriptor in the xs-security.json file contains XSUAA authorization artifacts. In general, XSUAA artifacts have a hierarchical relationship with role collections as root elements. Role collections can be assigned to end users.
For convenience, when adding the XSUAA facet, these artifacts are initially derived from the CDS model:
- XSUAA scopes: For every CAP role in the CDS model, a dedicated scope is generated with the exact name of the CDS role.
- XSUAA attributes: For every CAP attribute in the CDS model, one attribute is generated.
- XSUAA role templates: For every scope, a dedicated role template with the exact name is generated. The role templates are building blocks for concrete role collections that finally can be assigned to users.
{
"scopes": [
{
"name": "$XSAPPNAME.admin",
"description": "admin"
}
],
"attributes": [],
"role-templates": [
{
"name": "admin",
"description": "generated",
"scope-references": [
"$XSAPPNAME.admin"
],
"attribute-references": []
}
]
}Learn more about XSUAA attributes.Lean more about XSUAA security descriptor.Learn how to setup mTLS for XSUAA.
At runtime, after successful authentication, the scope prefix $XSAPPNAMEis removed by the CAP integration to match the corresponding CAP role.
In the deployment descriptor, the optional property role-collections contains a list of preconfigured role collections. In general, user administrators create role collections manually at runtime. However, if the underlying role template has no reference to an attribute, you can prepare a corresponding role collection for convenience.
In the example, role collection admin (bookshop <org>-<space>) containing the role template admin is defined and can be directly assigned to users.
Tip
You can re-generate the file on model changes via
cds compile srv --to xsuaa > xs-security.jsonConsult Application Security Descriptor Configuration Syntax in the SAP Help documentation for the syntax of the xs-security.json and advanced configuration options.
Tip
If you modify the xs-security.json manually, make sure that the scope names in the file exactly match the role names in the CDS model, as these scope names will be checked at runtime.
Start and Check the Deployment
Now let's pack and deploy the application:
npm install
cds upcds upand wait until the application is up and running. You can test the status with cf apps on CLI level or in BTP Cockpit, alternatively.
Run cf logs bookshop-srv --recent to confirm the activated XSUAA authentication:
... : Loaded feature 'IdentityUserInfoProvider' (IAS: <none>, XSUAA: bookshop-auth)... : "using auth strategy { kind: 'xsuaa' … }Tip
The local setup is still runnable on basis of mock users as there is no IAS binding in the environment.
CLI Level Testing
Due to CAP's autoconfiguration, all CAP endpoints are authenticated automatically and expect valid XSUAA tokens.
The following request as anonymous user without a token results in a 401 Unauthorized:
curl https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/CatalogService/Books --verbosecurl https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/catalog/Books --verboseThis is expected. Now let's fetch an XSUAA token to prepare an authenticated test request. Here, you need to interact with XSUAA service which requires a valid authentication as well.
As first step add a new client for XSUAA by creating an appropriate service key:
cf create-service-key bookshop-auth bookshop-auth-keyYou can inspect the service key credentials as follows:
cf service-key bookshop-auth bookshop-auth-keyThis command prints the information to the console:
{
"credentials": {
[...]
"clientid": "sb-bookshop-...",
"clientsecret": "...",
"url": "https://<org>.authentication.sap.hana.ondemand.com",
[...]
}
}Warning
❗ Never share service keys or tokens ❗
As second step, assign the generated role collection with name admin (bookshop <org>-<space>) to your test user. Follow the instructions from step 4 onwards of Assign Roles in SAP BTP Cockpit Step.
With the credentials, you can send an HTTP request to fetch the token from XSUAA /oauth/token endpoint:
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'grant_type=client_credentials' \
-d 'client_id=<clientid>' \
-d 'client_secret=<clientsecret>' \
<url>/oauth/tokencurl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'grant_type=password' \
-d 'client_id=<clientid>' \
-d 'client_secret=<clientsecret>' \
-d 'username=<username>' \
-d 'password=<userpassword>' \
<url>/oauth/tokenThe request returns with a valid XSUAA token which is suitable to pass authentication in the CAP application:
{"access_token":"<the token>", "token_type":"bearer","expires_in":43199, [...]}With the token for the technical user, you should be able to access endpoints that have no specific role requirements:
curl -H "Authorization: Bearer <access_token>" \
https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/CatalogService/Bookscurl -H "Authorization: Bearer <access_token>" \
https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/catalog/BooksIf you also want to access the AdminService that requires the role admin, you need to fetch the token for the named user instead. That is the user to whom you assigned the admin (bookshop <org>-<space>) role collection.
With the token for the named user, the following request should succeed:
curl -H "Authorization: Bearer <access_token>" \
https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/AdminService/Bookscurl -H "Authorization: Bearer <access_token>" \
https://<org>-<space>-bookshop-srv.<landscape-domain> \
/odata/v4/admin/BooksTip
Try out sending a request to the admin endpoint with the technical user token to see the expected 403 Forbidden response:
{ "error": { "message":"Forbidden","code":"403", … } }Don't forget to delete the service key after your tests:
cf delete-service-key bookshop-auth bookshop-auth-keyUI Level Testing
In the UI scenario, adding an Application Router as an ingress proxy to the deployment simplifies testing significantly. It fetches the required XSUAA tokens when forwarding requests to the backend service.
Enhancing the project with SAP Cloud Portal configuration adds an Application Router component as well as HTML5 Application Repository:
cds add portalThe resulting architecture is very similar to the IAS scenario, but only with XSUAA service instances instead of IAS service instances. There is one more difference: By default, XSUAA does not enforce mTLS.
To be able to fetch the token, the Application Router needs a binding to the XSUAA instance.
AppRouter component with XSUAA binding
modules:
- name: bookshop
type: approuter.nodejs
path: app/router
[...]
requires:
- name: srv-api
group: destinations
properties:
name: srv-api # must be used in xs-app.json as well
url: ~{srv-url}
forwardAuthToken: true
- name: bookshop-auth
[...]
provides:
- name: app-api
properties:
app-protocol: ${protocol}
app-uri: ${default-uri}
url: ${default-url}As the login flow is based on an HTTP redirect between the CAP application and XSUAA login page, XSUAA needs to know a valid callback URI that the Application Router offers out of the box. The same is true for the logout flow.
Redirect URIs for login and logout
- name: bookshop-auth
[...]
parameters:
[...]
config:
[...]
oauth2-configuration:
redirect-uris:
- https://*~{app-api/app-uri}/**
requires:
- name: app-apiNow update the Cloud deployment:
cds upVerify it by running cf apps in the targeted space:
> $ cf apps
name requested state processes routes
bookshop-portal started web:1/1 <org>-<space>-bookshop.<landscape-domain>
bookshop-portal-db-deployer stopped web:0/1
bookshop-portal-srv started web:1/1 <org>-<space>-bookshop-srv.<landscape-domain>Open the route exposed by the bookshop UI application in a new browser session.
Hybrid Authentication
will come soon
Custom Authentication
There are multiple reasons why customization might be required:
- Endpoints for non-business requests often require specific authentication methods (for example, health check, technical services).
- The application is deployed in the context of a service mesh with ingress authentication (for example, Istio).
- The application needs to integrate with a third-party authentication service.
Advanced configuration options allow you to control the behaviour of CAP's authentication behaviour according to your needs:
- For CAP endpoints you are fine to go with the automatic authentication fully derived from the CAP model.
- For custom endpoints that should be protected by the same authentication strategy you are also fine with automatic authentication as CAP will cover these endpoints by default.
- For custom endpoints that should have a different kind of authentication strategy (for example, X.509, basic or none) you can add a security configuration that partially overrules the CAP integration for exactly these endpoints.
- If the authentication is delegated to a different component, just fully overrule CAP authentication and replace it with any suitable strategy.
Secure by Default
By default, CAP authenticates all endpoints of the microservice, including the endpoints which are not served by CAP itself. This is the safe baseline on which minor customization steps can be applied on top.
Ideally, all authentication use-cases should be covered by the generic implementations CAP provides. However, your application's specific requirements may make it necessary to customize authentication. For these scenarios, the CAP Node.js runtime allows to specify an implementation of a custom authentication middleware in cds.requires.auth.impl, by providing a path relative to the project root.
Warning
Be very careful when creating your own auth implementation. This should be a last resort for when every other possible solution (e.g. through modelling or by configuration) has been investigated and dismissed.
Like any other custom middleware, the auth middleware you create needs to accept express's req, res and next and end up by sending a response, throwing an error or calling next(). Additionally, a custom auth middleware in CAP needs to set cds.context.user and, in a multitenant applications, cds.context.tenant.
module.exports = function custom_auth (req, res, next) {
// do your custom authentication
cds.context.user = new cds.User({
id: '<user-id>',
roles: ['<role-a>', '<role-b>'],
attr: {
<user-attribute-a>: '<value>',
<user-attribute-b>: '<value>'
}
})
cds.context.tenant = '<tenant>'
}Tip
In case you want to customize the cds.context.user, check out this example.
Automatic Authentication
As the auto-configuration authenticates all service endpoints found in the CDS model by default, you don't need to explicitly activate authentication for these endpoints.
Endpoints that should be public can be explicitly annotated with pseudo-role any:
service BooksService @(requires: 'any') {
@readonly entity Books @(requires: 'any') {...}
entity Reviews {...}
entity Orders @(requires: 'Customer') {...}
}| Path | Authenticated ? |
|---|---|
/BooksService and /BooksService/$metadata | ✗ |
/BooksService/Books | ✗ |
/BooksService/Reviews | ✓ |
/BooksService/Orders | ✓ |
Tip
In multitenant applications, anonymous requests to public endpoints are missing the tenant information and hence this gap needs to be filled by custom code.
By default, if a CAP service MyService is authenticated, also /MyService/$metadata is authenticated.
With cds.security.authentication.authenticateMetadataEndpoints: false you can switch off this behaviour on a global level.
Automatic authentication enforcement can be disabled via feature flag cds.requires.auth.restrict_all_services: false, or by using mocked authentication explicitly in production.
Overrule Partially
If you want to explicitly define the authentication for specific endpoints, you can add an additional Spring security configuration on top overriding the default configuration given by CAP:
@Configuration
@EnableWebSecurity
public class CustomSecurityConfig {
@Bean
@Order(1) // needs to have higher priority than CAP security config
public SecurityFilterChain customFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher(AntPathRequestMatcher.antMatcher("/public/**"))
.csrf(c -> c.disable()) // don't insist on csrf tokens in put, post etc.
.authorizeHttpRequests(r -> r.anyRequest().permitAll())
.build();
}
}Due to the custom configuration, all URLs matching /public/** are opened for public access in this example.
Ensure your custom configuration has higher priority than CAP's default security configuration by decorating the bean with a low order.
Warning
Be cautious with the configuration of the HttpSecurity instance in your custom configuration. Make sure that only the intended endpoints are affected.
Learn more about overruling Spring security configuration.
Overrule Fully
In services meshes such as Istio the authentication is usually fully delegated to a central ingress gateway and the internal communication with the services is protected by a secure channel:
Tip
User propagation should be done by forwarding the request token in Authorization-header accordingly. This will make standard CAP authorization work properly.
Warning
If you switch off CAP authentication, make sure that the internal communication channels are secured by the given infrastructure.
`cds.security.authentication.mode="never"`. Pitfalls
Don't miss to configure security middleware. Endpoints of (CAP) applications deployed on SAP BTP are, by default, accessible from the public network. Without security middleware configured, CDS services are exposed to the public.
Don't rely on Application Router authentication. Application Router as a frontend proxy does not shield the backend from incoming traffic. Therefore, you must secure the backend independently.
Don't deviate from security defaults. Only when absolutely necessary should experts make the decision to add modifications or replace parts of the standard authentication mechanisms.
Don't forget to add authentication tests to ensure properly configured security in your deployed application that rejects unauthenticated requests.
Warning
Without security middleware configured, CDS services are exposed to public. Basic configuration of an authentication strategy is mandatory to protect your CAP application.