Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Use AWS Cognito without using API Gateway for Custom Spring REST API Authorization

Scenario :
I will have Spring boot REST API application running in any EC2 with exposing multiple APIs and I am not using AWS API Gateway for them.
I need multiple users for accessing multiple APIs with different roles (Admin, WriteUser, ReadUser).
I can create Users and Groups in Cognito Userpool and can have multiple Roles in IAM.

How can I configure AWS Cognito's UserPool and IdentityPool to authorize different APIs access based on User role ? Is there any way to define such "API allow rules based on role" in Policy (associated with IdentityPool/Resource server) without using API Gateway.

Thanks in Advance.

like image 862
Viral Patel Avatar asked Nov 20 '19 06:11

Viral Patel


3 Answers

I did implementation with Spring security auth2 with Custom JWTFilter, which will get token from request and validate agains cognito pool's JWKs validation file.

  • User enters username/password in UI.
  • UI calls back-end Application, which calls Cognito.
  • Cognito returns JWT Tokens (Idtoken, accessToken, refreshTokens)
  • Backend application sends IdToken to UI as token and also store in cache(could be any DB also).
  • UI sends this IdToken for next calls.

JWTFilter does below steps, for authentication :

  • Backend Application takes token, validate in cache if present then validate signature and expiry with Cognito JWKs and get details out of it.
  • Backend Application creates UserAuthentication extending AbstractAuthenticationToken and populate details from parsed token values and store in context (session)

Authorization for resource would be done as per config mentioned in websecurity configurations.

like image 132
Viral Patel Avatar answered Oct 18 '22 01:10

Viral Patel


You need to implement JWT token approach with Spring security(can use spring security auth 2 impl.)

So auth steps will followings:

  • User will enter his/her credential on your front-end app.
  • Your auth service will send those credentials to AWS Cognito to verify.
  • If User credentials will verify then with the help of AWS Cognito user response, you will create a payload and then create a JWT token.
  • Sign JWT token with the public-private key so you can share your public key with your other services to validate JWT token.
  • Then JWT token return to front-end app.
  • Now Spring Security will secure you all private routes.
  • You also need to create a filter so when front-end app creates ant request to the server with attaching JWT in the header, then your filter will validate JWT token (as an authentication header) if the token is valid then will create security context for current request else throw 401 status.
like image 30
Bhushan Uniyal Avatar answered Oct 18 '22 01:10

Bhushan Uniyal


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

Spring boot Resource Server

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.

For Authorization, we will make use of Cognito Groups. We create two groups, ROLE_ADMIN & ROLE_EMPLOYEE. We map users to each group. When the user is authenticated, we get the Cognito group as claims. We make use of this to set Spring Security Authorities for the user.

Cognito Groups

@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

like image 1
Arjun Sunil Kumar Avatar answered Oct 18 '22 02:10

Arjun Sunil Kumar