Spring Security LDAP Authentication and gather user details from local database - java
In summary, user is being authenticated, but I do appear to actually have logged into the users account.
I'm currently working on implementing LDAP authentication on a project. It appears that the authentication portion of things are working in the sense that my application does accept the correct credentials. The issue I'm having is that I cant seem to access 'principal' in my jsp views. (I was able to access all of this before making the switch to LDAP). When running a trace my CustomUserDetails service is querying and pulling the correct account information. Any assistance is appreciated
This will display the proper username:
<sec:authorize access="isAuthenticated()">
<h2><sec:authentication property="name"/></h2>
</sec:authorize>
This does not (it did work before LDAP)
<sec:authorize access="isAuthenticated()">
<h2><sec:authentication property="principal.firstName"/></h2>
</sec:authorize>
Relevant Code
SecurityConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.authentication.UserDetailsServiceLdapAuthoritiesPopulator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private CustomUserDetailsService userDetailsService;
#Bean
public CustomSaltSource customSaltSource(){ return new CustomSaltSource();}
#Bean
public AuthenticationSuccessHandler myAuthenticationSuccessHandler(){
return new AuthenticationSuccessHandler();
}
#Autowired
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().contextSource()
.url("ldap://bar.foo.com")
.port(####)
.and()
.userDnPatterns("cn={0},cn=users,dc=ms,dc=ds,dc=foo,dc=com")
.ldapAuthoritiesPopulator(new UserDetailsServiceLdapAuthoritiesPopulator(userDetailsService));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/skins/**", "/css/**", "/**/laggingComponents", "/assets/**").permitAll().and()
.formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/", true).successHandler(myAuthenticationSuccessHandler())
.and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).deleteCookies("JSESSIONID").permitAll()
.and().authorizeRequests().antMatchers("/api/**").anonymous()
.and().authorizeRequests().anyRequest().authenticated().and().rememberMe().key("KEY").userDetailsService(userDetailsService);
}
#Override
public void configure(WebSecurity web) throws Exception {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(new PermissionEvaluator());
web.expressionHandler(handler);
web.ignoring().antMatchers( "/skins/**", "/css/**", "/api/**", "/assets/**", "/health"); //"/**/test/**"
}
}
CustomUserDetaulsService.java
import org.hibernate.Session;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Set;
#Service
public class CustomUserDetailsService implements UserDetailsService{
#Override
public CustomUserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
Session session = DBFactory.factory.openSession();
User user = (User) session.createQuery("from User where userName =:userName")
.setParameter("userName", username).uniqueResult();
if(user == null){
throw new UsernameNotFoundException("User Not Found");
}
//Needed to initialize permissions
Set<Role> roles = user.getRoles();
int i = roles.size();
for(Role role: roles){
int j = role.getPermissions().size();
}
CustomUserDetails userDetails = new CustomUserDetails(user);
session.close();
return userDetails;
}
}
If I'm not wrong,
You switched to Ldap Authorization, set url and DN patterns but still provide userDetailsService which search user in database.
You need to set UserDetailsContextMapper by implementing the interface and creating your custom one. This will map data from ldap directory context to your custom UserDetails and return it through mapUserFromContext method.
Here is an example CustomUserDetailsContextMapper:
public class CustomUserDetailsContextMapper implements UserDetailsContextMapper {
private LdapUser ldapUser = null;
private String commonName;
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
Attributes attributes = ctx.getAttributes();
UserDetails ldapUserDetails = (UserDetails) super.mapUserFromContext(ctx,username,authorities);
try {
commonName = attributes.get("cn").get().toString();
} catch (NamingException e) {
e.printStackTrace();
}
ldapUser = new LdapUser(ldapUserDetails);
ldapUser.setCommonName(commonName);
return ldapUser;
}
#Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
}
}
My custom LdapUser:
public class LdapUser implements UserDetails
{
private String commonName;
private UserDetails ldapUserDetails;
public LdapUser(LdapUserDetails ldapUserDetails) {
this.ldapUserDetails = ldapUserDetails;
}
#Override
public String getDn() {
return ldapUserDetails.getDn();
}
#Override
public void eraseCredentials() {
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return ldapUserDetails.getAuthorities();
}
#Override
public String getPassword() {
return ldapUserDetails.getPassword();
}
#Override
public String getUsername() {
return ldapUserDetails.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return ldapUserDetails.isAccountNonExpired();
}
#Override
public boolean isAccountNonLocked() {
return ldapUserDetails.isAccountNonLocked();
}
#Override
public boolean isCredentialsNonExpired() {
return ldapUserDetails.isCredentialsNonExpired();
}
#Override
public boolean isEnabled() {
return ldapUserDetails.isEnabled();
}
}
Then set CustomUserDetailsContextMapper in auth configuration. This is how you will be able to get your user from authentication.getPrincipal().
I hope I correctly understand your problem and answered.
I had to test LDAP auth + different roles for devs,admins,users
Many thanks to #Yernar Arystanov
The code is not so clean but works...
public class LdapUser implements UserDetails
{
private String commonName;
private List<String> groups;
private UserDetails ldapUserDetails;
public LdapUser(LdapUserDetails ldapUserDetails) {
this.ldapUserDetails = ldapUserDetails;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return ldapUserDetails.getAuthorities();
}
#Override
public String getPassword() {
return ldapUserDetails.getPassword();
}
#Override
public String getUsername() {
return ldapUserDetails.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return ldapUserDetails.isAccountNonExpired();
}
#Override
public boolean isAccountNonLocked() {
return ldapUserDetails.isAccountNonLocked();
}
#Override
public boolean isCredentialsNonExpired() {
return ldapUserDetails.isCredentialsNonExpired();
}
#Override
public boolean isEnabled() {
return ldapUserDetails.isEnabled();
}
public String getCommonName() {
return commonName;
}
public void setCommonName(String commonName) {
this.commonName = commonName;
}
public List<String> getGroups() {
return groups;
}
public void setGroups(List<String> groups) {
this.groups = groups;
}
}
Suggestion by #Ivan Baranuk was correct (extends LdapUserDetailsMapper):
public class CustomUserDetailsContextMapper extends LdapUserDetailsMapper {
private LdapUser ldapUser = null;
private String commonName;
private List<String> groups = new LinkedList<String>();
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
Attributes attributes = ctx.getAttributes();
UserDetails ldapUserDetails;
ldapUserDetails = (UserDetails) super.mapUserFromContext(ctx,username,authorities);
try {
commonName = attributes.get("cn").get().toString();
Arrays.stream(ctx.getObjectAttributes("memberOf"))
.iterator()
.forEachRemaining( m -> {
groups.add(m.toString());
});
} catch (NamingException | javax.naming.NamingException e) {
e.printStackTrace();
}
ldapUser = new LdapUser((LdapUserDetails) ldapUserDetails);
ldapUser.setCommonName(commonName);
ldapUser.setGroups(groups);
return ldapUser;
}
#Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
}
}
then finally in SecurityConfig:
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
public void configure(AuthenticationManagerBuilder auth) throws Exception {
...
auth.ldapAuthentication()
.userSearchBase("enter your search base")
.userSearchFilter("(&(objectClass=user)(sAMAccountName={0}))")
.userDetailsContextMapper(ldapUserDetailsMapper())
.ldapAuthoritiesPopulator(ldapAuthoritiesPopulator())
.contextSource()
.url(yourProperties.getLdapUrl())
.managerDn(yourProperties.getManagerDn())
.managerPassword(yourProperties.getManagerPassword());
}
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator() {
return new LdapAuthoritiesPopulator() {
#Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData,
String username) {
LinkedList<SimpleGrantedAuthority> res = new LinkedList();
Arrays.stream(userData.getObjectAttributes("memberOf"))
.iterator()
.forEachRemaining( m -> {
if(m.toString().equals("your_dev_group"))
res.add(new SimpleGrantedAuthority("DEV_USER"));
if(m.toString().equals("your_admin_group"))
res.add(new SimpleGrantedAuthority("ADMIN_USER"));
});
if(res.isEmpty())
return Arrays.asList(new SimpleGrantedAuthority("USER"));
else
return res;
}
};
}
#Bean
#Override
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Bean
protected LdapUserDetailsMapper ldapUserDetailsMapper() {return new CustomUserDetailsContextMapper();}
}
At the end - some simple get method(authorized users only):
#RequestMapping("/logger")
public String testLogger(Authentication authentication) {
if (authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_DEV_USER"))) {
LdapUser userDetails = (LdapUser) authentication.getPrincipal();
log.info("WELCOME :" + userDetails.getCommonName());
userDetails.getGroups().iterator().forEachRemaining((g) - > log.info("group: " + g.toString()));
}
return ""
}
Related
How can i display User-specific data after authentication
I have 2 microservices. An API gateway with a JWT authentication and a microservice that manages templates from the respective user. My goal is that the user can only see his templates. But I am not clear how I do it. Do I have to generate an additional ID token or can I also solve the problem with feign? #GetMapping("/templates/{name}/{template_id}") public Template retrieveTemplate(#PathVariable("name") String name,#PathVariable("template_id") int template_id) { return templateRepository.findByTemplateIdAndName(template_id, name); } This is my get method to be able to display the respective template. However, I don't want the user's name to be required in REST.After the authentication it should be possible to use the token to be able to output user-specific data or? I also have two database tables. One for authentication and one for templates. In the authentication table, I once have the data username and password as well as a name of the user. In the template table I only have the name of the user (to keep the table small). This means that in the case of a get request from templates, the name of the user must be requested from the authentication microservice in order to be able to display only the templates of the user. Can someone tell me which technology I work best with? #Service public class JwtUtil { private String SECRET_KEY = "helloworld"; public String extractUsername(String token) { return extractClaim(token, Claims::getSubject); } public Date extractExpiration(String token) { return extractClaim(token, Claims::getExpiration); } public <T> T extractClaim(String token, Function<Claims,T> claimsResolver) { final Claims claims = extractAllClaims(token); return claimsResolver.apply(claims); } private Claims extractAllClaims(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } public String generateToken(UserDetails userDetails) { Map<String,Object> claims =new HashMap<>(); return createToken(claims,userDetails.getUsername()); } private String createToken(Map<String, Object> claims, String subject) { return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000*60*60*24*360)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact(); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } } package sendMessage.LoginJwtAPIGateway; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; #EnableWebSecurity public class SecurityConfigurer extends WebSecurityConfigurerAdapter{ #Autowired private MyUserDetailsService myUserDetailsService; #Autowired private JwtRequestFilter jwtRequestFilter; #Autowired UserDetailsService userDetailsService; #Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailsService); } #Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().antMatchers("/authenticate").permitAll(). antMatchers("/users").hasRole("ADMIN") .anyRequest().authenticated() .and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } #Override #Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } #Bean public BCryptPasswordEncoder getBCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } } #Component public class JwtRequestFilter extends OncePerRequestFilter{ #Autowired private MyUserDetailsService userDetailsService; #Autowired private JwtUtil jwtUtil; #Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { final String authorizationHeader =request.getHeader("Authorization"); String username = null; String jwt = null; if(authorizationHeader !=null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); username= jwtUtil.extractUsername(jwt); } if (username != null && SecurityContextHolder.getContext().getAuthentication()==null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(jwt, userDetails)) { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); } } chain.doFilter(request,response); } } package sendMessage.LoginJwtAPIGateway; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; public class MyUserDetails implements UserDetails{ private String username; private String password; private boolean active; private List<GrantedAuthority> authorities; public MyUserDetails() { } public MyUserDetails(User user) { this.username=user.getUsername(); this.password=user.getPassword(); this.active=user.isActive(); this.authorities =Arrays.stream(user.getRoles().split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); } #Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO Auto-generated method stub return authorities; } #Override public String getPassword() { // TODO Auto-generated method stub return password; } public String getUsername() { // TODO Auto-generated method stub return username; } #Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return true; } #Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } #Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } #Override public boolean isEnabled() { // TODO Auto-generated method stub return active; } }
If you're using Spring and JWT for generating tokens, then you can add token enhancers to your JWT, token enhancers allow you to add additional information to your token. Then you can add the username or user id to your token. In your call to your template endpoint you can remove the name part of your url. and rely on the received token to get the username. You can find here how to add token enhancers https://www.baeldung.com/spring-security-oauth-jwt
You want to fetch some user data from his JWT token, so you need to add some extra information to user token when you're generating it, for this purpose you must use a custom TokenEnhancer. This post might be useful for your scenario : Can-i-include-user-information-while-issuing-an-access-token In summary Create CustomTokenEnhancer Add CustomTokenEnhancer to AuthorizationServerConfigurerAdapter as a bean Get saved data from token and use it (In the controller ,...)
Spring Security - Active Directory Get Custom User details
I am having a challenge extracting original user details from the LdapUserDetailsImpl such as the getUsername() returns null I have the following Java classes Custom User Class public class AppUserDetails extends LdapUserDetailsImpl { public AppUserDetails() { super(); } private String mail; //mail } Custom User Details Mapper public class AppUserDetailsContextMapper extends LdapUserDetailsMapper { public AppUserDetailsContextMapper() { super(); } #Override public AppUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) { UserDetails details = super.mapUserFromContext(ctx, username, authorities); String mail = ctx.getStringAttribute("mail"); AppUserDetails appUserDetails = new AppUserDetails(); appUserDetails.setMail(mail); return appUserDetails; } } Web security configuration #Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { #Autowired Environment env; #Bean public UserDetailsContextMapper userDetailsContextMapper() { return new AppUserDetailsContextMapper(); } #Bean public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() { ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider( env.getRequiredProperty("spring.ldap.domain"), env.getRequiredProperty("spring.ldap.urls") ); provider.setConvertSubErrorCodesToExceptions(true); provider.setUseAuthenticationRequestCredentials(true); provider.setUserDetailsContextMapper(userDetailsContextMapper()); return provider; } #Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .authenticationProvider(activeDirectoryLdapAuthenticationProvider()) .userDetailsService(userDetailsService()); } #Bean public AuthenticationManager authenticationManager() { return new ProviderManager( Collections .singletonList(activeDirectoryLdapAuthenticationProvider()) ); } } However I am having a serious challenge trying to getting Custom User Details in the controller: #Controller public class HomeController { #GetMapping(value = {"/home"}) public String home(Model model) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); System.out.println(authentication.getPrincipal()); AppUserDetails appUserDetails = (AppUserDetails) authentication.getPrincipal(); System.out.println(appUserDetails); return "home"; } } I am getting a NullPointer exception if I try to any property from the LdapUserDetailsImpl class. However, I am accurately getting all the properties from the AppUserDetails - which extends the LdapUserDetailsImpl class. Where might I be missing it?
Wrong Authentication-Object in Controller [Spring-Boot]
I'm pretty new to Spring-Boot. I have tried to block certain routes, permit some and implement authentication for them. This works so far, but somehow I want to get the user who makes the request. My WebSecurityConfig: #Configuration #Order(1) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final JwtTokenService tokenService; public WebSecurityConfig(JwtTokenService tokenService) { this.tokenService = tokenService; } #Bean public JwtTokenFilter tokenFilter() { return new JwtTokenFilter(); } #Bean public SecurityContextHolderAwareRequestFilter securityContextHolderAwareRequestFilter() { return new SecurityContextHolderAwareRequestFilter(); } #Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests() .antMatchers("/login", "/apply").permitAll() .anyRequest().authenticated(); http.addFilterBefore(tokenFilter(), UsernamePasswordAuthenticationFilter.class); http.headers().cacheControl(); } #Autowired public void configureAuthentication(AuthenticationManagerBuilder builder) { builder.authenticationProvider(new AuthenticationProvider() { #Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String token = (String) authentication.getCredentials(); return tokenService.decode(token).map(AuthenticatedUser::new).orElseThrow(JwtAuthenticationException::new); } #Override public boolean supports(Class<?> authentication) { return JwtAuthentication.class.equals(authentication); } }); } } The TokenFilter: #Component public class JwtTokenFilter extends OncePerRequestFilter { #Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { String header = request.getHeader("Anima-Authentication-Token"); if(header != null) { SecurityContextHolder.getContext().setAuthentication(new JwtAuthentication(header)); } filterChain.doFilter(request, response); } } The Authentications: public class JwtAuthentication implements Authentication { private final String token; public JwtAuthentication(String token) { this.token = token; } #Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } #Override public Object getCredentials() { return token; } #Override public Object getDetails() { return null; } #Override public Object getPrincipal() { return null; } #Override public boolean isAuthenticated() { return false; } #Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { } #Override public String getName() { return null; } } public class AuthenticatedUser implements Authentication { private final AnimaUser user; public AuthenticatedUser(AnimaUser user) { this.user = user; } #Override public Collection<? extends GrantedAuthority> getAuthorities() { return new ArrayList<>(); } #Override public Object getCredentials() { return null; } #Override public Object getDetails() { return null; } #Override public Object getPrincipal() { return user; } #Override public boolean isAuthenticated() { return true; } #Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { } #Override public String getName() { return user.getName(); } } I also tried to override the Authentication in the SecurityContextHolder with the AuthorizedUser Object: #Autowired public void configureAuthentication(AuthenticationManagerBuilder builder) { builder.authenticationProvider(new AuthenticationProvider() { #Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String token = (String) authentication.getCredentials(); return tokenService.decode(token).map(user - > { SecurityContextHolder.getContext().setAuthentication(new AuthenticatedUser(user)); return new AuthenticatedUser(user); }).orElseThrow(JwtAuthenticationException::new); } #Override public boolean supports(Class<?> authentication) { return JwtAuthentication.class.equals(authentication); } }); } But this hasn't worked either. I have tried to access the User with the following methods: #GetMapping("") #ResponseBody public String handle() { // This returns the JwtAuthentication, not the AuthenticatedUser return SecurityContextHolder.getContext().getAuthentication().getCredentials().toString(); } #GetMapping("") #ResponseBody public String handle(Authentication authentication) { // authentication is null } #GetMapping("") #ResponseBody public String handle(Principle principle) { // principle is null }
It is because of #Component annotation on JwtTokenFilter class. Remove that and you will be good to go. You are already defining that as a #Bean in your WebSecurityConfig class. Since you have #Component on the class it is running after the AuthenticationProvider code overriding the AuthenticatedUser set in SecurityContext with JwtAuthentication
Password hashing with Salt in Spring Boot Security
Hello I'm facing some problems with the authentification mechanism provided by Spring Boot Security The main issue is that I have a login form provided by Spring Boot Security and want to check the inputs with an underlying database of users with email, hashed_password, and user_salt I injected my UserDetailService in the WebSecurityConfigAdapter #Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(as); // #Autowired private AuthService as; } The AuthService is the following: #Service public class AuthService implements UserDetailsService { #Autowired MyUserClassRepository ur; #Override public UserDetails loadUserByUsername(String username) { MyUserClass user = ur.findUserByEmail(username); if(user == null){ throw new UsernameNotFoundException(username); } System.out.println("User found but we must check the password"); return new MyUserPrincipal(user); } #SessionScope public class MyUserPrincipal implements UserDetails { private MyUserClass user; MyUserClass getUser(){ return user; // I need to retrieve the user later for my Webapplication } MyUserPrincipal(MyUserClass user){ this.user = user; } #Override public Collection<? extends GrantedAuthority> getAuthorities() { System.out.println("Call Granted"); return null; } #Override public String getPassword() { return user.passwordHash; } #Override public String getUsername() { return user.email; } #Override public boolean isAccountNonExpired() { return true; } #Override public boolean isAccountNonLocked() { return true; } #Override public boolean isCredentialsNonExpired() { return true; } #Override public boolean isEnabled() { return true; } } } I need a hook or a method where I can get the input of the user so I can encode and salt the password. A default PassWordEncoder as a component doesn't have access to the inputs or at least I don't know how to get the credentials in the input field: //#Component public final class myPwEncoder implements PasswordEncoder { public String encode(CharSequence rawPassword) { System.out.println("Encode My Stuff: " + rawPassword); //MyUserClass user = ((AuthService.MyUserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUser(); NullPointerException because the User will be after the verification initialized... return rawPassword.toString(); } public boolean matches(CharSequence rawPassword, String encodedPassword) { System.out.println("Macthes call: "+rawPassword + " " + encodedPassword); return rawPassword.toString().equals(encodedPassword); } } Thank you for your help! (I want to use sha256-hash with random generated Salt stored in the user DB table. I know BCrypt is probably the best choice but I have to need to use sha256)
How to authenticate user in spring using AuthenticationManagerBuilder and userDetailsService based on credentials retrived from user entity
i am a newbie to spring was not able to implement login to the application, actually could not figure out where its wrong. followed a youtube video to do all this. Help would be very much appreciated. When i try to log in the application wont allow to log in. console logs shows querys are being executed but cant log into the system. also the password are saved in plain ASCII. WebSecurityConfig class #Configuration #ComponentScan(basePackageClasses = CustomUserDetailsService.class) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { #Autowired private AccessDeniedHandler accessDeniedHandler; #Autowired private UserDetailsService userDetailsService; #Autowired public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } // roles admin allow to access /actuator/** // roles user allow to access /Application/** // custom 403 access denied handler #Override protected void configure(HttpSecurity http) throws Exception { // some antMatchers permit all } } customUserDetailsService class #Service("customUserDetailsService") public class CustomUserDetailsService implements UserDetailsService{ private final UserRepo userRepo; #Autowired public CustomUserDetailsService(UserRepo userRepo) { this.userRepo = userRepo; } #Override // userId is reffered as username public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { User user=userRepo.findByUsername(userName); if(null == user){ System.out.println("\n\n\n No user present with username: "+userName); throw new UsernameNotFoundException("No user present with username: "+userName); }else{ CustomUserDetails c =new CustomUserDetails(user); //System.out.println(c.getAuthorities()); return c; } } } CustomUserDetails class public class CustomUserDetails extends User implements UserDetails{ private static final long serialVersionUID = 1L; public CustomUserDetails(User user){ super(user); } #Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<UserRole> roles = super.getUserRole(); List<String> userRoles= new ArrayList<String>(); for(UserRole r : roles) { userRoles.add(r.getRole().toString()); } String strRoles=StringUtils.collectionToCommaDelimitedString(userRoles); return AuthorityUtils.commaSeparatedStringToAuthorityList(strRoles); } #Override public boolean isAccountNonExpired() { return super.isAccountNonExpired(); } #Override public boolean isAccountNonLocked() { return super.isAccountNonLocked(); } #Override public boolean isCredentialsNonExpired() { return super.isCredentialsNonExpired(); } #Override public boolean isEnabled() { return super.isEnabled(); } #Override public String getUsername() { return super.getUsername(); } #Override public String getPassword() { return super.getPassword(); } }