Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow OPTIONS HTTP Method for oauth/token request

I'm trying to enable oauth2 token fetching for my angular application. My configuration is working fine (authentication is working correctly for all requests, token fetching is working fine as well) but there is one problem.

CORS requests require that before GET an OPTIONS request is sent to the server. To make it worse, that request does not contain any authentication headers. I would like to have this request always returning with 200 status without any authentication done on the server. Is it possible? Maybe I'm missing something

my spring security config:

@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"); } 

}

angular request:

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);     }); 
like image 382
Wojtek Wysocki Avatar asked Aug 05 '14 10:08

Wojtek Wysocki


People also ask

How do I use HTTP options method?

The HTTP OPTIONS method requests permitted communication options for a given URL or server. A client can specify a URL with this method, or an asterisk ( * ) to refer to the entire server.

Can OAuth work on HTTP?

More specifically, OAuth is a standard that apps can use to provide client applications with “secure delegated access”. OAuth works over HTTPS and authorizes devices, APIs, servers, and applications with access tokens rather than credentials.

What is authorization URL in OAuth?

The first step of the web flow is to request authorization from the user. This is accomplished by creating an authorization request link for the user to click on. The authorization URL is usually in a format such as: https://authorization-server.com/oauth/authorize.


1 Answers

@EnableAuthorizationServer is adding http security configuration for endpoints like /oauth/token, /oauth/token_key etc at order 0. So what you should do is to define a http security rule for /oauth/token endpoint only for the OPTIONS http method which is at a higher order.

Something like this:

@Order(-1) @Configuration public class MyWebSecurity extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        http           .authorizeRequests()           .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()    } } 
like image 98
idursun Avatar answered Sep 28 '22 10:09

idursun