Technical Articles
Mapping of SAML attributes with XSUAA JWT in Cloud Foundry
Introduction
As working with Cloud foundry & Custom Identity Authentication, I come across one scenario where I wanted to get logged in user’s information with some add on attributes [eg. City, Country etc.] from IdP in my application.
Back to Neo environment, we just need to add assertion attributes in IAS which we wanted, then once user authenticated with IdP, we can directly get all attributes in SAML session itself.
But now in CF, The Application router is the entry point for the application The application router triggers the authentication process in UAA. At the time of user authentication process, the container security APIs receive an Authorization: Bearer HTTP header that contains an OAuth access token in the JWT format from the application router.
JSON Web Tokens (JWT) contains header and information (like issuer, expiration time, etc.) and is signed with a private key of the UAA service. JWT transmits information as JSON object. When trying to access the application, the user must get the JWT token from the security API after which the application opens a session for the access.
While digging into it more, I come to know that not all SAML attributes are directly mapped with JWT token, JWT token only contains basic user identification information like name, email, userId etc.
In this blog post I will going to explain step by step on how to get all SAML attributes from custom IdP, which are not available directly in user’s JWT.
Let’s Do it!
Prerequisites
- SAP IAS Tenant Admin
- SCP Cockpit with Security Admin Role
Steps
1) Setup trust between custom IAS & CF Cockpit
Follow steps mentioned in descriptive blog by Murali Shanmugham [Thank you ?]
for configure Trust for your Identity Authentication Service & SCP CF Cockpit.
2) Expose SAML Assertion Attributes in IAS
Go to IAS Tenant admin, Navigate to Applications and choose your desired application and Select Assertion Attributes from Trust Tab.
Add SAML assertion attributes, you wanted in your application to be exposed,
In this example I wanted Groups, Country, City & Employee Number of logged in user from IdP.
3) Set default value for SAML Group Attribute
Set any default value for Group attribute, this group attribute will be assigned to all existing and new registering user in your IdP.
This Group attribute value we need in next Step No. 6 for setting up Role Collection Mapping in SCP Cockpit.
I set value for Group attribute is “SAML_XSUAA_Group”
4) Create a Simple NodeJS app
This app, we will use to demonstrate the user’s authenticated session response using XSUAA JWT
1. Create app.js file & paste below code
var express = require('express');
var app = express();
const request = require('request');
const bodyParser = require('body-parser');
var approuter = require('@sap/approuter');
const jwtDecode = require('jwt-decode');
var ar = new approuter();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(__dirname +'/'));
ar.beforeRequestHandler.use('/jwtdecode', function (req, res, next) {
if (!req.user) {
res.statusCode = 403;
res.end(`Missing JWT Token`);
} else {
res.statusCode = 200;
res.end(`${JSON.stringify(jwtDecode(req.user.token.accessToken))}`);
}
});
ar.start();
// serve app
app.get('/', function(req, res){
res.sendFile('index.html');
console.log('[server] index served');
});
2. Create package.json file & paste below code
{
"name": "userinfo",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js"
},
"author": "Prashant Patil",
"license": "ISC",
"dependencies": {
"@sap/approuter": "6.5.0",
"express": "*",
"jwt-decode": "2.2.0",
"request": "latest"
}
}
3. Create xs-app.json file & paste below code
{
"welcomeFile": "index.html",
"authenticationMethod": "route",
"routes": [
{
"source": "/*",
"localDir": "./",
"authenticationType": "xsuaa"
}
]
}
4. Create xs-security.json file & paste below code
{
"xsappname": "userInfo",
"tenant-mode": "dedicated",
"description": "Security profile of getuserinfo",
"scopes": [
{
"name": "uaa.user",
"description": "UAA"
},
{
"name": "$XSAPPNAME.Display",
"description": "display"
}
],
"attributes": [
{
"name": "Country",
"description": "Country",
"valueType": "s"
},
{
"name": "City",
"description": "City",
"valueType": "string"
},
{
"name": "EmployeeNum",
"description": "EmployeeNum",
"valueType": "int"
},
{
"name": "Groups",
"description": "Groups",
"valueType": "s"
}
],
"role-templates": [
{
"name": "Token_Exchange",
"description": "UAA",
"scope-references": ["uaa.user"]
},
{
"name": "Viewer",
"description": "View all",
"scope-references": ["$XSAPPNAME.Display"],
"attribute-references": ["Country", "City", "EmployeeNum", "Groups"]
}
]
}
Here I have created attributes which I wanted to be mapped with SAML attributes & created role template as “Viewer” & provided attribute references for this role template.
More details about Application Security Descriptor Config can be found here .
5. Create XSUAA Service Instance
XSUAA service instance can be created using SCP Cokpit directly and select xs-security file in Specify Parameter steps
OR
Create using CF command line
cf create-service xsuaa application userinfo-uaa -c xs-security.json
6. Create manifest.yml file & paste below code
---
applications:
- name: user-info
memory: 128M
instances: 1
services:
- userinfo-uaa
Mention xsuaa service instance name which you just created in previous step.
7. Push application to the SCP
cf push user-info
Now if you run application directly,
App URL : https://<Application Route>/jwtdecode.
{
"jti": "******",
"ext_attr": {
"enhancer": "XSUAA",
"zdn": "********"
},
"xs.system.attributes": {
"xs.saml.groups": [],
"xs.rolecollections": []
},
"given_name": "Prashant",
"xs.user.attributes": {},
"family_name": "Patil",
"sub": "********",
"scope": [
"openid",
"uaa.user"
],
"client_id": "********",
"cid": "********",
"azp": "********",
"grant_type": "authorization_code",
"user_id": "*******",
"origin": "********",
"user_name": "P000004",
"email": "******@********.com",
"auth_time": ****,
"rev_sig": "****",
"iat": ****,
"exp": *****,
"iss": "https://********/oauth/token",
"zid": "*****",
"aud": [
"uaa",
"openid"
]
}
You can observe this response only returns some of attributes related to logged in user like given_name, family_name, user_name, email.
Which is not solve our problem & that’s not the only information we wanted, So proceed for Next Step.
5) Map attributes exposed by your IdP to the attributes defined in your xs-security.json
Go to SCP Cockpit and navigate to your deployed application and click on Roles,
Click on “+” to add new Role, Here by default you can Token_Exchange role.
Choose “Role Template” which you created in xs-security file with attributes & Provide Role Name,
In next step, you can see all attributes listed which you mentioned in xs-security.json file, Select source as “Identity Provider” and in values provide same value which is exposed by IdP as Assertion Attributes
In Next step, you can select Role Collection if you created already or just skip and later we can can assign this role to desired role collection. Review and click Finish.
6) Role Collection Mapping for custom IdP in Cockpit
Navigate to subacccount and click on Role Collections under Security menu, and click on ‘+’ to create new Role collection.
Click on your role collection and click Edit to add Role which we created in previous step & Click on Save.
Select your Role Collection & assign default group value which we created in Step 3 and click on Save.
This mapping is for once user logged in using your custom IdP and access you application then this Role collection is assigned to the user id so that user’s JWT token has all SAML attributes which we mapped.
Result
Now access your deployed application,
App URL : https://<Application Route>/jwtdecode.
Response :
{
"jti": "******",
"ext_attr": {
"enhancer": "XSUAA",
"zdn": "********"
},
"xs.system.attributes": {
"xs.saml.groups": [
"SAML_XSUAA_Group"
],
"xs.rolecollections": [
"userinfo"
]
},
"given_name": "Prashant",
"xs.user.attributes": {
"City": [
"Pune"
],
"Country": [
"IN"
],
"EmployeeNum": [
"760"
],
"Groups": [
"SAML_XSUAA_Group"
]
},
"family_name": "Patil",
"sub": "********",
"scope": [
"userInfo!t159.Display",
"openid",
"uaa.user"
],
"client_id": "********",
"cid": "********",
"azp": "********",
"grant_type": "authorization_code",
"user_id": "*******",
"origin": "********",
"user_name": "P000004",
"email": "******@********.com",
"auth_time": ****,
"rev_sig": "****",
"iat": ****,
"exp": *****,
"iss": "https://********/oauth/token",
"zid": "*****",
"aud": [
"uaa",
"userInfo!t159",
"openid",
"sb-userInfo!t159"
]
}
Now finally in this response you can observe all our mapped attributes which we wanted are now getting under key “xs.user.attributes”
Conclusion
With this blog post you learned,
- How to configure Assertion & Default Attributes in IdP
- How to Create & Deploy simple NodeJS app in CF
- How to do Mapping of CF application attributes with attributes exposed by custom IdP
Hope this helps.
**********
Your feedback matters ?!
Prashant Patil
Great work Prashant, keep it up.
Thank you Devoo!
This is a great piece of content and yet helpful. Thank you for sharing this Prashant.
Thank you Nikita!
Hi Prashant
Thank you for sharing this great blog post. I’m wondering if you could help me out with my issue with CF XSUAA services with custom idp and SAP Cloud Integration.
Our app is a multi-tenant application set up with xsuaa and custom idp, it all works perfectly when accessing from browser. Now we need to receiving data from SCI (SAP Cloud Integration), according to their documentation: https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/92dd2a6fdb6045f98d23c828d1567fef.html. The supported methods are basic authentication and Client Certificate Authentication.
For the client credential, it seems xsuaa doesn’t support grant_type “password”, see: https://launchpad.support.sap.com/#/notes/2766354
Could you help to see if there is a solution for this issue?
Cheer
Andrew
Hi Prashant,
thank you for this great description. I've included your example in my demo application HTML5UserAPIforCF which can be deployed by building & deploying the MTA. Then only the creation of the Role to map the Attributes is needed.
Best regards
Gregor
Gregor Wolf : Wow that's great, Thank you.
Exactly what I wanted! Very helpful, thanks
Hi Prashant Patil,
Thanks for the wonderful blog.
I am able to get the SAML attributes. Now I want to use this attributes in another HTML5 applications.
I tried to create destination to deployed app and try to consume that in HTML5, but its giving error like Unauthorized.
Do you have any idea how can I resolve this Unauthorized issue?
Thanks in advance.
Best regards,
Kishan Panara
Hi Kishan,
What is Authentication method for the destination?
Regards,
Prashant
Hi Prashant,
Thank you for the reply.
I tried
Do you have any pointer on this.
Regards,
Kisahn Panara
OAuth2UserTokenExchange should work. Re-verify the credentials & properties of destination.
Any luck? I created a new desination, added a service to xs-app,json and added a service with url but it returnes error 500?
If you are looking to map a custom attribute from IAS to your application, be aware that custom attributes need to be mapped as default attributes per note https://launchpad.support.sap.com/#/notes/3193175
And not as an assertion attribute as described in this blog.
include in xs-security.json "foreign-scope-references": ["user_attributes"]