spring - Permitir OPCIONES Método HTTP para solicitud de oauth/token
spring-security oauth-2.0 (3)
Estoy tratando de habilitar la obtención de tokens oauth2 para mi aplicación angular. Mi configuración funciona bien (la autenticación funciona correctamente para todas las solicitudes, la recuperación de tokens también funciona bien), pero hay un problema.
Las solicitudes CORS requieren que antes de GET se envíe una solicitud de OPCIONES al servidor. Para empeorar las cosas, esa solicitud no contiene encabezados de autenticación. Me gustaría que esta solicitud siempre vuelva con el estado 200 sin ninguna autenticación realizada en el servidor. ¿Es posible? Tal vez me estoy perdiendo algo
mi configuración de seguridad de primavera:
@Configuration
@EnableWebSecurity
@EnableAuthorizationServer
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
@Inject
private UserService userService;
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
@Bean
public WebResponseExceptionTranslator webResponseExceptionTranslator() {
return new DefaultWebResponseExceptionTranslator() {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
OAuth2Exception body = responseEntity.getBody();
HttpHeaders headers = new HttpHeaders();
headers.setAll(responseEntity.getHeaders().toSingleValueMap());
headers.set("Access-Control-Allow-Origin", "*");
headers.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
headers.set("Access-Control-Max-Age", "3600");
headers.set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
return new ResponseEntity<>(body, headers, responseEntity.getStatusCode());
}
};
}
@Bean
public AuthorizationServerConfigurer authorizationServerConfigurer() {
return new AuthorizationServerConfigurer() {
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
oAuth2AuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());
security.authenticationEntryPoint(oAuth2AuthenticationEntryPoint);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("secret-client")
.secret("secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_LOGIN")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60 * 60 * 12); // 12 hours
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenServices(tokenServices());
endpoints.authenticationManager(authenticationManager());
}
};
}
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.warn("FIX ME: REMOVE AFTER DEBUG!!!!!!!!!!!!");
log.debug("authenticate: " + authentication.getPrincipal() + ":" + authentication.getCredentials());
final Collection<GrantedAuthority> authorities = new ArrayList<>();
WomarUser user = userService.findUser(authentication.getPrincipal().toString(), authentication.getCredentials().toString());
for (UserRole userRole : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(userRole.getName()));
}
return new UsernamePasswordAuthenticationToken(user.getLogin(), user.getPassword(), authorities);
}
};
}
@Bean
public OAuth2AuthenticationManager auth2AuthenticationManager() {
OAuth2AuthenticationManager oAuth2AuthenticationManager = new OAuth2AuthenticationManager();
oAuth2AuthenticationManager.setTokenServices(tokenServices());
return oAuth2AuthenticationManager;
}
@Bean
public OAuth2AuthenticationProcessingFilter auth2AuthenticationProcessingFilter() throws Exception {
OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter = new OAuth2AuthenticationProcessingFilter();
oAuth2AuthenticationProcessingFilter.setAuthenticationManager(auth2AuthenticationManager());
return oAuth2AuthenticationProcessingFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
oAuth2AuthenticationEntryPoint.setRealmName("realmName");
oAuth2AuthenticationEntryPoint.setTypeName("Basic");
oAuth2AuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());
http
.antMatcher("/**").httpBasic()
.authenticationEntryPoint(oAuth2AuthenticationEntryPoint)
.and().addFilterBefore(auth2AuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/rest/womar/admin/**").hasRole("ADMIN")
.antMatchers("/rest/womar/**").hasRole("USER");
}
}
solicitud angular:
var config = {
params: {
grant_type: ''password'',
username: login,
password: password
},
headers: {
Authorization: ''Basic '' + Base64.encode(''secret-client'' + '':'' + ''secret'')
}
};
$http.get("http://localhost:8080/oauth/token", config)
.success(function(data, status) {
$log.log(''success'');
$log.log(data);
$log.log(status);
})
.error(function(data, status) {
$log.log(''error'');
$log.log(data);
$log.log(status);
});
Estaba usando la solución propuesta por idursun. La llamada a OPTION comenzó a funcionar, pero aún tenía problemas con Access-Control-Allow-Origin.
Esta implementación de filtro definitivamente funcionó para mí:
Solo agrego
@Order (Ordered.HIGHEST_PRECEDENCE)
en
La clase pública OAuth2SecurityConfig amplía WebSecurityConfigurerAdapter {....}
y configurar el soporte de la primavera
@Frijol
public CorsConfigurationSource corsConfigurationSource () {
Configuración de CorsConfiguration = new CorsConfiguration ();
configuration.setAllowedOrigins (Arrays.asList (" "));
configuration.setAllowedMethods (Arrays.asList (" "));
configuration.setAllowedHeaders (Arrays.asList ("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource ();
source.registerCorsConfiguration ("/ **", configuración);
fuente de retorno;
}
Trabajó para mi.
@EnableAuthorizationServer
está agregando la configuración de seguridad http para puntos finales como /oauth/token
, /oauth/token_key
etc. al orden 0. Entonces, lo que debe hacer es definir una regla de seguridad http para /oauth/token
endpoint solo para el método OPTIONS http que es en un orden superior
Algo como esto:
@Order(-1)
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
}
}