SecurityConfig.java

/*
 * +====================================================================+
 * |         Copyright (C) 2015 Rochester Institute of Technology,      |
 * |            103 Lomb Memorial Drive, Rochester, NY - 14623          |
 * |                        All Rights Reserved.                        |
 * +====================================================================+
 *   FILENAME
 *    SecurityConfig.java
 *
 *   AUTHOR
 *    @author Khanh Ho (kchisd at rit.edu)
 *
 * =====================================================================
 */

package edu.rit.coopeval.security;

import java.util.LinkedHashMap;
import java.util.Map;

import edu.rit.coopeval.security.sso.ShibbolethAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.*;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

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

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Autowired
    private AuthenticationSettings props;

    @Autowired
    private Map<String, UserDetailsService> uds;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        if (props.getShib().isEnabled()) {
            logger.debug("Adding Shibboleth authentication filter");
            http.addFilter(shibFilter());
        }

        http.formLogin().loginPage("/login").usernameParameter("email").passwordParameter("password")
            .and().exceptionHandling()
            .authenticationEntryPoint(delegatingAep()).accessDeniedPage("/error/unauthorized")
            .and().authorizeRequests()
            .antMatchers("/login**", "/error**", "/libs**", "/api/testing/**").permitAll()
            .anyRequest().authenticated()
            .and().csrf().disable();
    }

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        if (props.getShib().isEnabled()) {
            logger.debug("Setting up Shibboleth authentication provider");
            auth.authenticationProvider(preauthAuthProvider());
        }
        auth.userDetailsService(uds.get("dbUserDetailsService")).passwordEncoder(passwordEncoder);
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
        PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
        provider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
        return provider;
    }

    private UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> userDetailsServiceWrapper() {
        UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper = new UserDetailsByNameServiceWrapper<>();
        wrapper.setUserDetailsService(uds.get("shibUserDetailsService"));
        return wrapper;
    }

    private ShibbolethAuthenticationFilter shibFilter() throws Exception {
        ShibbolethAuthenticationFilter filter = new ShibbolethAuthenticationFilter();
        filter.setShibPath(props.getShib().getPath());
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    private AuthenticationEntryPoint delegatingAep() {
        LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
        entryPoints.put(new AntPathRequestMatcher(props.getShib().getPath()), new Http403ForbiddenEntryPoint());
        entryPoints.put(new AntPathRequestMatcher("/**"), new LoginUrlAuthenticationEntryPoint("/login"));
        return new DelegatingAuthenticationEntryPoint(entryPoints);
    }
}