Implementing a ldapAuthentication into my Spring Security configuration makes the process ignoring the boolean field : "enabled" on Users (org.springframework.security.core.userdetails) so it's allowing disabled Users to connect..
The Security Config works well and it disallow disabled Users to connect with a simple authentication using userDetailsService but it fails with ldapAuthentication.
Here is SecurityConfig class :
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan(basePackages = {"com.mykeys.test"})
public class SecurityConfig {
#Resource
Environment environment;
#Resource
BaseLdapPathContextSource contextSource;
private static final String PROPERTY_NAME_SECURITY_KEY = "security.key";
#Resource(name="userDetailsService")
private UserDetailsService userDetailsService;
#Resource
public void configureAuthentification(AuthenticationManagerBuilder auth) throws Exception {
//auth.userDetailsService(userDetailsService);
auth.ldapAuthentication()
.userSearchFilter("uid={0}")
.ldapAuthoritiesPopulator(new UserDetailsServiceLdapAuthoritiesPopulator(userDetailsService))
.userSearchBase(environment.getProperty(LdapConfig.PROPERTY_LDAP_USER_SEARCH_BASE, LdapConfig.DEFAULT_LDAP_USER_SEARCH_BASE) )
.contextSource(contextSource);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.headers()
.addHeaderWriter(new StaticHeadersWriter("X-Frame-Options", "SAMEORIGIN"))
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Resource
Environment environment;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/js/**", "/css/**", "/fonts/**", "/less/**", "/favicon.ico", "/holder.js/**", "/img/**", "/partial/**");
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.permitAll()
.defaultSuccessUrl("/")
.failureUrl("/login?error")
.and()
.logout()
.permitAll()
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?error")
.and()
.and()
.rememberMe()
.key(environment.getProperty(PROPERTY_NAME_SECURITY_KEY, UUID.randomUUID().toString()))
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
}
Here is UserDetailsServiceImpl class (this bean is auto injected into SecurityConfig class):
#Service("userDetailsService")
#Transactional(readOnly = true)
public class UserDetailsServiceImpl implements UserDetailsService{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Resource MessageSource messageSource;
#Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
List<GrantedAuthority> list = getAllAuthor();
org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(
username,
username,
false,
false,
false,
false,
list
);
return user;
} catch (Exception e) {
logger.warn("Authentification refusée pour l'utilisateur au login {}", username, e);
throw new UsernameNotFoundException(e.getMessage());
}
}
public static List<GrantedAuthority> getAllAuthor(){
Collection<String> roles = new ArrayList<>();
roles.add("ROLE1");
roles.add("ROLE2");
ArrayList<GrantedAuthority> authorities=new ArrayList<GrantedAuthority>();
if (roles != null) {
for (String roleName : roles) {
authorities.add(new SimpleGrantedAuthority(roleName));
}
}
return authorities;
}
}
And here is the LdapConfig class :
#Configuration
#EnableLdapRepositories
public class LdapConfig {
public static final String PROPERTY_LDAP_URL = "ldap.url";
public static final String DEFAULT_PROPERTY_LDAP_URL = "ldap://localhost:33899";
public static final String PROPERTY_LDAP_LDIF_FILE = "ldap.ldif";
public static final String DEFAULT_LDAP_LDIF_FILE = "classpath:data/ldif/corp.mykeys.com.ldif";
public static final String PROPERTY_LDAP_LOGIN_DN = "ldap.login.dn";
public static final String DEFAULT_PROPERTY_LDAP_LOGIN_DN = "LOGIN";
public static final String PROPERTY_LDAP_PASSWORD = "ldap.password";
public static final String DEFAULT_PROPERTY_LDAP_PASSWORD = "pass";
public static final String PROPERTY_LDAP_SEARCH_BASE = "ldap.searchbase";
public static final String DEFAULT_LDAP_SEARCH_BASE = "dc=corp,dc=mykeys,dc=com";
public static final String PROPERTY_LDAP_USER_SEARCH_BASE = "ldap.usersearchbase";
public static final String DEFAULT_LDAP_USER_SEARCH_BASE = "OU=FR,OU=Employees";
#Resource
Environment environment;
#Bean
BaseLdapPathContextSource contextSource() throws Exception {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(environment.getProperty(PROPERTY_LDAP_URL, DEFAULT_PROPERTY_LDAP_URL));
contextSource.setBase(environment.getProperty(PROPERTY_LDAP_SEARCH_BASE, DEFAULT_LDAP_SEARCH_BASE));
contextSource.setAnonymousReadOnly(true);
contextSource.setUserDn(environment.getProperty(PROPERTY_LDAP_LOGIN_DN, DEFAULT_PROPERTY_LDAP_LOGIN_DN));
contextSource.setPassword(environment.getProperty(PROPERTY_LDAP_PASSWORD, DEFAULT_PROPERTY_LDAP_PASSWORD));
if (environment.getProperty(PROPERTY_LDAP_URL, DEFAULT_PROPERTY_LDAP_URL).contains("ldap://localhost")) {
ldapServer();
}
return contextSource;
}
#Bean
LdapTemplate ldapTemplate() throws Exception { return new LdapTemplate(contextSource());
}
#Bean
#Lazy
public ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer= new ApacheDSContainer(environment.getProperty(PROPERTY_LDAP_SEARCH_BASE, DEFAULT_LDAP_SEARCH_BASE), environment.getProperty(PROPERTY_LDAP_LDIF_FILE, DEFAULT_LDAP_LDIF_FILE));
apacheDSContainer.setPort(Integer.valueOf(DEFAULT_PROPERTY_LDAP_URL.substring(DEFAULT_PROPERTY_LDAP_URL.lastIndexOf(":")+1)));
return apacheDSContainer;
}
#Bean
public String userSearchBase() {
return environment.getProperty(PROPERTY_LDAP_USER_SEARCH_BASE, DEFAULT_LDAP_USER_SEARCH_BASE);
}
}
And implementing a custom userDetailsContextMapper doesn't work too..
Related
I added Username and password field to an existing Customer entity. I have added a Custom JWT filter and authentication provider with a WebSecurityConfig annotated #Order(2). But when I send a post request with the Username and password payload , I get an Unauthorized Error 401 response But no error message in Server Log I have checked the WebConfig file appropriately .What am I not getting right ? I've been on this all day and I seem to be frustrated already.
This is UserDetails class
public class MyCustomerDetails implements UserDetails{
/**
*
*/
private static final long serialVersionUID = -5087929420394311276L;
private Long id;
private String username;
private String password;
public MyCustomerDetails() {
}
public MyCustomerDetails(Long id, String username, String password) {
super();
this.id = id;
this.username = username;
this.password = password;
}
public static MyCustomerDetails build(Customer customer) {
return new MyCustomerDetails(customer.getId(),
customer.getUserName(), customer.getPassword());
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getPassword() {
// TODO Auto-generated method stub
return password;
}
#Override
public String getUsername() {
// TODO Auto-generated method stub
return username;
}
............
This is the Controller class
#CrossOrigin(origins = {"http://localhost:3000"})
#RestController
public class CustomerController {
#Autowired
CustomerAccountService customerRepo;
#Autowired
private CustomerJwtTokenUtil customerJwtTokenUtil;
#Autowired
private AuthenticationManager authenticationManager;
#PostMapping(value="/validateCustomer")
public ResponseEntity <?> createAuthenticationToken( #RequestBody MyCustomerDetails
authenticationRequest) throws Exception
{
authenticate(authenticationRequest.getUsername(),
authenticationRequest.getPassword());
// Long userId = authenticationRequest.getId();
final MyCustomerDetails userDetails =
(MyCustomerDetails) customerRepo.loadUserByUsername(authenticationRequest.getUsername());
final String token =
customerJwtTokenUtil.generateToken(userDetails);
return new ResponseEntity<>(new JwtResponse(token), HttpStatus.OK) ;
}
private void authenticate(String username, String password) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
}
This is the WebSecurityconfig class
#Configuration
#Order(2)
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class CustomerSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomerJwtAuthenticationEntryPoint customerJwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService myCustomerDetailsService;
#Autowired
private CustomerJwtRequestFilter customerJwtRequestFilter;
#Bean
public CustomerAccountService myCustomerAccountService() {
return new CustomerAccountService();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/*
* #Bean public UserDetailsService myCustomerDetailsService() { return
* myCustomerDetailsService(); }
*/
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider(PasswordEncoder passwordEncoder,
UserDetailsService userDetailsService){
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
return daoAuthenticationProvider;
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
protected void configure(AuthenticationManagerBuilder auth ) throws Exception {
auth.userDetailsService(myCustomerDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/***").permitAll()
// .antMatchers("/customer/**").hasAuthority("CUSTOMER")
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(customerJwtAuthenticationEntryPoint)
.and()
.formLogin().permitAll()
// .loginPage("/login")
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/login")
.and()
.sessionManagement()
.maximumSessions(1)
.and()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(customerJwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
The Service class
#Primary
public class CustomerAccountService implements UserDetailsService {
#Autowired
private CustomerAccountRepo custRepo;
#Qualifier("passwordEncoder")
#Autowired
private PasswordEncoder bCryptPasswordEncoder;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Customer customer = custRepo.findByUserName(username);
if(customer == null) {
throw new UsernameNotFoundException("Customer not found");
}
return MyCustomerDetails.build(customer);
}
This is the Base class
#Configuration
#EnableWebMvc
//#ComponentScan(basePackages = "com.bethsaida.org.security")
#EnableJpaRepositories
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class BethsaidaApplication {
public static void main(String[] args)
{SpringApplication.run(BethsaidaApplication.class, args);}
public class WebConfig implements WebMvcConfigurer
{
private static final long MAX_AGE_SECS = 3600;
#Override
public void addCorsMappings(CorsRegistry registry)
{ registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
.maxAge(MAX_AGE_SECS);}
}
}
You can use this
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "PUT", "DELETE")
.allowedHeaders("header1", "header2")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
inside your CustomerSecurityConfiguration class directly.
Because WebMvcConfigurer is implemented by WebMvcConfigurerAdapter so you can define this method inside your CustomerSecurityConfiguration class.
For more information, you can see here
I am building a project spring boot.
I want call UserService to query get authorities of user. But #Autowire in class JWTFilter not working with UserService and return NULL.
Class SecurityConfiguration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
#Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf().disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.contentSecurityPolicy("default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:")
.and()
.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
.and()
.featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
.and()
.frameOptions()
.deny()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/students/check-account/*").permitAll()
.antMatchers("/api/students/request-active").permitAll()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/students/activate").permitAll()
.antMatchers("/api/account/reset-password/init").permitAll()
.antMatchers("/api/account/reset-password/finish").permitAll()
.antMatchers("/api/image").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/websocket/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/websocket/**").permitAll()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll()
.antMatchers("/management/prometheus").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.httpBasic()
.and()
.apply(securityConfigurerAdapter());
// #formatter:on
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
Class JWTConfigurer
public class JWTConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private TokenProvider tokenProvider;
public JWTConfigurer(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
#Override
public void configure(HttpSecurity http) throws Exception {
JWTFilter customFilter = new JWTFilter(tokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
Class JWTFilter (I want #Autowire UserService here to call getUserWithAuthorities() )
/**
* Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
* found.
*/
public class JWTFilter extends GenericFilterBean {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String AUTHORIZATION_TOKEN = "access_token";
private TokenProvider tokenProvider;
public JWTFilter(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String jwt = resolveToken(httpServletRequest);
if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
Authentication authentication = this.tokenProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(servletRequest, servletResponse);
}
private String resolveToken(HttpServletRequest request){
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
String jwt = request.getParameter(AUTHORIZATION_TOKEN);
if (StringUtils.hasText(jwt)) {
return jwt;
}
return null;
}
}
Class UserService
/**
* Service class for managing users.
*/
#Service
#Transactional
public class UserService {
private final Logger log = LoggerFactory.getLogger(UserService.class);
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final UserSearchRepository userSearchRepository;
private final AuthorityRepository authorityRepository;
private final CacheManager cacheManager;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder,
UserSearchRepository userSearchRepository, AuthorityRepository authorityRepository,
CacheManager cacheManager) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.userSearchRepository = userSearchRepository;
this.authorityRepository = authorityRepository;
this.cacheManager = cacheManager;
}
#Transactional(readOnly = true)
public Optional<User> getUserWithAuthorities() {
return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByEmailIgnoreCase);
}
Using the #Autowired annotation requires the class to be a #Component. Note that other annotations imply #Component, for example a #Service is also a #Component.
I'm learning about Spring Security and I want to add the BCryptPasswordEncoder at the JdbcUserDetailsManager.
This is the code:
#Configuration
#EnableWebSecurity
public class DemoSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Autowired
public UserDetailsManager userDetailsManager(DataSource securityDataSource) {
JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager();
jdbcUserDetailsManager.setDataSource(securityDataSource);
return jdbcUserDetailsManager;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").hasRole("EMPLOYEE")
.antMatchers("/leaders/**").hasRole("MANAGER")
.antMatchers("/systems/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/showMyLoginPage")
.loginProcessingUrl("/authenticateTheUser")
.permitAll()
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/access-denied");
}
}
I need the UserDetailsManager bean to inject in other class. Thank you!
You should use this class to create the UserDetails Bean
#Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
#Autowired
private com.fortsolution.schedmate.data.services.UserService userService;
#Transactional(readOnly=true)
public UserDetails loadUserByUsername(String ssoId)
throws UsernameNotFoundException {
System.out.println("fine here murtaza");
int id = Integer.parseInt(ssoId);
User user = userService.findById(id);
logger.info("User : {}", user);
if(user==null){
logger.info("User not found");
throw new UsernameNotFoundException("Username not found");
}
return new org.springframework.security.core.userdetails.User(""+user.getId(), user.getPassword(),
true, true, true, true, getGrantedAuthorities(user));
}
private List<GrantedAuthority> getGrantedAuthorities(User user){
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for(UserProfile userProfile : user.getUserProfiles()){
logger.info("UserProfile : {}", userProfile);
authorities.add(new SimpleGrantedAuthority("ROLE_"+userProfile.getType()));
}
return authorities;
}
}
after creating this class you will add these two method in your
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Override
#Autowired // <-- This is crucial otherwise Spring Boot creates its own
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
and
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
I'm new to spring and I'm trying to implement spring security in a project. I was able to create user with hash password using Bcrypt, but whenever I tried to login using the same password it fails. I've also tried checking other SO answers (like Spring Security BCryptPasswordEncoder Inserted But Not Match) non solved the issues faced.
Below is what have tried so far
WebSecurityConfigurerAdapter Class
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.csrf().disable();
http.authorizeRequests().antMatchers("/login", "/app-assets/**", "/assets/**").permitAll();
http.authorizeRequests().antMatchers("/add-user", "/users-list").hasRole("ADMIN");
http.authorizeRequests().antMatchers("/", "/index", "/add-content", "/mange-content").hasAnyRole("ADMIN", "USER");
http
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/index")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
//.failureUrl("/login-error.html")
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/login?logout")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll();
}
#Bean
public DaoAuthenticationProvider authProvider() {
System.out.println("GOT CALLED HERE.....");
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
//auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
auth.authenticationProvider(authProvider());
}
}
UserDetailsService
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserDAO userDAO;
#Autowired
private RoleDAO roleDAO;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDAO.findUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User "+username+"not fount");
}
List<String> roleNames = roleDAO.getRoleNames(user.getAdminId());
System.out.println("USERNAME: "+user.getAdminId() + " "+user.getPassword());
List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>();
if (roleNames != null) {
for (String role : roleNames) {
GrantedAuthority authority = new SimpleGrantedAuthority(role);
grantList.add(authority);
}
}
UserDetails userDetails = (UserDetails) new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantList);
return userDetails;
}
}
TEST
#RunWith(SpringRunner.class)
#SpringBootTest
public class ApplicationTests {
#Autowired
private UserDAO userDAO;
#Autowired
private BCryptPasswordEncoder encoder;
#Test
public void contextLoads() {
String password = "eureka";
String encrytedPassword = encoder.encode(password);
User user = userDAO.findUserByEmail("xxx#gmail.com");
System.out.println(encrytedPassword);
System.out.println("Matched: " + encoder.matches("eureka", encrytedPassword));//This line returns true
assertEquals(encrytedPassword, user.getPassword());
}
}
I also tried overriding matches() but to no avail
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder() {
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
// This throws an error
return matches(rawPassword, encodedPassword);
}
};
}
Note: Hashed password and raw password was gotten from matches() method. So there's no issues retrieving hashpassword from database.
I am doing basic authentication using Spring Security using DaoAuthenticationProvider. I want to preauthorize my requests, so I am using the #PreAuthorize annotation. The problem is that it appears that Spring Security doesn't differentiate between multiple roles and authorities. For example, if I access /users, I am being prompted to the login screen, but no matter what user I login with, I always get the list of all users displayed. This is not what I want to achieve I want to restrict access to users list to the role admin.
Here is my SecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
#RequiredArgsConstructor(onConstructor = #__({#Autowired}))
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Resource(name = "userRestClient")
UserService userService;
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
#Qualifier("authenticationProvider")
public void setAuthenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProvider = authenticationProvider;
}
#Autowired
public void configureAuthManager(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(authenticationProvider);
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userService);
// authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/", "/users", "/user").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout().permitAll();
httpSecurity
.csrf().disable();
httpSecurity
.headers()
.frameOptions().disable();
}
#Bean
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}
Here is my Controller:
#Controller
#Component
public class UserWebController {
private final UserRestClient userService = new UserRestClient();
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/users", method = RequestMethod.GET)
#Produces(MediaType.APPLICATION_JSON)
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.findAllUsers().stream().map(UserMapper.INSTANCE::from).collect(Collectors.toList());
return new ResponseEntity<List<User>>(users, HttpStatus.OK);
}
}
My implementation of the UserDetails interface:
public class MyUser implements UserDetails {
private User user;
public MyUser(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> roles = new HashSet<>();
roles.add(new Authority(user.getRole()));
return roles;
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
User entity:
#Table(name = "users")
#AllArgsConstructor
#Data
#NoArgsConstructor
#javax.persistence.Entity
public class User extends Entity implements Serializable {
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "role")
private String role;
}
You have to enable #PreAuthorize, see EnableGlobalMethodSecurity#prePostEnabled:
Determines if Spring Security's pre post annotations should be enabled. Default is false.
Your modified and simplified configuration:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#RequiredArgsConstructor(onConstructor = #__({#Autowired}))
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Resource(name = "userRestClient")
UserService userService;
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
#Qualifier("authenticationProvider")
public void setAuthenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProvider = authenticationProvider;
}
#Autowired
public void configureAuthManager(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(authenticationProvider);
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userService);
return authProvider;
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/", "/users", "/user").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.csrf()
.disable()
.and()
.headers()
.frameOptions().disable();
}
#Bean
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}