Tidak dapat memverifikasi hash rahasia untuk klien di Amazon Cognito Userpools

132

Saya terjebak dalam proses "kumpulan pengguna Amazon Cognito Identity".

Saya mencoba semua kode yang mungkin untuk mengautentikasi pengguna di cognito userpools. Tetapi saya selalu mendapatkan kesalahan yang mengatakan "Kesalahan: Tidak dapat memverifikasi hash rahasia untuk klien 4b ******* fd".

Ini kodenya:

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);
});
Ronak Patel
sumber
9
Jawaban yang diterima TIDAK valid lagi. Petunjuk cara membuat hash rahasia ada di sini docs.aws.amazon.com/cognito/latest/developerguide/…
jasiustasiu
Ya, dan lihat jawaban @Simon Buchan di bawah ini untuk implementasi JavaScript. Ini bekerja dengan sempurna.
guzmonne

Jawaban:

182

Sepertinya saat ini AWS Cognito tidak menangani rahasia klien dengan sempurna. Ini akan berfungsi dalam waktu dekat tetapi untuk saat ini masih versi beta.

Bagi saya ini berfungsi dengan baik untuk aplikasi tanpa rahasia klien tetapi gagal untuk aplikasi dengan rahasia klien.

Jadi di kumpulan pengguna Anda, cobalah membuat aplikasi baru tanpa membuat rahasia klien. Kemudian gunakan aplikasi itu untuk mendaftarkan pengguna baru atau untuk mengonfirmasi pendaftaran.

thomas.g
sumber
14
FYI: Ini baru saja terjadi pada saya, barusan. Ini masih berfungsi dengan cara ini, Jan 2017. Ketika saya membuat aplikasi tanpa client_secret, saya bisa menggunakan JS SDK. Ketika saya membuat aplikasi dengan client_secret, saya mendapatkan faillure yang sama seperti pada pertanyaan awal.
Cheeso
5
Mulai 21 Apr 2017, itu masih tidak berfungsi menggunakan AWS CLI saat kunci rahasia diaktifkan untuk Klien Aplikasi. aws cognito-idp admin-inisiate-auth \ --region ap-northeast-1 \ --user-pool-id MY_POOL_ID \ --client-id MY_CLIENT_ID \ --auth-flow ADMIN_NO_SRP_AUTH \ --auth-parameter USERNAME = nama pengguna @ gmail.com, PASSWORD = som3PassW0rd
Stanley Yong
26
Mulai Jan 2018, ini masih belum didukung. Dokumentasi di repo Github github.com/aws/amazon-cognito-identity-js menyebutkannya:"When creating the App, the generate client secret box must be unchecked because the JavaScript SDK doesn't support apps that have a client secret."
kakoma
5
19 Mei 2018, kesalahan yang sama kami perlu membuat aplikasi tanpa rahasia klien.
Dileep
4
12 September 2018 - Masalah yang sama. Bahkan ketika tidak menggunakan klien yang menghasilkan rahasia, saya mendapatkan 400 apakah pengguna diautentikasi atau tidak. Namun, aplikasi berfungsi seperti yang diharapkan.
foxtrotuniform6969
37

Ini mungkin terlambat beberapa tahun tetapi hapus centang pada opsi "Buat rahasia klien" dan ini akan berfungsi untuk klien web Anda.

menghasilkan opsi klien aplikasi

Tiisetso Tjabane
sumber
8
Perhatikan bahwa Anda tidak dapat mengeditnya setelah klien dibuat, jadi buat yang baru jika perlu.
URL87
Jika Anda membuat klien aplikasi baru dan memiliki kumpulan identitas (pada "Federated Identities") yang menggunakan penyedia autentikasi Cognito, ingatlah untuk memperbarui bidang id klien aplikasi dengan id dari klien aplikasi baru.
AMS777
21

Karena semua orang telah memposting bahasa mereka, inilah node (dan berfungsi di browser dengan browserify-crypto, secara otomatis digunakan jika Anda menggunakan webpack atau browserify):

const crypto = require('crypto');

...

crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')
Simon Buchan
sumber
4
ini adalah solusi bawaan Node.js yang sederhana dan terbaik, terima kasih @simon
Engineer
19

Saya memiliki masalah yang sama di .net SDK.

Inilah cara saya menyelesaikannya, jika ada orang lain yang membutuhkannya:

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

Mendaftar kemudian terlihat seperti ini:

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;
    }
}
Ron Sijm
sumber
Mengonfirmasi bahwa ini masih diperlukan dan masih berfungsi di v3.5 AWS .NET SDK (pratinjau).
pieSquared
13

Bagi siapa pun yang tertarik menggunakan AWS Lambda untuk mendaftarkan pengguna menggunakan AWS JS SDK, berikut adalah langkah-langkah yang saya lakukan:

Buat fungsi lambda lain di python untuk menghasilkan kunci:

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

Panggil fungsi tersebut melalui fungsi nodeJS di AWS. Tanda tangan tersebut bertindak sebagai hash rahasia untuk Cognito

Catatan: Jawabannya sangat didasarkan pada jawaban George Campbell di tautan berikut: Menghitung hash SHA dengan string + kunci rahasia di python

Molezz
sumber
12

Solusi untuk golang. Sepertinya ini harus ditambahkan ke 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))
}
syvex
sumber
8

Solusi untuk NodeJS dengan SecretHash

Tampaknya konyol bahwa AWS menghapus kunci rahasia dari SDK karena tidak akan terekspos di NodeJS.

Saya membuatnya berfungsi di NodeJS dengan mencegat pengambilan dan menambahkan kunci hash menggunakan jawaban @Simon Buchan .

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 ( Bercabang dan diedit untuk NodeJS dari Fork dari 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,
}
ptimson
sumber
Saya dapat mendaftar mengikuti prosedur Anda, tetapi saya tidak dapat masuk menggunakan proc ini. Apakah ada modifikasi yang perlu dilakukan untuk masuk? Akan sangat membantu jika Anda bisa menambahkannya di sini. Terima kasih sebelumnya.
Vinay Wadagavi
8

Amazon menyebutkan bagaimana Menghitung Nilai SecretHash untuk Amazon Cognito dalam dokumentasinya dengan kode aplikasi Java. Di sini kode ini bekerja dengan boto 3 Python SDK .

detail klien aplikasi

Anda dapat menemukan Anda App clientsdi menu sisi kiri di bawah General settings. Dapatkan itu App client iddan App client secretbuat SECRET_HASH. Agar Anda lebih mengerti, saya mengomentari semua output dari setiap baris.

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=

Dalam dokumentasi boto 3 , kita bisa melihat banyak waktu bertanya SECRET_HASH. Jadi baris kode di atas membantu Anda membuat ini SECRET_HASH.

Jika Anda tidak ingin menggunakan, SECRET_HASHhapus centang Generate client secretsaat membuat aplikasi.

pembuatan aplikasi baru

Kushan Gunasekera
sumber
1
Bagi saya, ini hanya berfungsi jika saya mengganti msg = byte (app_client_id + nama pengguna, 'latin-1') ke msg = byte (nama pengguna + app_client_id, 'latin-1'). Untuk memperjelas, saya mengganti urutan clientId dan nama pengguna sehingga nama pengguna muncul lebih dulu.
Josh Wolff
1
Terima kasih banyak @JoshWolff, saya salah menukar app_client_iddan username. Tapi saya menampilkan keluaran yang benar sebagai komentar yang ditampilkan sesuai dengan username+ app_client_id. Sekali lagi terima kasih banyak.
Kushan Gunasekera
1
Tidak masalah sama sekali! @Kushan Gunekera
Josh
7

Di Java, Anda dapat menggunakan kode ini:

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);
}
gandrademello
sumber
Di mana Anda menggunakan hash rahasia ini di SDK selain menampilkannya ke layar?
Aaron
1
Adakah yang bisa menunjuk ke dokumen AWS mana pun secara online di mana otentikasi terhadap rahasia klien dijelaskan? Pengodean tanda tangan base64 / sha256 adalah solusi yang menarik - tetapi tidak berguna kecuali jika secara eksplisit sesuai dengan dokumen AWS yang menjelaskan cara mengautentikasi terhadap rahasia klien.
Kode Charlie
6

ini adalah contoh kode php yang saya gunakan untuk menghasilkan hash rahasia

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

dalam hal ini hasilnya adalah:

DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=
Titi Wangsa bin Damhore
sumber
5

untuk JAVA dan .NET Anda harus meneruskan rahasia yang ada di parameter auth dengan nama 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
};

Dan itu harus berhasil.

Shanmukhi Goli
sumber
3

C ++ dengan 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();
};
vpicaver
sumber
1

Mungkin ada versi yang lebih ringkas, tetapi ini berfungsi untuk Ruby, khususnya di Ruby on Rails tanpa harus memerlukan apa pun:

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))
Nikolay D
sumber
0

Otentikasi Penyamaran

Kesalahan: Klien aplikasi tidak dikonfigurasi untuk rahasia tetapi hash rahasia telah diterima

Memberikan secretKey sebagai nol berhasil untuk saya. Kredensial yang diberikan meliputi: -

  • CognitoIdentityUserPoolRegion (wilayah)
  • CognitoIdentityUserPoolId (userPoolId)
  • CognitoIdentityUserPoolAppClientId (ClientId)
  • AWSCognitoUserPoolsSignInProviderKey (AccessKeyId)

    // setup service configuration
    let serviceConfiguration = AWSServiceConfiguration(region: CognitoIdentityUserPoolRegion, credentialsProvider: nil)
    
    // create pool configuration
    let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoIdentityUserPoolAppClientId,
                                                                    clientSecret: nil,
                                                                    poolId: CognitoIdentityUserPoolId)
    
    // initialize user pool client
    AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: poolConfiguration, forKey: AWSCognitoUserPoolsSignInProviderKey)
    

Semua hal di atas bekerja dengan contoh kode tertaut di bawah ini.

Kode Sampel AWS: https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Swift

Beri tahu saya jika itu tidak berhasil untuk Anda.

Siddharth Kavthekar
sumber
ini adalah tautan mati
Jpnh
0

Ini adalah 1 perintah saya, dan berfungsi (Dikonfirmasi :))

EMAIL="[email protected]" \
CLIENT_ID="[CLIENT_ID]" \
CLIENT_SECRET="[CLIENT_ID]" \
&& SECRET_HASH=$(echo -n "${EMAIL}${CLIENT_ID}" | openssl dgst -sha256 -hmac "${CLIENT_SECRET}" | xxd -r -p | openssl base64) \
&& aws cognito-idp ...  --secret-hash "${SECRET_HASH}"
Tuong Le
sumber