Abstract

JavaでAWS Cognitoをローカルエミュレータ(cognito-local)上で使ってみました。

1. Introduction

1.1. Preparation

  1. Launch cognito-local (AWS Cognito Mock)

    docker-compose.yaml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    services:
      cognito-local:
        image: jagregory/cognito-local:latest
        ports:
          - "9229:9229"
        volumes:
          - ./.cognito:/app/.cognito
        environment:
          - COGNITO_LOCAL_DEVMODE=1
        command: ["yarn", "start"]
    
      # オプション: 設定用のinit用コンテナ
      cognito-init:
        image: amazon/aws-cli:latest
        depends_on:
          cognito-local:
            condition: service_started
        environment:
          - AWS_ACCESS_KEY_ID=local
          - AWS_SECRET_ACCESS_KEY=local
          - AWS_DEFAULT_REGION=us-east-1
        volumes:
          - ./localstack/init/init-cognito.sh:/init-cognito.sh
        command: ["sh", "/init-cognito.sh"]
        profiles:
          - init
    

    init-cognito.sh

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    #!/bin/bash
    
    # Cognito-localが起動するまで待機
    sleep 10
    
    # エンドポイントの設定
    export AWS_ENDPOINT_URL=http://localhost:9229
    
    # ユーザープールの作成
    USER_POOL_ID=$(aws cognito-idp create-user-pool \
      --pool-name "test-pool" \
      --policies "PasswordPolicy={MinimumLength=8,RequireUppercase=false,RequireLowercase=false,RequireNumbers=false,RequireSymbols=false}" \
      --query 'UserPool.Id' \
      --output text)
    
    echo "Created User Pool: $USER_POOL_ID"
    
    # ユーザープールクライアントの作成
    CLIENT_ID=$(aws cognito-idp create-user-pool-client \
      --user-pool-id "$USER_POOL_ID" \
      --client-name "test-client" \
      --generate-secret \
      --query 'UserPoolClient.ClientId' \
      --output text)
    
    echo "Created User Pool Client: $CLIENT_ID"
    
    # テストユーザーの作成
    aws cognito-idp admin-create-user \
      --user-pool-id $USER_POOL_ID \
      --username "testuser@example.com" \
      --temporary-password "TempPass123!" \
      --message-action "SUPPRESS"
    
    echo "Created test user: testuser@example.com"
    
    # 設定情報を出力
    echo "=== Cognito Local Configuration ==="
    echo "User Pool ID: $USER_POOL_ID"
    echo "Client ID: $CLIENT_ID"
    echo "Endpoint: http://localhost:9229"
    echo "Test User: testuser@example.com / TempPass123!"
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    # 検証時
    ## Dockerコンテナ起動
    $ colima start
    
    ## cognito-local起動
    $ docker compose up -d
    
    # 検証終了時
    ## cognito-local停止
    $ docker compose down
    
    ## Dockerコンテナ停止
    $ colima stop
    

2. Java Source Code

CognitoUserController.java

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
package com.example.cognito_sample.controller;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.cognitoidp.AWSCognitoIdentityProvider;
import com.amazonaws.services.cognitoidp.AWSCognitoIdentityProviderClientBuilder;
import com.amazonaws.services.cognitoidp.model.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

import java.util.stream.Collectors;

/**
 * Controller for interacting with AWS Cognito User Pools.
 * 
 * This controller provides endpoints for checking the health of the service,
 * debugging connection to Cognito, and listing users in a user pool.
 * It uses a locally running Cognito endpoint for development/testing purposes.
 */
@RestController
public class CognitoUserController {

    private final AWSCognitoIdentityProvider cognitoClient;

    @Value("${aws.cognito.endpoint:http://localhost:9229}")
    private String cognitoEndpoint;

    @Value("${aws.cognito.region:us-east-1}")
    private String region;

    @Value("${aws.cognito.userPoolId}")
    private String userPoolId;

    @Value("${aws.cognito.clientId}")
    private String clientId;

    /**
     * Constructs a CognitoUserController with endpoint and region configurations.
     *
     * @param endpoint   The endpoint URL of the local Cognito service.
     * @param region     The AWS region (e.g., "us-east-1").
     * @param userPoolId The Cognito User Pool ID to be used.
     * @param clientId   The Cognito App Client ID.
     */
    public CognitoUserController(
            @Value("${aws.cognito.endpoint:http://localhost:9229}") String endpoint,
            @Value("${aws.cognito.region:us-east-1}") String region,
            @Value("${aws.cognito.userPoolId}") String userPoolId,
            @Value("${aws.cognito.clientId}") String clientId) {

        this.userPoolId = userPoolId;
        this.clientId = clientId;

        this.cognitoClient = AWSCognitoIdentityProviderClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(
                        new BasicAWSCredentials("local", "local")
                ))
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region))
                .build();
    }

    /**
     * Health check endpoint.
     *
     * @return A simple status message including the configured Cognito endpoint.
     */
    @GetMapping("/health")
    public String health() {
        return "Service is running. Cognito endpoint: " + cognitoEndpoint;
    }

    /**
     * Debug endpoint to test if the Cognito connection is working.
     *
     * @return A success message if the connection is established; otherwise, the error message.
     */
    @GetMapping("/debug/cognito")
    public String debugCognito() {
        try {
            // Test connectivity by listing user pools (limit 1)
            cognitoClient.listUserPools(new ListUserPoolsRequest().withMaxResults(1));
            return "Cognito connection OK";
        } catch (Exception e) {
            return "Cognito connection failed: " + e.getMessage();
        }
    }

    /**
     * Debug endpoint to list all users in the configured Cognito user pool.
     *
     * @return A comma-separated list of usernames, or an error message if listing fails.
     */
    @GetMapping("/debug/users")
    public String listUsers() {
        try {
            ListUsersRequest request = new ListUsersRequest()
                    .withUserPoolId(this.userPoolId);

            ListUsersResult result = cognitoClient.listUsers(request);
            return result.getUsers().stream()
                    .map(user -> "Username: " + user.getUsername())
                    .collect(Collectors.joining(", "));
        } catch (Exception e) {
            return "Error listing users: " + e.getMessage();
        }
    }
}

3. Execution Result

1
2
3
4
5
6
❯ curl http://localhost:8080/health
Service is running. Cognito endpoint: http://localhost:9229%
❯ curl http://localhost:8080/debug/cognito
Cognito connection OK%
❯ curl http://localhost:8080/debug/users
Username: e08a1de2-b91f-4c58-a250-904c3ed0fe65%

4. Reference