I am developing an API using Spring 3. I want all my users to be logged in when performing a request and so I tried to implement Basic HTTP Auth. I don't want to use XML (most of the doc uses XML).
The server currently replies 401 to every requests and my web-browser does not ask me for authentication. Where am I going wrong?
I searched many websites and here's what I've got so far:
Application class:
@Configuration
@EnableJpaRepositories
@EnableAutoConfiguration
@ComponentScan
public class Application
{
@Bean
public BasicAuthenticationFilter basicAuthenticationFilter(BasicAuthenticationEntryPoint basicAuthenticationEntryPoint,
AuthenticationManager authenticationManager)
{
BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(authenticationManager, basicAuthenticationEntryPoint);
return basicAuthenticationFilter;
}
@Bean
public UserDetailsService userDetailsService()
{
return new PersonService();
}
@Bean
public AuthenticationManager authenticationManager()
{
return new AuthenticationManagerImpl();
}
@Bean
public AuthenticationProvider authenticationProvider()
{
return new CustomAuthenticationProvider();
}
@Bean
public BasicAuthenticationEntryPoint basicAuthenticationEntryPoint()
{
BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthenticationEntryPoint.setRealmName("Doccto");
return basicAuthenticationEntryPoint;
}
}
My custom AuthenticationManager
@Component
public class AuthenticationManagerImpl implements AuthenticationManager
{
@Autowired
protected AuthenticationProvider authenticationProvider;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
return this.authenticationProvider.authenticate(authentication);
}
}
PersonService.class :
@Service
public class PersonService implements UserDetailsService
{
@Autowired
protected PersonRepository personRepository;
@Override
public Person loadUserByUsername(String s) throws UsernameNotFoundException
{
return this.personRepository.getUserByEmail(s);
}
}
CustomAuthenticationProvider
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider
{
@Autowired
protected PersonService personService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
String username = authentication.getName();
String password = (String) authentication.getCredentials();
Person person = this.personService.loadUserByUsername(username);
if (person == null)
{
throw new BadCredentialsException("Username not found.");
}
if (!password.equals(person.getPassword()))
{
throw new BadCredentialsException("Wrong password.");
}
Collection<? extends GrantedAuthority> authorities = person.getAuthorities();
return new UsernamePasswordAuthenticationToken(username, password, authorities);
}
@Override
public boolean supports(Class<?> aClass)
{
return true;
}
}
SecurityConfig.class
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/api/**").hasRole("USER")
.anyRequest().authenticated();
}
I think that's it.
I finally found the solution. I had to bind all my pieces of code together in SecurityConfig like
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
protected BasicAuthenticationFilter filter;
@Autowired
protected AuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.addFilter(filter)
.authenticationProvider(authenticationProvider)
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/**").hasRole("USER")
.anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
}
}