sharing the principal object received from an oauth2 provider between spring and angular - spring

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.

Related

How does spring basic authentication works for subsequent requests after login via basic authentication

I am implementing REST services using springMVC. Now i have added basic authentication entry point in my spring security file. But i don`t know that, Once user authenticated by passing credentials in Authorization header does he need to pass those credentials for all subsequent requests?
for example,
I have two URLs:
1) localhost/apppName/login
// Here user passes credentials in Authorization header. So, user authenticated successfully.
2) localhost/appName/getUsers/1
//Here, client need to pass those credentials in Authorization header?
if it is needed, then why spring kept prinicpal object in the SecurityContextHoder after authentication done via BasicAuthenitcationEntryPoint?
Clients of this services can be any thing like Android, java, .Net
Any suggestions will be appreciated.
Pure REST is stateless, which means that no client context is being stored on the server between requests. That means you need to send the Authorization header for each request.
You don't need to hit the login URL when using Basic auth, that's the point.
However, you can use sessions in combination with Basic auth, and in that case you should pass session cookie between requests. It may have some performance advantage, but generally I would not recommend it.

How to protect REST API when using AJAX?

There are SNS application with 2 servers. Web backend server and REST API server.
The web server allows user login/logout with username/password, and show user information
The REST API server provides APIs like /topics, /comments, it should be stateless without session
The REST API will serve other web applications
There are some potential solutions, but neither is security.
Base Auth, the browser hold the username/password
Token with expiry timestamp, the problem is user could stay on the page until token expires
So, is there a way to protect the REST API when calling it from AJAX?
If I have understood your problem correctly I may suggest you use the Token solution. In order to maintain security you may generate new token on every request (& send it to client in response), which should be used to make next request, and disable token if it is once used or has expired.
Sorry, I meant to mention it as a comment, but I don't have enough reputation.

In GWT: how to bookmark a page and be able to be redirected to it after authentication?

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.

Spring template connect to OpenSSO/JAAS secure endpoint

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));

Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"

Disclaimer: I'm new to the REST school of thought, and I'm trying to wrap my mind around it.
So, I'm reading this page, Common REST Mistakes, and I've found I'm completely baffled by the section on sessions being irrelevant. This is what the page says:
There should be no need for a client
to "login" or "start a connection."
HTTP authentication is done
automatically on every message. Client
applications are consumers of
resources, not services. Therefore
there is nothing to log in to! Let's
say that you are booking a flight on a
REST web service. You don't create a
new "session" connection to the
service. Rather you ask the "itinerary
creator object" to create you a new
itinerary. You can start filling in
the blanks but then get some totally
different component elsewhere on the
web to fill in some other blanks.
There is no session so there is no
problem of migrating session state
between clients. There is also no
issue of "session affinity" in the
server (though there are still load
balancing issues to continue).
Okay, I get that HTTP authentication is done automatically on every message - but how? Is the username/password sent with every request? Doesn't that just increase attack surface area? I feel like I'm missing part of the puzzle.
Would it be bad to have a REST service, say, /session, that accepts a GET request, where you'd pass in a username/password as part of the request, and returns a session token if the authentication was successful, that could be then passed along with subsequent requests? Does that make sense from a REST point of view, or is that missing the point?
To be RESTful, each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP.
Okay, I get that HTTP authentication
is done automatically on every message
- but how?
Yes, the username and password is sent with every request. The common methods to do so are basic access authentication and digest access authentication. And yes, an eavesdropper can capture the user's credentials. One would thus encrypt all data sent and received using Transport Layer Security (TLS).
Would it be bad to have a REST
service, say, /session, that accepts a
GET request, where you'd pass in a
username/password as part of the
request, and returns a session token
if the authentication was successful,
that could be then passed along with
subsequent requests? Does that make
sense from a REST point of view, or is
that missing the point?
This would not be RESTful since it carries state but it is however quite common since it's a convenience for users; a user does not have to login each time.
What you describe in a "session token" is commonly referred to as a login cookie. For instance, if you try to login to your Yahoo! account there's a checkbox that says "keep me logged in for 2 weeks". This is essentially saying (in your words) "keep my session token alive for 2 weeks if I login successfully." Web browsers will send such login cookies (and possibly others) with each HTTP request you ask it to make for you.
It is not uncommon for a REST service to require authentication for every HTTP request. For example, Amazon S3 requires that every request have a signature that is derived from the user credentials, the exact request to perform, and the current time. This signature is easy to calculate on the client side, can be quickly verified by the server, and is of limited use to an attacker who intercepts it (since it is based on the current time).
Many people don't understand REST principales very clearly, using a session token doesn't mean always you're stateful, the reason to send username/password with each request is only for authentication and the same for sending a token (generated by login process) just to decide if the client has permission to request data or not, you only violate REST convetions when you use weither username/password or session tokens to decide what data to show !
instead you have to use them only for athentication (to show data or not to show data)
in your case i say YES this is RESTy, but try avoiding using native php sessions in your REST API and start generating your own hashed tokens that expire in determined periode of time!
No, it doesn't miss the point. Google's ClientLogin works in exactly this way with the notable exception that the client is instructed to go to the "/session" using a HTTP 401 response. But this doesn't create a session, it only creates a way for clients to (temporarily) authenticate themselves without passing the credentials in the clear, and for the server to control the validity of these temporary credentials as it sees fit.
Okay, I get that HTTP authentication
is done automatically on every message
- but how?
"Authorization:" HTTP header send by client. Either basic (plain text) or digest.
Would it be bad to have a REST
service, say, /session, that accepts a
GET request, where you'd pass in a
username/password as part of the
request, and returns a session token
if the authentication was successful,
that could be then passed along with
subsequent requests? Does that make
sense from a REST point of view, or is
that missing the point?
The whole idea of session is to make stateful applications using stateless protocol (HTTP) and dumb client (web browser), by maintaining the state on server's side. One of the REST principles is "Every resource is uniquely addressable using a universal syntax for use in hypermedia links". Session variables are something that cannot be accessed via URI. Truly RESTful application would maintain state on client's side, sending all the necessary variables over by HTTP, preferably in the URI.
Example: search with pagination. You'd have URL in form
http://server/search/urlencoded-search-terms/page_num
It's has a lot in common with bookmarkable URLs
I think your suggestion is OK, if you want to control the client session life time. I think that RESTful architecture encourages you to develop stateless applications. As #2pence wrote "each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP" .
However, not always that is the case, sometimes the application needs to tell when client logs-in or logs-out and to maintain resources such as locks or licenses based on this information. See my follow up question for an example of such case.

Resources