User goes back to authorization URI when authenticated with Spring Security OAuth2 Login - spring-boot

I'm using Spring Security OAuth2 Login to authenticated users with Facebook account. Everything works well. However, I have an issue, when a user logs in successfully and clicks back button and opens Facebook authorization URI for a second time (https://www.facebook.com/v2.8/dialog/oauth). It again redirects to callback URL /login/oauth2/code/facebook with a new code, but this time authentication fails. Oauth2 Login failure handler gets called and redirects to default failure URL. Here is the exception
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [authorization_request_not_found]
Therefore the issue is that the second authentication was not initiated by security oauth2 code and it doesn't expect this second callback. Any idea how this can be solved? Is it possible to ignore this second callback? Ideally the second authentication should also be successful.

My solution to this problem was to open the authorization URL (/oauth2/authorization/facebook) in a pop-up window with JavaScript. The pop-up window would respond to the parent window with JavaScript postMessage.

Related

Keycloak not logging out the Identity provider after calling the /logout endpoint

I'm trying to use Keycloak (13.0.1) as an identity broker. I have an iOS app that uses keycloak to log in via an OIDC identity provider, and then use the token to access a spring-boot backend.
My issue is that I simply can't get the keycloak logout to also log the user out of the Identity Provider session.
I've spent days googling this and looking at both stackoverflow and the keycloak discourse page and git repo, but I couldn't find an answer to my specific issue.
Using the postman to test, the first time I click "Get New Access Token":
It successfully redirects me to the identity provider login page (I use the keycloak hint to bypass the initial keycloak login page). Pressing the button again will skip the IDP login and give me the token directly. How convenient, or so I thought...
The problem is that when I use keycloak's /logout endpoint to invalidate the refresh token:
And it successfully returns 204, when I click "Get new access token" again, it skips the login form and gives me the token directly, so there is effectively no way to logout the user and then login with a different user. The only way to bypass this is to manually click the "clear all cookies" button.
Here is my IDP configuration:
Also note that, in the keycloak admin guied it is specified that keycloak should be logging out of the IDPs when a logout is triggered, so it doesn't seem like I should be making any special configs:
https://www.keycloak.org/docs/latest/server_admin/#identity-broker-logout
IMPORTANT EDIT:
I marked this question as solved and the solution is correct, but I also needed to turn off the IDP "backchannel logout", because our corporate SSO doesn't like it. Keycloak seems to be able to log out regardless.
It successfully redirects me to the identity provider login page
That redirect is the key. It opens a browser, where Keycloak cookie is created - that is your IdP session. You have to open Keycloak /logout endpoint in the same browser, so Keycloak can clear own Keycloak cookies.
Summary: you have to open/redirect (API call doesn't work) user to the same browser to the logout endpoint (API call doesn't work) as you have used for the login. Of course this may not be case for some special flows, but it should be working for standard Authorization Code (with/without PKCE).

SpringBoot 2 SSO with OAM using SAML2

I am working on a web application of tech stack contains front end ReactJS and backend SpringBoot 2 Microservices. Now it's time for the SSO integration **(single sign on) using the OAM(Oracle Access Manager) using SAML2 **.
I had a discussion with OAM Team and they had given me below details
Entity ID or Issuer ID
OAM Entry Point or OAM SSO URL
X509 Certificate
Assertion consumer URL (ACS URL) which i had given to them to receive SAML Response
online i could find few SSO option with SSOCIRCLE, OKTA, ONEIDENTITY etc but couldn't find any resources with Springboot2 + SSO + OAM.
Please throw some lights or any response on how to start would be greatly appreciated.
You can start with OAM installation:
https://docs.oracle.com/en/middleware/idm/access-manager/12.2.1.4/tutorial-oam-install-oam/
Refer to the following link to understand deployment and usage in application:
https://docs.oracle.com/en/middleware/idm/access-manager/12.2.1.4/tutorial-oam-protect-wlsapp/#deploy-a-sample-application-to-weblogic-server
You have to integrate below flows
Login flow: From your web application (frontend) redirect to the Federation system endpoint (get their login endpoint), this is a browser redirect. Here 2 types of configurations options are available- Either you send the xml Metadata to them when you redirect to their portal OR
These configurations can be set at OAM manually and you only have to do a simple browser redirect. (I have tried the 2nd option).
User enters the credentials in Federation page which gets authenticated by IdP and after successful authentication the SP is notified on ACS login url. So your login url will be basically a callback url which will be called by them and they will be sending a SAML response on that callback api. Once you get a notification on your callback you need to redirect the user to your portal.
For this your callback url should set http response status code as 302 and response.headers.location as the endpoint (along with saml response) where you want the user to redirect. Take care of validating saml signature before redirecting user to your portal.
On your frontend code, you will have to check for the SAML response with windows.location.search.
These steps will redirect user back to SP portal.
Logout flow: when user clicks on SP logout button, execute your logout api and then redirect user to Federation System's logout url, browser redirection, in this case User's session will also terminate at their(SAML) end and they redirect user to SP portal.
Ensure that user's sessions (both) are in sync. For this keep idle timeout and max session timeout same at both ends.
Hope this helps.

SAMLException: InResponseToField of the Response doesn't correspond to sent message

We are working on an application, which is protected with spring security saml.
Authentication works fine, but there is one problem with the following workflow in production environment.
user requests the unprotected address www.server.com
response is a html page with an inline script that changes window.location.href to the saml protected page (service provider) www.server.com/app/action?param1=value1&param2=value2
spring saml detects that authentication is needed and redirects the user to the login form (identity provider) on www.login-server.com
at this point the login form is the first page that is displayed to the user
user adds this login page as bookmark (including saml related url params for this http session) www.login-server.com/adfs/ls/?SAMLRequest=xxx&SigAlg=xxx&Signature=arGdsZwJtHzTDjQP1oYqbjNO
user works with the application...
at the next day the user opens this bookmark and login
IdP redirects to the SP but the belonging http session has already expired
Now we get the following exception in our application:
org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message arGdsZwJtHzTDjQP1oYqbjNO
Any ideas how to handle this workflow so the user can use the application after successful login?
Thanks for your answers!
We have solved our issue with following changes to the spring saml configuration:
In bean with id successRedirectHandler (org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler) we set the defaultTargetUrl to the init-Action of our application (including all request parameters). This url will be automatically used in case of IdP initiated SSO.
In Bean with id contextProvider (org.springframework.security.saml.context.SAMLContextProviderLB) we set storageFactory to org.springframework.security.saml.storage.EmptyStorageFactory. This disables the check of the InResponseToField.
When you applicate generated an AuthnRequest, the request has an ID which your application somehow keeps. The corresponding response from IdP must have InResponseTo attribute set to that same ID value so that your application can verify that the response is meant to be for the request it sent.
However, when your user bookmarked the adfs link that contains request (www.login-server.com/adfs/ls/?SAMLRequest=xxx...), your application had totally forgotten about that request. In other word, it no longer kept the request ID somewhere and couldn't verify response.
The solution is to tell your users not to bookmark the www.login-server.com/adfs/ls/?SAMLRequest=xxx... link. Instead, they must bookmark a link in your application where it can generate a new request and send to ADFS.

OAuth2 Implicit flow vs 'Traditional' session based auth for small SPA

Some background:
I am writing a small SPA that will use a back end that I have also written. The JS and the back end API are on the same server.
i.e. SPA will load from foo.com, back end is at foo.com/api
In the past I have always used Spring Security with simple form based login. After logging in the user will get a session cookie. Pretty standard stuff.
For this app I looked into OAuth2 implicit flow. My understanding is the User would load my page, then from the SPA I would direct the user to the authorization endpoint so my app could get a token. The user would be redirected from the authorization endpoint to a login form. After the user authenticated with the form.. they would be redirected back to the authorization endpoint to get the token and possibly grant access to the JS client. After that the user would be redirected to a URL specified by the client, with the new access token as a URL fragment.
I have this working and its all great. The part I don't quite get is this:
When the user is redirected to the login form and they authenticate a session is created on the server that has to at least last long enough for the user to be redirected to the authorization endpoint to get the token. At that point they already have an authenticated session on my server, why not just stop there and use traditional cookie and session based logins?

Issue token to logged in user via spring

I have a Spring (3.2) based web app that a user can log into. The site will also provide an API secured via OAuth 2.0. My question then, is how do I go about generating a token for a logged in user?
The underlying idea here is that there will be a mobile app that opens up a web frame to the login page, which will eventually redirect to a url schema with an oauth token that the app will catch and then use for the api calls. Looking at the code for TokenEndpoint, I see that it defers token creation to a list of TokenGranter types. Should I be creating my own TokenGranter extended class, or am I looking at this all wrong?
I ended up writing a controller like this:
OAuthClientRequest request = OAuthClientRequest
.authorizationLocation(csOauthAuthorizeUrl)
.setClientId(csClientId)
.setRedirectURI(
UrlLocator.getBaseUrlBuilder().addSubpath(AUTH_CODE_HANDLER_URL).asUnEscapedString())
.setResponseType("code")
.buildQueryMessage();
UrlUtils.temporarilyRedirect(httpResponse, request.getLocationUri());
return null;
Then handling the code returned. My big problem here was that I had the /oauth/authorize endpoint set to use client credentials. Once I realized that tokens were being issued for the client ID instead of the user, it started to make sense.
So you want to use the Authorization Flow of OAuth. Spring has already support that, if you have configured the spring-security-oauth correctly, you just have to redirect the user/your mobile apps to /oauth/authorize?client_id=xxx&response_type=code this will redirect user to authorization page, if user has not login yet, it will redirect the user to login page then to the authorization page.
After the user completed the authorization process, it will redirect the user to an already registered redirect_url parameter with the authorization_code 'yourapp.com/callback?code=xxxx'.
Your application should exchange this authorization_code with the real token access to /oauth/token?grant_type=authorization_code&code=xxxx&client_id=xxxx&client_secret=xxxx
After that you will receive the token access that can be used to access the resource server.

Resources