balteo
balteo

Reputation: 24679

Can I use both a GlobalMethodSecurityConfiguration and a WebSecurityConfigurerAdapter in a Spring app

My application has both a GlobalMethodSecurityConfiguration and a WebSecurityConfigurerAdapter configuration classes. My implementations are given below:

My GlobalMethodSecurityConfiguration implementation:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

    @Override
    protected AuthenticationManager authenticationManager() {
        AuthenticationManager authenticationManager = new ProviderManager();
        return authenticationManager;
    }

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(permissionEvaluator());
        return expressionHandler;
    }

    @Bean
    public ApplicationPermissionEvaluator permissionEvaluator() {
        return new ApplicationPermissionEvaluator(permissionMap());
    }

    private Map<String, Permission> permissionMap() {
        Map<String, Permission> map = new HashMap<>();
        map.put("CurriculumService:findCurriculumIsAllowed", curriculumByIdOwnerPermission());
        map.put("CurriculumService:updateCurriculumIsAllowed", curriculumOwnerPermission());

        return map;
    }

    @Bean(autowire=Autowire.BY_NAME)
    public CurriculumByIdOwnerPermission curriculumByIdOwnerPermission() {
        return new CurriculumByIdOwnerPermission();
    }

    @Bean(autowire=Autowire.BY_NAME)
    public CurriculumOwnerPermission curriculumOwnerPermission() {
        return new CurriculumOwnerPermission();
    }

}

and my WebSecurityConfigurerAdapter implementation:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //@formatter:off
        http
        //.csrf().disable()
        .exceptionHandling().authenticationEntryPoint(delegatingAuthenticationEntryPoint())
        .and().formLogin()
            .loginProcessingUrl("/signin")
            .loginPage("/signin")
            .failureUrl("/signin?login_error=t")
            .defaultSuccessUrl("/dashboard", Boolean.TRUE)
        .and().logout()
            .logoutUrl("/resources/j_spring_security_logout")
            .logoutSuccessUrl("/signin")
        .and().authorizeRequests()
            .accessDecisionManager(accessDecisionManager())
            .antMatchers("/preference/sendPasswordReset/**", "/preference/passwordReset/**", "/preference/activateEmail/**", "/preference/resendActivationEmail/**").permitAll()
            .antMatchers("/preference/**").access("hasAnyRole('ROLE_BASIC_CHILDMINDER', 'ROLE_BASIC_FAMILY')")
            .antMatchers("/dashboard").access("hasAnyRole('ROLE_BASIC_CHILDMINDER', 'ROLE_BASIC_FAMILY')")
            .antMatchers("/curriculum/**").access("hasRole('ROLE_BASIC_CHILDMINDER')")
            .antMatchers("/advertisement/**/view/**").permitAll()
            .antMatchers("/advertisement/family/**").access("hasRole('ROLE_BASIC_FAMILY')")
            .antMatchers("/advertisement/childminder/**").access("hasRole('ROLE_BASIC_CHILDMINDER')")
            .antMatchers("/resources/**", "/**").permitAll();
        //@formatter:on
        super.configure(http);
    }

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

    @Bean
    public MemberUserDetailsService userDetailsService() {
        return new MemberUserDetailsService();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder;
    }

    @Bean
    public SessionRegistryImpl sessionRegistry() {
        SessionRegistryImpl sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    }

    @Bean
    public AffirmativeBased accessDecisionManager() {
        AffirmativeBased accessDecisionManager = new AffirmativeBased(accessDecisionVoters());
        return accessDecisionManager;
    }

    public List<AccessDecisionVoter> accessDecisionVoters() {
        List<AccessDecisionVoter> accessDecisionVoters = new ArrayList<>();
        accessDecisionVoters.add(roleHierarchyVoter());
        accessDecisionVoters.add(webExpressionVoter());
        return accessDecisionVoters;
    }

    @Bean
    public WebExpressionVoter webExpressionVoter() {
        WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
        webExpressionVoter.setExpressionHandler(defaultWebSecurityExpressionHandler());
        return webExpressionVoter;
    }

    @Bean
    public DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler() {
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
        return defaultWebSecurityExpressionHandler;
    }

    @Bean
    public RoleHierarchyVoter roleHierarchyVoter() {
        RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());
        return roleHierarchyVoter;
    }

    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        //@formatter:off
        roleHierarchy.setHierarchy(
                "ROLE_ADMINISTRATOR > ROLE_MODERATOR\n" +
                "ROLE_MODERATOR > ROLE_SUBSCRIBED_FAMILY\n" +
                "ROLE_MODERATOR > ROLE_SUBSCRIBED_CHILDMINDER\n" +
                "ROLE_SUBSCRIBED_FAMILY > ROLE_BASIC_FAMILY\n" +
                "ROLE_SUBSCRIBED_CHILDMINDER > ROLE_BASIC_CHILDMINDER");
        //@formatter:on
        return roleHierarchy;
    }

    @Bean
    public DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint() {
        DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint = new DelegatingAuthenticationEntryPoint(map());
        delegatingAuthenticationEntryPoint.setDefaultEntryPoint(loginUrlAuthenticationEntryPoint());
        return delegatingAuthenticationEntryPoint;
    }

    public LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> map() {
        LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> map = new LinkedHashMap<>();
        map.put(ajaxRequestMatcher(), ajaxAuthenticationEntryPoint());
        return map;
    }

    @Bean
    public LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint() {
        LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint = new LoginUrlAuthenticationEntryPoint("/signin");
        return loginUrlAuthenticationEntryPoint;
    }

    @Bean
    public AjaxAuthenticationEntryPoint ajaxAuthenticationEntryPoint() {
        AjaxAuthenticationEntryPoint ajaxAuthenticationEntryPoint = new AjaxAuthenticationEntryPoint();
        return ajaxAuthenticationEntryPoint;
    }

    @Bean
    public AjaxRequestMatcher ajaxRequestMatcher() {
        AjaxRequestMatcher ajaxRequestMatcher = new AjaxRequestMatcher();
        return ajaxRequestMatcher;
    }

    @Bean
    public RequestDataValueProcessor requestDataValueProcessor() {
        return new CsrfRequestDataValueProcessor();
    }
}

I am not sure how to configure the authentication manager. Is the following a correct way of proceeding?

 @Override
    protected AuthenticationManager authenticationManager() {
        AuthenticationManager authenticationManager = new ProviderManager();
        return authenticationManager;
    }

Any input welcome...

Upvotes: 22

Views: 12028

Answers (2)

John Velonis
John Velonis

Reputation: 1649

I was looking for a way to do this too. The following worked for me:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends GlobalMethodSecurityConfiguration {
    @Autowired
    protected void configureGlobal (AuthenticationManagerBuilder auth) {
        // Configure auth mgr
    }

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        // Configure expression handler
    }

    @Configuration
    public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // Configure HTTP security
        }
    }
}

Upvotes: 9

user2374125
user2374125

Reputation: 1

You could override the configure(AuthencationManagerBuilder auth) method in WebSecurityConfigurerAdapter. If your requirement is just use your UserDetailsService, you could do as below

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
}

From your code, you may use below method.

authenticationManagerBuilder.authenticationProvider(AuthenticationProvider authenticationProvider)

If you have more complex requirement, you may refer spring security API. http://docs.spring.io/spring-security/site/docs/3.2.0.RC2/apidocs/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.html

Upvotes: 0

Related Questions