Configuring 0-legged OAuth 1.0 in Spring Boot

后端 未结 1 1507
清酒与你
清酒与你 2020-12-28 22:58

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

相关标签:
1条回答
  • 2020-12-28 23:38

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

    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

    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.

    Application.java

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

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

    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 - only the key parts)

    <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>
    
    0 讨论(0)
提交回复
热议问题