Why?
Right now the
SAP Cloud Application Programming Model (CAP) is very focused to be deployed either on SAP Cloud Platform Cloud Foundry or SAP HANA. The runtimes in Node.JS and Java are very portable. But for authentication
only the SAP HANA or SAP Cloud Platform Cloud Foundry UAA Service and for persistency only SQLite (for development) and SAP HANA are supported. With some limitations
PostgreSQL is supported in CAP Java.
In this post I want to show that the XSUAA Service is not the only option for authentication. I've also started the project
cap-postgres that does the first little steps to support PostgreSQL with Node.JS beside SQLite and SAP HANA. I hope that the CAP Team get's the option to open up more and support such initiatives. I think the broader the supported environments are, the broader the adoption can be.
How?
I'm quite a fan of the
Azure Active Directory B2C (Azure AD B2C in short). Together with
CONCETO I've implemented it for several SAP customers to have a central Identity Provider (IdP) for their customers. We've used it in combination with SAP Cloud Platform Neo but also for an SAPUI5 App hosted on SAP NetWeaver Java. Here the now also
properly documented SAML2 support using custom policies comes in handy. But let's get into the meat of the matter: how can we use Azure AD B2C to get an authenticated request to a CAP service implementation?
Having a working application as a starting point sounds like a good idea or? So I followed
Quickstart Guide: Set up sign-in for a single-page app using Azure Active Directory B2C. That resulted in a HTML frontend that uses
Microsoft Authentication Library for JavaScript (MSAL.js) for authentication. The JSON Web Token (JWT) received using the authentication is then used to call a backend service implemented in JavaScript using the Node.JS runtime. There the JWT is verified using the npm package
Microsoft Azure Active Directory Passport.js Plug-In.
With that working example in place I've started a fresh CAP project using the command:
cds init cap-azure-ad-b2c --modules db,srv
Following
Getting Started in a Nutshell I've created a simple data model and service serving only a list of books that I've populated with one entry. Using the annotation
@(requires: 'authenticated-user') I've restricted the access to the service as described in User-Specific Restrictions with @requires and @restrict. That restriction can be tested locally by following the CAP Documentation
Mocked Authentication.
My first working
iteration was quite a hack. As the
JSON Web Token (JWT) that is created by Azure AD B2C looks like this:
{
"iss": "https://cswb2b.b2clogin.com/fd18cc3e-9960-4e35-9076-dba588896ff3/v2.0/",
"exp": 1586011467,
"nbf": 1586007867,
"aud": "ac6f2c18-a2c6-4b5f-9148-13abaaf8e5aa",
"sub": "a625892d-353a-4f01-a736-b4436847bfe4",
"name": "unknown",
"given_name": "Gregor",
"family_name": "Wolf",
"tid": "fd18cc3e-9960-4e35-9076-dba588896ff3",
"nonce": "e1446223-967e-45a9-9762-34773b55c808",
"scp": "openid",
"azp": "ac6f2c18-a2c6-4b5f-9148-13abaaf8e5aa",
"ver": "1.0",
"iat": 1586007867
}
The validation failed as no "scope" attribute is provided. This is expected by CAP. Here for comparison the JWT issued by the SAP CP Cloud Foundry or SAP HANA XSUAA:
{
"jti": "eef51d429374461d96b6760fdd55b876",
"ext_attr": {
"enhancer": "XSUAA",
"zdn": "asia"
},
"xs.system.attributes": {
"xs.rolecollections": []
},
"given_name": "Gregor",
"xs.user.attributes": {},
"family_name": "Wolf",
"sub": "26adb6b5-1e16-45b7-85f8-f06041a3a699",
"scope": [
"openid",
"uaa.user"
],
"client_id": "sb-HTML5UserAPIforCF!t128",
"cid": "sb-HTML5UserAPIforCF!t128",
"azp": "sb-HTML5UserAPIforCF!t128",
"grant_type": "authorization_code",
"user_id": "26adb6b5-1e16-45b7-85f8-f06041a3a699",
"origin": "httpstfs.csw.comadfsservicestrust",
"user_name": "Gregor.Wolf@gmail.com",
"email": "Gregor.Wolf@gmail.com",
"auth_time": 1586009488,
"rev_sig": "7ef5522f",
"iat": 1586009489,
"exp": 1586052689,
"iss": "http://asia.localhost:8080/uaa/oauth/token",
"zid": "c5f5acac-a05b-485f-94c6-7854723bcd19",
"aud": [
"sb-HTML5UserAPIforCF!t128",
"uaa",
"openid"
]
}
But some days later
vobu approached me and sent me
pull request. Now only one file in the CAP standard must be patched and this approach even supports now different authorisations using a custom attribute in Azure AD B2C to store the scopes.
Next Steps
I hope that this can be the start of OpenCAP. Open up for different means of authentication, persistence and other services. Open up also like OpenUI5 to allow the usage under a permissive licence outside of the SAP ecosystem. Let's see what we can learn from the talks at the
1st online reCAP conference scheduled for 15th May 2020. Especially "Modularized CAP (e.g. other DBs)" by
marcbecker, Adrian Goerler and
andreas.schoesser seems to be exactly what I'm looking for.
Looking forward for your feedback.