복붙노트

[SPRING] Spring 부트에서 0-legged OAuth 1.0 설정하기

SPRING

Spring 부트에서 0-legged OAuth 1.0 설정하기

0 다리가있는 (요청이나 액세스 토큰이 없으므로) OAuth 1.0으로 스프링 부트 응용 프로그램을 설치하려고합니다. 나는 예를 찾기 위해 잠시 동안 주위를 파고 있었고, 나는 (xml없이) 새로운 스타일을 사용하여 사물을 구성하는 방법에 주로 집착하고있다.

지금은 단지 하나의 경로 (/ oauth)가 OAuth로 보호되는 곳에서 작업하는 간단한 유스 케이스를 얻고 싶습니다. 그리고 다른 곳에서는 커밋되지 않은 ConsumerDetailsService를 사용합니다 (간단한 코드 버전 참조).

여기 내 WebSecurityConfigurerAdapter (Application.java 옆에 SecurityConfiguration.java가있다. 스프링 부트 애플리케이션에서 이런 종류의 것을 구성하는 올바른 방법이라고 생각한다). 나는 공급자 설정 (http://projects.spring.io/spring-security-oauth/docs/oauth1.html에 언급 된)이 없다는 것을 확신하지만, 시행 착오는 결과를 가져 오지 않는다.

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 0-Legged OAuth on the /oauth and /lti paths only
        http.requestMatchers().antMatchers("/oauth"); // .and().... what?
        // ??? something must be missing here - provider?
    }

}

나는 또한 내 maven pom.xml에 이것을 가지고있다 :

<!-- security and oauth -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth -->
<dependency>
  <groupId>org.springframework.security.oauth</groupId>
  <artifactId>spring-security-oauth</artifactId>
  <version>2.0.2.RELEASE</version>
</dependency>

내 맞춤형 ConsumerDetailsService

@Component
public class LTIConsumerDetailsService implements ConsumerDetailsService {

    @Override
    public ConsumerDetails loadConsumerByConsumerKey(String consumerKey) throws OAuthException {
        BaseConsumerDetails cd;
        // TODO really lookup the key and related consumer details, for sample here we just hardcoded
        if ("key".equals(consumerKey)) {
            cd = new BaseConsumerDetails();
            cd.setConsumerKey(consumerKey);
            cd.setSignatureSecret(new SharedConsumerSecretImpl("secret"));
            cd.setConsumerName("Sample consumerName");
            cd.setRequiredToObtainAuthenticatedToken(false); // no token required (0-legged)
            cd.setResourceDescription("Sample consumer details - AZ");
            cd.setResourceName("Sample resourceName");
        } else {
            throw new OAuthException("For this example, key must be 'key'");
        }
        return cd;
    }

}

스프링 부트 OAuth 1.0 코드로이 작업 또는 포인터를 얻는 방법에 대한 제안은 크게 감사 할 것입니다. 이미 별도의 스프링 부트 보안 및 OAuth 가이드를 살펴 보았으므로 성공적으로 병합 할 수 없었습니다.

해결법

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

    1.다음은 Java Config를 통해 스프링 부트 1.1.4에서 0 다리가있는 OAuth 1.0을 사용하는 방법입니다.

    다음은 Java Config를 통해 스프링 부트 1.1.4에서 0 다리가있는 OAuth 1.0을 사용하는 방법입니다.

    참고 : 제 경우에는 OAuth가 단일 경로 (/ oauth / **)를 보호하기를 원했기 때문에 모든 것을 보호하려면 OAuth가이 부분을 단순화 할 수 있어야합니다. 내 전체 코드는 https://github.com/azeckoski/lti_starter에서 확인할 수 있습니다.

    아래에 표시된 최소한의 부품이 있으면 스프링 부트 응용 프로그램을 실행하고 / oauth에서 ConsumerKey : key 및 Secret : secret로 OAuth 1.0 호환 요청을 실행하고 경로를 성공적으로로드 할 수 있어야합니다.

    중요 사항 : (1) ZeroLeggedOAuthProviderProcessingFilter를 Bean으로 선언하지 마십시오. 그렇게하면 모든 경로에 영향을 미치게됩니다 (스프링에 의해 자동으로 선택됩니다) (2) 보호 된 경로 외부의 보안 데이터 (이 경우 / oauth)에 액세스하려면 NoAuthConfigurationAdapter가 있어야합니다.

    @ComponentScan
    @Configuration
    @EnableAutoConfiguration
    @EnableWebMvcSecurity // enable spring security and web mvc hooks
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
    public class Application extends WebMvcConfigurerAdapter {
        final static Logger log = LoggerFactory.getLogger(Application.class);
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
        // Spring Security
    
        @Autowired
        @Order(Ordered.HIGHEST_PRECEDENCE + 10)
        @SuppressWarnings("SpringJavaAutowiringInspection")
        public void configureSimpleAuthUsers(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("admin").password("admin").roles("ADMIN", "USER")
                    .and().withUser("user").password("user").roles("USER");
        }
    
        @Configuration
        @Order(1) // HIGHEST
        public static class OAuthSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
            private ZeroLeggedOAuthProviderProcessingFilter zeroLeggedOAuthProviderProcessingFilter;
            @Autowired
            OAuthConsumerDetailsService oauthConsumerDetailsService;
            @Autowired
            OAuthAuthenticationHandler oauthAuthenticationHandler;
            @Autowired
            OAuthProcessingFilterEntryPoint oauthProcessingFilterEntryPoint;
            @Autowired
            OAuthProviderTokenServices oauthProviderTokenServices;
            @PostConstruct
            public void init() {
                zeroLeggedOAuthProviderProcessingFilter = new ZeroLeggedOAuthProviderProcessingFilter(oauthConsumerDetailsService, new InMemoryNonceServices(), oauthProcessingFilterEntryPoint, oauthAuthenticationHandler, oauthProviderTokenServices);
            }
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.antMatcher("/oauth/**")
                        .addFilterBefore(zeroLeggedOAuthProviderProcessingFilter, UsernamePasswordAuthenticationFilter.class)
                        .authorizeRequests().anyRequest().hasRole("OAUTH");
            }
        }
    
        @Order(45) // LOW
        @Configuration
        public static class BasicAuthConfigurationAdapter extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.antMatcher("/basic/**").authorizeRequests().anyRequest().authenticated()
                        .and().httpBasic();
            }
        }
    
        @Order(67) // LOWEST
        @Configuration
        public static class NoAuthConfigurationAdapter extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.antMatcher("/**").authorizeRequests().anyRequest().permitAll();
            }
        }
    
        // OAuth beans
    
        public static class OAuthProcessingFilterEntryPointImpl extends OAuthProcessingFilterEntryPoint {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                log.info("OAuth FILTER Failure (commence), req=" + request + ", ex=" + authException);
                // Called when there is an OAuth Auth failure, authException may be InsufficientAuthenticationException
                super.commence(request, response, authException);
            }
        }
    
        @Bean(name = "oauthAuthenticationEntryPoint")
        public OAuthProcessingFilterEntryPoint oauthAuthenticationEntryPoint() {
            return new OAuthProcessingFilterEntryPointImpl();
        }
    
        @Bean(name = "oauthProviderTokenServices")
        public OAuthProviderTokenServices oauthProviderTokenServices() {
            // NOTE: we don't use the OAuthProviderTokenServices for 0-legged but it cannot be null
            return new InMemoryProviderTokenServices();
        }
    
        public static class ZeroLeggedOAuthProviderProcessingFilter extends ProtectedResourceProcessingFilter {
            ZeroLeggedOAuthProviderProcessingFilter(OAuthConsumerDetailsService oAuthConsumerDetailsService, OAuthNonceServices oAuthNonceServices, OAuthProcessingFilterEntryPoint oAuthProcessingFilterEntryPoint, OAuthAuthenticationHandler oAuthAuthenticationHandler, OAuthProviderTokenServices oAuthProviderTokenServices) {
                super();
                log.info("CONSTRUCT Zero Legged OAuth provider");
                setAuthenticationEntryPoint(oAuthProcessingFilterEntryPoint);
                setAuthHandler(oAuthAuthenticationHandler);
                setConsumerDetailsService(oAuthConsumerDetailsService);
                setNonceServices(oAuthNonceServices);
                setTokenServices(oAuthProviderTokenServices);
                //setIgnoreMissingCredentials(false); // die if OAuth params are not included
            }
        }
    }
    
    @Component
    public class OAuthConsumerDetailsService implements ConsumerDetailsService {
        final static Logger log = LoggerFactory.getLogger(OAuthConsumerDetailsService.class);
    
        @Override
        public ConsumerDetails loadConsumerByConsumerKey(String consumerKey) throws OAuthException {
            BaseConsumerDetails cd;
            // NOTE: really lookup the key and secret, for the sample here we just hardcoded
            if ("key".equals(consumerKey)) {
                // allow this oauth request
                cd = new BaseConsumerDetails();
                cd.setConsumerKey(consumerKey);
                cd.setSignatureSecret(new SharedConsumerSecretImpl("secret"));
                cd.setConsumerName("Sample");
                cd.setRequiredToObtainAuthenticatedToken(false); // no token required (0-legged)
                cd.getAuthorities().add(new SimpleGrantedAuthority("ROLE_OAUTH")); // add the ROLE_OAUTH (can add others as well)
                log.info("OAuth check SUCCESS, consumer key: " + consumerKey);
            } else {
                // deny - failed to match
                throw new OAuthException("For this example, key must be 'key'");
            }
            return cd;
        }
    
    }
    

    이 마지막 부분은 OAuth 요청에서 들어오는 데이터를 기반으로 실제 사용자 (및 사용자)를 정의하는 데 중요합니다. 이것은 로컬로 처리하는 방법에 따라 달라질 것이지만 이는이를 수행하는 방법의 예입니다.

    @Component
    public class MyOAuthAuthenticationHandler implements OAuthAuthenticationHandler {    
        final static Logger log = LoggerFactory.getLogger(MyOAuthAuthenticationHandler.class);
    
        static SimpleGrantedAuthority userGA = new SimpleGrantedAuthority("ROLE_USER");
        static SimpleGrantedAuthority adminGA = new SimpleGrantedAuthority("ROLE_ADMIN");
    
        @Override
        public Authentication createAuthentication(HttpServletRequest request, ConsumerAuthentication authentication, OAuthAccessProviderToken authToken) {
            Collection<GrantedAuthority> authorities = new HashSet<>(authentication.getAuthorities());
            // attempt to create a user Authority
            String username = request.getParameter("username");
            if (StringUtils.isBlank(username)) {
                username = authentication.getName();
            }
    
            // NOTE: you should replace this block with your real rules for determining OAUTH ADMIN roles
            if (username.equals("admin")) {
                authorities.add(userGA);
                authorities.add(adminGA);
            } else {
                authorities.add(userGA);
            }
    
            Principal principal = new NamedOAuthPrincipal(username, authorities,
                    authentication.getConsumerCredentials().getConsumerKey(),
                    authentication.getConsumerCredentials().getSignature(),
                    authentication.getConsumerCredentials().getSignatureMethod(),
                    authentication.getConsumerCredentials().getSignatureBaseString(),
                    authentication.getConsumerCredentials().getToken()
            );
            Authentication auth = new UsernamePasswordAuthenticationToken(principal, null, authorities);
            return auth;
        }
    
        public static class NamedOAuthPrincipal extends ConsumerCredentials implements Principal {
            public String name;
            public Collection<GrantedAuthority> authorities;
    
            public NamedOAuthPrincipal(String name, Collection<GrantedAuthority> authorities, String consumerKey, String signature, String signatureMethod, String signatureBaseString, String token) {
                super(consumerKey, signature, signatureMethod, signatureBaseString, token);
                this.name = name;
                this.authorities = authorities;
            }
    
            @Override
            public String getName() {
                return name;
            }
    
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return authorities;
            }
        }
    }
    
    @Controller
    @RequestMapping("/oauth")
    public class OAuthController extends BaseController {
    
        @RequestMapping({"", "/"})
        public String home(HttpServletRequest req, Principal principal, Model model) {
            return "home"; // name of the template
        }
    }
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- security and oauth -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- OAuth -->
    <dependency>
      <groupId>org.springframework.security.oauth</groupId>
      <artifactId>spring-security-oauth</artifactId>
      <version>2.0.2.RELEASE</version>
    </dependency>
    
  2. from https://stackoverflow.com/questions/24616708/configuring-0-legged-oauth-1-0-in-spring-boot by cc-by-sa and MIT license