web-dev-qa-db-ja.com

UserRedirectRequiredExceptionを処理します(ユーザーの承認を得るにはリダイレクトが必要です)

前書き

1週間前、OAuth2フレームワーク(Spring Boot v1.3.0.M4を使用)を使用してアプリケーションの開発を開始しました。私にとってまったく新しい経験。それで、私はそれをよりよく理解するためにできるだけ簡単にするようにしています。 Spring Security OAuth2を使用していますが、正しく使用するのが困難です。

私がしたいこと

これが私のアプリケーションを承認するときにユーザーを認証します。実は、退屈なフォームに記入しなくても自由に使えるように、私のアプリケーションに登録してほしくないのです。

発生した問題

UserRedirectRequiredExceptionを処理する方法が見つかりません。私はそれをしないので、ユーザーが承認ページにリダイレクトされることはなく、例外がスローされます(そして処理されません)。


私のアプリケーション

StandardController.Java

package org.test.oauth.web;

import Java.security.Principal;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class StandardController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String getHelloWorld() {
        return "Hello world !";
    }

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public Principal getUser(Principal principal) {
        return principal;
    }
}

StandardConfiguration.Java

package org.test.oauth.configuration;

import Java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.web.access.ExceptionTranslationFilter;

@Configuration
@EnableOAuth2Sso
public class StandardConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private OAuth2ClientContextFilter oauth2ClientContextFilter;

    @Autowired
    private OAuth2ClientContext oauth2ClientContext;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
        .authorizeRequests().antMatchers("/login").anonymous().and()
        .authorizeRequests().anyRequest().authenticated().and()
        .httpBasic().and()
        .addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);
        // @formatter:on
    }

//  org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.security.oauth2.client.OAuth2RestOperations] is defined: expected single matching bean but found 2: restTemplate,userInfoRestTemplate
//  @Bean
//  public OAuth2RestOperations restTemplate() {
//      return new OAuth2RestTemplate(bnetResource(), oauth2ClientContext);
//  }

    @Bean
    public OAuth2ProtectedResourceDetails bnetResource() {
        AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
        resource.setId("bnet");
        resource.setClientId("***");
        resource.setClientSecret("***");
        resource.setAccessTokenUri("https://eu.battle.net/oauth/token");
        resource.setUserAuthorizationUri("https://eu.battle.net/oauth/authorize");
        resource.setScope(Arrays.asList("wow.profile"));
        return resource;
    }
}

私の問題

ルートアプリケーションにアクセスすると、認証されていないため、SpringSecurityからリダイレクトされます。ログインページにリダイレクトされます。多くの例外は、Spring Bootのデフォルト構成によってスローおよび処理されますが、UserRedirectRequiredExceptionが作成およびスローされると、フィルターはそれを処理しません。アプリケーションをデバッグしたところ、oauth2ClientContextFilterによって検出された最後の例外はAccessDeniedExceptionであることがわかりました。私のフィルター(実際にはデフォルト構成のOAuth2ClientContextFilter)がフィルターチェーンに正しく設定されていないのではないかと思います。

スタックトレース

org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: A redirect is required to get the users approval
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.getRedirectForAuthorization(AuthorizationCodeAccessTokenProvider.Java:347) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.Java:194) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.Java:221) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.Java:173) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.Java:94) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.Java:217) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.Java:120) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.Java:96) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.Java:64) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.Java:91) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.Java:53) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.Java:213) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.Java:176) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:239) ~[Tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:206) ~[Tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.Java:87) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]

スタックトレースを見て、フィルターチェーン内のフィルターの順序を変更しようとしました。そこで、OAuth2ClientAuthenticationProcessingFilterの後にOAuth2ClientContextFilterを配置しようとしました。残念ながら、アプリケーションを起動すると、フィルターが登録解除されているというエラーが発生します。

変更

.addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);

.addFilterAfter(oauth2ClientContextFilter, OAuth2ClientAuthenticationProcessingFilter.class);

スタックトレース

2015-08-25 12:05:50.990 ERROR 9132 --- [ost-startStop-1] o.s.b.c.embedded.Tomcat.TomcatStarter    : Error starting Tomcat context: org.springframework.beans.factory.UnsatisfiedDependencyException
2015-08-25 12:05:51.054  WARN 9132 --- [           main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt
Java.lang.IllegalArgumentException: Cannot register after unregistered Filter class org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter
    at org.springframework.security.config.annotation.web.builders.FilterComparator.registerAfter(FilterComparator.Java:145) ~[spring-security-config-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.security.config.annotation.web.builders.HttpSecurity.addFilterAfter(HttpSecurity.Java:960) ~[spring-security-config-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.test.oauth.configuration.StandardConfiguration.configure(StandardConfiguration.Java:36) ~[classes/:na]
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.Java:199) ~[spring-security-config-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]

だから私はこれを乗り越えてこの問題を取り除くのを手伝ってくれるようにお願いします。この問題についてはすでに回答済みの質問がたくさんあることは承知していますが、希望どおりに解決できませんでした。

あなたが私を助けるために費やした時間を割いてくれてありがとう。

セドリック

7
Stilleur

@Stilleurのソリューションの代替案は以下のとおりです。これは、「リダイレクトの処理」という見出しの下にある公式のSpringガイドで提案されています: https://spring.io/guides/tutorials/spring-boot-oauth2/

@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
    OAuth2ClientContextFilter filter) {
  FilterRegistrationBean registration = new FilterRegistrationBean();
  registration.setFilter(filter);
  registration.setOrder(-100);
  return registration;
}
8
geg

.addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);.addFilterAfter(oauth2ClientContextFilter, SecurityContextPersistenceFilter.class);に変更すると、未処理のserRedirectRequiredExceptionが処理されるようになります。

6
Stilleur

@gegの回答を参照してください。顧客フィルターを自分で実装しない場合は、@EnableOAuth2Clientを追加することもできます。

公式デモでは、@EnableOAuth2Clientにもこのためのデフォルトのフィルターが含まれていると書かれているためです。

リダイレクトの処理

最後に行う必要がある変更は、アプリからFacebookへのリダイレクトを明示的にサポートすることです。これは、Spring OAuth2でサーブレットフィルターを使用して処理されます。@ EnableOAuth2Clientを使用したため、フィルターはアプリケーションコンテキストで既に使用可能です。必要なのは、SpringBootアプリケーションで正しい順序で呼び出されるようにフィルターを配線することだけです。これを行うには、FilterRegistrationBeanが必要です。

1
chendu

Weblogicでこの問題を抱えている方のために:組み込みTomcatサーバーではすべてが正常に実行されますが、WebLogicを使用すると失敗します。 weblogic.xmlでデプロイメントを既に構成していると仮定すると( ここに良い例があります )、WebLogic12.1.2.0からWebLogic12.2.1.2にアップグレードする必要があります。 WLには、特にスプリングセキュリティに関するライブラリに関するいくつかの問題があります。

0
lmiguelmh