9
votes

I have custom authentication filter which creates PreAuthenticatedAuthenticationToken and stores it in security context. The filter works fine, it creates the token with the appropriate granted authorities "ROLE_user" and "ROLE_adminuser". Here's my config:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        X509AuthenticationFilter filter = new X509AuthenticationFilter()
        filter.setAuthenticationManager(authenticationManager())
        http.addFilterAfter(filter, SecurityContextPersistenceFilter.class)
        http.authorizeRequests().anyRequest().permitAll()
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean()
        X509AuthenticationFilter filter = new X509AuthenticationFilter()
        filter.setAuthenticationManager(authenticationManager())
        registrationBean.setFilter(filter)
        registrationBean.setEnabled(false)
        return registrationBean
    }

I'm inserting the Filter before the SecurityContextPersistenceFilter as mentioned in: Spring security and custom AuthenticationFilter with Spring boot.

This seems to work fine, however, when I attempt to add a PreAuthorize annotation to my controller method, like so:

@Controller
@RequestMapping("/security")
class SecurityController {

    @RequestMapping("/authenticate")
    @PreAuthorize("hasRole('ROLE_user')")
    @ResponseBody
        ResponseEntity<String> authenticate(HttpServletRequest request,     Principal principal) {
        println "authenticate: " +     SecurityContextHolder.getContext().getAuthentication()

        return new ResponseEntity<String>(getPreAuthenticatedPrincipal(request), HttpStatus.OK)
    }

I get a 404 error. If I comment out the PreAuthorize annotation the method call works and you can see that I print out the authentication information and the authenticated user has ROLE_user and ROLE_adminuser for its granted authorities. I'm not sure what I'm doing wrong.

Here's the print out of the authentication object in the principal when "PreAuthorize" is commented out:

authenticate: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@817a0240: Principal: org.springframework.security.ldap.userdetails.LdapUserDetailsImpl@c279eab8: Dn: uid=1,ou=people,dc=cdpe,dc=mil; Username: [email protected]; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; CredentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_adminuser, ROLE_user; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_adminuser, ROLE_user authorities: [ROLE_adminuser, ROLE_user]

Update: I've made a little progress. I added the proxyTargetClass to the following annotation:

 @EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)

Now I'm getting 403 Forbidden returns when I call my method. I have no idea what that is doing.

2
If this is Spring Security 4 or higher, than hasRole() method accepts role without ROLE_ prefix. So your check should be some think like this @PreAuthorize("hasRole('user')")Oleg Kuts

2 Answers

10
votes

Spring Security has always been tedious to configure, and the only foolproof ways are:

  • either being an expert on it and be prepared to look in the sources and then you can do hard things by hand
  • or use as much as possible of what is provided by framework using examples from the documentation whenever possible

For the configuration of an X509AuthenticationFilter, HttpSecurity javadoc gives the method x509 with following example (adapted to your config - see javadoc for original one) :

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {    

     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http
             .authorizeRequests().anyRequest().permitAll()
             // Example x509() configuration
             .x509();
     }
 }

with following indication: method returns the X509Configurer for further customizations.

Unless you have a good reason to do differently (and if it is the case please say it) I strongly advise you to stick to that method.

But it is really a bad idea to use pre-post annotation on a controller, for what could be done directly in HttpSecurity configuration. It forced you to use proxyTargetClass = true.

Pre and post annotation are normally applied to methods of service layer what do not require proxyTargetClass=true since services are normally wired to controller through interfaces allowing JDK proxying.

0
votes

Thanks for your help. For this example I'm being forced to re-use an already working Spring security custom filter. I'm just trying to get it to work in the spring-boot context.

Adding the proxyTargetClass = true to the above code seems to have fixed the problem.