package it.inaf.ia2.gms.authn; import java.util.Arrays; 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 { @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/basic/**", "/ws/jwt/**", "/error"); } /** * Checks the BasicAuth for GMS clients. */ @Bean public FilterRegistrationBean serviceBasicAuthFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new ServiceBasicAuthFilter()); bean.addUrlPatterns("/ws/basic/*"); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } /** * Checks JWT for web services. */ @Bean public FilterRegistrationBean serviceJWTFilter(JwkTokenStore jwkTokenStore) { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new JWTFilter(jwkTokenStore)); 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() { 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; } }