Technical Articles
Deploying a CAP based Fiori app to a central Launchpad – Part2: Add Authentication
Introduction
Recently I posted the following blog.
Deploying a CAP based Fiori app to a central Launchpad
If you follow the steps described there, you can get rid of Approuter, because the central Launchpad does the work of Approuter. After publishing the blog, I received a question asking, “How can we implement authentication and authorization checks for CAP without Approuter?” The answer is, the Launchpad takes care of them too! So why not give it a try?
In this blog, I’m going to add authentication and authorization checks to the app which I have build in my previous blog. The content is available at GitHub.
Steps
- Clone the repository from GitHub
- Add authorizations to CAP service
- Configure xs-app.json
- Install dependencies
- Configure package.json
- Configure xs-security.json (optional)
- Configure mta.yaml
- Build & Deploy
1. Clone the repository from GitHub
1.1. Clone the repository.
//If you deploy to HANA Cloud
git clone https://github.com/miyasuta/central-launchpad-cap.git
//If you deploy to HANA Service (Trial)
git clone -b hana-service https://github.com/miyasuta/central-launchpad-cap.git
1.2. Run the CAP service locally.
npm install
cds watch
2. Add authorizations to CAP service
The scenario is to allow users to view books data created by themselves only.
2.1. Add createdBy field to Books entity in db/data-mode.cds.
namespace my.bookshop;
entity Books {
key ID : Integer;
title : String;
stock : Integer;
createdBy: String @cds.on.insert : $user; //add
}
2.2. Add the same field to db/data/my.bookshop-Books.csv.
ID;title;stock;createdBy
1;Wuthering Heights;100;<your scp userID>
2;Jane Eyre;500;<NOT your scp userID>
2.3. Add the following annotations to srv/cat-service.cds.
using my.bookshop as my from '../db/data-model';
service CatalogService @(requires: 'authenticated-user') {
entity Books as projection on my.Books;
}
annotate CatalogService.Books with @(restrict: [
{ grant: ['READ'], where: 'createdBy = $user'}
]);
At this point, an error occurs at the terminal. I’ll fix this next.
2.4. Install passport.
By installing passport, above error will disappear.
npm install passport
3.Configure xs-app.json
Go to app/fiori/xs-app.json and remove “authenticationType: none” from the CAP service route. By doing so default authentication type “xsuaa” will be applied to this route.
{
"welcomeFile": "/index.html",
"authenticationMethod": "route",
"logout": {
"logoutEndpoint": "/do/logout"
},
"routes": [
{
//"authenticationType": "none", Remove this
"csrfProtection": false,
"source": "^/catalog/",
"destination": "cap-launchpad"
},
{
"source": "^(.*)$",
"target": "$1",
"service": "html5-apps-repo-rt",
"authenticationType": "xsuaa"
}
]
}
4. Install dependencies
Install the following modules for JWT-based authentication.
npm install @sap/xssec @sap/xsenv
5. Configure package.json
Add “uaa” section to package.json.
"cds": {
"requires": {
"db": {
"kind": "sql"
},
"uaa": {
"kind": "xsuaa"
}
}
}
6. Configure xs-security.json (optional)
If there’s a requirement to create new roles, configure xs-security.json like below sample.
In this specific project I don’t need additional roles, so I skip this step.
{
"xsappname": "fiori",
"tenant-mode": "dedicated",
"scopes": [
{
"name": "$XSAPPNAME.admin",
"description": "admin"
},
{
"name": "uaa.user",
"description": "UAA"
}
],
"attributes": [],
"role-templates": [
{
"name": "admin",
"description": "generated",
"scope-references": [
"$XSAPPNAME.admin"
],
"attribute-references": []
},
{
"name": "Token_Exchange",
"description": "UAA",
"scope-references": [
"uaa.user"
]
}
]
}
7. Configure mta.yaml
Add xsuaa service (“uaa_fiori” in this case) as required resource of CAP service and db-deployer.
# --------------------- SERVER MODULE ------------------------
- name: cap-launchpad-srv
# ------------------------------------------------------------
type: nodejs
path: gen/srv
parameters:
memory: 256M
disk-quota: 1024M
requires:
# Resources extracted from CAP configuration
- name: cap-launchpad-db
- name: uaa_fiori //add
provides:
- name: srv-api # required by consumers of CAP services (e.g. approuter)
properties:
srv-url: ${default-url}
# -------------------- SIDECAR MODULE ------------------------
- name: cap-launchpad-db-deployer
# ------------------------------------------------------------
type: hdb
path: gen/db
parameters:
buildpack: nodejs_buildpack
requires:
# 'hana' and 'xsuaa' resources extracted from CAP configuration
- name: cap-launchpad-db
- name: uaa_fiori //add
resources:
...
- name: uaa_fiori
type: org.cloudfoundry.managed-service
parameters:
path: ./xs-security.json
service: xsuaa
service-name: fiori-xsuaa-service
service-plan: application
8. Build & Deploy
8.1. First go to app/fiori folder and install dependency (so that build will not fail).
cd app/fiori
npm install
8.2. Go back to the project root and execute build.
mbt build
8.3. Deploy mtar file to Cloud Foundry.
cf deploy mta_archives/cap-launchpad_1.0.0.mtar
After successful deployment, go to your Launchpad site and execute the app. (I you have not configured your Launchpad yet, please refer to the step 6 of my previous blog).
You will only see the record ID 1, as your user ID is set as createdBy only for this record.
Conclusion
The central Launchpad takes care of authentication and authorization tasks.
The steps to enable authentication and authorization is almost the same as CAP & Approuter project. The only difference would be where you define routes for CAP service: In Approuter approach, you would configure routes in xs-app.json in Approuter, whereas in central Launchpad approach, you configure routes in xs-app.json under html5 application module.
Looks good !!!
Thanks so much for the post and all information!
Those posts help me soo much with my project.
My apps now are deployed in Lauchpad service successfully.
But I have one question.
I realized in MTA file, the resource org.cloudfoundry.managed-service, has the property ForwardAuthToken, and checking in the SAP HELP documentation, the property described is HTML5.ForwardAuthToken.
which one is correct?
And the another problem, is when I add some records in a Entity with "managed" aspect, the user is still filled as anonymous
Hi Savio,
Thanks for your comment. Glad that this blog helped you.
Regarding destination property, you're right. According to the document, HTML5.ForwardAuthToken is the correct one.
About anonymous user issue, please refer to Jodel's blog - OData Context on OData Create Operation section.
It seems that need to use transaction object to set user information to db.
Regards,
Mio
Mio, thanks so much for the information! I realized that the anotation "@(requires: 'authenticated-user') was missing in the cds service. I re-deployed the app with those corrections and worked fine!!!
One more thing. The app ui (html5 module) in MTA doesn't have to be binded with the xsuaa service? Just the server module, the sidecar module and the application content module?
Hi Savio,
Thanks for the update. Your input has helped me implement insert operation to my project.
html5 module doesn’t have to be bound to the xsuaa service, because it is launchpad that takes care of authentication, and html5_repo_host is just a repository for html5 content.
Hi Mio,
thank you for the great second blog (again).
I additionally was having issues with my authentication using
i also had to explicitely define JWT strategy
to get it working with the destinations. I used this only for production, because locally i am using mock strategy with mock users instead.
This issue was introduced with CAP 4.x (it was formerly working with out this setting for me ?!?).
Anyhow, great to have my PoCs running in SAP Cloud Launchpad.
Best Regards
Holger
Hi Mio Yasutake
when we clone your git repo and install npm install... we are getting this error..
Hi Yogananda Muthaiah,
Thanks for letting me know.
There seems to have been issues related to library versions.
I've updated the repo and now it should work.