web-dev-qa-db-fra.com

Impossible de vérifier le hachage secret pour le client dans les pools d'utilisateurs Amazon Cognito

Je suis bloqué dans le processus "Groupes d'utilisateurs Amazon Cognito Identity". 

J'ai essayé tous les codes possibles pour authentifier l'utilisateur dans les groupes d'utilisateurs cognito. Mais j'ai toujours une erreur en disant "Erreur: Impossible de vérifier le hachage secret pour le client 4b ******* fd".

Voici le 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

Il semble qu'actuellement AWS Cognito ne gère pas parfaitement le secret du client. Cela fonctionnera dans un avenir proche, mais pour l’instant, c’est toujours une version bêta.

Pour moi, cela fonctionne bien pour une application sans secret client mais échoue pour une application avec un secret client.

Dans votre groupe d'utilisateurs, essayez de créer une nouvelle application sans générer de secret client. Ensuite, utilisez cette application pour inscrire un nouvel utilisateur ou pour confirmer l'inscription.

100
thomas.g

Selon les documents: http://docs.aws.Amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html

Le SDK Javascript ne prend pas en charge les applications avec un secret client.

Les instructions indiquent maintenant que vous devez décocher "Générer le secret du client" lors de la création de l'application pour le groupe d'utilisateurs.

54
Dr Douglas GhD

Puisque tout le monde a posté sa langue, voici le noeud (et cela fonctionne dans le navigateur avec browserify-crypto, utilisé automatiquement si vous utilisez webpack ou browserify):

const crypto = require('crypto');

...

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

Pour toute personne souhaitant utiliser AWS Lambda pour inscrire un utilisateur à l'aide du kit SDK AWS JS, voici les étapes que j'ai effectuées:

Créez une autre fonction lambda en python pour générer la clé:

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()

Appelez la fonction par le biais de la fonction nodeJS dans AWS. La signature a servi de hachage secret pour Cognito

Remarque: La réponse est fortement basée sur la réponse de George Campbell dans le lien suivant: Calcul d'un hachage SHA avec une chaîne + clé secrète en python

9
Molezz

Cela peut prendre quelques années de retard, mais décochez simplement l'option "Générer le secret du client" "et cela fonctionnera pour vos clients Web.

 generate app client option

7
Tiisetso Tjabane

Solution pour golang. On dirait que cela devrait être ajouté au SDK.

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 mentionner comment Computing SecretHash Values pour Amazon Cognito dans leur documentation avec le code d'application Java. Ici ce code fonctionne avec boto 3 Python SDK .

app client details

Vous pouvez trouver votre App clients dans le menu de gauche sous General settings. Obtenez ces App client id et App client secret pour créer SECRET_HASH. Pour que vous compreniez mieux, j'ai commenté toutes les sorties de chaque ligne.

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=

Dans la documentation boto , nous pouvons voir beaucoup de temps poser des questions sur SECRET_HASH. Les lignes de code ci-dessus vous aident donc à créer ce SECRET_HASH.

Si vous ne voulez pas utiliser SECRET_HASH décochez simplement Generate client secret lors de la création d'une application.

new app create

5
Kushan Gunasekera

En Java, vous pouvez utiliser ce code:

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

J'ai eu le même problème dans le SDK .net.

Voici comment j'ai résolu le problème, au cas où quelqu'un d'autre en aurait besoin:

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;
        }
    }
}

L'inscription ressemble alors à ceci:

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

pour Java et .NET, vous devez passer le secret a dans les paramètres d'authentification avec le nom SECRET_HASH.

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
};

Et ça devrait marcher.

3
Shanmukhi Goli

ceci est un exemple de code php que j'utilise pour générer le hachage secret

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

dans ce cas, le résultat est:

DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=

Solution pour NodeJS avec SecretHash

Il semble ridicule qu'AWS ait supprimé la clé secrète du SDK car elle ne sera pas exposée dans NodeJS.

Je l'ai fait fonctionner dans NodeJS en interceptant fetch et en ajoutant la clé hachée en utilisant @Simon Buchan 's answer.

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 (Forked et édité pour NodeJS depuis Fork of 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

Il existe peut-être une version plus compacte, mais cela fonctionne pour Ruby, en particulier dans Ruby on Rails, sans rien exiger:

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++ avec le framework Qt

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