【问题标题】:How to create a SECRET_HASH for AWS Cognito using boto3?如何使用 boto3 为 AWS Cognito 创建 SECRET_HASH?
【发布时间】:2017-10-29 21:04:17
【问题描述】:

我想使用 boto3 和 python 为 AWS Cognito 创建/计算 SECRET_HASH。这将被合并到我的 warrant 的 fork 中。

我将我的 cognito 应用程序客户端配置为使用 app client secret。但是,这破坏了以下代码。

def renew_access_token(self):
    """
    Sets a new access token on the User using the refresh token.

    NOTE:
    Does not work if "App client secret" is enabled. 'SECRET_HASH' is needed in AuthParameters.
    'SECRET_HASH' requires HMAC calculations.

    Does not work if "Device Tracking" is turned on.
    https://stackoverflow.com/a/40875783/1783439

    'DEVICE_KEY' is needed in AuthParameters. See AuthParameters section.
    https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html
    """
    refresh_response = self.client.initiate_auth(
        ClientId=self.client_id,
        AuthFlow='REFRESH_TOKEN',
        AuthParameters={
            'REFRESH_TOKEN': self.refresh_token
            # 'SECRET_HASH': How to generate this?
        },
    )

    self._set_attributes(
        refresh_response,
        {
            'access_token': refresh_response['AuthenticationResult']['AccessToken'],
            'id_token': refresh_response['AuthenticationResult']['IdToken'],
            'token_type': refresh_response['AuthenticationResult']['TokenType']
        }
    )

当我运行它时,我收到以下异常:

botocore.errorfactory.NotAuthorizedException: 
An error occurred (NotAuthorizedException) when calling the InitiateAuth operation: 
Unable to verify secret hash for client <client id echoed here>.

This answer 通知我,需要 SECRET_HASH 才能使用 cognito 客户端密码。

aws API reference docs AuthParameters 部分声明如下:

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

SECRET_HASH 的boto3 docs 状态

使用密钥计算的哈希消息验证码 (HMAC) 用户池客户端的密钥和用户名加上客户端 ID 消息。

文档解释了需要什么,但没有解释如何实现这一点。

【问题讨论】:

    标签: python amazon-web-services boto3 amazon-cognito hmac


    【解决方案1】:

    下面的get_secret_hash 方法是我用 Python 为 Cognito 用户池实现编写的解决方案,示例用法:

    import boto3
    import botocore
    import hmac
    import hashlib
    import base64
    
    
    class Cognito:
        client_id = app.config.get('AWS_CLIENT_ID')
        user_pool_id = app.config.get('AWS_USER_POOL_ID')
        identity_pool_id = app.config.get('AWS_IDENTITY_POOL_ID')
        client_secret = app.config.get('AWS_APP_CLIENT_SECRET')
        # Public Keys used to verify tokens returned by Cognito:
        # http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html#amazon-cognito-identity-user-pools-using-id-and-access-tokens-in-web-api
        id_token_public_key = app.config.get('JWT_ID_TOKEN_PUB_KEY')
        access_token_public_key = app.config.get('JWT_ACCESS_TOKEN_PUB_KEY')
    
        def __get_client(self):
            return boto3.client('cognito-idp')
    
        def get_secret_hash(self, username):
            # A keyed-hash message authentication code (HMAC) calculated using
            # the secret key of a user pool client and username plus the client
            # ID in the message.
            message = username + self.client_id
            dig = hmac.new(self.client_secret, msg=message.encode('UTF-8'),
                           digestmod=hashlib.sha256).digest()
            return base64.b64encode(dig).decode()
    
        # REQUIRES that `ADMIN_NO_SRP_AUTH` be enabled on Client App for User Pool
        def login_user(self, username_or_alias, password):
            try:
                return self.__get_client().admin_initiate_auth(
                    UserPoolId=self.user_pool_id,
                    ClientId=self.client_id,
                    AuthFlow='ADMIN_NO_SRP_AUTH',
                    AuthParameters={
                        'USERNAME': username_or_alias,
                        'PASSWORD': password,
                        'SECRET_HASH': self.get_secret_hash(username_or_alias)
                    }
                )
            except botocore.exceptions.ClientError as e:
                return e.response
    

    【讨论】:

    • SECRET_HASH 计算是否总是使用用户名作为输入,对于 API 需要的每种情况,即使是 REFRESH_TOKEN_AUTH 流,其中用户名不是 AuthParameters 的一部分?
    • 好东西。我刚刚在dig=hmac.new(...) 行收到此错误"TypeError: key: expected bytes or bytearray, but got 'str' "。解决方案是在hmac.new的第一个参数处做一个简单的bytearray(self.client_secret, "utf-8")
    猜你喜欢
    • 2017-05-22
    • 2019-07-31
    • 2021-04-07
    • 1970-01-01
    • 2019-11-03
    • 2019-07-09
    • 1970-01-01
    • 2019-12-24
    • 2019-08-09
    相关资源
    最近更新 更多