Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PreAuthorize and custom AuthenticationFilter with Spring boot

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.

like image 509
cwittah Avatar asked Apr 21 '15 14:04

cwittah


People also ask

What is Spring boot PreAuthorize?

Method-level security is implemented by placing the @PreAuthorize annotation on controller methods (actually one of a set of annotations available, but the most commonly used). This annotation contains a Spring Expression Language (SpEL) snippet that is assessed to determine if the request should be authenticated.

What is the primary difference between @secured and @PreAuthorize?

The real difference is that @PreAuthorize can work with Spring Expression Language (SpEL). You can: Access methods and properties of SecurityExpressionRoot . (Advanced feature) Add your own methods (override MethodSecurityExpressionHandler and set it as <global-method-security><expression-handler ... /></...> ).


1 Answers

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.

like image 135
Serge Ballesta Avatar answered Sep 20 '22 08:09

Serge Ballesta