Amazon Cognito User Pool - amazon-web-services
I have a user pool in Amazon Cognito used for authenticating the APIs. And I have a user table in my database RDS where user will be inserted via application and website. I am looking for a way to auto insert user in Cognito user pool when user gets inserted in user table.
I am using java as the programming language.
Can anyone please suggest me any possible solution for it?
Can I use lambda for this? And if I can, is there any example for it, where users are inserted using lambda using java sdk?
You can use the AWS SDK for Java v2 to perform this task. To add a user to a user Pool, you can use this Java code. Specifically, you use the software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient and use the signUp method.
If you are not familiar with the AWS SDK for Java V2, refer to the DEV Guide.
Code to add a user to a user pool is:
package com.example.cognito;
//snippet-start:[cognito.java2.new_admin_user.import]
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient;
import software.amazon.awssdk.services.cognitoidentityprovider.model.AdminCreateUserRequest;
import software.amazon.awssdk.services.cognitoidentityprovider.model.AdminCreateUserResponse;
import software.amazon.awssdk.services.cognitoidentityprovider.model.AttributeType;
import software.amazon.awssdk.services.cognitoidentityprovider.model.CognitoIdentityProviderException;
import java.util.ArrayList;
import java.util.List;
//snippet-end:[cognito.java2.new_admin_user.import]
/**
* Before running this Java V2 code example, set up your development environment, including your credentials.
*
* For more information, see the following documentation topic:
*
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*/
public class CreateUser {
public static void main(String[] args) {
final String usage = "\n" +
"Usage:\n" +
" <userPoolId> <userName> <email> <password>\n\n" +
"Where:\n" +
" userPoolId - The Id value for the user pool where the user is created.\n\n" +
" userName - The user name for the new user.\n\n" +
" email - The email to use for verifying the user.\n\n" +
" password - The password for this user.\n\n" ;
if (args.length != 4) {
System.out.println(usage);
System.exit(1);
}
String userPoolId = args[0];
String userName = args[1];
String email = args[2];
String password = args[3];
CognitoIdentityProviderClient cognitoClient = CognitoIdentityProviderClient.builder()
.region(Region.US_EAST_1)
.credentialsProvider(ProfileCredentialsProvider.create())
.build();
createNewUser(cognitoClient, userPoolId, userName, email, password);
cognitoClient.close();
}
//snippet-start:[cognito.java2.add_login_provider.main]
public static void createNewUser(CognitoIdentityProviderClient cognitoClient,
String userPoolId,
String name,
String email,
String password){
try{
AttributeType userAttrs = AttributeType.builder()
.name("email")
.value(email)
.build();
AttributeType userAttrs1 = AttributeType.builder()
.name("autoVerifyEmail")
.value("true")
.build();
List<AttributeType> userAttrsList = new ArrayList();
userAttrsList.add(userAttrs);
userAttrsList.add(userAttrs1);
AdminCreateUserRequest userRequest = AdminCreateUserRequest.builder()
.userPoolId(userPoolId)
.username(name)
.temporaryPassword(password)
.userAttributes(userAttrs)
.messageAction("SUPPRESS")
.build() ;
AdminCreateUserResponse response = cognitoClient.adminCreateUser(userRequest);
System.out.println("User " + response.user().username() + "is created. Status: " + response.user().userStatus());
} catch (CognitoIdentityProviderException e){
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
}
//snippet-end:[cognito.java2.add_login_provider.main]
}
Code to sign up a user is:
//snippet-sourcedescription:[SignUp.java demonstrates how to register a user in the specified Amazon Cognito user pool.]
//snippet-keyword:[AWS SDK for Java v2]
//snippet-keyword:[Code Sample]
//snippet-keyword:[Amazon Cognito]
//snippet-sourcetype:[full-example]
//snippet-sourcedate:[05/18/2022]
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package com.example.cognito;
//snippet-start:[cognito.java2.signup.import]
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient;
import software.amazon.awssdk.services.cognitoidentityprovider.model.CognitoIdentityProviderException;
import software.amazon.awssdk.services.cognitoidentityprovider.model.SignUpRequest;
import software.amazon.awssdk.services.cognitoidentityprovider.model.AttributeType;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
//snippet-end:[cognito.java2.signup.import]
/**
* To run this Java code example, you need to create a client app in a user pool with a secret key. For details, see:
* https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html
*
* In addition, set up your development environment, including your credentials.
*
* For more information, see the following documentation topic:
*
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*
*/
public class SignUpUser {
public static void main(String[] args) {
final String usage = "\n" +
"Usage:\n" +
" <clientId> <secretkey> <userName> <password> <email>\n\n" +
"Where:\n" +
" clientId - The app client id value that you can obtain from the AWS Management Console.\n\n" +
" secretkey - The app client secret value that you can obtain from the AWS Management Console.\n\n" +
" userName - The user name of the user you wish to register.\n\n" +
" password - The password for the user.\n\n" +
" email - The email address for the user.\n\n";
if (args.length != 5) {
System.out.println(usage);
System.exit(1);
}
String clientId = args[0];
String secretKey = args[1];
String userName = args[2];
String password = args[3];
String email = args[4];
CognitoIdentityProviderClient identityProviderClient = CognitoIdentityProviderClient.builder()
.region(Region.US_EAST_1)
.credentialsProvider(ProfileCredentialsProvider.create())
.build();
signUp(identityProviderClient, clientId, secretKey, userName, password, email);
identityProviderClient.close();
}
//snippet-start:[cognito.java2.signup.main]
public static void signUp(CognitoIdentityProviderClient identityProviderClient,
String clientId,
String secretKey,
String userName,
String password,
String email) {
AttributeType attributeType = AttributeType.builder()
.name("email")
.value(email)
.build();
List<AttributeType> attrs = new ArrayList<>();
attrs.add(attributeType);
try {
String secretVal = calculateSecretHash(clientId, secretKey, userName);
SignUpRequest signUpRequest = SignUpRequest.builder()
.userAttributes(attrs)
.username(userName)
.clientId(clientId)
.password(password)
.secretHash(secretVal)
.build();
identityProviderClient.signUp(signUpRequest);
System.out.println("User has been signed up");
} catch(CognitoIdentityProviderException e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
public static String calculateSecretHash(String userPoolClientId, String userPoolClientSecret, String userName) throws NoSuchAlgorithmException, InvalidKeyException {
final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
SecretKeySpec signingKey = new SecretKeySpec(
userPoolClientSecret.getBytes(StandardCharsets.UTF_8),
HMAC_SHA256_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
mac.update(userName.getBytes(StandardCharsets.UTF_8));
byte[] rawHmac = mac.doFinal(userPoolClientId.getBytes(StandardCharsets.UTF_8));
return java.util.Base64.getEncoder().encodeToString(rawHmac);
}
//snippet-end:[cognito.java2.signup.main]
}
This code example assumes that the user pool requires a Client secret when adding a user. More info here:
Configuring a user pool app client
After you get the user details from the database, use this Cognito code to add the user to a user pool. Notice you need these input values:
clientId - The app client id value that you can obtain from the AWS Management Console.\n\n" +
secretkey - The app client secret value that you can obtain from the AWS Management Console.\n\n" +
userName - The user name of the user you wish to register.\n\n" +
password - The password for the user.\n\n" +
email - The email address for the user.\n\n";
This Java code can be wrapped in an AWS Lambda function that uses the Java Lambda runtime API.
Related
Amazon S3 files sharing
In my project there is a need for creating share link for external users without aws user from my researching found out a couple ways for doing so Bucket policy based on tag Lambda that creates sign url every time some user request the file The question is what is the best practice for doing so I need the download to be available until the user sharing the file stopes it Thank guys for any answers
Using the AWS SDK, you can use Amazon S3 Pre-sign functionality. You can perform this task in any of the supported programming languages (Java, JS, Python, etc). The following code shows how to sign an object via the Amazon S3 Java V2 API. import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.time.Duration; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.utils.IoUtils; // snippet-end:[presigned.java2.getobjectpresigned.import] /** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class GetObjectPresignedUrl { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " GetObjectPresignedUrl <bucketName> <keyName> \n\n" + "Where:\n" + " bucketName - the Amazon S3 bucket name. \n\n"+ " keyName - a key name that represents a text file. \n\n"; if (args.length != 2) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String keyName = args[1]; Region region = Region.US_WEST_2; S3Presigner presigner = S3Presigner.builder() .region(region) .build(); getPresignedUrl(presigner, bucketName, keyName); presigner.close(); } // snippet-start:[presigned.java2.getobjectpresigned.main] public static void getPresignedUrl(S3Presigner presigner, String bucketName, String keyName ) { try { GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) .getObjectRequest(getObjectRequest) .build(); // Generate the presigned request PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(getObjectPresignRequest); // Log the presigned URL System.out.println("Presigned URL: " + presignedGetObjectRequest.url()); HttpURLConnection connection = (HttpURLConnection) presignedGetObjectRequest.url().openConnection(); presignedGetObjectRequest.httpRequest().headers().forEach((header, values) -> { values.forEach(value -> { connection.addRequestProperty(header, value); }); }); // Send any request payload that the service needs (not needed when isBrowserExecutable is true) if (presignedGetObjectRequest.signedPayload().isPresent()) { connection.setDoOutput(true); try (InputStream signedPayload = presignedGetObjectRequest.signedPayload().get().asInputStream(); OutputStream httpOutputStream = connection.getOutputStream()) { IoUtils.copy(signedPayload, httpOutputStream); } } // Download the result of executing the request try (InputStream content = connection.getInputStream()) { System.out.println("Service returned response: "); IoUtils.copy(content, System.out); } } catch (S3Exception e) { e.getStackTrace(); } catch (IOException e) { e.getStackTrace(); } // snippet-end:[presigned.java2.getobjectpresigned.main] } }
how to start a AWS Personalize project in Java
Can someone help with getting starting using the AWS Java SDK for Personalize? I used to the console to build a Campaign. Now I want to query for recommendations using Java. Amazon has many examples in Python, but I need Java. Starting with the client builder is especially useful. Thanks.
To query for recommendations by using Java V2, you use the PersonalizeRuntimeClient object. Here is an example that uses Java V2. We will have the full examples posted in Java V2 Github very soon. ** package com.example.personalize; //snippet-start:[personalize.java2.get_recommendations.import] import software.amazon.awssdk.awscore.exception.AwsServiceException; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.personalizeruntime.PersonalizeRuntimeClient; import software.amazon.awssdk.services.personalizeruntime.model.GetRecommendationsRequest; import software.amazon.awssdk.services.personalizeruntime.model.GetRecommendationsResponse; import software.amazon.awssdk.services.personalizeruntime.model.PredictedItem; import java.util.List; //snippet-end:[personalize.java2.get_recommendations.import] public class GetRecommendations { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " GetRecommendations <campaignArn> <userId>\n\n" + "Where:\n" + " campaignArn - The ARN of the campaign.\n\n" + " userId - The user ID to provide recommendations for\n\n"; if (args.length < 2) { System.out.println(USAGE); System.exit(1); } /* Read the name from command args */ String campaignArn = args[0]; String userId = args[1]; Region region = Region.US_EAST_1; PersonalizeRuntimeClient personalizeRuntimeClient = PersonalizeRuntimeClient.builder() .region(region) .build(); getRecs(personalizeRuntimeClient, campaignArn, userId); } //snippet-start:[personalize.java2.get_recommendations.main] public static void getRecs(PersonalizeRuntimeClient personalizeRuntimeClient, String campaignArn, String userId){ try { GetRecommendationsRequest recommendationsRequest = GetRecommendationsRequest.builder() .campaignArn(campaignArn) .numResults(20) .userId(userId) .build(); GetRecommendationsResponse recommendationsResponse = personalizeRuntimeClient.getRecommendations(recommendationsRequest); List<PredictedItem> items = recommendationsResponse.itemList(); for (PredictedItem item: items) { System.out.println("Item Id is : "+item.itemId()); System.out.println("Item score is : "+item.score()); } } catch (AwsServiceException e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } //snippet-end:[personalize.java2.get_recommendations.main] } **
Unable to verify secret hash for client in Amazon Cognito Userpools
I am stuck at "Amazon Cognito Identity user pools" process. I tried all possible codes for authenticating user in cognito userpools. But I always get error saying "Error: Unable to verify secret hash for client 4b*******fd". Here is 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 : 'ronakpatel#gmail.com', 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); });
It seems that currently AWS Cognito doesn't handle client secret perfectly. It will work in the near future but as for now it is still a beta version. For me it is working fine for an app without a client secret but fails for an app with a client secret. So in your user pool try to create a new app without generating a client secret. Then use that app to signup a new user or to confirm registration.
According to the Docs: http://docs.aws.amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html The Javascript SDK doesn't support Apps with a Client Secret. The instructions now state that you need to uncheck the "Generate Client Secret" when creating the app for the User Pool.
This might be a fews years late but just uncheck the "Generate client secret" option" and it will work for your web clients.
Since everyone else has posted their language, here's node (and it works in the browser with browserify-crypto, automatically used if you use webpack or browserify): const crypto = require('crypto'); ... crypto.createHmac('SHA256', clientSecret) .update(username + clientId) .digest('base64')
I had the same problem in the .net SDK. Here's how I solved in, in case anyone else needs it: 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; } } } Signing up then looks like this: 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; } }
Amazon mention how Computing SecretHash Values for Amazon Cognito in their documentation with Java application code. Here this code works with boto 3 Python SDK. You can find your App clients in left side menu under General settings. Get those App client id and App client secret to create SECRET_HASH. For your better understand I commented out all the outputs of each and every line. 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 the boto 3 documentation, we can see lot of time ask about SECRET_HASH. So above code lines help you to create this SECRET_HASH. If you don't want to use SECRET_HASH just uncheck Generate client secret when creating an app.
For anybody interested in using AWS Lambda to sign up a user using the AWS JS SDK, these are the steps I did: Create another lambda function in python to generate the key: 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() Call the function through the nodeJS function in AWS. The signature acted as the secret hash for Cognito Note: The answer is based heavily off George Campbell's answer in the following link: Calculating a SHA hash with a string + secret key in python
Solution for golang. Seems like this should be added to the 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)) }
Solution for NodeJS with SecretHash It seems silly that AWS removed the secret key from the SDK as it will not be exposed in NodeJS. I got it working in NodeJS by intercepting fetch and adding in the hashed key using #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 and edited for NodeJS from 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, }
A quick fix for the above mentioned problem statement would be to delete the existing "App Client" and crate a new one with unchecked Generate client secret Note : Don't forget to change the app client string in the code.
In Java you could use this 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); }
this is a sample php code that I use to generate the secret hash <?php $userId = "aaa"; $clientId = "bbb"; $clientSecret = "ccc"; $s = hash_hmac('sha256', $userId.$clientId, $clientSecret, true); echo base64_encode($s); ?> in this case the result is: DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=
for JAVA and .NET you need to pass the secret has in the auth parameters with the name 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 }; And it should work.
The crypto package for javascript is deprecated so using crypto-js: import CryptoJS from 'crypto-js'; import Base64 from 'crypto-js/enc-base64'; const secretHash = Base64.stringify(CryptoJS.HmacSHA256(username + clientId, clientSecret)); Remeber to run npm install #types/crypto-js crypto-js before
C++ with the 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(); };
Here is my 1 command, and it works (Confirmed :)) EMAIL="EMAIL#HERE.com" \ 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}"
This solution works in March 2021: In case you're working with a client which has both "client_secret" and "client_id" generated, instead of calculating the SECRET_HASH and providing it to the function as specified in AWS docs, pass the "client_secret". Note: I was trying to generate new tokens from the refresh token. let result = await cognitoIdentityServiceProvidor .initiateAuth({ AuthFlow: "REFRESH_TOKEN", ClientId: clientId, AuthParameters: { REFRESH_TOKEN: refresh_token, SECRET_HASH: clientSecret, }, }) .promise(); It's absurd, but it works!
There might be a more compact version, but this works for Ruby, specifically in Ruby on Rails without having to require anything: 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))
NodeJS solution: Compute secret hash for authenticating action: import * as crypto from 'crypto'; const secretHash = crypto .createHmac('SHA256', clientSecret) .update(email + clientId) .digest('base64'); Compute secret hash for refresh token action: import * as crypto from 'crypto'; const secretHash = crypto .createHmac('SHA256', clientSecret) .update(sub + clientId) .digest('base64'); The parameter object looks like this: const authenticateParams = { ClientId: clientId, UserPoolId: poolId, AuthFlow: CognitoAuthFlow.ADMIN_NO_SRP_AUTH, AuthParameters: { PASSWORD: password, USERNAME: email, SECRET_HASH: secretHash, }, }; const refreshTokenParams = { ClientId: clientId, UserPoolId: poolId, AuthFlow: CognitoAuthFlow.REFRESH_TOKEN_AUTH, AuthParameters: { REFRESH_TOKEN: refreshToken, SECRET_HASH: secretHash, }, }; Usage: import * as CognitoIdentityProvider from 'aws-sdk/clients/cognitoidentityserviceprovider'; const provider = new CognitoIdentityProvider({ region }); provider.adminInitiateAuth(params).promise(); // authenticateParams or refreshTokenParams, return a promise object.
Cognito Authentication Error: App client is not configured for secret but secret hash was received Providing secretKey as nil worked for me. Credentials provided include :- CognitoIdentityUserPoolRegion (region) 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) All above things work with below linked code sample. AWS Sample code : https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Swift Let me know if that doesn't work for you.
The below seems to work with .NET now, for asp.net pages using the Alexa Skills SDK for .NET by Time Heur Inject dependency private readonly CognitoUserManager<CognitoUser> _userManager; public RegisterModel( UserManager<CognitoUser> userManager, ) _userManager = userManager as CognitoUserManager<CognitoUser> as CognitoUserManager<CognitoUser>; Then assign a hash var user = _pool.GetUser(Input.UserName); _userManager.PasswordHasher.HashPassword(user,Input.Password); var result = await _userManager.CreateAsync(user, Input.Password);
I saw a .NET one suggested here, but here is the variation that worked for me since I couldn't find access to "EncryptionHelper.GetSecretHash": private string GetHMAC(string text, string key) { // TODO: null checks or whatever you want on your inputs... using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key))) { var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(text)); return Convert.ToBase64String(hash); } } And you call this for something like a sign up request as follows: SignUpRequest signUpRequest = new SignUpRequest { ClientId = "<your_client_app_id>", Password = "<the-password-your-user-wanted>", Username = "<the-username-your-user-wanted", }; // TODO: add whatever else you need to on your sign up request (like email, phone number etc...) // and the magic line right here: signUpRequest.SecretHash = GetHMAC( signUpRequest.Username + "<your_client_app_id>", "<your_client_app_secret>"); SignUpResponse response = await _provider.SignUpAsync(signUpRequest); For me this worked like a charm. I originally was putting the client app secret directly assigned to this "SecretHash" property, but from scanning the rest of the answers here, I realized I truly needed to hash some data using that key as an input to the hash.
WSO2 Identity Server programmatically creating an application throwing 'Illegal Access Attempt' warning
I am developing a Java client which will create an application in WSO2 Identity Server through calling the OAuthAdminService. After some digging I found that registerOAuthApplicationData() method is the one used for creating an application in IS. Before calling the method, I have authenticated the admin user via login() method of AuthenticationAdminStub type. Even after such authentication the registerOAuthApplicationData() method make the IS console to print [2016-04-26 13:08:52,577] WARN {org.wso2.carbon.server.admin.module.handler.AuthenticationHandler} - Illegal access attempt at [2016-04-26 13:08:52,0577] from IP address 127.0.0.1 while trying to authenticate access to service OAuthAdminService and the application is not getting created in the IS database. The code which I have tried goes as follows import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.axis2.transport.http.HTTPConstants; import org.wso2.carbon.authenticator.proxy.AuthenticationAdminStub; import org.wso2.carbon.identity.oauth.OAuthAdminServicePortTypeProxy; import org.wso2.carbon.identity.oauth.dto.xsd.OAuthConsumerAppDTO; public class IdentityClientOne { private final static String SERVER_URL = "https://localhost:9443/services/"; private final static String APP_ID = "myapp"; /** * #param args */ public static void main(String[] args) { AuthenticationAdminStub authstub = null; ConfigurationContext configContext = null; System.setProperty("javax.net.ssl.trustStore", "wso2carbon.jks"); System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon"); try { configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem( "repo", "repo/conf/client.axis2.xml"); authstub = new AuthenticationAdminStub(configContext, SERVER_URL + "AuthenticationAdmin"); // Authenticates as a user having rights to add users. if (authstub.login("admin", "admin", APP_ID)) { System.out.println("admin authenticated"); OAuthConsumerAppDTO consumerApp = new OAuthConsumerAppDTO("Oauth-2.0", "sample_app", "", "authorization_code implicit password client_credentials refresh_token urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm","","",""); OAuthAdminServicePortTypeProxy OAuthAdminProxy = new OAuthAdminServicePortTypeProxy(); OAuthAdminProxy.registerOAuthApplicationData(consumerApp); } } catch (Exception e) { e.printStackTrace(); } } } Please help what should be done right ?
You have to access the stub via the authenticated session. Could you try below. public class Test { private final static String SERVER_URL = "https://localhost:9443/services/"; public static void main(String[] args) throws RemoteException, OAuthAdminServiceException { OAuthAdminServiceStub stub = new OAuthAdminServiceStub(null, SERVER_URL + "OAuthAdminService"); ServiceClient client = stub._getServiceClient(); authenticate(client); OAuthConsumerAppDTO consumerAppDTO = new OAuthConsumerAppDTO(); consumerAppDTO.setApplicationName("sample-app"); consumerAppDTO.setCallbackUrl("http://localhost:8080/playground2/oauth2client"); consumerAppDTO.setOAuthVersion("OAuth-2.0"); consumerAppDTO.setGrantTypes("authorization_code implicit password client_credentials refresh_token " + "urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm"); stub.registerOAuthApplicationData(consumerAppDTO); } public static void authenticate(ServiceClient client) { Options option = client.getOptions(); HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator(); auth.setUsername("admin"); auth.setPassword("admin"); auth.setPreemptiveAuthentication(true); option.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth); option.setManageSession(true); } }
sending request to wso2 identity server
am trying to send a request to the identity server but don't know how to do it. I know that identity server can help you test your policy by generating a request for you within the identity server but I don't know how to do this outside the identity server. So my question is how do I sent requests to identity server in order to have it check the request against the policy and return to me a result. I have tried the blog at http://hasini-gunasinghe.blogspot.com/2011/12/entitlement-service-xacml-pdp-as-web.html and it is not working. thank you
I tried the code in the blogpost and could get it worked with the following settings with WSO2 Identity Server 4.1.0 in localhost. Don't forget to give correct path to the wso2carbon.jks. import org.apache.axis2.AxisFault; import org.apache.axis2.client.Options; import org.apache.axis2.client.ServiceClient; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.axis2.transport.http.HTTPConstants; import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub; import org.wso2.carbon.identity.entitlement.stub.EntitlementServiceStub; import org.wso2.carbon.identity.entitlement.ui.client.EntitlementServiceClient; public class EntitlementClient { private static String serverUrl = "https://localhost:9443/services/"; private AuthenticationAdminStub authstub = null; private static ConfigurationContext ctx; private static String authCookie = null; private static EntitlementServiceClient entitlementServiceClient; private static EntitlementServiceStub stub; //sample XACML request captured from TryIt tool of IdentityServer. private static String sampleRequest = "<Request xmlns=\"urn:oasis:names:tc:xacml:2.0:context:schema:os\"\n" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + " <Resource>\n" + " <Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:resource:resource-id\"\n" + " DataType=\"http://www.w3.org/2001/XMLSchema#string\">\n" + " <AttributeValue>ABCResource</AttributeValue>\n" + " </Attribute>\n" + " </Resource>\n" + " <Subject>\n" + " <Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject:subject-id\"\n" + " DataType=\"http://www.w3.org/2001/XMLSchema#string\">\n" + " <AttributeValue>admin</AttributeValue>\n" + " </Attribute>\n" + " <Attribute AttributeId=\"http://wso2.org/claims/role\"\n" + " DataType=\"http://www.w3.org/2001/XMLSchema#string\">\n" + " <AttributeValue>admin</AttributeValue>\n" + " </Attribute>\n" + " </Subject>\n" + " <Action>\n" + " <Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:action:action-id\"\n" + " DataType=\"http://www.w3.org/2001/XMLSchema#string\">\n" + " <AttributeValue>read</AttributeValue>\n" + " </Attribute>\n" + " </Action>\n" + " <Environment/>\n" + "</Request>"; public static void main(String[] args) { try { //set trust store properties required in SSL communication. System.setProperty("javax.net.ssl.trustStore", "/home/pushpalanka/Servers/wso2is-4.1.1/repository/resources/security/wso2carbon.jks"); System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon"); //initialize authentication admin stub EntitlementClient remoteEntitlementClient = new EntitlementClient(); //login using authentication admin stub providing valid credentials remoteEntitlementClient.login("admin", "admin"); //initialize entitlement service stub with obtained authentication cookie remoteEntitlementClient.initEntitlementClient(); //invoke EntitlementService by passing the XACML request and obtain the authorization decision String decision = entitlementServiceClient.getDecision(sampleRequest); //print the authorization decision System.out.println(decision); } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } public EntitlementClient() { try { ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null); String authEPR = serverUrl + "AuthenticationAdmin"; authstub = new AuthenticationAdminStub(ctx, authEPR); ServiceClient client = authstub._getServiceClient(); Options options = client.getOptions(); options.setManageSession(true); options.setProperty(org.apache.axis2.transport.http.HTTPConstants.COOKIE_STRING, authCookie); } catch (AxisFault axisFault) { axisFault.printStackTrace(); } } public String login(String username, String password) throws Exception { //String cookie = null; boolean loggedIn = authstub.login(username, password, "127.0.0.1"); if (loggedIn) { System.out.println("The user " + username + " logged in successfully."); authCookie = (String) authstub._getServiceClient().getServiceContext().getProperty( HTTPConstants.COOKIE_STRING); } else { System.out.println("Error logging in " + username); } return authCookie; } public void initEntitlementClient() throws AxisFault { entitlementServiceClient = new EntitlementServiceClient(authCookie, serverUrl, ctx); } } Reference - http://hasini-gunasinghe.blogspot.com/2011/12/entitlement-service-xacml-pdp-as-web.html