在 Spring Boot 中配置 0-legged OAuth 1.0 [英] Configuring 0-legged OAuth 1.0 in Spring Boot

查看:24
本文介绍了在 Spring Boot 中配置 0-legged OAuth 1.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想设置一个带有 0-legged(因此没有请求或访问令牌)OAuth 1.0 的 Spring Boot 应用程序.我已经研究了一段时间试图找到一个例子,但我主要是在如何使用新的样式(没有 xml)来配置东西.

I want to setup a spring boot application with 0-legged (so no request or access tokens) OAuth 1.0. I have been digging around for awhile trying to find an example and I am mostly stuck on how to configure things using the new style (without xml).

现在我只想得到一个简单的用例,其中只有 1 个路径 (/oauth) 受 OAuth 保护(其他所有内容都是开放的)并且它使用自定义 ConsumerDetailsS​​ervice(见下文)对于该代码的简单版本).

For now I just want to get a simple use case working where only 1 path (/oauth) is OAuth protected (everything else is just wide open) and it uses a custom ConsumerDetailsService (see below for the simple version of that code).

这是我的 WebSecurityConfigurerAdapter(在我的 Application.java 旁边的 SecurityConfiguration.java,我认为这是在 Spring Boot 应用程序中配置此类事物的正确方法).我很确定我缺少提供程序配置(如:http://projects.spring.io/spring-security-oauth/docs/oauth1.html) 但我的反复试验没有产生结果.

Here is my WebSecurityConfigurerAdapter (SecurityConfiguration.java next to my Application.java, which I think is the right way to configure this kind of thing in a spring boot application). I am pretty sure I am missing the provider configuration (as referred to in: http://projects.spring.io/spring-security-oauth/docs/oauth1.html) but my trial-and-error is not yielding results.

@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 中也有这个:

I also have this in my 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>

我的自定义 ConsumerDetailsS​​ervice

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

}

任何有关如何使其工作的建议或指向 spring boot OAuth 1.0 代码的指针将不胜感激.请注意,我已经尝试查看单独的 Spring Boot 安全和 OAuth 指南,但无法成功合并它们.

Any suggestions on how to get this working or pointers to spring boot OAuth 1.0 code would be greatly appreciated. Please note that I already tried looking at the separate spring boot security and OAuth guides and wasn't able to merge them successfully.

推荐答案

这是我如何通过 Java Config 在 spring-boot 1.1.4 中使用 0-legged OAuth 1.0.

Here is how I got 0-legged OAuth 1.0 working in spring-boot 1.1.4 via Java Config.

注意:就我而言,我只希望 OAuth 保护单个路径 (/oauth/**),因此如果您希望它保护所有内容,那么您可以简化其中的某些部分.你可以在这里看到我的完整代码:https://github.com/azeckoski/lti_starter

NOTE: In my case I only wanted OAuth to protect a single path (/oauth/**) so if you want it protecting everything then you may be able to simplify some parts of this. You can see my complete code here: https://github.com/azeckoski/lti_starter

一旦您拥有如下所示的最小部分,您应该能够运行您的 spring-boot 应用程序并在/oauth 上使用 ConsumerKey:key 和 Secret:secret 发出 OAuth 1.0 兼容请求并成功加载路径.

Once you have the minimal parts shown below you should be able to run your spring-boot app and fire an OAuth 1.0 compatible request at /oauth with ConsumerKey:key and Secret:secret and successfully load the path.

重要说明:(1) 不要只将 ZeroLeggedOAuthProviderProcessingFilter 声明为 Bean,如果你这样做,它最终会影响所有路径(它会被 spring 自动拾取)(2) NoAuthConfigurationAdapter 如果你想访问受保护路径之外的安全数据(在这种情况下是/oauth)

Important notes: (1) Do not just declare the ZeroLeggedOAuthProviderProcessingFilter as a Bean, if you do that it will end up affecting all paths (it will get picked up by spring automatically) (2) NoAuthConfigurationAdapter has to be there if you want to access the security data outside the protected path (in this case /oauth)

@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
        }
    }
}

OAuthConsumerDetailsS​​ervice.java

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

}

MyOAuthAuthenticationHandler.java

最后一部分对于根据来自 OAuth 请求的数据定义实际用户(和委托人)很重要.这将根据您在本地处理事情的方式而有所不同,但这是一个如何做到的示例.

MyOAuthAuthenticationHandler.java

This last part is important to define the actual user (and Principal) based on the data coming in from the OAuth request. This is going to vary depending on how you handle things locally but this is an example of how to do it.

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

OAuthController.java

@Controller
@RequestMapping("/oauth")
public class OAuthController extends BaseController {

    @RequestMapping({"", "/"})
    public String home(HttpServletRequest req, Principal principal, Model model) {
        return "home"; // name of the template
    }
}

pom.xml (maven - 只有关键部分)

<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>

这篇关于在 Spring Boot 中配置 0-legged OAuth 1.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆