We are working on an existing application where web services (tomcat) as well as UI (nginx) applications are hosted on separate containers. One of the service application is used for sending login request (SAML request) to identity provider (ping). Here are the steps for user login to the system:
User loads the application (domain URL: https://ui.domain.com), it loads the UI where it checks for logged in user (JWT token string generated for user/role) on local storage and when not found, it redirects to ping (IDP) for authentication.
Once authenticated with ping, it calls the spring controller which is configured for the success URL on service application (https://api.domain.com/auth-service/auth).
This controller service (/auth), gets the SAML response sent by ping and processes it further to get user details and generates the JWT token for the user and redirects the user to UI (https://ui.domain.com).
Problem Statement:
To pass the token to UI, the JWT token string is added to URL by using
redirectAttributes.addAttribute(“auth-token”, token);
With the above, it shows up in the address bar like: https://ui.domain.com/?auth-token=
This has raised a concern with respect to security as the token is displayed on address bar and exposed which can be decoded to get user information.
Current Approach (tried):
Before redirection from controller to UI, tried to set cookie
Cookie cookie = new Cookie(“auth-token”, token);
cookie.setMaxAge(-1);
cookie.setPath(“https://ui.domain.com”);
response.addCookie(cookie);
However we couldn’t find the cookie from UI.
We tried to set it to response header too.
response.addHeader(“auth-token”, token);
Since it is a redirection, the adding to response doesn’t help.
Further trials:
We are also putting a thought about changing the approach of authentication controls where after ping authentication is done, the success URL can be replaced with UI url rather than service URL, i.e.
Current: saml.sso.default-success-url= https://api.domain.com/auth-service/auth
Proposed: saml.sso.default-success-url= https://ui.domain.com/
With the above, the SAML response supposed to go directly to UI (after ping authentication is successful).
However we couldn’t get the response in UI and it also behaves like ping is doing a redirection to UI and due to the same reason, UI doesn’t get it.
Any ideas and suggestions over this would be great.
Related
I have stumbled upon a problem with Spring Security and Angular.
On my BE (Spring Boot application), there are defined OAuth2 providers, such as Google, GitHub and Facebook.
My BE works fine with this providers, since I can authenticate on the desired providers.
The problem is when I try to send the principal object to the FE (Angular 6 application).
I get undefined value when i try to subscribe the value from the rest endpoint.
I assume this is due to the Spring Servlet creating a new thread for the login request.
I am doing my login request from the Angular app.
I did watch dozens of tutorials and rad so many articles, but I just can't find the answer. If it's possible for you to share some code on how it is done, or give me a link, since for sure I am making a silly mistake and can't seem to find the answer here.
Thanks for understanding, have a good day.
:)
I am assuming that you are using the Authorization Code flow from your BE to authenticate the user that interacts with your FE Angular application (you in your example). Otherwise, you would be trying to authenticate the BE Client with the Client flow and you wouldn't need to return the "principal object" to the FE application. If my assumptions are correct... read on.
The Authorization Code flow goes as follows:
1) The user somehow selects an Authentication provider (ex: Google) and that selection is returned to some endpoint in the BE as a non-authenticated request..
2) The BE Client receives this request, preferably intercepted by a filter and, since the request is not authenticatedd, redirects the browser to the selected auth provider's authorization endpoint.
3) The user then proceed to authenticate against that provider which, upon succesfull authentication, returns a response that redirects the browser to a BE Client endpoint. That redirect holds a parameter that provides a code that the BE Client will use to get an idToken representing the user. At this point, it is important to note that the browser has not been returned any response for this redirect.
4) The BE Client then proceeds to send a regular HTTP request to the provider's token endpoint along with the received authorization code. The provider then returns the idToken an HTTP response directly to the BE Client. All this is happening while the browser is still waiting for the response to the last redirect.
5) The BE Client then process the idToken (verification, validation, user details, session etc) and only then, will finally send the response to the browser patiently waiting since the code redirect. That response may provide a header or a cookie with a sessionId or token (your choice) that the FE application will be able to read or use for the given purpose.
This flow is relatively easy to implement and requires minimal SS configuration. You must keep the BE Client auth endpoint with permitAll() otherwise, you would not be able to trigger this flow. Also, make sure that, once the FE app. has received the header/cookie, all subsequent calls shall be processed as "authenticated calls". Finally, make sure to document yourself on the perils of stateless sessions as well as cookie security and always use HTTPS.
Jake.
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¶m2=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.
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.
I am running spring web application in broswer. I logged in to my account and update some value using a url say localhost:80/update/name. On the controller side I check principal==null if not redirect to login page.
Now while login to this application. I open other web application page in the same browser and execute the same update url localhost:80/update/name through ajax call and it is updating the value. How can i avoid this security threat.
How can i make sure that Application1 update url will be executed by application1 request only? Application2 should not be allowed to execute app1's update request no matter whether it is in same browser ?
Why are you surprised ? You are logged, thus the browser has a valid session cookie. You ask the browser to send a request to the host (be it in first window or any other window, it is the same) : it sends the request with all relevant cookies, including session cookie and if appropriate any other security cookie. The server receives a request containing a valid session cookie for a valid logged user and even if it controls IP addressed coming from same address : all is valid and it proceeds with the request.
If you have a different browser on your client machine and if you open the connection from this unrelated browser, the server should reject your request, because the browser would not present a valid cookie.
You are describing a variant of cross-site request forgery, you should enable Spring Security CSRF protection. You can read about it in the reference manual.
Even if the two applications are on the same server, they will get different CSRF tokens, which will protect your case.
You described Cross-Site request forgery attack. Typically when POST method is used hidden token is added to prevent it. I assume You are using GET method - It is good practice to not change any state using GET method.
I am trying to authenticate a user and getting the user to authorize my application. But, whenever the user authenticates with the system, the redirect url never return back to my application.
In the console output i get the following information message:
INFO: Unable to retrieve OAuth2.0 handler for redirect request tohttps://localhost:8443/sbt.sample.web/service/oauth20_cb. Please check you are accessing the application using the same hostname used in the OAuth 2.0 redirect URI.
Please find below the code:
// Check if user is authenticated, if not redirect to SmartCloud for authentication.
ep= EndpointFactory.getEndpoint("connectionsOA2");
if(!ep.isAuthenticationValid())
{
// Check, Do we have a valid token for this user
ep.authenticate(false);// Authenticate
return; // Exit, JSP would be invoked from Callback handler
}
I am not able to figure out what is the problem. Any help is highly appreciated.
generally the warning comes from the following:
User logs in to
http://localhost:8080/sbt.sample.web/
or
http://qs.renovations.com:8443/sbt.sample.web
or
http://localhost:8080/my.project
The app redirects to Connections
User Logs in to Connections
Connections redirects to https://localhost:8443/sbt.sample.web/service/oauth20_cb
1 the components in the URL are not the same as the initiator of the OAuth session
2 uses a different port or different hostname
The request was initiated on one URL and the response was redirected to another.