001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.gbif.ws.security; 015 016import org.gbif.ws.server.filter.AppIdentityFilter; 017import org.gbif.ws.server.filter.HttpServletRequestWrapperFilter; 018import org.gbif.ws.server.filter.IdentityFilter; 019import org.gbif.ws.server.filter.RequestHeaderParamUpdateFilter; 020 021import java.util.Arrays; 022import java.util.Collections; 023 024import org.springframework.context.ApplicationContext; 025import org.springframework.context.annotation.Bean; 026import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 027import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 028import org.springframework.security.config.annotation.web.builders.HttpSecurity; 029import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 030import org.springframework.security.config.http.SessionCreationPolicy; 031import org.springframework.security.core.userdetails.UserDetailsService; 032import org.springframework.security.crypto.password.PasswordEncoder; 033import org.springframework.security.web.csrf.CsrfFilter; 034import org.springframework.web.cors.CorsConfiguration; 035import org.springframework.web.cors.CorsConfigurationSource; 036import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 037 038/** 039 * Security Adapter that disables the authentication redirect and use GBIF identity filters for secure endpoints. 040 * UserDetailsService and PasswordEncoder must be supplied by the SpringContext. 041 * This class is not annotated to avoid automatic instantiation. To use it create a subclass of it: 042 * <pre> 043 * @Configuration 044 * @EnableWebSecurity 045 * public static class ValidatorWebSecurity extends NoAuthWebSecurityConfigurer { 046 * 047 * public ValidatorWebSecurity( 048 * UserDetailsService userDetailsService, ApplicationContext context, PasswordEncoder passwordEncoder 049 * ) { 050 * super(userDetailsService, context, passwordEncoder); 051 * } 052 * } 053 * <pre/> 054 */ 055public class NoAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter { 056 057 private final UserDetailsService userDetailsService; 058 059 private final PasswordEncoder passwordEncoder; 060 061 public NoAuthWebSecurityConfigurer( 062 UserDetailsService userDetailsService, 063 ApplicationContext context, 064 PasswordEncoder passwordEncoder) { 065 this.userDetailsService = userDetailsService; 066 setApplicationContext(context); 067 this.passwordEncoder = passwordEncoder; 068 } 069 070 @Override 071 protected void configure(AuthenticationManagerBuilder auth) { 072 auth.authenticationProvider(dbAuthenticationProvider()); 073 } 074 075 private DaoAuthenticationProvider dbAuthenticationProvider() { 076 final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); 077 authProvider.setUserDetailsService(userDetailsService); 078 authProvider.setPasswordEncoder(passwordEncoder); 079 return authProvider; 080 } 081 082 @Override 083 protected void configure(HttpSecurity http) throws Exception { 084 http.httpBasic() 085 .disable() 086 .addFilterAfter( 087 getApplicationContext().getBean(HttpServletRequestWrapperFilter.class), 088 CsrfFilter.class) 089 .addFilterAfter( 090 getApplicationContext().getBean(RequestHeaderParamUpdateFilter.class), 091 HttpServletRequestWrapperFilter.class) 092 .addFilterAfter( 093 getApplicationContext().getBean(IdentityFilter.class), 094 RequestHeaderParamUpdateFilter.class) 095 .addFilterAfter( 096 getApplicationContext().getBean(AppIdentityFilter.class), IdentityFilter.class) 097 .csrf() 098 .disable() 099 .cors() 100 .and() 101 .authorizeRequests() 102 .anyRequest() 103 .authenticated(); 104 105 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); 106 } 107 108 @Bean 109 CorsConfigurationSource corsConfigurationSource() { 110 // CorsFilter only applies this if the origin header is present in the request 111 CorsConfiguration configuration = new CorsConfiguration(); 112 configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type")); 113 configuration.setAllowedOrigins(Collections.singletonList("*")); 114 configuration.setAllowedMethods( 115 Arrays.asList("HEAD", "GET", "POST", "DELETE", "PUT", "OPTIONS")); 116 configuration.setExposedHeaders( 117 Arrays.asList( 118 "Access-Control-Allow-Origin", 119 "Access-Control-Allow-Methods", 120 "Access-Control-Allow-Headers")); 121 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 122 source.registerCorsConfiguration("/**", configuration); 123 return source; 124 } 125}