Spring: Enable global method security in Controller layer by java config

22,899

Solution 1

Update (after updated question)

It appears you are encountering SEC-2479. There are a few ways around this. The easiest of which is to use the result of @Autowired for the AuthenticationManager. To do this you must extend GlobalMethodSecurityConfiguration and override the authenticationManager method.

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Autowired
    private AuthenticationManager am;

    @Override
    protected AuthenticationManager authenticationManager() {
        return am;
    }
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        // ... create and return custom MethodSecurityExpressionHandler ...
        return expressionHander;
    }
}

Original Answer

You need to configure some sort of Authentication. So you will need to have the following:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .inMemoryAuthentication()
            .withUser("user").password("password").roles("USER");
}

If you are not using web based security, the reference provides an example of how to configure the method security expression handler.

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        // ... create and return custom MethodSecurityExpressionHandler ...
        return expressionHander;
    }
}

If you are only wanting a custom method expression handler to provide a permission evaluator, then you only need to create a PermissionEvaluator bean like this:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }
    @Bean
    public PermissionEvaluator permissionEvaluator() {
        // ... create and return custom PermissionEvaluator ...
        return permissionEvaluator;
    }
}

Solution 2

first of all you need a separate Configuration class like

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {...

where you need to define

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
}

that should help with your exception.

I am not sure how to configure expressionHandler, but seems you can tweak it in configure(WebSecurity web)

@Override
public void configure(WebSecurity web) throws Exception {
    web.expressionHandler().....
}
Share:
22,899
gipinani
Author by

gipinani

Updated on July 10, 2022

Comments

  • gipinani
    gipinani almost 2 years

    I'm trying to migrate my xml servlet config to java config.

    The below config is my servlet configuration, that enables custom security annotations on Controller layer.

    <security:global-method-security pre-post-annotations="enabled">
        <security:expression-handler ref="expressionHandler"/>
    </security:global-method-security>
    
    <bean id="expressionHandler" class="yyy.MyMethodSecurityExpressionHandler" />
    

    I've also have a working spring security xml configuration, that is in order to be replaced by java config, but not now. Here some pieces of my security config:

    <bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
            <property name="userDetailsService" ref="userDetailsService" />
        </bean>
    
    <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <constructor-arg>
             <ref bean="authenticationProvider"/>
        </constructor-arg>
    </bean>
    
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userDetailsService" />
    </security:authentication-manager>
    
    <security:global-method-security pre-post-annotations="enabled" />
    

    I want to start to migrate my servlet config enabling security @PreAuthorize and @PostAuthorize tag in Controller layer.

    I've found this annotation: @EnableGlobalMethodSecurity(prePostEnabled=true), but putting it on my servlet config:

    @Configuration
    @ComponentScan(basePackages= {
            "....."         
    })
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    
    public class WebappServletConfig extends WebMvcConfigurationSupport {
    

    I get this exception:

    java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
    

    Moreover I don't know how to set my custom expression-handler!

    someone with some tips? Thank you

  • Rob Winch
    Rob Winch about 10 years
    the protected configure method is isolated to only the WebSecurityConfigurerAdapter (that is why the method scope is protected). This means the authentication will not be found by the global method security support. Instead global authentication should be configured as demonstrated in my example. Also note that the expression handler you have here is for the web and not method level security.
  • gipinani
    gipinani about 10 years
    thank you for your answer. I already have a spring security configuration that is in xml. It will be translated but not now. I wan't only to extend Pre/Post Authorize tags to Controller layer..
  • gipinani
    gipinani about 10 years
    thank you for your answer. I already have a spring security configuration that is in xml. It will be translated but not now. I wan't only to extend Pre/Post Authorize tags to Controller layer..
  • Rob Winch
    Rob Winch about 10 years
    How did you define your AuthenticationManager?