AuthenticationManagerBuilder in Spring Security is not working all time correctly, why?

Question

I am going to implement spring security on my spring boot application. For that I usually follow Spring boot and Spring Security integration for Rest API's and I got details at SpringSecurity : Authenticate User with Custom UserDetailsService.

Entity: User and Role creates 3 tables into database (user, role & user_roles)

User

package com.maxpro.entity;

import javax.persistence.*;
import java.util.Set;


@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String username;
    private String password;
    private boolean enabled;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;

    // getters, setters & toString
}

Role

package com.maxpro.entity;

import javax.persistence.*;
import java.util.Set;


@Entity
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String role;

    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
    private Set<User> users;

    // getters, setters & toString
}

Repository: UserRepository

package com.maxpro.repository;

import com.maxpro.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;


@Repository("userRepository")
public interface UserRepository extends JpaRepository<User, Long> {

    User findByUsername(String username);

}

Config: WebSecurityConfigurer uses WebUserDetailsService custom authentication builder

WebSecurityConfigurer

package com.maxpro.security;

import com.maxpro.repository.UserRepository;
import com.maxpro.security.service.WebUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
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.web.util.matcher.AntPathRequestMatcher;


@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserRepository userRepository;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsServiceBean());
    }

    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return new WebUserDetailsService(userRepository);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/css/**", "/img/**", "/js/**").permitAll()
                    .antMatchers("/", "/home").permitAll()
                    .antMatchers("/admin/**").hasAuthority("ADMIN")
                    .antMatchers("/user/**").hasAuthority("USER")
                    .anyRequest().authenticated()
                .and()
                    .formLogin()
                        .loginPage("/login")
                            .usernameParameter("username").passwordParameter("password").permitAll()
                .and()
                    .logout()
                        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                        .logoutSuccessUrl("/")
//                .and()
//                    .exceptionHandling().accessDeniedPage("/403")
//                .and()
//                    .csrf();
        ;
    }

}

WebUserDetailsService

package com.maxpro.security.service;

import com.maxpro.entity.Role;
import com.maxpro.entity.User;
import com.maxpro.repository.UserRepository;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import javax.transaction.Transactional;
import java.util.HashSet;
import java.util.Set;


@Transactional
public class WebUserDetailsService implements UserDetailsService {

    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(WebUserDetailsService.class);

    private UserRepository userRepository;

    public WebUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            User user = userRepository.findByUsername(username);
            if (user == null) {
                LOGGER.debug("user not found with the provided username");
                return null;
            }
            LOGGER.debug(" user from username " + user.toString());
            return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthorities(user));
        }
        catch (Exception e){
            throw new UsernameNotFoundException("User not found");
        }
    }

    private Set<GrantedAuthority> getAuthorities(User user){
        Set<GrantedAuthority> authorities = new HashSet<>();
        for(Role role : user.getRoles()) {
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRole());
            authorities.add(grantedAuthority);
        }
        LOGGER.debug("user authorities are " + authorities.toString());
        return authorities;
    }

}

Problems: Sometime it can authenticate and sometime not. Why?

Questions: Is there any problem with loadUserByUsername() in WebUserDetailsService custom authentication builder?

Notes: I figured out that username is passed to loadUserByUsername() in WebUserDetailsService class. I think UserRepository returns null User even though I passed correct username to the repository.

Resources: Here is my codes on Github.


Show source
| java   | security   | spring   | spring-mvc   | spring-security   2017-01-07 12:01 0 Answers

Answers ( 0 )

◀ Go back