package it.inaf.ia2.gms.authn; import it.inaf.ia2.gms.persistence.LoggingDAO; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration @EnableOAuth2Sso public class SecurityConfig extends WebSecurityConfigurerAdapter { private static final Logger LOG = LoggerFactory.getLogger(SecurityConfig.class); @Autowired private Environment env; @Value("${cors.allowed.origin}") private String corsAllowedOrigin; @Value("${security.oauth2.resource.jwk.key-set-uri}") private String keySetUri; @Bean public JwkTokenStore jwkTokenStore() { return new JwkTokenStore(keySetUri); } @Override public void configure(HttpSecurity http) throws Exception { super.configure(http); // CORS are necessary only for development (API access from npm server) if (Arrays.asList(env.getActiveProfiles()).contains("dev")) { http.authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll(); } http.csrf().disable(); } /** * The authentication is ignored for these endpoints. The "/ws/basic" * endpoints (web service API for programmatic access) are protected by the * custom ServiceBasicAuthFilter that checks BasicAuth for GMS clients, * while the "/ws/jwt" endpoints are protected by the JWTFilter. */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/ws/jwt/**", "/error", "/logout", "/invited-registration"); } /** * Checks JWT for web services. */ @Bean public FilterRegistrationBean serviceJWTFilter(JwkTokenStore jwkTokenStore, LoggingDAO loggingDAO) { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new JWTFilter(jwkTokenStore, loggingDAO)); bean.addUrlPatterns("/ws/jwt/*"); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } /** * CORS are necessary only for development (API access from npm server). */ @Bean @Profile("dev") public FilterRegistrationBean corsFilter() { LOG.warn("Development profile active: CORS filter enabled"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); config.addAllowedMethod(HttpMethod.PUT); config.addAllowedMethod(HttpMethod.DELETE); config.setAllowedOrigins(Arrays.asList(corsAllowedOrigin)); config.setAllowCredentials(true); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } }