Spring Security with Custom AuthenticationProvider Custom UserDetails and Custom Security Context - java

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.

Related

Spring Security user authentication against customers and employee

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.

Spring SwitchUserFilter with Active Directory authentication

I have set up authentication with Active Directory like this:
AuthenticationProvider activeDirectoryAuthenticationProvider(UserDetailsContextMapper userDetailsContextMapper) {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
"company.local",
"ldap://active-directory-dc:389");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper);
return provider;
I would like to use SwitchUserFilter for users impersonation. However, I can see only method SwitchUserFilter#setUserDetailsService to set up authentication object and it's not possible to pass AuthenticationProvider to the filter. Alternatively, I don't know if (and how) is possible to use UserDetailsService for authentication with Active Directory.
I solved the problem by implementing my own UserDetailsService which searches LDAP for user names. Alternatively, it is possible to use LdapUserDetailsService (if you don't need significant customization).

ldap & JWT authentication without spring security

I'm trying to create a security module that will check against LDAP for user credentials (on login) and on successful login generate a JWT for further requests to the server.
currently my module works like this:
i have 3 rest API endpoints to provide authentication (login, validate JWT, logout) that are not protected as anyone must be able to access those endpoints,
and also 1 userUpdate endpoint protected with spring security via a JWTAuthenticationProvider
all the stuff pertaining the JWT is ready, now I just need to create a method to check in LDAP if the user and password are correct. but i am having some trouble understanding how am i supposed to do so
i already have the master user and pass to conect to ldap, but most of the examples i find about ldap authentication are with spring security and i dont think thats the way to do it in this case as i need to verify the matching us/pass only on login (and not protect my endpoints with security).
can anyone tell me how im supposed to do that verification? any stuff i am not being clear on? please ask and comment and answer.
thanks
oh one edit:
#Override
public AuthenticationResponse login(AuthenticationRequest authenticationRequest) {
checkNotNull(authenticationRequest, "The authenticationRequest is a required argument!");
AuthenticationResponse authenticationResponse = AuthenticationResponse.builder().build();
//currently a pseudo authentication, here is where i should authenticate against LDAP
Optional<Usuario> optionalUsuario = service.findByNombreUsuario(authenticationRequest);
if (optionalUsuario.isPresent()) {
Usuario usuario = optionalUsuario.get();
String token = JwtTokenUtil.generateToken(authenticationRequest);
authenticationResponse.setAuthenticationToken(token);
repository.saveToken(UserToken.builder()
.nombreUsuario(usuario.getNombreUsuario())
.roles(usuario.getRoles())
.build(), token);
as you can see i intent to make the authentication against ldap only at login, and only to check if the user and pass are correct, i will manage the roles and authorities using other DB
another edit: i have some basic ldap structure for ldap auth using spring security, but i always get bad credentials
edit again: i managed to make it work with spring security, but (as expected) was told by my team that we need to implement that authentication without spring security to integrate with our custom role loader and token creation
use http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/ldap/authentication/LdapAuthenticationProvider.html to authenticate and get roles from LDAP, it should be done using spring security, I probably missed smth but could you explain why you don't want use it as far it is security standart

Add optional authentication steps after FORM_LOGIN_FILTER in Spring Security

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.

When and where java security set UserPrincipal?

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

Categories

Resources