Search code examples
javasecurityspring-securityspring-4userdetailsservice

Spring Security (Java Configuration) problems


Hello everybody,

I have a task where I have to create 3 pages: /login- where we have email and password inputs, /result - where we have to tell user does he authificated or not, and in case of successful we can show 3rd page - /dataEntry where we can saveOrUpdate user's info in DataBase.

The difference of typical project is users email and passwords are in USERS.XML not in DataBase(DB)

I've parsed it by sax and dom.

Parser returns HashMap where 'key' is 'email'and 'value' is 'password'.

Than I did default domains:

1) Login.class - is the main class to auth and to work only with users.xml. It has next fields: email , password.

2) User.class - to work with DB (save,update,load user's info). It has next fields: id, email, firstName, secondName, gender.

Next I did dao and service layers of this domains. On the bottom of my ask I will give a link for bitbucket but please read my question all.

I configure project by Java , so I did Hibernate configuration (it works correct), Web configuration (seems like it works correctly too) and Security Configuration (at this moment I want to start crying).

My Security Configuration:

SecurityWebApplicationInitializer

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
}

SecurityConfiguration

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

/**
 * Holds userDetailsService
 */
@Autowired
@Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;

/**
 * Gets BCryptPasswordEncoder object.
 *
 * @return BCryptPasswordEncoder object.
 */
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

/**
 * Gets DaoAuthenticationProvider with its parameters
 *
 * @return authenticationProvider
 */
@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
    authenticationProvider.setUserDetailsService(userDetailsService);
    authenticationProvider.setPasswordEncoder(passwordEncoder());
    return authenticationProvider;
}

/**
 * Sets GlobalSecurity parameters.
 *
 * @param auth - AuthenticationManagerBuilder object.
 * @throws Exception
 */
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider());
}

/**
 * Sets Encoding parameters to work with russian locale, filters to get access to any page.
 * /index is login and logout page by default - everybody can open this page.
 * /result is page with results of login - everybody can open this page.
 * /dataEntry is page to save/update/load user's info - only registered user can open this page.
 *
 * @param http - {@link HttpSecurity} object
 * @throws Exception
 */
@Override
public void configure(HttpSecurity http) throws Exception {
    //To work with UTF-8 and RU locale
    CharacterEncodingFilter f = new CharacterEncodingFilter();
    f.setEncoding("UTF-8");
    f.setForceEncoding(true);

    http
            .addFilterBefore(f, CsrfFilter.class)
            .formLogin().loginPage("/index").defaultSuccessUrl("/result")
            .usernameParameter("email").passwordParameter("password")
            .and().logout().logoutSuccessUrl("/index").invalidateHttpSession(true)
            .and().httpBasic().realmName("ArtezioWebApp")
            .and().authorizeRequests()
            .antMatchers("/", "/index", "/result/**").permitAll()
            .antMatchers("/result/**").hasAnyAuthority("ROLE_USER","ROLE_ANONYMOUS")
            .antMatchers("/dataEntry/**").hasAuthority("ROLE_USER")
            .and().csrf()
            .and().exceptionHandling().accessDeniedPage("/result?error");
}

CustomUserDetailsService

public class CustomUserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {

/**
 * Holds logger.
 */
private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);

/**
 * Holds {@link LoginService} object
 */
@Autowired
@Qualifier("loginService")
private LoginService loginService;

@Autowired
@Qualifier("login")
Login login;

/**
 * Gets UserDetailsService object with parameters - email, password, authorities.
 *
 * @param email - by default has alias 'userName'
 * @return UserDetailsService object with email,password and authorities.
 * @throws UsernameNotFoundException if user was not found in *.xml file.
 */
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    //All users emails and passwords
    HashMap<String, String> h = loginService.getUsers();
    logger.info("Searching user with email '{}'...", email);

    if (loginService.isValidEmail(email)) {
        logger.info("User with email '{}' was found.", email);

        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        //Saves data in Login object
        login.setPassword(h.get(email));
        login.setEmail(email);
        return new org.springframework.security.core.userdetails.User(login.getEmail(),
                login.getPassword(), true, true, true, true, authorities);
    }
    throw new UsernameNotFoundException("User with email '" + email + "' not found.");
}

When I debugged project I noticed that @Overloaded method loadByUsername(String email) is never invoked.

SecurityContext returns me anonymusUser even I entered correct email and password. So I cant get access to /dataEntry page.

LINK TO BITBUCKET: Bitbucket

Anybody please help me. Thank you much.


Solution

  • Need to add login-processing-url as "/j_spring_security_check" to work and add action on your login form as "j_spring_security_check". Read more here : Spring migration