it-swarm.com.de

Geheimer Hash für Client in Amazon Cognito Userpools kann nicht überprüft werden

Ich stecke beim Prozess "Amazon Cognito Identity-Benutzerpools" fest. 

Ich habe alle möglichen Codes zur Authentifizierung von Benutzern in Cognito-Benutzerpools ausprobiert. Ich erhalte jedoch immer die Fehlermeldung "Fehler: Geheimer Hash für Client 4b ******* fd kann nicht überprüft werden".

Hier ist der Code:

AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:b64bb629-ec73-4569-91eb-0d950f854f4f'
});

AWSCognito.config.region = 'us-east-1';
AWSCognito.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:b6b629-er73-9969-91eb-0dfffff445d'
});

AWSCognito.config.update({accessKeyId: 'AKIAJNYLRONAKTKBXGMWA', secretAccessKey: 'PITHVAS5/UBADLU/dHITesd7ilsBCm'})

var poolData = { 
    UserPoolId : 'us-east-1_l2arPB10',
    ClientId : '4bmsrr65ah3oas5d4sd54st11k'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);

var userData = {
     Username : '[email protected]',
     Pool : userPool
};

var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);

cognitoUser.confirmRegistration('123456', true,function(err, result) {
if (err) {
    alert(err);
    return;
}
console.log('call result: ' + result);
});
71
Ronak Patel

Es scheint, dass AWS Cognito derzeit das Kundengeheimnis nicht perfekt verarbeitet. Es wird in naher Zukunft funktionieren, aber bis jetzt ist es noch eine Beta-Version.

Für mich funktioniert es gut für eine App ohne ein Clientgeheimnis, aber für eine App mit einem Clientgeheimnis.

Versuchen Sie also, in Ihrem Benutzerpool eine neue App zu erstellen, ohne ein Clientgeheimnis zu generieren. Verwenden Sie dann diese App, um einen neuen Benutzer anzumelden oder die Registrierung zu bestätigen.

100
thomas.g

Laut den Dokumenten: http://docs.aws.Amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html

Das Javascript SDK unterstützt keine Apps mit einem Client-Secret.

Die Anweisungen geben jetzt an, dass Sie das "Generate Client Secret" deaktivieren müssen, wenn Sie die App für den Benutzerpool erstellen.

54
Dr Douglas GhD

Da alle anderen ihre Sprache eingestellt haben, ist hier der Knoten (und er arbeitet im Browser mit browserify-crypto, wird automatisch verwendet, wenn Sie webpack oder browserify verwenden)

const crypto = require('crypto');

...

crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')
10
Simon Buchan

Für jeden, der an AWS Lambda interessiert ist, um einen Benutzer mit dem AWS JS SDK zu registrieren, sind die folgenden Schritte ausgeführt:

Erstellen Sie eine weitere Lambda-Funktion in Python, um den Schlüssel zu generieren:

import hashlib
import hmac
import base64

secretKey = "key"
clientId = "clientid"
digest = hmac.new(secretKey,
                  msg=username + clientId,
                  digestmod=hashlib.sha256
                 ).digest()
signature = base64.b64encode(digest).decode()

Rufen Sie die Funktion über die nodeJS-Funktion in AWS auf. Die Unterschrift fungierte als geheimer Hash für Cognito

Hinweis: Die Antwort basiert stark auf der Antwort von George Campbell im folgenden Link: Berechnung eines SHA -Hashs mit einer Zeichenfolge + geheimem Schlüssel in Python

9
Molezz

Dies kann ein paar Jahre zu spät sein, aber deaktivieren Sie einfach die Option "Client geheim erstellen" und es funktioniert für Ihre Web-Clients.

 generate app client option

7

Lösung für golang. Anscheinend sollte dies zum SDK hinzugefügt werden.

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
)

func SecretHash(username, clientID, clientSecret string) string {
    mac := hmac.New(sha256.New, []byte(clientSecret))
    mac.Write([]byte(username + ClientID))
    return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
7
syvex

Amazon Erwähnen Sie, wie SecretHash-Werte berechnen für Amazon Cognito in der Dokumentation mit Java Anwendungscode. Hier funktioniert dieser Code mit boto 3 Python SDK .

app client details

Sie finden Ihren App clients im Menü auf der linken Seite unter General settings. Holen Sie sich diese App client id und App client secret, um SECRET_HASH zu erstellen. Zum besseren Verständnis habe ich alle Ausgaben jeder einzelnen Zeile auskommentiert.

import hashlib
import hmac
import base64

app_client_secret = 'u8f323eb3itbr3731014d25spqtv5r6pu01olpp5tm8ebicb8qa'
app_client_id = '396u9ekukfo77nhcfbmqnrec8p'
username = 'wasdkiller'

# convert str to bytes
key = bytes(app_client_secret, 'latin-1')  # b'u8f323eb3itbr3731014d25spqtv5r6pu01olpp5tm8ebicb8qa'
msg = bytes(username + app_client_id, 'latin-1')  # b'wasdkiller396u9ekukfo77nhcfbmqnrec8p'

new_digest = hmac.new(key, msg, hashlib.sha256).digest()  # b'P$#\xd6\xc1\xc0U\xce\xc1$\x17\xa1=\x18L\xc5\x1b\xa4\xc8\xea,\x92\xf5\xb9\xcdM\xe4\x084\xf5\x03~'
SECRET_HASH = base64.b64encode(new_digest).decode()  # UCQj1sHAVc7BJBehPRhMxRukyOoskvW5zU3kCDT1A34=

In der boto Dokumentation können wir sehen, wie viel Zeit nach SECRET_HASH fragt. Die obigen Codezeilen helfen Ihnen also, diesen SECRET_HASH zu erstellen.

Wenn Sie SECRET_HASH nicht verwenden möchten, deaktivieren Sie beim Erstellen einer App einfach Generate client secret.

new app create

5

In Java können Sie diesen Code verwenden:

private String getSecretHash(String email, String appClientId, String appSecretKey) throws Exception {
    byte[] data = (email + appClientId).getBytes("UTF-8");
    byte[] key = appSecretKey.getBytes("UTF-8");

    return Base64.encodeAsString(HmacSHA256(data, key));
}

static byte[] HmacSHA256(byte[] data, byte[] key) throws Exception {
    String algorithm = "HmacSHA256";
    Mac mac = Mac.getInstance(algorithm);
    mac.init(new SecretKeySpec(key, algorithm));
    return mac.doFinal(data);
}
5
gandrademello

Ich hatte das gleiche Problem im .net SDK.

Hier ist, wie ich es gelöst habe, falls jemand anderes es braucht:

public static class CognitoHashCalculator
{
    public static string GetSecretHash(string username, string appClientId, string appSecretKey)
    {
        var dataString = username + appClientId;

        var data = Encoding.UTF8.GetBytes(dataString);
        var key = Encoding.UTF8.GetBytes(appSecretKey);

        return Convert.ToBase64String(HmacSHA256(data, key));
    }

    public static byte[] HmacSHA256(byte[] data, byte[] key)
    {
        using (var shaAlgorithm = new System.Security.Cryptography.HMACSHA256(key))
        {
            var result = shaAlgorithm.ComputeHash(data);
            return result;
        }
    }
}

Die Anmeldung sieht dann so aus:

public class CognitoSignUpController
{
    private readonly IAmazonCognitoIdentityProvider _amazonCognitoIdentityProvider;

    public CognitoSignUpController(IAmazonCognitoIdentityProvider amazonCognitoIdentityProvider)
    {
        _amazonCognitoIdentityProvider = amazonCognitoIdentityProvider;
    }

    public async Task<bool> SignUpAsync(string userName, string password, string email)
    {
        try
        {
            var request = CreateSignUpRequest(userName, password, email);
            var authResp = await _amazonCognitoIdentityProvider.SignUpAsync(request);

            return true;
        }
        catch
        {
            return false;
        }
    }

    private static SignUpRequest CreateSignUpRequest(string userName, string password, string email)
    {
        var clientId = ConfigurationManager.AppSettings["ClientId"];
        var clientSecretId = ConfigurationManager.AppSettings["ClientSecretId"];

        var request = new SignUpRequest
        {
            ClientId = clientId,
            SecretHash = CognitoHashCalculator.GetSecretHash(userName, clientId, clientSecretId),
            Username = userName,
            Password = password,
        };

        request.UserAttributes.Add("email", email);
        return request;
    }
}
5
Ron Sijm

für Java und .NET müssen Sie das Secret in den Auth-Parametern mit dem Namen SECRET_HASH übergeben.

AdminInitiateAuthRequest request = new AdminInitiateAuthRequest
{
  ClientId = this.authorizationSettings.AppClientId,
  AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH,
  AuthParameters = new Dictionary<string, string>
  {
    {"USERNAME", username},
    {"PASSWORD", password},
    {
      "SECRET_HASH", EncryptionHelper.GetSecretHash(username, AppClientId, AppClientSecret)
    }
  },
  UserPoolId = this.authorizationSettings.UserPoolId
};

Und es sollte funktionieren.

3
Shanmukhi Goli

dies ist ein Beispiel-PHP-Code, den ich zum Erzeugen des geheimen Hashes verwende

<?php
    $userId = "aaa";
    $clientId = "bbb";
    $clientSecret = "ccc";
    $s = hash_hmac('sha256', $userId.$clientId, $clientSecret, true);
    echo base64_encode($s);
?>

in diesem Fall lautet das Ergebnis:

DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=

Lösung für NodeJS mit SecretHash

Es scheint dumm zu sein, dass AWS den geheimen Schlüssel aus dem SDK entfernt hat, da er in NodeJS nicht verfügbar ist.

Ich habe es in NodeJS zum Laufen gebracht, indem ich das Abholen abfängt und den Hash-Schlüssel unter Verwendung der Antwort von @Simon Buchan hinzufügt.

cognito.js

import { CognitoUserPool, CognitoUserAttribute, CognitoUser } from 'Amazon-cognito-identity-js'
import crypto from 'crypto'
import * as fetchIntercept from './fetch-intercept'

const COGNITO_SECRET_HASH_API = [
  'AWSCognitoIdentityProviderService.ConfirmForgotPassword',
  'AWSCognitoIdentityProviderService.ConfirmSignUp',
  'AWSCognitoIdentityProviderService.ForgotPassword',
  'AWSCognitoIdentityProviderService.ResendConfirmationCode',
  'AWSCognitoIdentityProviderService.SignUp',
]

const CLIENT_ID = 'xxx'
const CLIENT_SECRET = 'xxx'
const USER_POOL_ID = 'xxx'

const hashSecret = (clientSecret, username, clientId) => crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')

fetchIntercept.register({
  request(url, config) {
    const { headers } = config
    if (headers && COGNITO_SECRET_HASH_API.includes(headers['X-Amz-Target'])) {
      const body = JSON.parse(config.body)
      const { ClientId: clientId, Username: username } = body
      // eslint-disable-next-line no-param-reassign
      config.body = JSON.stringify({
        ...body,
        SecretHash: hashSecret(CLIENT_SECRET, username, clientId),
      })
    }
    return [url, config]
  },
})

const userPool = new CognitoUserPool({
  UserPoolId: USER_POOL_ID,
  ClientId: CLIENT_ID,
})

const register = ({ email, password, mobileNumber }) => {
  const dataEmail = { Name: 'email', Value: email }
  const dataPhoneNumber = { Name: 'phone_number', Value: mobileNumber }

  const attributeList = [
    new CognitoUserAttribute(dataEmail),
    new CognitoUserAttribute(dataPhoneNumber),
  ]

  return userPool.signUp(email, password, attributeList, null, (err, result) => {
    if (err) {
      console.log((err.message || JSON.stringify(err)))
      return
    }
    const cognitoUser = result.user
    console.log(`user name is ${cognitoUser.getUsername()}`)
  })
}

export {
  register,
}

fetch-inceptor.js (Für NodeJS von Fork of forked und bearbeitet - https://github.com/werk85/fetch-intercept/blob/develop/src/index.js )

let interceptors = []

if (!global.fetch) {
  try {
    // eslint-disable-next-line global-require
    global.fetch = require('node-fetch')
  } catch (err) {
    throw Error('No fetch available. Unable to register fetch-intercept')
  }
}
global.fetch = (function (fetch) {
  return (...args) => interceptor(fetch, ...args)
}(global.fetch))

const interceptor = (fetch, ...args) => {
  const reversedInterceptors = interceptors.reduce((array, _interceptor) => [_interceptor].concat(array), [])
  let promise = Promise.resolve(args)

  // Register request interceptors
  reversedInterceptors.forEach(({ request, requestError }) => {
    if (request || requestError) {
      promise = promise.then(_args => request(..._args), requestError)
    }
  })

  // Register fetch call
  promise = promise.then(_args => fetch(..._args))

  // Register response interceptors
  reversedInterceptors.forEach(({ response, responseError }) => {
    if (response || responseError) {
      promise = promise.then(response, responseError)
    }
  })

  return promise
}

const register = (_interceptor) => {
  interceptors.Push(_interceptor)
  return () => {
    const index = interceptors.indexOf(_interceptor)
    if (index >= 0) {
      interceptors.splice(index, 1)
    }
  }
}

const clear = () => {
  interceptors = []
}

export {
  register,
  clear,
}
2
ptimson

Möglicherweise gibt es eine kompaktere Version, aber dies funktioniert für Ruby, insbesondere in Ruby on Rails, ohne dass etwas erforderlich ist:

key = ENV['COGNITO_SECRET_HASH']
data = username + ENV['COGNITO_CLIENT_ID']
digest = OpenSSL::Digest.new('sha256')

hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, key, data))
0
Nikolay D

C++ mit dem Qt Framework

QByteArray MyObject::secretHash(
     const QByteArray& email,
     const QByteArray& appClientId, 
     const QByteArray& appSecretKey)
{
            QMessageAuthenticationCode code(QCryptographicHash::Sha256);
            code.setKey(appSecretKey);
            code.addData(email);
            code.addData(appClientId);
            return code.result().toBase64();
};
0
vpicaver