gipinani
gipinani

Reputation: 14408

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

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

Upvotes: 6

Views: 24293

Answers (2)

Rob Winch
Rob Winch

Reputation: 21720

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;
    }
}

Upvotes: 5

rocky
rocky

Reputation: 5004

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().....
}

Upvotes: 3

Related Questions