Cognito SRP с использованием AWS Java SDK v2.x

Мне нужно использовать AWS cognito, чтобы получить токен, а затем вызвать секретный API. У меня есть этот скрипт Python, который работает. Как я могу преобразовать его в Java SDK v2?

Я нашел пример, в котором используется Java SDK V1, но он не работал с v2. .

from warrant.aws_srp import AWSSRP
username = "user"
password = "pass"
client_id = "xxxxxxxxxxxxxxxxx"
user_pool_id = "us-east-1_xxx123445"
region = "us-east-1"
aws = AWSSRP(username=username, password=password, pool_id=user_pool_id, client_id=client_id)
tokens = aws.authenticate_user()
print(tokens)

person Tina J    schedule 14.05.2021    source источник


Ответы (1)


Преобразование AuthenticationHelper из SDK v1 в v2 не так уж сложен. Вызовы v1 просто необходимо обновить до версий v2. Все поколения SRP остаются прежними. Ниже показано, как я преобразовал основные методы этого класса для использования v2 sdk.

Выполнить аутентификацию SRP

public String PerformSRPAuthentication(String username, String password) {
    String authresult = null;

    InitiateAuthRequest authReq = initiateUserSrpAuthRequest(username);

    try {
        AnonymousCredentialsProvider creds = AnonymousCredentialsProvider.create();
        CognitoIdentityProviderClient cognitoclient = CognitoIdentityProviderClient.builder()
            .region(Region.of(this.region))
            .credentialsProvider(creds)
            .build();
        
        InitiateAuthResponse authRes = cognitoclient.initiateAuth(authReq);
        if(authRes.challengeName().equals(ChallengeNameType.PASSWORD_VERIFIER)) {
            RespondToAuthChallengeRequest challengeRequest = userSrpAuthRequest(authRes, password);
            RespondToAuthChallengeResponse result = cognitoclient.respondToAuthChallenge(challengeRequest);
            authresult = result.authenticationResult().idToken();
        }
    } catch(Exception e) {
        System.out.println("Exception: " + e);
    }
    return authresult;
}

инициироватьUserSrpAuthRequest

private InitiateAuthRequest initiateUserSrpAuthRequest(String username) {

    HashMap<String, String> authParams = new HashMap<String, String>();
    authParams.put("USERNAME", username);
    authParams.put("SRP_A", this.getA().toString(16));

    InitiateAuthRequest authReq = InitiateAuthRequest.builder()
        .authFlow(AuthFlowType.USER_SRP_AUTH)
        .clientId(this.clientId).authParameters(authParams).build();
    return authReq;
}

userSrpAuthRequest

private RespondToAuthChallengeRequest userSrpAuthRequest(InitiateAuthResponse challenge,
                                                         String password
) {
    String userIdForSRP = challenge.challengeParameters().get("USER_ID_FOR_SRP");
    String usernameInternal = challenge.challengeParameters().get("USERNAME");

    BigInteger B = new BigInteger(challenge.challengeParameters().get("SRP_B"), 16);
    if (B.mod(AWSAuthenticationHelper.N).equals(BigInteger.ZERO)) {
        throw new SecurityException("SRP error, B cannot be zero");
    }

    BigInteger salt = new BigInteger(challenge.challengeParameters().get("SALT"), 16);
    byte[] key = getPasswordAuthenticationKey(userIdForSRP, password, B, salt);

    Date timestamp = new Date();
    byte[] hmac = null;
    try {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
        mac.init(keySpec);
        mac.update(this.userPoolID.split("_", 2)[1].getBytes(Charset.forName("UTF-8")));
        mac.update(userIdForSRP.getBytes(Charset.forName("UTF-8")));
        byte[] secretBlock = Base64.decode(challenge.challengeParameters().get("SECRET_BLOCK"));
        mac.update(secretBlock);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy", Locale.US);
        simpleDateFormat.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
        String dateString = simpleDateFormat.format(timestamp);
        byte[] dateBytes = dateString.getBytes(Charset.forName("UTF-8"));
        hmac = mac.doFinal(dateBytes);
    } catch (Exception e) {
        System.out.println(e);
    }

    SimpleDateFormat formatTimestamp = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy", Locale.US);
    formatTimestamp.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));

    Map<String, String> srpAuthResponses = new HashMap<>();
    srpAuthResponses.put("PASSWORD_CLAIM_SECRET_BLOCK", challenge.challengeParameters().get("SECRET_BLOCK"));
    srpAuthResponses.put("PASSWORD_CLAIM_SIGNATURE", new String(Base64.encode(hmac), Charset.forName("UTF-8")));
    srpAuthResponses.put("TIMESTAMP", formatTimestamp.format(timestamp));
    srpAuthResponses.put("USERNAME", usernameInternal);

    RespondToAuthChallengeRequest authChallengeRequest = RespondToAuthChallengeRequest.builder()
        .challengeName(challenge.challengeName())
        .clientId(clientId)
        .session(challenge.session())
        .challengeResponses(srpAuthResponses).build();

    return authChallengeRequest;
}

Вам также потребуется заменить два служебных класса v1, com.amazonaws.util.Base64 и com.amazonaws.util.StringUtils. Все экземпляры StringUtils.UTF8 можно заменить на java.nio.charset.Charset.forName("UTF-8"). Замена Base64 немного сложнее. В итоге я просто скопировал 4 связанных класса в свой проект локально. Те, кто

com.amazonaws.util.Base64 
com.amazonaws.util.CodecUtils
com.amazonaws.util.Codec
com.amazonaws.util.Base64Codec

Это не красиво, но это работает для меня. Я не уверен, почему AWS не может реализовать оболочку для аутентификации SRP, как и все другие SDK.

person nos9    schedule 27.05.2021
comment
Хотя я согласен с тем, что обновление с 1.x до 2.x не супер модно, но этот фрагмент очень помогает! Большое спасибо @nos9 - person user3443646; 26.07.2021