9

Amazon提供iOS,Android和Javascript Cognito SDK,可提供高級身份驗證用戶操作。對AWS Cognito使用python boto3實現USER_SRP_AUTH

例如,請參閱使用案例4瀏覽:

https://github.com/aws/amazon-cognito-identity-js

但是,如果你正在使用python/boto3,你所得到的是一對原語:cognito.initiate_authcognito.respond_to_auth_challenge

我想使用這些原語連同pysrp lib與USER_SRP_AUTH流驗證,但我有什麼不工作。

它在調用RespondToAuthChallenge操作時發生錯誤(NotAuthorizedException)時總是失敗:不正確的用戶名或密碼。「 (使用JS SDK可以找到用戶名/密碼對)

我懷疑我構建了挑戰響應錯誤(步驟3),並且/或者在想要base64時傳遞Congito十六進制字符串,反之亦然。

有沒有人得到這個工作?任何人看到我做錯了什麼?

我試圖複製在使用Javascript SDK中發現的authenticateUser調用的行爲:

https://github.com/aws/amazon-cognito-identity-js/blob/master/src/CognitoUser.js#L138

,但我做錯了什麼,不能弄清楚什麼。

#!/usr/bin/env python 
import base64 
import binascii 
import boto3 
import datetime as dt 
import hashlib 
import hmac 

# http://pythonhosted.org/srp/ 
# https://github.com/cocagne/pysrp 
import srp 

bytes_to_hex = lambda x: "".join("{:02x}".format(ord(c)) for c in x) 

cognito = boto3.client('cognito-idp', region_name="us-east-1") 

username = "[email protected]" 
password = "123456" 

user_pool_id = u"us-east-1_XXXXXXXXX" 
client_id = u"XXXXXXXXXXXXXXXXXXXXXXXXXX" 

# Step 1: 
# Use SRP lib to construct a SRP_A value. 

srp_user = srp.User(username, password) 
_, srp_a_bytes = srp_user.start_authentication() 

srp_a_hex = bytes_to_hex(srp_a_bytes) 

# Step 2: 
# Submit USERNAME & SRP_A to Cognito, get challenge. 

response = cognito.initiate_auth(
    AuthFlow='USER_SRP_AUTH', 
    AuthParameters={ 'USERNAME': username, 'SRP_A': srp_a_hex }, 
    ClientId=client_id, 
    ClientMetadata={ 'UserPoolId': user_pool_id }) 

# Step 3: 
# Use challenge parameters from Cognito to construct 
# challenge response. 

salt_hex   = response['ChallengeParameters']['SALT'] 
srp_b_hex  = response['ChallengeParameters']['SRP_B'] 
secret_block_b64 = response['ChallengeParameters']['SECRET_BLOCK'] 

secret_block_bytes = base64.standard_b64decode(secret_block_b64) 
secret_block_hex = bytes_to_hex(secret_block_bytes) 

salt_bytes = binascii.unhexlify(salt_hex) 
srp_b_bytes = binascii.unhexlify(srp_b_hex) 

process_challenge_bytes = srp_user.process_challenge(salt_bytes,       
                srp_b_bytes) 

timestamp = unicode(dt.datetime.utcnow().strftime("%a %b %d %H:%m:%S +0000 %Y")) 

hmac_obj = hmac.new(process_challenge_bytes, digestmod=hashlib.sha256) 
hmac_obj.update(user_pool_id.split('_')[1].encode('utf-8')) 
hmac_obj.update(username.encode('utf-8')) 
hmac_obj.update(secret_block_bytes) 
hmac_obj.update(timestamp.encode('utf-8')) 

challenge_responses = { 
    "TIMESTAMP": timestamp.encode('utf-8'), 
    "USERNAME": username.encode('utf-8'), 
    "PASSWORD_CLAIM_SECRET_BLOCK": secret_block_hex, 
    "PASSWORD_CLAIM_SIGNATURE": hmac_obj.hexdigest() 
} 

# Step 4: 
# Submit challenge response to Cognito. 

response = cognito.respond_to_auth_challenge(
    ClientId=client_id, 
    ChallengeName='PASSWORD_VERIFIER', 
    ChallengeResponses=challenge_responses) 
+0

你有沒有得到這個工作?我在我的項目中正在做同樣的事情。 – man2xxl

+0

不,我對它進一步加以強調,但目前還沒有運氣。作爲解決辦法,我已經建立了一個自定義授權lambda('DefineAuthChallenge'),它總是授權用戶:'exports.handler = function(event,context){event.response.issueTokens = true; event.response.failAuthentication = false; context.done(null,event);}'。這是我現在需要的,因爲我只是在構建原型。但我希望最終能夠實現這一目標。 – billc

+0

man2xxl,結帳armicron的答案在下面。 – billc

回答

5

您的實施中存在很多錯誤。例如:

  1. pysrp默認使用SHA1算法。它應該被設置爲SHA256。
  2. _ng_const長度應3072位和它應該從amazon-cognito-identity-js
  3. 複製有一個在pysrp沒有hkdf功能。
  4. 響應應該包含secret_block_b64,不secret_block_hex
  5. 錯誤的時間戳格式。 %H:%m:%S表示「小時:月:秒」,+0000應替換爲UTC

有沒有人得到這個工作?

是的。它在warrant.aws_srp模塊中實施。 https://github.com/capless/warrant/blob/develop/warrant/aws_srp.py

from warrant.aws_srp import AWSSRP 


USERNAME='xxx' 
PASSWORD='yyy' 
POOL_ID='us-east-1_zzzzz' 
CLIENT_ID = '12xxxxxxxxxxxxxxxxxxxxxxx' 

aws = AWSSRP(username=USERNAME, password=PASSWORD, pool_id=POOL_ID, 
      client_id=CLIENT_ID) 
tokens = aws.authenticate_user() 
id_token = tokens['AuthenticationResult']['IdToken'] 
refresh_token = tokens['AuthenticationResult']['RefreshToken'] 
access_token = tokens['AuthenticationResult']['AccessToken'] 
token_type = tokens['AuthenticationResult']['TokenType'] 

注意,即aws_srp模塊並沒有合併到master分支呢。

authenticate_user方法僅支持PASSWORD_VERIFIER挑戰。如果您想回應其他挑戰,請查看authenticate_userboto3文檔。

+0

感謝armicron! – billc

2

不幸的是這是一個困難的問題,因爲你沒有得到服務的任何提示與問候的計算(這主要是因爲你提到說未授權)。

我們正致力於改善開發者體驗,當用戶嘗試使用我們沒有SDK的語言自行實施SRP時。另外,我們正在嘗試添加更多SDK。

聽起來令人生畏,我建議採取Javascript或Android SDK,修復輸入(SRP_A,SRP_B,TIMESTAMP)並在實現中的各個位置添加console.log語句,以確保您的計算是相似的。然後你會在你的實現中運行這些計算,並確保你得到相同的結果。正如您所建議的那樣,密碼聲明簽名需要作爲base64編碼字符串傳遞給服務,這可能是其中一個問題。

我在實現這個時遇到的一些問題與BigInteger庫的差異有關(它們進行字節填充和將負數轉換爲字節數組的方式和相反)。

+0

感謝Ionut。我希望有人會看到我明顯地犯了一些錯誤,並且我可以避免你提出的痛苦過程,但我想我會陷入困境。感謝PASSWORD_CLAIM_SIGNATURE的提示。我假設你的意思是base64編碼從HMAC操作返回的*原始字節*,對吧? (而不是說,這些字節的* hexstring *的base64?) – billc

+1

是的,我的意思是,base64對從hmac操作返回的原始字節進行編碼。 –