I mentioned "simulate" previously since the demo application turns the two factor authentication problem into a normal authentication plus authorisation problem. When valid credentials (here: email and password) are provided the PRE_AUTH_USER role is assigned to the user. With this role the user is authorised only to access the view where the verification code can be provided. If the correct verification code is provided the user will be granted with the USER role, with which all the views can be accessed.
Below you can see how easy is to configure Spring Security with the Java config introduced in version 3.2
In order to support non-security related user information, the AccountRepository is adapted to the UserDetailsService, so Spring Security can use it as an authentication source.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/signup", "/static/**").permitAll()
.antMatchers("/code").hasRole("PRE_AUTH_USER")
.antMatchers("/home").hasRole("USER")
.anyRequest().authenticated();
http.formLogin()
.loginPage("/login")
.permitAll()
// always use the default success url despite if a protected page had been previously visited
.defaultSuccessUrl("/code", true)
.and()
.logout()
.permitAll();
For the second step verification a time based one time password (TOTP) verification algorithm is used, which is described very good here.
public class UserDetailsServiceAdapter implements UserDetailsService {
@Autowired
private AccountRepository accountRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountRepository.findByEmail(username);
if (account == null) {
throw new UsernameNotFoundException(username);
}
return new UserDetailsAdapter(account);
}
}