We have written a custom approach of Integrating SAML login flow with Hybris and Spartacus with the sequence as follows.
Sequence flow :
User gets redirected to IDP (OKTA) since there is no auth
session
User will login on the IDP login page and then the
request gets redirected to Hybris along with SAML assertions
On Hybris end, Hybris will validate these assertions and and will
generate a "Login Token" (Authentication Code) and will redirect to
Spartacus
On Spartacus end, it will Identify if there is a
"LoginToken" and if it exists spartacus will send this LoginToken to
Hybris and Hybris will return the access_token which will then be
set in localStorage of browser.
We have written a customer controller that will take the LoginToken as a parameter and will return the access_token in the response. We have used the below code in Spartacus to implement this and set the access_token in the localStorage on the browser. But the issue is spartacus is sending a token revocation request to Hybris on accessing any of the Spartacus pages and the access_token is being emptied.
**
What is the correct way of setting the access_token in spartacus if we are using a custom controller to generate OAuth ?
Or is there a different approach we should take in generating and persisting the access_token in Spartacus ?**
Code Snippet :
ngOnInit() {
var LoginToken = this.cookies.get('LoginToken');
var authToken= JSON.parse(localStorage.getItem('spartacus⚿⚿auth')).token.access_token;
var mainToken= JSON.parse(localStorage.getItem('spartacus⚿⚿auth'));
console.log('token value '+authToken);
if(!authToken && !LoginToken) {
console.log("Make call to Hybris for OAuth token");
let fetchUrl ='https://localhost:9002/occ/v2/{baseSite}/ssoauthenticate/?client_id=mobile_android';
this.http.post<any>(fetchUrl,"",{withCredentials:true,headers:{"Access-Control-Allow-Origin":"*"}}).subscribe(data => {
console.log(data.value);
mainToken.token.access_token=data.value;
mainToken.token.granted_scopes=data.scope;
mainToken.token.token_type=data.tokenType;
mainToken.token.expires_at=1631632676508;
mainToken.userId="current";
localStorage.setItem('spartacus⚿⚿auth',JSON.stringify(mainToken));
});
}
if(!authToken && LoginToken) {
console.log("Redirect for SSO");
window.location.href="https://localhost:9002/samlsinglesignon/saml/sso/";
}
There is an existing integration module for SAP Customer Data Cloud that implements this pattern (1905 Cloud Extension Pack: https://help.sap.com/viewer/bad9b0b66bac476f8a4a5c4a08e4ab6b/v1905/en-US/4658aaba5ff242ab99f2f89aa1a51ec8.html, 2005 onwards it is in the Integration Extension Pack: https://help.sap.com/viewer/b6a1e8b75222421a8faf0269e8fbd0dc/2102/en-US/f9df5c14bfdf47349dc9b82de84a574f.html)
However what the documents don't really say is: to enable this, there was a change to the OAuth capability to support CustomTokenGranter implementations. The SAP CDC integration then builds on that to provide CDC-specific logic in this area.
You need an OAuth token to access OCC APIs, and that needs to be issued from the SAP Commerce OAuth features. However in the CDC case the login is via automatically generated screensets that all work at the browser level. Broadly: the CDC login process is between the screensets in the browser + the CDC servers, the wrapper components in Spartacus take the output (call it login token if you like) and passes that into the OAuth token request. The CustomTokenGranter implemented in the CDC integration will then verify that token at the backend, so that OAuth can issue the a valid auth token back to Spartacus. Spartacus then uses that token in any OCC API calls, in just the same way that it handles a standard auth token.
There are analogies here to your process with Okta & you could do something similar (in terms of process). In these scenarios you really should have backend integration to your IdP as well ... to validate the tokens server-side & prevent spoofing.
The Spartacus side of this integration is open source, as with the rest of the Spartacus project. You can find the code here: https://github.com/SAP/spartacus/tree/develop/integration-libs/cdc
Related
Consider:
An SPA or a statically generated JAMStack website (written in Vue/Nuxt).
A REST API (Node + Express) running in the cloud.
The website is being served through a CDN.
We are required to add a Social Sign-On functionality for user convenience. The API already authenticates users with a credential based JWT (access/refresh) token flow. Social sign-on will be in addition to that.
We have selected the Authorization Code Flow as the mechanism for this implementation (instead of PKCE, because we want the SPA to use the API's access tokens instead of the authorization provider's).
Our flow is as follows:
The user clicks on a button and is directed to the Identity Provider's (in our case, Google) website to prove its identity. We provide a randomly generated state token as a request parameter to prevent CSRF attacks.
On the IdP's authentication page, the user submits their credentials and if successful, the user is redirected back to our website (the SPA) with the state token and a code as url parameters.
We then match the state value with the one that we generated on our app to defeat CSRF attacks.
We send the code value to our API in an AJAX request.
The API takes this code and our client secret and exchanges them for an identity taken with the identity provider (disregarding the access tokens as we only require proof of identity).
If the user identity is verified, the API generate a pair of access and refresh token and sends them to the SPA. (If the user does not exist in our database, it is added and similarly returned tokens for our API).
NOTE: We do not store the identity token received from the IdP on the server at all.
One receiving the response, the SPA stores the access token in localStorage, (the refresh token is stored in an HTTP only cookie by the API).
All further requests to our API from the SPA are made with the access token issued by our API, once both the refresh token and access tokens expire (through logout or timeout), the user has to re-initiate the authentication flow from step 1.
I have two questions:
Assuming that all communication between the IdP and SPA, the SPA and the API, and the API and the IdP is happening over TLS, are there any security vulnerabilities present in our process?
This one perplexes me more, how do you persist the state token that we generate during the initial request to the authentication server between page redirects? (from when we leave our SPA to authenticate on IdP's webpage to when the IdP redirects us back to our SPA). Is localStorage a secure enough option? If not, would sessionStorage suffice?
For a new project I would consider using the BFF pattern to avoid dealing with tokens at all in the SPA/browser. Because there is no secure way to deal/store tokens in the browser.
Do check out these resources for more details about why this pattern is recommended for new projects:
alert‘OAuth 2 0’; // The impact of XSS on OAuth 2 0 in SPAs
Using the BFF pattern to secure SPA and #Blazor Applications
The BFF Pattern (Backend for Frontend): An Introduction
I'm new to keycloak and would like to check what is the common design on the said architecture.
I have 1 backend(quarkus) 1 frontend (angular) and 1 flutter.
I would like to see if I could leverage the features of client. My idea is to have a separate client within the realm. For example
REALM = MyAppRealm
Client = backend-client and front-endclient
Is it possible that the token i got from front-endclient can be use to access the api from the backend?
Reason I have this setup is that the front-endclient has a public accesstype while the backend has confidential
to sum up. I would like to see if i can reuse the token i got from front-endclient to my backend-client
Yes of course you can do that.
The purpose of openid is to share authentication and authorization between a diversity of clients without needing to share credentials (no password is known by any of the clients). A trusted third party (here Keycloak) will give back a signed token in exchange for credentials. And this token will be a proof of who the user is and what he is allowed to do in the communications between the frontend and backend.
To sum up :
Your angular frontend authenticates an user using a public client and an implicit flow. When successfully authenticated, the frontend obtains an access token and a refresh token.
When making a REST call to the backend, your frontend needs to set the header Authorization using the access token as a bearer token ('Authorization: Bearer insert access token here'). You can automate this by using an interceptor (example)
Finally, when your backend receive an API request it can check the Authorization header to ensure the request is authenticated and authorized. For how to do that with Quarkus, everything is explained in this documentation page : https://quarkus.io/guides/security-openid-connect
I am working on a Web Application in asp.net core 2.2. Web API serves every request coming from Web Application. I am using JWT Token Authentication in Web API. That token goes in every request from web application.
Web APP -----> Web API ----> Data Layer----> EF Core ---->DB
In the login, the user enters email and password on the web interface and hit on login button. The request goes to Web API than to DB passing from all other layers. If the user is valid then in Web API a token is generated and pass it in the response to Web App. Now, in every further request from Web App to Web API, Web-APP sends this token in the header.
Now, I want to add an external authentication provider like Google. Problem is that I am not sure how to handle the flow of my application? Because Google Authentication is just for web application and not affects the functionality of Web API.
Any suggestion?
What you need to do is to delegate user authentication to an external Identity Provider (IdP). In the login screen, you would typically allow users to choose between using email/password or external IdP (e.g. Google, Facebook, etc ...). If a user choose the latter, the "identity verification" step will be taken care by the IdP and then HTTP redirected to you (to a URL that you define) along with an ID token that is digitally signed and contains some user's information (name, email, ...)
The change to the application flow in that case would be as follow:
Web APP -----> Web API ----> Data Layer----> EF Core ---->DB
| ^
v |
Identity Provider (e.g. Google)
Note that the redirection to and from the IdP are generally based on HTTP redirect. In the simple nominal case, you don't need to call the IdP from the Web API layer, although you must define each supported one as a trusted issuer of ID Tokens (required for signature verification)
Step-by-step instructions are generally provided by the IdP, r.f. Google Sign-In and Facebook login
I would suggest you use Identity server 4 as your identity provider .
Your web api will be a resource which protected by Identity server . In your client app, when starting the authentication process , according to authentication flow , user will be redirected to identity server for authentication , user could choose local db user login or external login via Google authentication . If user choose local db , user will enter his credential on identity server's login page and validate the credential in your local db. if credential is correct , then identity server will issue a token and redirect back with token to client app . If user choose external login , user will be redirect to Google's login page for sign in , identity server will issue token after redirecting from Google(get claims from token issued by Google) and redirect back with token to client app .
During the authentication flow , client could set which api resource he want to access , after user consent the permission for accessing the api resource(your web api ) , the issued access token could be used to access your web api .
Identity Server document : http://docs.identityserver.io/en/latest
& Code samples .
We have a Web App using REST API. The REST API is based on Loopback and uses it's built-in token-based authentication. For the Web App we use forms based authentication over HTTPS, so the user has to enter his username and password which we then use to get access token from the REST API via POST /users/login endpoint.
One of our customers asked us to support single sign-on (SSO) authentication through SAML 2.0 and AD FS.
We configured our Web App as a service provider (Relying Party in AD FS) and managed to support SSO for it. The changeling part is the authentication between Web App and the REST API. The idea right now is to configure both Web App and the REST API as the same Relying Party and add new POST /users/saml-login endpoint to the REST API, so the Web App can send a SAML response to that end point and get an access token based on the claims specified in the SAML response. Everything else should work as it used to work before. Here is the flow I imagine:
Web App generates SAML request and redirects a user to the IdP login page
After a successful login the user is redirected back to the Web App with the SAML Response
Web App acts as a proxy and redirects the SAML Response to the REST API endpoint (POST /users/saml-login) where it is validated
If the SAML response is valid the API returns an access token based on the claims
Web App uses access token for further communication with the REST API same as before
Here is the question: Is it OK to implement SAML-based SSO this way? Do you see any issues or security considerations with this approach? Are there any alternatives?
I have read a lot of articles on the web and questions here on StackOverflow about how to use SAML & REST API together:
Propagate SAML Assertion Response/Security Context to downstream Services/Apps
REST API authentication with SAML
SAML and back-end REST service authentication
Attacking SSO: Common SAML Vulnerabilities and Ways to Find Them
None of them really helped me to confirm or reject the idea described above.
That sounds like a reasonable approach. I can't think of any security issues.
You're simply re-posting the SAML response internally within your application for processing. As long as you then perform the various security checks on the SAML response and assertion within your REST API, there shouldn't be any issues.
I have question regarding setup of access token renewal/refresh. Our Setup:
Implicit flow
Angular SPA using bearer token for API
Thin MVC frontend serving cshtml containing SPA
Short access token (10min)
20 min Idsrv cookie sliding (used as activity timeout)
The application has to apply to some strict security rules and intellectual property.
We need to renew the access token before it expires and API returns 401.
I’ve looked at the oidc-client-js to handle that. But that would remove the option of authenticating the static files like we do today, since there would no longer be a cookie for the MVC app.
Is there a way of securing them, or is that just something that we have to accept when building a SPA with OpenID Connect?
If you would like to enforce authorization on static files then this needs to be done by server-side code. Since your client is using an MVC backend, my recommendation would be to use the Hybrid Flow in conjunction with the Katana OpenID Connect middleware. You may then pass on any tokens you would like to use from the server-side code to your SPA via your view (cshtml).
The middleware required is available on NuGet:
install-package Microsoft.Owin.Security.Cookies
install-package Microsoft.Owin.Security.OpenIdConnect
The following snippet allows for configuration in your OWIN pipeline (taken and slightly altered from this tutorial):
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
ClientId = "mvc",
RedirectUri = "https://localhost:44319/",
ResponseType = "code id_token",
Scope = "openid offline_access",
SignInAsAuthenticationType = "Cookies"
});
Using this flow, you are no longer given tokens immediately but will need to exchange the auth code returned ("code" grant type) for a pair of tokens being the:
access_token (the one you are already receiving in implicit flow)
refresh_token (this can be used at the token endpoint to renew the access_token)
The main things to note about the above configuration are response type and scope.
Response type is no longer just asking for tokens (implicit) but now asks for code.
Scope includes "offline_access" scope which will return the refresh_token.
Like this we have solved both your access token expiry problem and have begun to solve your static asset problem by moving authorization to the back-end. To help you with the next part I would need to know how you are serving your assets as there are different ways depending on whether you are using OWIN to serve or IIS.