I'm trying to access a REST service via a server-to-server GET request that is secured by OpenSSO/Spring Security and am unable to. It's like my Spring Rest Template client is not stateful to hold the cookies it should as I get redirected through the authentication workflow.
When doing this with a browser, the initial request is redirected to OpenSSO, I'm challenged for my cert (PKI), I present it, get a response with my authentication cookie header. Then I am redirected back to my original destination, I present my auth cookie in the request header and I'm on my way.
This isn't happening in my server-to-server invocations.
I've searched for quite a while now and can't seem to find any solutions that hold onto this state across redirects!
Following the link in zagyi's comment may have worked, but I spent some more time and found the following solution, which does not involve overriding anything:
To handle the authentication cookie in the REST controller, you have to explicitly tell it to accept cookies. Before handling the call, add the following line of code:
CookieHandler.setDefault(new cookieManager(null, CookiePolicy.ACCEPT_ALL));
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.
I'm trying to use Spring Social Facebook login along side form login, more or less following the guide here: http://www.baeldung.com/get-user-in-spring-security, only using header-based session management rather than cookies. Right now the login is successful. Facebook sends a 302 to my server at /api/signin/facebook, and my server sends a 302 to the post-sign-in url I've set on my ProviderSignInController along with the x-auth-token header. The issue is that when following the last redirect my browser throws away the auth token.
I think I want to just add the auth token as a query param on the final redirect uri, but I don't know how to intercept the final response. I've called setSignInInterceptors on my ProviderSignInController but that seems to be ignored after the first sign in. How can I keep my session information when it's not a cookie?
Just added the token as a query parameter and returned it from my custom SignInAdapter.signIn method. I feel like there's probably a better solution but I needed something.
So, I have a WAS Liberty server which configured to work with OpenID provider. Then I have an Angular application which heavily using REST Api endpoint.
When I first open an application or open it after token has been expired everything is ok, WAS redirects me to OpenID provider and then regular flow defined by OpenID and backed by openidConnectClient-1.0 implementation.
But how do I suppose to care about following use case: token has been expired while the application were open, and user issues GET or POST request without reloading the application? Right now WAS perform redirect too, so I can't actually distinguish between regular response and redirect (both return status 200).
The only solution which I think about is to say to Websphere not to perform redirect for some endpoints but to return 401/403 errors. So I'll be able to monitor response codes in my client side and perform accordingly. Is it possible to achieve? Perhaps there's another solution which I didn't know about?
Update: After I've written this I thought about using Authentication Filters, i.e. define something like:
<authFilter id="testFilter">
<webApp id="simple" matchType="contains" name="simple"/>
<requestUrl id="excludeUrl1" matchType="notContain" urlPattern="/basic"/>
<requestUrl id="excludeUrl1" matchType="notContain" urlPattern="/api"/>
</authFilter>
But I immediately see two drawbacks on this approach:
Maintain app's logic in two different places, server.xml and app itself. It'll make maintenance of the application very cumbersome.
Due to nature of Authentication Filters it will fallback to another registry to perform login. It potentially can be a security flaw.
Update 2: Solution from above doesn't work. When server returns 401 Error together with www-authenticate header, browser shows popup of basic authentication, see proposed solution below.
To resolve this issue I've used Angular's Interceptors, where I check if there're following headers within the response: no-cache, no-store, must-revalidate, private, max-age=0. If they persist within the response I know that session expired and perform reloading of my application.
While reloading, liberty itself redirect it to SSO provider. Another solution is to extract redirect URL from response and redirect to it manually.
I have written a REST- API in Java and I have secured this API with Spring Security. The procedure is like this:
Frontend invokes /login RestService in Backend
Backend gives back token to frontend
at each REST- API Backend invokation the token has to be placed in header
This works fine, but I have read that it is also possible (with Node.JS/Passport.js/Express.js) that the session object with the cookie inside can be transfered out of the box without any custom code.
My question now would be if there is a better approach so that the frontend/client do not need to set the token into the header all the time for any request.
Usually token based authentication has advantages over cookie based.
You can achieve this using middle-ware layer
Here is a good Post - https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
Server side, I usually first check in the headers if there is an auth token. If not, I then check in the cookies as a fallback.
If you want to use cookies, then at your step 2, you need to add a Set-Cookie header to the response, so that browsers know they must store a cookie. Once done, no need to add a header client-side, since browsers will send cookies each request. You'll need to add a CSRF protection though (here is a good example).
I have implemented an OAuth2 authentication mechanism in my GWT app. The OAuth2 server is based on Spring framework 3.x (using its Spring security OAuth2 implementation).
I am using the OAuth2 "Authorization code flow" to get the user authenticated (though implicit flow may have been a better choice in our case). So at first, the user is redirected to the OAuth2 server authentication page, he enters his credentials and if he is successfully authenticated, he is redirected back to a url with an oauth code. He will then make a second call to get an access token from the OAuth2 server.
Now, the issue is, we would like the user to be able to bookmark a page in the application and directly access it. If he has already authenticated then he would have direct access to it (no more auth involved). Otherwise, he would have to go into the OAuth2 authentication flow but in the end, should be redirected back to the bookmarked page he intended to access at the beginning.
How can I store this page url and get redirected to it after the user successfully authenticates ?
any help would be appreciated. Thanks!
EDITED
The initial url redirection is done via javascript's document.location.href
The way to maintain the original URI in an OAuth 2.0 Authorization Grant flow is to pass it in the state parameter so that the redirection endpoint can use it, after it exchange the authorization code for an access token, to redirect the user back to that URI.
FYI, this is exactly what Google suggests in the examples in their OAuth 2.0 documentation, e.g. https://developers.google.com/accounts/docs/OAuth2Login
Original answer:
The problem is using the hash part of the URL for the place, which is not sent to the server and thus cannot be used in the redirection to the OAuth2 server authentication page.
You have 2 (maybe 3) solutions:
stop using the hash for the place and switch to HTML5 History; either through gwt-pushstate at the History level, or a custom PlaceHistoryHandler.Historian if you use the Places API. That limits your audience though: http://caniuse.com/history
stop using an HTTP redirect, and instead use JavaScript so you can put the hash in the OAuth2 redirect_uri. So instead of redirecting, send an error page with the appropriate scripts bits.
some browsers append the hash to the URL after a redirection, so your OAuth2 server might be able to pick it (in JavaScript) and append it to the redirect_uri. That might depend on the HTTP status code used for redirecting (from experience, it works with a 301, but you don't want a 301 here). Needs testing.
You can do this using GWT activities and places.