0

I am working on a Spring Boot 1.4.1 application (that implements some REST web services) and I am finding some difficulties trying to implement Spring Security into this project.

I have the following situation:

1) I have the CustomUserDetails that implements the Spring Security UserDetails interface:

import com.betrivius.domain.User;
import com.betrivius.domain.UserRole;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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() {
        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        for(UserRole role : this.getUserRoles() ){
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName());
            authorities.add(grantedAuthority);
        }

        return authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public String getUsername() {
        return super.getUsername();
    }

}

2) Then I have the CustomUserDetailsService implementing the Spring Security UserDetailsService interface:

import com.betrivius.dao.UserDAO;
import com.betrivius.domain.User;
import com.betrivius.security.bean.CustomUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
    @Autowired
    private UserDAO userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.findByUsername(username);
        if(user == null){
            throw new UsernameNotFoundException("No user present with username: "+username);
        }else{
            return new CustomUserDetails(user);
        }
    }

}

3) Finnally I have the Spring Security confinguration class named WebSecurityConfig extending the WebSecurityConfigurerAdapter:

import com.betrivius.security.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/Accomodation/**").access("hasRole('ROLE_USER')")
                .anyRequest().permitAll()
                .and()
                .csrf().disable();

  /*.and()
    .formLogin().loginPage("/login")
    .usernameParameter("username").passwordParameter("password")
  .and()
    .logout().logoutSuccessUrl("/login?logout") 
   .and()
   .exceptionHandling().accessDeniedPage("/403")
  .and()
    .csrf();*/
    }

    @Bean(name = "passwordEncoder")
    public PasswordEncoder passwordencoder() {
        return new BCryptPasswordEncoder();
    }
}

As you can see in the previous code snippet in the configuration class I have specified that only a user having the ROLE_USER setted can access to all the resources under the /Accomodation/ path, I have done it by:

.antMatchers("/Accomodation/**").access("hasRole('ROLE_USER')")

4) This is the UserDAO that obtain the user information used into the previous CustomUserDetailsService class:

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface UserDAO extends JpaRepository<User, Long> {

    User findByUsername(String username);

    @Query("SELECT r FROM User u JOIN u.userRoles r where u.username = :username")
    List<UserRole> findRoleByUserName(String username);
}

The username and password are stord in the DB and are:

USERNAME: ErSabba

PASSWORD: pswd

User table have a many to many relationship with User_Roles, the role of ErSabba user is ROLE_USER (tried setting USER as role).

So, by PostMan Chrome plugin I perform a GET Request toward the URL:

http://localhost:8080/Accomodation/7

passing the previous credential in this way:

enter image description here

As you can see the problem is that inserting the right username and password into the basic authentication form it give me 403 error Access denied.

I think that it means that I have perform the authentication but I have not the authorization.

The strange thing is that I also tried to put bad credential and I always obtain the same instead of 401 Bad Credential error.

I also have put a breakpoint on this line of the loadUserByUsername() method into the CustomUserDetailsService class (that retrieve the User info).

User user = userDao.findByUsername(username);

Running in debug mode it doesn't stop on this line so it seems that Spring Security configuration doesn't works fine...

What could be the problem? What am I missing? How can I try to fix it?

AndreaNobili
  • 40,955
  • 107
  • 324
  • 596

1 Answers1

0

I would recommend you to do a test without a DB. You can provide an inMemoryconfiguration, like this:

auth.inMemoryAuthentication().withUser("ErSabba").password("pswd").authorities("ROLE_USER");

and try to login then. If it would work, it will show that there is something wrong with credentials in DB.

How do you store password in DB? If it's plain text, it will not work, as you have password encoder, that should read you password as a hash.

Hope that helps.

m.aibin
  • 3,528
  • 4
  • 28
  • 47