web-dev-qa-db-ja.com

oauth / tokenリクエストのOPTIONS HTTPメソッドを許可する

私はangular application。のoauth2トークンフェッチを有効にしようとしています。すべてのリクエストに対して認証が正常に機能し、トークンフェッチも正常に動作しています)、1つの問題があります。

CORS要求では、GETの前にOPTIONS要求がサーバーに送信される必要があります。さらに悪いことに、そのリクエストには認証ヘッダーが含まれていません。サーバーで認証を行わずに、常に200ステータスでこのリクエストを返すようにしたいと思います。出来ますか?たぶん私は何かを見逃している

私の春のセキュリティ設定:

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

}

角度のリクエスト:

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);
    });
35
Wojtek Wysocki

@EnableAuthorizationServerは、/oauth/token/oauth/token_keyなどのエンドポイントのHTTPセキュリティ設定を0の順序で追加しています。したがって、/oauth/tokenエンドポイントのみのHTTPセキュリティルールを定義する必要があります高次のOPTIONS httpメソッド。

このようなもの:

@Order(-1)
@Configuration
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
   @Override
   protected void configure(HttpSecurity http) throws Exception {
       http
          .authorizeRequests()
          .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
   }
}
40
idursun

Idursunが提案したソリューションを使用していました。 OPTION呼び出しは機能し始めましたが、Access-Control-Allow-Originにはまだ問題がありました。

このフィルターの実装は、私にとって間違いなく機能しました。

スタンドアロンSpring OAuth2 JWT承認サーバー+ CORS

5
camposer

追加するだけです

@Order(Ordered.HIGHEST_PRECEDENCE)

public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {....}

スプリングのサポートを設定します

@Bean
public CorsConfigurationSource corsConfigurationSource() {
  CorsConfiguration configuration = new CorsConfiguration();
  configuration.setAllowedOrigins(Arrays.asList("*"));
  configuration.setAllowedMethods(Arrays.asList("*"));
  configuration.setAllowedHeaders(Arrays.asList("*"));

  UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  source.registerCorsConfiguration("/**", configuration);
  return source;
}

私のために働いた。

3

以下は、Spring Boot 2で機能します。それ以外の場合、他のCORS構成は選択されません。

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    // this is a Spring ConfigurationProperty use any way to get the CORS values
    @Autowired
    private CorsProperties corsProperties;

    // other things
    //...

    @Override
    public void configure(
            AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .tokenStore(tokenStore())
                .authenticationManager(authenticationManager);
        if (corsProperties.getAllowedOrigins() != null) {
            Map<String, CorsConfiguration> corsConfigMap = new HashMap<>();
            Arrays.asList(corsProperties.getAllowedOrigins().split(",")).stream()
                    .filter(StringUtils::isNotBlank).forEach(s -> {
                CorsConfiguration config = new CorsConfiguration();
                config.setAllowCredentials(true);
                config.addAllowedOrigin(s.trim());
                if (corsProperties.getAllowedMethods() != null) {
                    config.setAllowedMethods(Arrays.asList(corsProperties.getAllowedMethods().split(",")));
                }
                if (corsProperties.getAllowedHeaders() != null) {
                    config.setAllowedHeaders(Arrays.asList(corsProperties.getAllowedHeaders().split(",")));
                }
                // here the /oauth/token is used
                corsConfigMap.put("/oauth/token", config);
            });
            endpoints.getFrameworkEndpointHandlerMapping()
                    .setCorsConfigurations(corsConfigMap);
        }
    }


}

さらに、OPTIONSリクエストの前述の許可:

@Order(-1)
@Configuration
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
   @Override
   protected void configure(HttpSecurity http) throws Exception {
       http
          authorizeRequests()
            .antMatchers("/**/oauth/token").permitAll()
            .and().httpBasic().realmName(securityRealm)
            // would throw a 403 otherwise
            .and().csrf().disable()
            // optional, but with a token a sesion is not needed anymore
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
   }
}
1
k_o_

Spring-Boot 1.4.7.RELEASEと同じ問題

私のWebSecurityConfigurerAdapterは_SecurityProperties.ACCESS_OVERRIDE_ORDER_を使用していたため、選択した回答は機能しませんでした。

_@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class AuthServerSecurityConfig extends WebSecurityConfigurerAdapter 
_

したがって、前の順序で次のフィルター構成を追加しました。

_  @Bean
  public FilterRegistrationBean corsFilter() {
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource()));
    bean.setOrder(SecurityProperties.DEFAULT_FILTER_ORDER);
    return bean;
  }

  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    return source;
  }
_

そしてそれは仕事を成し遂げました。

:同等の結果は、以下のように@Order(SecurityProperties.DEFAULT_FILTER_ORDER)アノテーションを付けた_javax.servlet.Filter_ Beanで達成できます。

_@Component
@Order(SecurityProperties.DEFAULT_FILTER_ORDER)
public class CorsFilter implements Filter {

  @Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    final HttpServletResponse response = (HttpServletResponse) res;

    response.setHeader("Access-Control-Allow-Origin"  , "*"                               );
    response.setHeader("Access-Control-Allow-Methods" , "POST, PUT, GET, OPTIONS, DELETE" );
    response.setHeader("Access-Control-Allow-Headers" , "Authorization, Content-Type"     );
    response.setHeader("Access-Control-Max-Age"       , "3600"                            );

    if("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
      response.setStatus(HttpServletResponse.SC_OK);
    }
    else {
      chain.doFilter(req, res);
    }
  }
  // ...
}
_
0