How to authenticate user with specific role in spring boot? - java

SecurityConfiguration
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailService customUserDetailService;
#Autowired
CustomSuccessHandler successHandler;
#Autowired
CustomFailureHandler failureHandler;
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
CustomBeanDefinition customBeanDefinition;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService userDetailsService = customBeanDefinition.jpaUserDetails();
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/signup").permitAll()
.antMatchers("/register").permitAll()
.antMatchers("/book/index").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin()
.successHandler(successHandler)
.loginPage("/login")
.failureHandler(failureHandler)
.usernameParameter("username")
.passwordParameter("password")
.and().logout().permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/img/**", "/icon/**");
}
}
CustomUserDetailService
#Service
public class CustomUserDetailService implements UserDetailsService {
#Autowired
UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
List<GrantedAuthority> authorities = getUserAuthority(user.getRoles());
UserDetails userDetails = buildUserForAuthentication(user, authorities);
return userDetails;
}
private List<GrantedAuthority> getUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> roles = new HashSet<>();
for (Role role : userRoles) {
roles.add(new SimpleGrantedAuthority(role.getAuthority()));
}
return new ArrayList<>(roles);
}
private UserDetails buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), authorities);
}
}
CustomBeanDefinition
#Configuration
public class CustomBeanDefinition {
#Bean
public UserDetailsService jpaUserDetails() {
return new CustomUserDetailService();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserService
#Service
public class UserService {
private UserRepository userRepository;
private RoleRepository roleRepository;
private BCryptPasswordEncoder passwordEncoder;
#Autowired
public UserService(UserRepository userRepository,
RoleRepository roleRepository, BCryptPasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
this.passwordEncoder = passwordEncoder;
}
public void save(String username, String email, String password, String name) {
User user = userRepository.findByUsername(username);
if (user == null) {
user = new User();
user.setName(name);
user.setUsername(username);
user.setEmail(email);
user.setPassword(passwordEncoder.encode(password));
user.setActive(true);
Role role = roleRepository.findByAuthority("ADMIN");
user.setRoles(new HashSet<>(Collections.singletonList(role)));
userRepository.save(user);
System.out.println("...user saved with ADMIN role");
}
}
}
In my application user is currently being saved successfully and binding with specific role.
However, when i try to authenticate my application with saved user, it never goes on success handler, it redirects me on failure handler.
It looks like authentication is not working.
Any help would be appreciated.

Change your Security Configuration, configure() method like below,
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService).
passwordEncoder(bCryptPasswordEncoder);
}

Related

Getting the error "The dependencies of some of the beans in the application context form a cycle"

Checked similar threads with the same errors, but still unable to find where is the cause of the error. I am following tutorial and trying to create simple login page with username and password using spring, as well as implementing two roles of user.
Here is my securityConfig file and my userServiceImplement file which are causing this error.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/ws").permitAll()
.antMatchers("/users").hasAnyAuthority(Role.ADMIN.name())
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/auth")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.csrf().disable();
}
}`
#Service
public class UserServiceImplement implements UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserServiceImplement(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
#Override
public boolean save(UserDTO userDto) {
if(!Objects.equals(userDto.getPassword(), userDto.getMatchingPassword())){
throw new RuntimeException("Password is not equal");
}
User user = User.builder()
.name(userDto.getUsername())
.password(passwordEncoder.encode(userDto.getPassword()))
.email(userDto.getEmail())
.role(Role.USER)
.build();
userRepository.save(user);
return true;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findFirstByName(username);
if (user == null) {
throw new UsernameNotFoundException("User was not found with this name" + username);
}
List<GrantedAuthority> roles = new ArrayList<>();
roles.add(new SimpleGrantedAuthority(user.getRole().name()));
return new org.springframework.security.core.userdetails.User(
user.getName(),
user.getPassword(),
roles
);
}
}
Class SecurityConfig provides a PasswordEncoder and requires a UserService. Class UserServiceImplement is a UserService and requires a PasswordEncoder. In other words, to create a SecurityConfig you need a UserService, but to create a UserService you need a SecurityConfig to provide the PasswordEncoder.
The easiest fix is probably to move the PasswordEncoder method outside of SecurityConfig.
An alternative is to treat UserServiceImplement as a POJO (remove the #Service annotation) and create it manually inside the authenticationProvider method. You'll need a UserRepository for that, but you can use method argument injection for that:
#Bean
public DaoAuthenticationProvider authenticationProvider(UserRepository userRepository) {
PasswordEncoder passwordEncoder = passwordEncoder();
UserService userService = new UserServiceImplement(userRepository, passwordEncoder);
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder);
return auth;
}

Spring Security - 403 Forbidden for every role except ROLE_USER

I am creating an application using Role based restriction to certain REST endpoints.
I have a Roles table, user_roles table and a users table.
ROLE_USER is working fine, and users with that Role can successfully access their pages. Even if I swap it around so that only ROLE_USER can access /admin/**, it works.
However, when I try use ROLE_ADMIN on the admin page, it never works. It always redirects me to the 403 Forbidden page
Security Config:
#Bean
DaoAuthenticationProvider provider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsServiceImpl);
provider.setPasswordEncoder(passwordEncoder);
return provider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/banking/**").hasAnyRole("USER", "ADMIN")
.antMatchers(HttpMethod.GET, "/admin/**").hasRole("ADMIN")
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/403");
}
}
MyUserDetails:
public class MyUserDetails implements UserDetails {
private static final long serialVersionUID = -2067381432706760538L;
private User user;
public MyUserDetails(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<Role> roles = user.getRoles();
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
}
return authorities;
}
UserDetailsServiceImpl:
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserService userService;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException("User not found");
}
return new MyUserDetails(user);
}
}
Would appreciate any help as I've been stuck on this for a while. Thanks!

How to add PasswordEncoder into JdbcUserDetailsManager in Spring Security?

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;
}

Spring security authentication failing with BCryptPasswordEncoder

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.

Spring Security and BCryptPasswordEncoder for registration and login

I am new in Java Spring and I want to create a system with registration for users, which are stored in my DB (Postgres), where a password is stored encrypted by BCryptPasswordEncoder. The registration process is working fine, but when I want to log in, I always get an "Invalid username or password." message. I already search everywhere and read a lot of articles, but everything that I did had the same result.
Here is my SecurityConfiguration class:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("customUserDetailsService")
private CustomUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).and().authenticationProvider(authProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/signin", "/confirm", "/error","/signup", "/css/**","/js/**","/images/**").permitAll()
.antMatchers("/admin/**").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/signin")
.usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/cockpit.html")
.permitAll()
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/signin").and().exceptionHandling()
.accessDeniedPage("/error");
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
}
And here is my CustomUserDetailsService class:
#Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
private final UserRepository userRepository;
private final RoleRepository userRolesRepository;
#Autowired
private PasswordEncoder bCryptPasswordEncoder;
#Autowired
public CustomUserDetailsService(UserRepository userRepository,RoleRepository userRolesRepository) {
this.userRepository = userRepository;
this.userRolesRepository=userRolesRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
Logger LOGGER = Logger.getLogger(CustomUserDetailsService.class.getName());
User user = userRepository.findByUsername(username);
if (null == user) {
return null;
} else {
List<GrantedAuthority> authorities =
buildUserAuthority(userRolesRepository.findRoleByUserName(username));
LOGGER.info("Loaded account: " + user.getUsername() + " password: " + user.getPassword() + " password matches: " + bCryptPasswordEncoder.matches("password", user.getPassword()));
org.springframework.security.core.userdetails.User userDetails = new org.springframework.security.core.userdetails.User(user.getUsername(), Deuser.getPassword(),authorities);
return userDetails;
}
}
private List<GrantedAuthority> buildUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<>();
// add user's authorities
for (Role userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
return new ArrayList<>(setAuths);
}
public User findByConfirmationToken(String confirmationToken) {
return userRepository.findByConfirmationToken(confirmationToken);
}
public void saveUser(User user){
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRepository.save(user);
}
public void saveRole(User user) {
Role role = new Role();
role.setRole("ROLE_USER");
role.setId(user.getId());
role.setUsername(user.getUsername());
userRolesRepository.save(role);
}
}
I call the method saveUser(user) and saveRole(user) during registration. The LOGGER.info message gives me "false" for bCryptPasswordEncoder.matches("password", user.getPassword()) even I wrote right password.
SOLVED
Okay, I just found out where was the mistake. I called method saveUser twice, during registration, and then during activation, so the password was encrypted twice. I solved that by adding method updateUser without using encryption.
Thank you for your help.
Try like this:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Create a default account
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
CustomUserDetails:
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User account = userDao.getUserByUsername(username);
System.out.println("User got from DB----------------------" + account.getPassword());
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
User user = new User(account.getUserName(), account.getPassword(), enabled, accountNonExpired,
credentialsNonExpired, accountNonLocked, getAuthorities(account.getRole()));
System.out.println(user.getPassword());
return user;
}

Categories