2017-05-29 54 views
2

我想使用boto3和python爲AWS Cognito創建/計算SECRET_HASH。這將被納入我的分叉warrant如何使用boto3爲AWS Cognito創建SECRET_HASH?

我將我的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客戶端密鑰。

對於REFRESH_TOKEN_AUTH/REFRESH_TOKEN:

以下的aws API reference docs AuthParameters部狀態USERNAME(必需),SECRET_HASH (必需如果應用程序的客戶端被配置爲與客戶端密鑰), REFRESH_TOKEN(必需), DEVICE_KEY

boto3 docs狀態,一個SECRET_HASH是

使用用戶池客戶端的祕密密鑰和用戶名加上 消息中的客戶端ID計算的密鑰哈希消息驗證代碼(HMAC)。

該文檔解釋了需要什麼,但不是如何實現這一點。

回答

2

的下面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