복붙노트

[SPRING] Spring Boot + Spring OAuth Java 구성

SPRING

Spring Boot + Spring OAuth Java 구성

나는 단순한 Spring Boot + Spring OAuth 앱에서 OAuth 1 (3 legged)을 소비자로서 만 얻으려고하고있다.

XML 대신 Java config를 사용하기 위해 spring-security-oauth 저장소 (https://github.com/spring-projects/spring-security-oauth)에서 tonr 샘플을 이식하려고했습니다.

그러나, 나는지고있다 :

java.lang.NullPointerException: null
at org.springframework.security.oauth.consumer.filter.OAuthConsumerProcessingFilter.doFilter(OAuthConsumerProcessingFilter.java:87)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

... 아마도 OAuthConsumerContextFilter가 제대로 설정되지 않았기 때문일 수 있습니다.

부분을 다음과 같이 구성하려고했습니다.

@Bean
public OAuthConsumerProcessingFilter oAuthConsumerProcessingFilter()
{
    OAuthConsumerProcessingFilter result = new OAuthConsumerProcessingFilter();
    result.setProtectedResourceDetailsService(protectedResourceDetailsService());

    final LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = new LinkedHashMap<>();
    map.put(new RegexRequestMatcher("/sparklr/*", null), Collections.singletonList(ConsumerSecurityConfig.PERMIT_ALL_ATTRIBUTE));
    result.setObjectDefinitionSource(new DefaultFilterInvocationSecurityMetadataSource(map));
    return result;
}

@Bean
public ProtectedResourceDetailsService protectedResourceDetailsService()
{
    return (String id) -> {
        switch (id) {
            case "sparklrPhotos":
                sparklrProtectedResourceDetails();
                break;
        }
        throw new RuntimeException("Error");
    };
}

@Bean
public OAuthConsumerContextFilter oAuthConsumerContextFilter() {
    final CoreOAuthConsumerSupport consumerSupport = new CoreOAuthConsumerSupport();
    consumerSupport.setProtectedResourceDetailsService(protectedResourceDetailsService());

    final OAuthConsumerContextFilter filter = new OAuthConsumerContextFilter();
    filter.setConsumerSupport(consumerSupport);
    return filter;
}

...하지만 분명히 뭔가 빠져 있습니다. 나는 스위치를 제거하고 항상 동일한 보호 된 리소스 세부 정보를 반환했지만 컨텍스트가 없다는 사실을 변경하지는 않습니다.

이 작업을하려면 어떻게해야합니까? 내 코드의 다른 부분을 보여줘야하는지 알려주세요.

업데이트 : 소비자 컨텍스트 필터를 추가했지만 동일한 오류가 발생하여 적용되지 않는 것 같습니다.

해결법

  1. ==============================

    1.Java Config와 함께 Spring Security를 ​​사용하려면 SecurityConfig 파일에 다음과 같은 내용이 있어야합니다 (http://projects.spring.io/spring-security-oauth/docs/oauth2.html에서 가져옴).

    Java Config와 함께 Spring Security를 ​​사용하려면 SecurityConfig 파일에 다음과 같은 내용이 있어야합니다 (http://projects.spring.io/spring-security-oauth/docs/oauth2.html에서 가져옴).

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests().antMatchers("/login").permitAll().and()
        // default protection for all resources (including /oauth/authorize)
            .authorizeRequests()
                .anyRequest().hasRole("USER")
        // ... more configuration, e.g. for form login
    }
    

    또한 http.addFilterAfter (oAuthConsumerContextFilter (), AnonymousAuthenticationFilter.class)를 사용하여 필터를 특정 순서로 추가 할 수 있습니다.

    코드의 문제점은 인증이 생성되기 전에 필터가 실행되고 있다는 것입니다.

    그래서 적어도 두 필터는 AnonymousAuthenticationFilter.class 뒤에 있어야한다고 생각합니다.

    필터 목록은 http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#filter-stack에서 찾을 수 있습니다.

    이것은 나를 위해 일했다 :

    http
    .addFilterAfter(oAuthConsumerContextFilter(), SwitchUserFilter.class)
    .addFilterAfter(oAuthConsumerProcessingFilter(), OAuthConsumerContextFilter.class)
    
  2. ==============================

    2.나는이 질문과 다른 답변에있는 코드의 여러 부분이 불완전하고 전체적으로 취한 여러 가지 이유로 작동하지 않는다는 것을 알게되었습니다. 다음은 Java 설정을 사용하여 스프링 부트 OAuth 1이 작동하도록하는 완벽한 솔루션입니다.

    나는이 질문과 다른 답변에있는 코드의 여러 부분이 불완전하고 전체적으로 취한 여러 가지 이유로 작동하지 않는다는 것을 알게되었습니다. 다음은 Java 설정을 사용하여 스프링 부트 OAuth 1이 작동하도록하는 완벽한 솔루션입니다.

    다음과 같은 구성 클래스가 필요합니다.

    @Configuration
    @EnableWebSecurity
    public class OAuthConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.addFilterAfter(
                this.oauthConsumerContextFilter(),
                SwitchUserFilter.class
            );
            http.addFilterAfter(
                this.oauthConsumerProcessingFilter(),
                OAuthConsumerContextFilter.class
            );
        }
    
        // IMPORTANT: this must not be a Bean
        OAuthConsumerContextFilter oauthConsumerContextFilter() {
            OAuthConsumerContextFilter filter = new OAuthConsumerContextFilter();
            filter.setConsumerSupport(this.consumerSupport());
            return filter;
        }
    
        // IMPORTANT: this must not be a Bean
        OAuthConsumerProcessingFilter oauthConsumerProcessingFilter() {
            OAuthConsumerProcessingFilter filter = new OAuthConsumerProcessingFilter();
            filter.setProtectedResourceDetailsService(this.prds());
    
            LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map =
                new LinkedHashMap<>();
    
            // one entry per oauth:url element in xml
            map.put(
                // 1st arg is equivalent of url:pattern in xml
                // 2nd arg is equivalent of url:httpMethod in xml
                new AntPathRequestMatcher("/oauth/**", null),
                // arg is equivalent of url:resources in xml
                // IMPORTANT: this must match the ids in prds() and prd() below
                Collections.singletonList(new SecurityConfig("myResource"))
            );
    
            filter.setObjectDefinitionSource(
                new DefaultFilterInvocationSecurityMetadataSource(map)
            );
    
            return filter;
        }
    
        @Bean // optional, I re-use it elsewhere, hence the Bean
        OAuthConsumerSupport consumerSupport() {
            CoreOAuthConsumerSupport consumerSupport = new CoreOAuthConsumerSupport();
            consumerSupport.setProtectedResourceDetailsService(prds());
            return consumerSupport;
        }
    
        @Bean // optional, I re-use it elsewhere, hence the Bean
        ProtectedResourceDetailsService prds() {
            return (String id) -> {
                switch (id) {
                // this must match the id in prd() below
                case "myResource":
                    return prd();
                }
                throw new RuntimeException("Invalid id: " + id);
            };
        }
    
        ProtectedResourceDetails prd() {
            BaseProtectedResourceDetails details = new BaseProtectedResourceDetails();
    
            // this must be present and match the id in prds() and prd() above
            details.setId("myResource");
    
            details.setConsumerKey("OAuth_Key");
            details.setSharedSecret("OAuth_Secret");
    
            details.setRequestTokenURL("...");
            details.setUserAuthorizationURL("...");
            details.setAccessTokenURL("...");
    
            // any other service-specific settings
    
            return details;
        }
    }
    

    이해해야 할 요점은 내가 직면 한 문제를 피할 수 있습니다.

    첫째, 원래 질문은 ConsumerSecurityConfig.PERMIT_ALL_ATTRIBUTE로 처리 필터를 구성하지만 작동하지 않습니다. 지도의 값은 해당 경로의 OAuth 소유자 인 리소스의 ID가 포함 된 SecurityConfig 여야합니다.

    이 ID는 ProtectedResourceDetailsService 및 ProtectedResourceDetails의 ID와 일치해야하며 두 ID가 모두 있어야합니다. 비록 다소 중복 되더라도 ID를 ProtectedResourceDetails에 두지 않으면 설치가 중단됩니다.

    둘째, 원래 질문은 두 필터를 모두 Bean으로 구성합니다. 그러나 Spring Boot는 메인 애플리케이션 필터 체인에 Filter를 구현하는 Bean을 자동으로 등록합니다.이 경우 Bean은 재생 공격처럼 보이기 때문에 매번 OAuth 액세스 토큰 프로세스가 두 번 실행되고 실패하게됩니다. 이 질문에 대한 자세한 내용 : Oauth 1.0a 액세스 토큰을 두 번 준 소비자 코드

    이 문제를 해결하는 데는 두 가지 방법이 있습니다. 위의 짧은 것을 사용했는데 Bean을 만들지는 않았지만 FilterRegistrationBean을 만들어 자동 등록 비헤이비어를 비활성화 할 수도 있습니다.

    이러한 수정을 통해 위의 코드는 Spring 부트 컨테이너에서 순수 Java 구성을 사용하여 OAuth 1 협상을 지원하도록 테스트 및 확인되었습니다.

    참고 문헌 :

    Spring OAuth 1 문서는 관련 클래스와 그 내용을 이해하는 데 유용합니다. https://projects.spring.io/spring-security-oauth/docs/oauth1.html

    Bean Definition Parser는 XML을 Java로 변환하는 표준 구현이므로, 언급하지 않은 모든 엣지 경우를 참조하십시오. https://github.com/codehaus/spring-security-oauth/blob/master/spring-security -oauth / src / main / java / org / springframework / security / oauth / config / OAuthConsumerBeanDefinitionParser.java

  3. from https://stackoverflow.com/questions/29001343/spring-boot-spring-oauth-java-configuration by cc-by-sa and MIT license