问题描述
我需要使用 AWS Cognito 获取令牌,然后调用秘密 API。我有这个有效的 python 脚本。如何将其转换为 Java SDK v2?
我发现了一个使用 Java SDK V1 的 sample,但它不适用于 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)
解决方法
将 AuthenticationHelper 示例类从 v1 sdk 转换为 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;
}
initiateUserSrpAuthRequest
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 不能像所有其他 SDK 一样为 SRP 身份验证实现包装器。