Amazon Cognito Oauth2 with Spring Security

后端 未结 2 855
一整个雨季
一整个雨季 2020-12-28 08:37

I\'m trying to implement Spring Security in a resource server with \"Cognito Oauth2\", however I don\'t seem to find too much info. about it (or if It\'s even possible to do

相关标签:
2条回答
  • 2020-12-28 09:13

    A great starting point for Oauth2 using the latest Sprint Boot 2.x / Sprint Security 5.x can be found here : https://spring.io/blog/2018/03/06/using-spring-security-5-to-integrate-with-oauth-2-secured-services-such-as-facebook-and-github

    It uses Facebook / Github as an example but you can apply it to AWS Cognito also.

    This is by far the easiest way to setup a secure REST backend with Spring Security / Cognito OAuth2. Your backend will be secured via Spring Security, and AWS Cognito will be used as the identity provider.

    You can setup a vanilla spring boot app using the spring security starter as outlined in the article using the following dependencies :

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>
    

    and provide your cognito configuration (client registration + provider definition) like this :

    spring:
      security:
        oauth2:
          client:
            registration:
              cognito-client-1:
                client-id: 391uhnjlr8v8kicm3cru6g1s8g
                client-secret: xxxxxxxxxxxxxxxxxxxxxxxxxx
                client-name: Cognito Code Grant
                provider: cognito
                scope: openid
                redirect-uri-template: http://localhost:8080/login/oauth2/code/cognito
                authorization-grant-type: authorization_code
            provider:
              cognito:
                authorization-uri: https://custom-domain.auth.eu-central-1.amazoncognito.com/oauth2/authorize
                token-uri: https://custom-domain.auth.eu-central-1.amazoncognito.com/oauth2/token
                user-info-uri: https://custom-domain.auth.eu-central-1.amazoncognito.com/oauth2/userInfo
                jwk-set-uri: https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxxxxxxx/.well-known/jwks.json
                user-name-attribute: cognito:username
    

    As far as Cognito is concerned you need to have a user pool / identity pool with a couple of users and a valid app client ( = client-id in spring config) in cognito with

    • a secret ( = client-secret in the spring config)
    • the correct grants and scopes (in this case I'm using the authorization_code grant with an openid scope)
    • the correct redirect callback ( = redirect-uri-template in the spring config)
    • a domain configuration in cognito
    • a JWK uri containing your cognito user pool (jwk-set-uri in the spring config)

    With everything in place, the Spring Boot app will automatically generate a login url

    Redirecting you to the cognito login page where you can enter your cognito credentials

    And after a successful authentication you'll be able to do a secure REST call

    With a REST controller like this :

    @RestController
    public class ExampleController {
    
        @RequestMapping("/")
        public String email(Principal principal) {
            return "Hello " + principal.getName();
        }
    
    }
    
    0 讨论(0)
  • 2020-12-28 09:14

    We can create Spring Boot resource server, keeping Cognito as Identity Provider.

    Dependency:

        <!--  Spring Security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
    

    Spring Security Configuration:

    EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class OAuth2ResourceServerSecurityConfiguration extends ResourceServerConfigurerAdapter {
    
      private final ResourceServerProperties resource;
    
      public OAuth2ResourceServerSecurityConfiguration(ResourceServerProperties resource) {
        this.resource = resource;
      }
    
      @Override
      public void configure(HttpSecurity http) throws Exception {
    
        http.cors();
    
        http.csrf().disable();
    
        http.authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .antMatchers("/actuator/health").permitAll()
            .anyRequest().authenticated();
      }
    
    
      // Note: Cognito Converter
      @Bean
      public TokenStore jwkTokenStore() {
        return new JwkTokenStore(
            Collections.singletonList(resource.getJwk().getKeySetUri()),
            new CognitoAccessTokenConverter(),
            null);
      }
    }
    

    Cognito Access Token Converter:

    Here we are converting the Cognito claims to Spring Security consumable format.

    @Component
    public class CognitoAccessTokenConverter extends JwtAccessTokenConverter {
    
      // Note: This the core part.
      private static final String COGNITO_GROUPS = "cognito:groups";
      private static final String SPRING_AUTHORITIES = "authorities";
      private static final String COGNITO_USERNAME = "username";
      private static final String SPRING_USER_NAME = "user_name";
    
      @SuppressWarnings("unchecked")
      @Override
      public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
    
        if (claims.containsKey(COGNITO_GROUPS))
          ((Map<String, Object>) claims).put(SPRING_AUTHORITIES, claims.get(COGNITO_GROUPS));
        if (claims.containsKey(COGNITO_USERNAME))
          ((Map<String, Object>) claims).put(SPRING_USER_NAME, claims.get(COGNITO_USERNAME));
        return super.extractAuthentication(claims);
      }
    }
    

    application.properties

    server:
      port: 8081
    security:
      oauth2:
        resource:
          userInfoUri: https://<cognito>.auth.eu-west-1.amazoncognito.com/oauth2/userInfo
          tokenInfoUri: https://<cognito>.auth.eu-west-1.amazoncognito.com/oauth2/token
          jwk:
            key-set-uri: https://cognito-idp.<region>.amazonaws.com/<user-pool-id>/.well-known/jwks.json
        client:
          clientId: <client-id>
    

    For complete article, refer: Integrate Spring Boot Resource Server with Cognito Identity Provider

    0 讨论(0)
提交回复
热议问题