I have a springboot application which uses usual HTTP basic authentication using spring-security-ldap.
Later I modified it to use Single Sign On (Kerberos) authentication using spring-security-kerberos-core and spring-security-kerberos-web.
Everything is working fine so far.
Now I need to use both mechanisms. The idea is to use SSO for the front-end application, so that users are logged in automatically. And to use HTTP basic (username/password) for REST interface or for testing.
Probably I need to have two entry points (e.g. '/login' for SSO and '/login-userpass' for HTTP basic). Is it a correct approach? Or are there other ways to implement it?
It seems to me a common requirement but I'm not able to find examples of how to implement this.
EDIT:
Actually, it's a duplicated question. And the accepted answer works perfectly.
I have not used Kerberos with Spring, but I have previously implemented an application with both basic, form and CA SSO. However without looking at some code, particularly WebSecurityConfigurerAdapter I can only give general guidlines.
With Spring you need a number of authentication filteres mapped to different URLs, these will intercept the login, do 401 challenge if needed, and then create an unauthenticated Authentication instance. The typical filters are BasicAuthenticationFilter and UsernamePasswordAuthenticationFilter, and you need to find the one for KerBeros.
Later the unauthenticated authentications are give to the AuthenticationProviderManager which find the appropriate AuthenticationProvider to perform the authentication. This is where you do you database query with password hash (potentially SSO callback) and if the user is authenticated you create a new Authentication, typically you would want to extend AbstractAuthenticationToken or select one of the existing authentication. Remember to copy the details for the unauthenticated Authentication.
In Spring 4 AuthenticationProvider are configured using AuthenticationManagerBuilder, this is done in the configure method of WebSecurityConfigurerAdapter which you need to override.
Remember that you can have a single filter and many AuthenticationProviders or many filters and a single AuthenticationProvider, depending on your needs.
The application I have access to at the moment has a single form login, but some additional hidden fields (and stuff in the session), controls which of the 4 available AuthenticationProviders will be responsible for authentication, and different Authentication classes are created based on which provider authenticated the user, so we can restrict some areas of the application to specific Authentication types.
Related
I'm implementing an authentication and authorization mechanism to unify login mechanism's across three different websites using an external identity provider and OAuth2.
The requirements that are causing design implications.
- Users and permissions managed externally to the existing websites in an external identity provider.
- The user should only have to log in once.
- The login screen needs to be embedded in our application rather than using an identity providers.
I'm creating a login web application. I'm not sure which OAuth2 flow to use. I've used the Authorization code flow previously with Spring security, but that seems to need an external identity provider's login form.
Should I use the implicit flow directly from the login site's javascript? How concerned do I need to be that it's not as secure as the code flow.
Do I need to handroll a solution to call an idp's sdk to get tokens and then sling them into http headers for subsequent use by the other domains Presumably CORS will be an issue? I'll need to include the id token for the other domain to know which user it is - is it secure to pass around the id token via the resource user's browser.
thanks for any guidance, as you can tell its a bit of a muddle in my mind!
I have a spring app, which is hidden behind the proxy. App requires authentication on the start screen (log in form). Proxy also requires authentication (basic auth). Let assume that I cannot get rid of proxy.
Obvious idea is to not force users to log in twice (credentials are usualy the same).
However, that would mean, that users would be authenticated with GET request (using basic auth), which seems a bad idea, so I have few questions:
Is it a generally not-so-bad idea to authenticate users during GET request ?
I still try to implement it by my own with spring authentication filters, however I want to ask if this a good approach? For log in form I have my own WebSecurityConfigurerAdapter and also my own endpoint which handles authentication (which basically sets a cookie).
I assume that for my case I would have to have second WebSecurityConfigurerAdapter which will authenticate users through basic auth using authentication filter ?
If yes, is there a way to set ant matchers only once ? Otherwise how I see it, is that I will have to set the request matchers for both Configurations which of course some day may lead to inconsistency ?
We are maintaining two versions of our application from security perspective
1. SAML based spring security
2. Spring and JDBC based application security.
As some of our customers already have SAML IDP (like ADFS and GLUU) which they want us to integrate for SSO and some customer doesn't have SAML IDP.
Is there a way that both configurations can coexist and based on the customer using the application, security is imposed on the user.
For ex: if the request is coming for customer a.myserverhost.com SAML based security configurations are imposed. and if the request is form b.myserverhost.com the other webSeciurityConfig is imposed
Yes, all of this is possible. What I would suggest is implementing your own AuthenticationManager which manages multiple AuthenticationProviders (e.g. SAML, JDBC).
That's where you can insert your conditional logic for choosing the correct provider based on certain criteria.
For inspiration, look at the default implementation ProviderManager.
Out of the box the ProviderManager will iterate over all of your AuthenticationProviders and attempt to authenticate the User. If it doesn't find the User it moves on to the next one. If that's all you need then you don't need any custom implementations.
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 got hand-written security, simple servlet-filter which redirect not-authorized user to their login pages. Login controller redirect them to the requested URL after successfull authentication or their main page. This approach work fine, the only disadvantage, that I have to pass User object which is stored in the HttpSession through stacktrace to EJB beans.
Now I rewrote some code and use Spring-security as http based authentication. It is integrated automatically with Glassfish JAAS.
I don't need to pass User through stacktrace anymore, invocation sessionContext.getCallerPrincipal() is enough. But the principal object return me only userName, not userId, so i have to perform addition select if i need userId for example.
1) Is there anyway to extend Principal object, so it can store more properties ?
2) Why i should use JAAS or Spring Security or another security framework, why not just hand writen servlet filter ?
2) Using a standard security mechanism like JAAS has many advantages:
You can easily change the way user authenticates solely by configuring your server - without need to change anything inside your code.
You can be sure your security is up-to-date, supporting strongest algorithms, storing Principal in a secure manner and so on. Again just by staying up-to-date with your server, framework etc. Having a hand-written security module is prone to errors and to be outdated soon.
You can leverage framework security - eg. web.xml security tags, EJB security annotations. Because JAAS is a standard way to authenticate, you can be sure adopting future technologies will be easier, because all serious technologies will support JAAS (Spring security etc.). If your software is planned to grow, you will definitely need a standard.
It will save you time and effort. JAAS provides both authentication and authorization, neatly packed and configurable within minutes.
I recommend futher reading on J2EE security or you can find more resources in OWASP guides.
1) I don't know if you can extend the class Principal. But note, in your LoginModule, before you finish the authentication calling the commit() (probably in your login() method), it is possible to add credentials in the Subject. For this, just add the object to one of the lists: Subject.getPrivateCredentials() or Subject.getPublicCredentials() (with no arguments). You can add many objects like your own class, a String, or whatever you want.
To retrieve the objects in your application, use the procedure detailed in my other answer.
import javax.security.jacc.PolicyContext;
Subject subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container");