in my project, I m using request.getUserPrincipal() to check whether user is logged in or not, but I am confused where to set the instance as logged in user?
and i also notice that request.getUserPrincipal().getName() return user login id .
Finally I found where is the place we set our own db user details to the spring security Principal, we have a class which implemented spring security AuthenticationProvider interface , and inside public Authentication authenticate(Authentication authentication) method, we set the value from USER_TB to Spring security UserDetails object. I am still investagating, spring security is a big part to learn
Related
I am new to Spring Security. I have a Spring Boot application with two different types of entities. Customers and employees. In Employees I have normal employees, admins and super users. Since I am using JPA, each entity has its own repository. How to model my UserDetailsService with loadUserByUsername since this is a common method to validate against many repositories. Is there anything that I am missing to model around my entities?
Additional Info:
In my design, I have two entities. Customer and Employee. Employee will have roles like NORMAL, ADMIN and SUPER_USER. Customer is a different entity.
Will there be two UserDetailsService and two AuthenticationProvider each pointing to its own table (Customer and Employee)?
As your requirement is to have multiple authentication entry points it is not as simple as Atul's answer.
What you need is
You need to differentiate customer and employee while logging in. (Preferred way radio button)
You need to implement your custom authentication filter i.e, implementation of UsernamePasswordAuthenticationFilter instead of spring-security provided default .formLogin()
Create two UsernamePasswordAuthenticationToken as EmployeeUsernamePasswordAuthenticationToken and CustomerUsernamePasswordAuthenticationToken
In your custom filter get userType from request and based on userType set authToken as empAuthToken or customerAuthToken to differentiate required authentication provider.
Create AuthenticationProvider as EmployeeCustomAuthenticationProvider and CustomerCustomAuthenticationProvider where each AuthenticationProvider should be overridden supports method where AuthenticationProvider supports specific token either customerAuthToken or employeeAuthToken.
Override authenticate method where authenticate method has been passed with Authentication parameter from which you can get both username and password which you can pass to any of you custom service to authenticate user and grant authorities required for user.
While implementing your CustomAuthenticationFilter it is also required to provide your custom authenticationSuccessHandler and AuthenticationFailureHandlers.
If you implement all above without any mistake you can avoid fallback authentication which spring-security provides by default if two customAuthenticationProviders are configured.
For more detail of implementing multiple authentication entry point using java configuration refer my answer given below
Multiple AuthenticationProvider with different UsernamePasswordAuthToken to authenticate different login forms without fallback authentication
and also you can download working code from my github repository
"Will there be two UserDetailsService and two AuthenticationProvider each pointing to its own table (Customer and Employee)?" ..... The answer is yes.
Spring security has filter, UsernamePasswordAuthenticationFilter (check the name of the filter)where you can implement the specific implementation based on input type.
I did the same thing but for different auth mechanisms.
But as per your requirement, it is possible what your looking for.
I have a Keycloak connector that allows me to retrieve the user's username through SSO. I want to use this username to authenticate the user and to look up his authorities in a database and inject this user authority in spring security to be able to use its functionalities.
I've created a custom authenticationProvider with a custom UserDetailsService and the problem I keep facing is that I get redirected every time to spring security login page. I think when it sees that there is no authentication object in the request it does it by its own.
This is the code to retrieve the username. I feel like I have most of the pieces but I don't know how to inject it in spring security or at least all the ideas I had until now wouldn't work. This is why I hope to find someone who's an expert in Spring security who would point me in the right direction.
Thanks in advance
KeycloakSecurityContext sc = (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
IDToken idToken=sc.getIdToken();
String userId=idToken.getPreferredUsername();
This is what i ended up doing, i created a CustomAuthenticationFilter extends GenericFilterBean that i placed in the filter chain through SecurityConfig extends WebSecurityConfigurerAdapter , inside this filter in the doFilter method i retrieve the username and create a UsernamePasswordAuthenticationToken that is then added to the SecurityContext from which i retrieve the username in a CustomAuthenticationProvider that creates the authentication by calling a database and retrieving the roles.
I have a Spring REST-API which is secured by SpringSecurity.
I have different ways to authenticate in that application.
Customer (db)
Employees (ldap)
Other Applications/Services (inMemory)
Each of these are covered by a different authentication provider, which properly assigns the access roles. (Works)
However I need to know which authentication provider was used to authenticate the user, so I can write it to the logs, history...
User CUSTOMER/max.pain created a new entry.
And of course the username does not really contain that prefix, neither in the db, nor in ldap.
I considered adding a special role based on the authentication provider used, but extracting that information over and over is annoying and probably has bad performance and might cause problems in the future. (user.getGrantedAuthorities().findStartingWith("AP_"))
I also tried using org.springframework.security.config.annotation.SecurityConfigurerAdapter.addObjectPostProcessor(ObjectPostProcessor<?>) but i cannot use it to wrap the AuthenticationProvider with a custom AuthenticationProvider class, because it requires the use the same class for whatever reason.
Is there an inbuild method I could use to achieve that or do I have to use a custom implementation/configuration?
Prozess steps:
Login: EMPLOYEE/always.calm
Don't check CUSTOMER AuthenticationProvider
Check EMPLOYEE AuthenticationProvider
Don't check SERVICE AuthenticationProvider
authentication.getPrincipal().getAP() = EMPLOYEE
I have a basic login workflow with Spring Security in a Web application: The user logs in via a form which is eventually handled by the application logic in a UserDetailsService called from the DaoAuthenticationProvider with a token created by the UsernamePasswordAuthenticationFilter.
However, in some cases (decided at runtime via a user preference), I'd like to have an additional authentication step after that (basically two factor authentication). I tried adding another filter like so
<custom-filter ref="twoFactorAuthFilter" after="FORM_LOGIN_FILTER"/>
but this filter is never invoked if form login succeeds. My plan was to create a special TwoFactorAuthenticationToken that can be accepted by a TwoFactorAuthenticationProvider but as the filter is not invoked, my new authentication provider isn't either. I want the whole security chain to abort if the login credentials are wrong but continue traversing it if they are correct and continue to the (optional) next step.
Is it possible to do it how I want without rewriting the the existing UsernamePasswordAuthenticationFilter? I feel like this must be quite easy because Spring usually is pretty extensible but I have been fighting with this for many days now and have not yet had any success.
What you want is to have two filters: one for userNamePasswordFilter and one for your tokenFilter. In case your user has two-factor auth enabled, your userDetailsService for daoAuthenticationProvider should grant him only an instance of SimpleGrantedAuthority with a role "ROLE_PRE_AUTH" for example. The access to tokenFilter should be provided only to users with this role - "ROLE_PRE_AUTH" and that filter should attempt authentication on your secondary token and proceed to grant the user his actual authorities (USER, ADMIN, etc) from tokenProvider.
The way to display that additional pop-up form is, again, to check if the user's role is "ROLE_PRE_AUTH".
You just need to extend DaoAuthenticationProvider and override additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) with your after login authentication logic.
public CustomDaoAuthenticationProvider extends DaoAuthenticationProvider {
public additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
super.additionalAuthenticationChecks(userDetails, authentication);
// Your Logic Here
}
}
EDIT
May be I misunderstood your problem because you mentioned "Logic". Anyway this post shows a elegant solution to your problem.
I was able to integrate Spring Boot and Spring Security SAML by using the #ImportResource annotation.
Now, I'd like to go on as follows:
the user selects an IdP [DONE].
it performs the login (successful) [DONE].
the SP obtains user data (by parsing the SAMLCredential object) [DONE].
the webapp had to check if the userID (e.g email) retrieved via SAML exists in my own DB.
a) If yes, the webapp reads from the DB the role and sets related privileges.
b) If no, the webapp had to perform a redirect to a sign-up page, in order to insert the user into the system.
Make it sense perform the points 4 and 5 by using a UserDetailsService implementation or have I to setup the security context defining authentication providers, filters, etc?
You should implement org.springframework.security.saml.userdetails.SAMLUserDetailsService and plug it into the samlAuthenticationProvider bean. In case user doesn't exist you should throw UsernameNotFoundException exception, otherwise just populate and return data from your DB.
On top of that you should implement your own org.springframework.security.web.authentication.AuthenticationFailureHandler and plug it into samlWebSSOProcessingFilter bean. This implementation will be called with the UsernameNotFoundException sent as a parameter and you can then redirect the user to the correct sign-up page as a reaction to it.