Background:
I am developing a web application, planned to use spring-mvc and spring security. My plan is to use form based authentication where spring security authenticates credentials and sets a session JSESSIONID so that subsequent requests would be authenticated based on the cookie present in request header.
My understanding:
Web applications requests should have state. This state can be accomplished by using the session.
Purely session based authentication are vulnerable to CSRF attacks. As spring security provides CSRF protection, i didn't find any security loop holes using session + CSRF protection.
access-tokens are only used to give access to APIs which has been exposed for third party applications.
My Question:
But when i see lot of questions in this site, people are using token(OAuth2/JWT) based authentication for web application. But what i believed is tokens are only used to give access to APIs.
But when i see people using tokens for web applications i just got this question. Assuming token based web applications does not uses session but expects token in the header of every request.
When we should go for token based authentication in web application.
As far as security is concerned, which one is good? Session + CSRF or token based authentication.
I am confused with use cases of token and session.
EDIT:
From momo's comment
Most often, it depends on your clients.
For example, for mobile clients (e.g. JSON payload over HTTP), there is no such thing as a Session. JWT has the advantage to work cross-origin. In contrast, a Session-based auth method with Cookies works only for the same (Sub)-domain) and scales not that well.
However, it is easier to invalidate a Session than a JWT. Since you anyway use Spring-MVC and i guess scalability is not critical, just go with the one you are more comfortable.
conclusion: Session supports requests only from same origin, token based authentication preferred for authenticating cross origin requests.
Most often, it depends on your clients. For example, for mobile clients (e.g. JSON payload over HTTP), there is no such thing as a Session.
JWT
JWT has the advantage to work cross-origin over different domains
Therefore, JWT based authentification scale better
very popular in the age of single-page applications (SPA) / Web API's
keep attention to integrity protection by using either a signature or a MAC. Do not allow the unsecured JWTs: {"alg":"none"}
Session
primarily used in conjunction with web browsers
Easier to invalidate (remove) a Session. JWT has only an expiration date and is valid until it expires
keep attention to the following cookie attributes: secure; HttpOnly and to provide some protection against cross-site request forgery attacks: SameSite=Strict or SameSite=Lax
Other approaches:
Open Source Identity Providers like Keycloak with e.g. traefik as load balancer have become quite popular. This brings the advantage, that new routes can go live without restarting any service. Also, in some cases, it saves application downtime caused due to an excessive rate of API calls.
To conclude:
Many roads lead to Rome. It always depends on the specific requirements, the environment and the skills of the team. Since you anyway use Spring MVC and I guess scalability is not critical, just go with the one you are more comfortable..
For Stateless application use JWT
For third party applications use OAuth2
For Statefull application use Session + CSRF
Related
I'm working on an project that implements user authentication through Spring Security using a spring session ID stored in a cookie on the client's browser. There's no authentication server, the same server manages authentication and the whole app as a monolith.
So we are now in the need of implementing SSO with a third party system, so far everything I've read on the matter requires OAuth or some other implementation of token based authentication that supports an external identity provider. I would prefer not to migrate the authentication strategy as we are kinda on the clock.
I work on another project that has OAuth authentication so I'm not new on that topic (though not really an expert either).
Can someone throw some light on this? I just need to know if it is possible or there's no other way to migrate the authentication strategy.
Cookie based SSO is only possible (in an easy way) if you are using a so called 'domain cookie'. Technically all applications need to share the same 'cookie domain' then. However from security point of view this is highly discouraged, due to cookie hijacking being possible.
I'm about to implement user authentication in my app.
Since it is my first Angular + Spring project i would like to know what are the possible options for authentication. I don't wait for detailed instructions, concept level is enough, so that i know where to dig.
I consider two ways of further back-end app development:
REST like;
regular spring MVC, however i don't know how to combine angular and spring in this case. Any suggestions in this regard are also appreciated.
There are various ways to accomplish this. The general idea is that the angular clients adds a credential to every request (typically in the authorization header) which a servlet Filter on the backend verifies before executing the request.
There are various standard ways to accomplish this, ranging from simple HTTP Basic Authentication (which spring security can do easily) to full fledged single sign on protocols like OAuth 2 (and its extension OpenID Connect).
I've heard that jwt has drawbacks, one of them is impossibility to block user until his jwt token is expired, which is pretty important in my case
Not necessarily. JWT is a standard for authentication, not access control. That is, it simply describes a way to identify users, but does not constrain how you make access control decisions. In particular, it is entirely possible that an authorization framework will load user permissions for every request, though doing so may not be its default configuration.
I have a hopefully quick question about Spring Security.
I am looking for a solution to integrate security into our application which provides SSO but HTTP basic as well.
One of the automated pieces of our system can only support basic authentication and we are pretty locked into it. Currently we are targeting to use Kerberos for our SSO solution and then also support basic (for very restricted usage). All of this will protect RESTful web services that run through resteasy.
Does anyone see any inherent impossibilities in this solution of both Kerberos and BASIC chained together in spring security? We had problems with WildFly and undertow not being able to support multiple different authentication methods, that use HTTP response codes in their handshakes.
Thanks for the input
Since this question is a bit tough, I assume you are already familiar with the Spring Security Kerberos samples that show how to configure kerberos auth with a form auth as fallback.
I have no evidence that it'll work but I think you should be able to chain your kerberos auth with basic auth without any problems. I share my thoughts on this...
Thought 1: FilterChains
The trick to support mulitple authentication methods is to set the order of the authentication filters correctly.
If the order is wrong, the client could hang in the basic auth and might never reach the kerberos authentication filter, because the browser's basic auth dialog would pop up. This might depend a bit on how the basic auth provider and filters are implemented in Spring. Anyway, if the order is correct, the filter next in chain after the kerberos filter (the basic auth filter) will start its work.
Thought 2: Kerberos auth shouldn't break basic auth
The browser should treat the communication with the kerberos service provider different to the communication with the basic auth provider, since the protocols are different.
The SAML communication runs in it's own namespace, thus in my opinion it shouldn't affect the basic auth communication which is based on authorization element in the HTTP header.
EDIT: Even if the assumption about the namespace doesn't play any role in the browsers behavior, step 6 in the sequence diagram will be a crucial point. When the filter chaining is correct, Spring should return a 401 response like 401 - Access denied - WWW-authenticate - Basic realm = "your domain" which will force your browser into basic auth.
Thought 3: Spnego Negotiate in Spring Security Kerberos
The Spnego configuration in the Spring Security Kerberos documentation is acutally build upon those thoughts. This can be seen in the samples, too, in line 49 and 50 of this WebSecurityConfig.java
I would be surprised if you experience troubles.
One last thought
If no requirements force you to do a basic auth, I would recommend to not use it. Better stay with a token based authentication. Even if I don't fully agree on all details of this blog it explains why basic auth shouldn't be used, if you can avoid it.
I strongly recommend you read Mika's answer. It is very well done and gave me the confidence to move forward.
Ultimately this worked; but I will explain a couple sticking points I had.
I use Request matcher's to split my calls into different HTTP configuration blocks
In order 1 I configured a block to filter in requests from a specific tool, by user agent. In that block I configured basic authentication in basically the standard OOTB way. I did write and provide my own authentication provider though, this provider called to an underlying system we use to manager our users by username / password.
Then, in order 2, I configured a block to process Kerberos. After wrestling with the Kerberos provider configuration and coming up with a scheme to authenticate in our underlying system, this all processed fine. After getting the username from Kerberos for the domain user connected to my web app, I then checked to see if that username was in my system. If they are, we log them in. If not, we direct them to the login page. (Not every domain user is authorized for our web app, even if they are authenticated)
Then finally, the last block was configured for form authentication.
But there were a few sticking points.
I had to globally configure the authentication manager for both my custom basic/form and the Kerberos provider.
And also as a side note, I did have to configure my authentication manager bean like this link suggests. Probably due to the cobbled together shamble of of xml/java configuration I have created.
IE was also weird. Down my kerberos chain, I also configured a login form. This allowed users who qualified for the chain to navigate directly to the login form to authenticate; or if someone failed my Kerberos username check I could forward them to the login page. This worked fine with FireFox, but IE continues to send the Negotiate header even after my server sent a redirect. Basically the user fails kerberos, gets a redirect to the login page, but IE sends the Kerberos token along still. This causes the SpnegoAuthenticationProcessingFilter from Spring Security to fire again and validate the Kerberos token, of course this fails again, and sends the user the login page which continues the loop.
In summary Spring Security allowed for 3 nice, fairly clean blocks which all do various different authentication / authorization, and then it all works in tandem to provide the same user context object to our web app.
I have a Restful Java Web application which is to be deployed to a number of different environments (outside of my control) which will be using a SAML 2.0 SSO solution.
My application (which I believe is the "service provider") needs to store state generated by the user, and uses internal business logic to work out which users are allowed to view or update other user's data. In order for this to work we need to know who the user is, and what groups the user is part of. But how do I get this information?
Ideally my web app will be SSO agnostic, and would look for some configurable key headers in the http requests to get this information e.g. a SAML token in a request which could be parsed, or perhaps some custom headers specific to my "service provider".
Many Thanks
You are correct, your application is the Service Provider and you will have an external Identity Provider (IdP) to authenticate to.
Basically you need to issue an Authentication Request to the IdP (via either front channel HTTP POST or back channel SOAP/whatever they support) and use the authenticationResponse from the IdP to make your decision on whether they are who they say they are. As a rule you should be able to get the subject principal (ie username) and any group memberships from the authnResponse however exactly how this works will depend on what the IdP is or isn't configured to do.
Before you do this you will need to exchange SAML metadata with the IdP (this is generally part of being registered as a SP with the IdP) which gives both parties things like the public X509 cert for signing and validating requests.
There's a good spring library for SAML SP support, http://docs.spring.io/autorepo/docs/spring-security-saml/1.0.x-SNAPSHOT/reference/htmlsingle
you could run a reverse proxy in front of the Java web application to handle the SSO protocol part and relay user identity information to the application in HTTP headers; for SAML 2.0 there is mod_auth_mellon: https://github.com/UNINETT/mod_auth_mellon
If this is done in Java and running on a webcontainer (Tomcat, JBoss, etc.), then the agent could be implemented as a web authentication (servlet) filter (add into web.xml). The user would be typically derived from the SAML Auth response's <saml:NameID> or from <saml:Attribute> matching the userid attribute (uid,email, etc.). This user should be validated against the web app's identity repository (could be LDAP, database, etc.) and corresponding groups computed. Instead of using arbitrary headers or custom representation for the authenticated user, consider using java Principal (for users and groups) in a Subject.
The filter can then run the rest of the filter chain in a Subject.doAs(). That way, the Subject can be looked up any where in the downstream code using Subject.getSubject().
I have been struggling with this the last couple of days and haven't found a reliable, understandable solution on the web.
I have a web app that is comprised of a rest api and a presentation layer consuming it. Presentation layer has a login form, the data introduced by the user is sent to the REST api which then uses a third party service to authenticate the user. This part I have already set up.
What I want now is to inrtoduce a token-based authentication for every subsequent request so I don't have to send credentials on every request and then authenticate again against the third party service.
So basically, using Spring Security (v. 3.1.3), I am lost as to how to create a reliable, secure token, return it to the requester, then authenticate request based on said token.
Can you point me to the right direction? Or to some example online?
How do you generate the token? How do you return the token to the
client?
How would you send the token in subsequent requests?
How do you set the whole thing up so the first time you can
somehow send the credentials (user/pass) then the subsequent
requests send only the token?
How do you authenticate against the token?
I've seen implementations where token includes some expiryTime. So what happnes after expiryTime is exhausted? The user must login again, even if he's been making requests the whole time? Should I renew the token "behind the scenes"?
Is the server-side REST application stateful or stateless? If stateful, you won't need to do anything special using a regular HTTP Session. Just start using Spring Security and if the client and server are already exchanging session information, your protected API endpoints will work out of the box. The only caveat is if you have CSRF protection enabled, in which case you will need to tweak the client a little bit. Details for this are in the Spring Security documentation.
On the other hand, if the REST application is stateless, you will have to use a token-based approach like you have proposed. See my answer to a similar post for details. If you do choose to follow the steps in that answer, answers to your questions are:
The token has to be generated on the server-side. If you go through the sample code linked to my answer, you will see that I have replaced the default HTTP-session-dependent infrastructure of Spring Security with a cache-based infrastructure. In the session-based implementation, the unique conversation identifier, which is the session ID, is generated by the servlet container, whereas in the custom implementation, the identifier, which is the token, is generated within the application. Specifically, I have used a SecureRandom instance to generate strong tokens.
The token is sent back by the client as an HTTP header. This protects the content over an SSL channel.
The trick is to implement four very simple interfaces from Spring Security. My sample app has full details. The whole process took me less than an hour.
Authentication against the token is done automatically by Spring Security. We simply need to provide an implementation for storing and retrieving tokens, which is straightforward and takes only a few lines of code.
In my sample app I have used an expirable cache with sliding expiration for storing the tokens. If a client keeps sending requests periodically, the server keeps on accessing the cache for the authentication token, thereby keeping the token alive in the cache. Tokens are evicted from the cache only after a period of inactivity equaling or exceeding the cache expiration period.
So overall, a token-based authentication/authorization approach can be easily implemented with Spring Security and leveraging a caching library like EHCACHE.