【问题标题】:Unable to verify secret hash for client at REFRESH_TOKEN_AUTH无法在 REFRESH_TOKEN_AUTH 验证客户端的秘密哈希
【发布时间】:2019-06-23 03:59:56
【问题描述】:

问题

“无法验证客户端的秘密哈希...”在 REFRESH_TOKEN_AUTH 身份验证流程中。

{
    "Error": {
        "Code": "NotAuthorizedException",
        "Message": "Unable to verify secret hash for client 3tjdt39cq4lodrn60kjmsb****"
    },
    "ResponseMetadata": {
        "HTTPHeaders": {
            "connection": "keep-alive",
            "content-length": "114",
            "content-type": "application/x-amz-json-1.1",
            "date": "Tue, 29 Jan 2019 22:22:35 GMT",
            "x-amzn-errormessage": "Unable to verify secret hash for client 3tjdt39cq4lodrn60kjmsbv3jq",
            "x-amzn-errortype": "NotAuthorizedException:",
            "x-amzn-requestid": "610368ec-2414-11e9-9671-f11a8cac1e43"
        },
        "HTTPStatusCode": 400,
        "RequestId": "610368ec-2414-11e9-9671-f11a8cac1e43",
        "RetryAttempts": 0
    }
}

REFRESH_TOKEN_AUTH 的 Boto3 代码

遵循 AWS 文档(如下面的参考资料)。

对于 REFRESH_TOKEN_AUTH/REFRESH_TOKEN:REFRESH_TOKEN(必需)、SECRET_HASH(如果应用客户端配置了客户端密钥,则必需)、DEVICE_KEY

response = get_client().admin_initiate_auth(
    UserPoolId=USER_POOL_ID,
    ClientId=CLIENT_ID,
    AuthFlow='REFRESH_TOKEN_AUTH',
    AuthParameters={
        'REFRESH_TOKEN': refresh_token,
        'SECRET_HASH': get_secret_hash(username)
    }
)

在具有相同秘密哈希值的 ADMIN_NO_SRP_AUTH 身份验证流中不会发生这种情况。

ADMIN_NO_SRP_AUTH 的 Boto3 代码

response = get_client().admin_initiate_auth(
    UserPoolId=USER_POOL_ID,
    ClientId=CLIENT_ID,
    AuthFlow='ADMIN_NO_SRP_AUTH',
    AuthParameters={
        'USERNAME': username,
        'SECRET_HASH': get_secret_hash(username),
        'PASSWORD': password
    },
    ClientMetadata={
        'username': username,
        'password': password
    }
)

相同的秘密散列适用于 200。

{
    "AuthenticationResult": {
        "AccessToken": ...,
        "TokenType": "Bearer"
    },
    "ChallengeParameters": {},
    "ResponseMetadata": {
        "HTTPHeaders": {
            "connection": "keep-alive",
            "content-length": "3865",
            "content-type": "application/x-amz-json-1.1",
            "date": "Tue, 29 Jan 2019 22:25:33 GMT",
            "x-amzn-requestid": "cadf53cf-2414-11e9-bba9-4b60b3285418"
        },
        "HTTPStatusCode": 200,
        "RequestId": "cadf53cf-2414-11e9-bba9-4b60b3285418",
        "RetryAttempts": 0
    }
}

两者都使用相同的逻辑来生成秘密哈希。

def get_secret_hash(username):
    msg = username + CLIENT_ID
    digest = hmac.new(
        str(CLIENT_SECRET).encode('utf-8'),
        msg = str(msg).encode('utf-8'),
        digestmod=hashlib.sha256
    ).digest()
    hash = base64.b64encode(digest).decode()

    log_debug("secret hash for cognito UP is [{0}]".format(hash))
    return hash

值相同:

secret hash for cognito UP is [6kvmKb8almXpYKvfEbE9q4r1Iq/SuQvP8H**********].

环境

  • 启用客户端密码的 Cognito 用户池。

    打印 boto.Version 2.49.0

研究

AWS Javascript JDK

AWS Amplify Javascript JDK 不支持 Github 中所述的客户端密钥,但目前在 Boto3 上没有发现任何报告。

创建应用程序时,必须取消选中生成客户端密码框,因为 JavaScript SDK 不支持具有客户端密码的应用程序。

相关问题

参考文献

【问题讨论】:

    标签: python amazon-cognito


    【解决方案1】:

    行为是否符合预期有待确认。目前,解决这个问题。

    来自 AWS

    AWS 人员确定的原因和解决方法。

    当您的用户名中有“@”时,您会在 REFRESH_TOKEN_AUTH 调用中收到该错误。 Cognito 为他们生成一个 UUID 样式的用户名。而且您必须在刷新调用期间使用它。

    提供用于刷新令牌的示例代码。

    import boto3
    import hmac
    import hashlib
    import base64
    import time
    import jwt
    
    Region = "us-east-1"
    UserPoolId = "Your userpool ID"
    AppClientId = "yyyy"
    AppClientSecret = "zzzz"
    Username = "james@bond.com"
    Password = "shakennotstirred"
    
    Signature = hmac.new(AppClientSecret, Username+AppClientId,digestmod=hashlib.sha256)
    Hash = base64.b64encode(Signature.digest())
    
    Cognito = boto3.client("cognito-idp", region_name=Region)
    
    AuthResponse = Cognito.admin_initiate_auth(
        AuthFlow="ADMIN_NO_SRP_AUTH",
        ClientId=AppClientId,
        UserPoolId=UserPoolId,
        AuthParameters={"USERNAME":Username, "PASSWORD":Password, "SECRET_HASH":Hash})
    
    IdToken = AuthResponse["AuthenticationResult"]["IdToken"]
    RefreshToken = AuthResponse["AuthenticationResult"]["RefreshToken"]
    
    Decoded = jwt.decode(IdToken, verify=False)
    DecodedUsername = Decoded["cognito:username"]
    
    NewSignature = hmac.new(AppClientSecret, DecodedUsername+AppClientId, digestmod=hashlib.sha256) #!! Generate new signature and hash
    NewHash = base64.b64encode(NewSignature.digest())
    
    RefreshResponse = Cognito.admin_initiate_auth(
        AuthFlow="REFRESH_TOKEN_AUTH",
        ClientId=AppClientId,
        UserPoolId=UserPoolId,
        AuthParameters={"REFRESH_TOKEN":RefreshToken, "SECRET_HASH":NewHash}) #!! Use the new hash
    
    NewIdToken = RefreshResponse["AuthenticationResult"]["IdToken"]
    
    
    print("NewIdToken: "+NewIdToken)
    

    该示例使用 Python2。安装所需的软件包。

    pip2 install cryptography -t .
    pip2 install PyJWT -t .
    

    【讨论】:

    • 所以总结是:在调用REFRESH_TOKEN_AUTH时,在计算秘密哈希时使用Cognito分配的UUID用户名,而不是用于创建帐户并且与其他类型一起使用的电子邮件地址或其他ID通话次数。
    猜你喜欢
    • 2019-02-28
    • 2017-09-25
    • 2019-03-03
    • 2020-12-11
    • 2018-05-05
    • 2016-09-23
    • 2019-04-21
    • 2021-01-01
    • 1970-01-01
    相关资源
    最近更新 更多