Technical Articles
Appendix D: Using SAML with Kapsel
Here are a few terms that are used with SAML.
An identity provider (IdP) maintains a directory of users and provides authentication.
A service provider is the web site or service that is being accessed.
A user is the person who has an account with the identity provider.
When a user starts a Kapsel app that has been configured to use SAML, the SMP or SAP Cloud Platform Mobile Services server will send a request to the app to redirect to the identity provider if it does not have a valid token. Once the identity provider validates the user, a SAML token is returned that grants the application access for a certain length of time. If the SAML token is compromised it is only valid for a limited length of time against a specific application. Multiple applications can use the same identity provider so multiple applications can use the same user name and password, X.509 certificate or perhaps even a biometric like a fingerprint.
For additional details on SAML see the following links.
Enabling Secure Onboarding Using SAML
SAML 101 Video
Enabling Secure Onboarding Using SAML
Authenticate Applications Using SAML 2.0
Default Identity Federation with SAP ID Service
SAP Cloud Platform Identity Authentication Service Blueprint
Authenticate Applications Using SAML 2.0
The following sections demonstrate using SAML in a Kapsel app.
Registering using SAML with SAP Cloud Platform Mobile Services
Client Certificates and SAML
Handling Session Timeout
Offline Considerations
Known Issues
Registering using SAML with SAP Cloud Platform Mobile Services
The following steps demonstrate how to configure the Logon example to use SAML as the authentication provider for the application.
- Using the SAP Cloud Platform Mobile Services cockpit, modify the Security Configuration of the application com.kapsel.gs from Basic to Form.
Form indicates SAML should be used. The identity provider for the SAP Cloud Platform Mobile Services trial server is
https://accounts.sap.com/saml2/idp/sso/accounts.sap.com
and it requests your SAP Community credentials.
- On the Backend tab, delete the SSO provider and add a new Basic Authentication provider but this time specify the user name and password required to access the OData service.
https://sapes4.sapdevcenter.com/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT. - Modify the context variable in LogonDemo\www\serverContext.js to indicate that SAML should be used by adding.
"auth": [ { "type": "saml2.web.post", "config": { "saml2.web.post.authchallengeheader.name": "com.sap.cloud.security.login", "saml2.web.post.finish.endpoint.uri": "/SAMLAuthLauncher", "saml2.web.post.finish.endpoint.redirectparam": "finishEndpointParam" } } ],
- Add the settings plugin so that the user name of the authenticated user can be queried.
cordova plugin add kapsel-plugin-settings --searchpath %KAPSEL_HOME%/plugins or cordova plugin add kapsel-plugin-settings --searchpath $KAPSEL_HOME/plugins
- Modify the index.html file and add the following button.
<button onclick="sap.Settings.getConfigProperty(function(value) {alert(value)}, errorCallback, 'UserName')">Get User Name</button>
- Prepare, build and deploy the app with the following command.
cordova run android or cordova run ios or cordova run windows -- --archs=x64
Note, if the Remember me checkbox is checked, a cookie will be set that will remain valid for three months so the user name and password will not need to be re-entered.
Client Certificates and SAML
Android
If the SAML IdP presents the client with a certificate challenge the following screens will appear to allow the user to register with an installed certificate.
This screen will appear if the user has not configured a PIN or password on their device.
If you do not wish the user to see this screen, handling of client certificate challenges can be disabled by the following setting in the config.xml.
<preference name="SAPKapselHandleX509Challenges" value="false" />
iOS
Note that certificates installed on the system store (Settings > General > Profiles & Device Management) on iOS are not available to the app. For further information see Making Certificates and Keys Available To Your App. One technique to get a certificate into the apps keychain is to use a Mobile Device Management software such as SAP Afaria or Mobile Iron to provision the user certificate into the shared keychain.
Another technique where the certificate is loaded by one app and its keychain is shared with another app is demonstrated in the OAuth section.
If there are no certificates in the shared keychain the certificate dialog will not appear.
If there is only one certificate and the following method is called in the deviceready event, the certificate will be used automatically.
sap.AuthProxy.setAutoSelectCertificateConfig(successCB, errorCB, true);
If there are multiple certificates in the shared keychain the user will be prompted to select one.
Windows
On windows, if you do not wish the app to use a client certificate, remove the Shared User Certificates capability as shown below.
Handling Session Timeout
Note, the following information applies to SP14 and previous versions. In SP15, the Kapsel plugins were updated to automatically handle the expiration of a session.
A session is maintained between the client and the SMP or SAP Cloud Platform Mobile Services server. By default, it times out after 20 minutes of inactivity. See also Authentication and Handling Session Timeout.
When the application starts an attempt is made to refresh the session. This behavior can be disabled via the setting refreshSAMLSessionOnResume which is discussed further in the Offline Considerations.
If the WebView makes a request such as to open a page proxied through the SAP Cloud Platform Mobile Services server and the session has timed out, the WebView is redirected to the IdP to refresh the session. The original requested page is then shown after the redirect.
To simulate this add the following code to index.html.
function logout() { updateStatus2("Calling logout"); var sUrl = "https://" + applicationContext.registrationContext.serverHost + ":" + applicationContext.registrationContext.serverPort + "/mobileservices/sessions/logout"; var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { console.log(xmlhttp.responseText); if (xmlhttp.readyState == 4) { updateStatus2("Successfully Logged Out"); console.log("SUCCESS " + xmlhttp.responseText + " " + xmlhttp.status) } } xmlhttp.open("POST", sUrl, true); xmlhttp.setRequestHeader("Content-Type", "application/json"); xmlhttp.send(); } function openProxiedURL() { var sUrl = "https://" + applicationContext.registrationContext.serverHost + ":" + applicationContext.registrationContext.serverPort + "/" + appId; window.open(sUrl, "_self"); }
Then near the bottom of the index.html file add the following two buttons.
<button onclick="logout()">Logout</button> <button onclick="openProxiedURL()">Open Proxied URL</button>
Modify the config.xml and add the following line which enables the WebView to be navigated to a new URL.
<allow-navigation href="*" />
Deploy and run the modified app. Notice that it is now possible to end the session between the app and the SAP Cloud Platform Mobile Services server by pressing the Logout button. If a request is then made to open a proxied URL, the SAP Cloud Platform Mobile Services server directs the app to the IdP to first get a SAML session. Note, the session between the app and the SAP Cloud Platform Mobile Services server can also be terminated by removing the app from memory.
If the request is made with an XMLHttpRequest or with datajs, extra code is required to detect that the session has expired and needs to be refreshed.
Try pressing Logout and then Read. Notice that an HTML page was returned rather than an ODATA result.
Add the below code to the top of the errorCallback method to handle this case.
function errorCallback(e) { if (e.hasOwnProperty("response")) { if (e.response.hasOwnProperty("headers")) { if (e.response.headers.hasOwnProperty("com.sap.cloud.security.login")) { alert("SAML session has expired. Please retry the operation after the session has been re-established."); sap.Logon.performSAMLAuth(function () {}, errorCallback); return; } } }
Note, a handler could also be added with the below code. The method mySAMLHandler would be called whenever the app receives a response that includes the com.sap.cloud.security.login header.
function mySAMLHandler(calledURL) { //TODO display error, call performSAMLAuth } sap.AuthProxy.setSAMLChallengeHandler(function() {}, function() {}, mySAMLHandler, context.auth[0].config);
Offline Considerations
Note, the following information applies to SP14 and previous versions. In SP15, the Kapsel plugins were updated to automatically handle the expiration of a session.
When the application starts an attempt is made to refresh the SAML token. For an offline app that opens when there is no network connectivity this request will fail.
LogonJSView: error sending initial SAML request{"errorCode":-1,"description":"Unknown Error. Details : Unable to resolve host \"hcpms-i826567trial.hanatrial.ondemand.com\": No address associated with hostname."}
To disable this refresh attempt on startup, add the following value to the serverContext.js file.
"refreshSAMLSessionOnResume": "skip", //skip, always(default)
This indicates that after the initial registration, it is up to the application to renew the SAML session. Before this setting takes effect, you may need to unregister and re-register if a previous registration exists.
Known Issues
If you are using a custom identity provider, it is recommended to use a POST binding rather than a REDIRECT binding.
Rather confusing title. Appendix to what is this? And where are A-C? If it's part of the blog series then kindly mention this in the first sentence.
Thanks for the feedback. I added a link back to the first part of the blog series at the top in addition to the existing one at the bottom.
Regards,
Dan van Leeuwen
Hi,
Thanks for this blog post .. very helpful hints.
I was wondering if there is any good tutorial on using oauth with kapsel applications. Is there any blog describing how to implement this?
Best Regards,
Edmund Hupf
It is on my todo list. Hope to get to it early next week.
Regards,
Dan van Leeuwen
It is now published at https://blogs.sap.com/2017/02/22/appendix-f-using-oauth-with-kapsel/
Hi,
thank you for your blog post!
Is it possible to use SAML without HCP as a service provider?
best regards
Ines Grawinkel
I believe you could change the IDP used by the SAP Cloud Platform Mobile Services server (HCP) but I think the SAP Cloud Platform Mobile Services server is required.
Regards,
Dan van Leeuwen
Hello Daniel,
Thanks for your Kapsel blog, very helpful.
I have a related issue on HCPms (Mobile Service for Development and Operations into SAP Cloud Platform).
Is it possible to remove HCPms sessions from the Kapsel App, just in a similar way you do in the function logout() of your sample?
Trying "logoutPage": "<path to logout page>" into neo-app.json does not seem to work.
I'm using SAP Business ByDesign as backend of my Kapsel App. Also provide a Form in order to login into ByD with a specific ByD User. This is working fine, the problem is in the logout. I didn't fine the way to remove the ByD session created by the form, so even I try to login again, the old session still continue.
Here is the problem description post (just in case):
https://blogs.sap.com/2017/03/13/how-to-login-to-an-sap-business-bydesign-system-with-javascript/
Thanks in advance and regards,
Óscar Espinar Lázaro
Hello,
I've opened a new post here:
https://answers.sap.com/questions/258800/kapsel-backend-sessions.html?childToView=258853#answer-258853
Thanks so much and regards,
Óscar
Hi Daniel,
Thanks a lot for this blog!
I followed step-by-step and now I have SAML authentication using ADFS, which is great. I have one last thing that I couldn't find regarding SSO propagation. Basically, I have a SAP Cloud Connector with some Gateway endpoints and I tried to set up as "Destinations" at SCP and also Mobile Service for Development and Operations. I tried to configure two types of Destinations: Cloud Platform Destination (it worked with basic and harcoded credentials) and Mobile Destination (not possible because when I added the url it says “Invalid URL. Only ‘http://’ is allowed for OnPremise Destination”). I wondering what's the proper configuration to set up the Destinations in order to propagate the SAML auth as a SSO to the backend endpoint.
Thanks again
Emi
Proxy type setting of OnPremise indicates that the URL is a virtual URL that points to a Cloud Connector. So, if the URL you are pointing at is not available on the internet, then you could use the SAP Cloud Connector to connect from you SAP Cloud Platform Mobile Services to your on premise system. See also https://blogs.sap.com/2017/05/24/appendix-i-sap-cloud-connector/#
Regards,
Dan van Leeuwen
Hi Daniel,
Last question: do you have any tip or post regarding how to call a mobile services' API/Destination using SAML auth from the app?
I tried using Postman to get Application Connection ID or fetch X-CSRF-Token in the registration API but it always responses the IDP (ADFS in my case). I found AppID and the token debuging the app but I cannot call the API/Destinations sending X-CSRF-Token as header in the app or with Postman. I get a 401 error. The OData Application Destination Test works perfect with the same user that I'm triying within the app. Thanks!
Hi Daniel,
Maybe i'm looking over it, but when using SAML for the login, using your "register()" function, will trigger the SCP login page, but afterwards, I stay on the "Loading..." screen because I don't see in which success function it returns the context.
Do we need to use another login method for SAML insead of following one?
Regards,
Hans
I recreated the project and was not able to reproduce the problem. I used an Android emulator. Perhaps double check that you have changed the authentication tab to use SAML in your application and have added the auth parameter in your serverContext.js file.
If it would help, message me directly and I can share the project.
Regards,
Dan van Leeuwen
it appeared that there was an issue in saml2.js (in the errorListener).
Because we’re using windows, following code was missing in the error Listener.
because I had an issue, I never saw what it was, but now this is also fixed.
But If you would like to follow me also, so I can send you some additional questions, that would be very helpfull 🙂
Regards,
Hans
Hi Daniel,
We are getting login page again m again of ADFS-SAML2. without enabling remember me option,is there any way we can achieve it.
BR,
Saurabh
Hi Daniel Van Leeuwen ,
I know this is a really old post and I'm aware that Fiori Client will be unsupported by SAP after the end of 2024. But i have one question...
Can the auth proxy SAML plugin functionality be used by a Fiori Client that is not using SAP BTP Mobile Services? i.e. in the appConfig.js file fioriURLIsSMP = false so the Fiori Client goes direct to the BTP Fiori Launchpad, the same as a desktop browser user does.
I would like to have some automatic handling of requests that occur after the 20 min timeout so that the user's session is refreshed automatically and the request the user did is automatically sent after the session refresh so the user does not lose anything. Just like happens when using Mobile Services (fioriURLIsSMP = true).
We are also planning how we will run our Fiori Launchpad/UI5 apps on mobile devices once Fiori Client is gone (Mobile Start isn't an option for all of our users due to us needing certain hardware related plugins - but I guess Mobile Start would handle session reconnection automatically?). Is there any good link from SAP on how to manually code the logic to do what I've asked above? Your link in your blog to "Authentication and Handling Session Timeout." no longer works, probably due to it being very old, not sure if that would have helped.
Thanks,
Brendan