SecretHash does not match for the client - amazon-web-services

I am trying to access AWS S3 files using Identity pool of Cognito. I am able to do all functionalities of Congito user pool and faced no issue in secret hash. I use same way here but now having the issue in this process.
I am providing my code below for more understanding. I am getting error at line AuthFlowResponse context = await user.StartWithSrpAuthAsync below.
secretHash = crypto.GetMACHash(username + "<ClientID>");
AmazonCognitoIdentityProviderConfig config = new AmazonCognitoIdentityProviderConfig();
var provider = new AmazonCognitoIdentityProviderClient("<accessKey>", "<SecretKey>",RegionEndpoint.USEast1);
CognitoUserPool userPool = new CognitoUserPool("<userpool>", "<clientId>", provider, "<clientSecret>");
CognitoUser user = new CognitoUser(username, "<clientId>", userPool, provider, secretHash);
string userpassword = "Testtest#1";
AuthFlowResponse context = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
Password = userpassword
}).ConfigureAwait(false);
CognitoAWSCredentials s3Credentials =
user.GetCognitoAWSCredentials("<IdentityPoolID>", RegionEndpoint.USEast1);

Related

Authenticating with AWS .NET SDK for Amazon Chime

I'm trying to create meeting using Chime SDK and I'm passing accessKey and accessKeyId to authenticate. However, the request fails with error, 'Invalid session token'. When I pass session token generated using AWS CLI it works fine. I want to generate the session token programmatically from within .net. How to achieve this.
AWSCredentials credentials = new Chime.Credentials(awsAccessKeyId, awsSecretAccessKey, token);
RegionEndpoint region = RegionEndpoint.USEast1;
client = new AmazonChimeClient(credentials, RegionEndpoint.USEast1);
CreateMeetingRequest request = new CreateMeetingRequest();
request.MeetingHostId = meetingHostId;
request.ExternalMeetingId = externalMeetingId;
return await client.CreateMeetingAsync(request);
You are not setting the ClientRequestToken
CreateMeetingRequest request = new CreateMeetingRequest();
request.MeetingHostId = meetingHostId;
request.ExternalMeetingId = externalMeetingId;
//needs request.ClientRequestToken = ????
Tim

Amazon Cognito Identity with API Gateway

I'm develop app IOS and Android with Xamarin cross-platform.
I'm trying hard to use credentials receiving from Cognito Identity to authorize app invoking API Gateway.
My user flow is:
Authenticate on Cognito User Pool and get tokens
Exchange tokens for credentials on Cognito Identity Pools
Access API Gateway using credentials retrieved in the previous step.
Step 1 and 2 seems to works fine. But when app try to connect to api gateway it's getting error 403 (Forbidden).
My code:
Authenticate on Cognito User Pool and get tokens
**
public async Task<AppUser> Login(string username, string password)
{
CognitoUser cognitoUser = new CognitoUser(username, Aws.COGNITO_CLIENT_ID, CognitoUserPool, CognitoIdentityProviderClient);
AppUser appUser = new AppUser() { Email = username };
// Send a login request and wait for the response from Amazon
try
{
AuthFlowResponse response = await cognitoUser.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
Password = password
});
;
appUser.IsAuthenticated = true;
}
catch (NotAuthorizedException e)
{
appUser.IsAuthenticated = false;
appUser.ErrorMessage = e.Message;
}
await _tokenManagement.SaveTokens(cognitoUser.SessionTokens) ;
return appUser;
}
Exchange tokens for credentials on Cognito Identity Pools
**
public async Task<ImmutableCredentials> GetAppCredentialsAsync()
{
CognitoAWSCredentials cac;
if (_tokenManagement.CheckIsAnonymous())
{
//Anonymous credentials
cac = new CognitoAWSCredentials(Aws.COGINITO_IDENTITY_POLL_ID, RegionEndpoint.USEast1);
}
else
{
//Retrieve saved tokens from previous authentication
var tm = await _tokenManagement.RetrieveTokens();
CognitoUser user = new CognitoUser(null, Aws.COGNITO_CLIENT_ID, CognitoUserPool, CognitoIdentityProviderClient)
{
SessionTokens = new CognitoUserSession(tm.IdToken, tm.AccessToken, tm.RefreshToken, tm.IssuedTime, tm.ExpirationTime)
};
//Retrieve authenticated credentials
cac = user.GetCognitoAWSCredentials(Aws.COGINITO_IDENTITY_POLL_ID, RegionEndpoint.USEast1);
}
}
return await cac.GetCredentialsAsync();
}
Access API Gateway using credentials retrieved in the previous step:
**
public async Task<IList<MediaImage>> GetCoversAWSAsync()
{
// Getting credentials and sign request
var request = await BuildRequestAsync("/listMedia");
var client = new HttpClient();
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
IList<MediaImage> covers = JsonConvert.DeserializeObject<IList<MediaImage>>(await response.Content.ReadAsStringAsync());
return covers;
}
private async Task<HttpRequestMessage> BuildRequestAsync(string service)
{
var request = new HttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(baseURL + service)
};
ImmutableCredentials awsCredential = await _loginService.GetAppCredentialsAsync( );
var signer = new AWS4RequestSigner(awsCredential.AccessKey, awsCredential.SecretKey);
request = await signer.Sign(request, "execute-api", awsRegion);
return request;
}
This code works fine when I hard code credentials from one IAM user. But credentials retrieved from Cognito Identities its getting Forbidden error.
I did a test using SDK for S3 and I was able to successfully list the buckets with the same credentials received from Cognito Identities, but it is not possible to make requests on the API Gateway.
Can you help me? Where did I get lost?
I figure out what was going on.
After ensuring that the permissions settings were correct on AWS.
I found in the documentation that it is necessary to include in the HTTP header the token returned by the cognito (header name x-amz-security-token). So I changed the code to the following:
private async Task<HttpRequestMessage> BuildRequestAsync(string service)
{
var request = new HttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(baseURL + service)
};
ImmutableCredentials awsCredential = await _loginService.GetAppCredentialsAsync( );
//This where I add header to the HTTP request
request.Headers.Add("x-amz-security-token", awsCredential.Token);
var signer = new AWS4RequestSigner(awsCredential.AccessKey, awsCredential.SecretKey);
request = await signer.Sign(request, "execute-api", awsRegion);
return request;
}

WebJobs storage with Managed Identity

By default WebJobs requires to specify Azure Storage account using AzureWebJobsStorage connection string.
But I already have access to my storage with Managed Identity:
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://storage.azure.com/");
StorageCredentials storageCredentials = new StorageCredentials(new TokenCredential(accessToken));
CloudStorageAccount cloudStorageAccount = new CloudStorageAccount(storageCredentials, "mystorageaccount", "core.windows.net", true);
Can I configure WebJobs to use this cloudStorageAccount instead of AzureWebJobsStorage connection string?
Can I configure WebJobs to use this cloudStorageAccount instead of AzureWebJobsStorage connection string?
Yes, you could use cloudStorageAccount to get blob account and do some operation on blobs. However, you still need to provide AzureWebJobsDashboard and AzureWebJobsStorage when you use Webjob. Because they are not only connectionstring, they are also the log path.
In my test, I set AzureWebJobsStorage value with storage1 connection and in code I get storage2 account and it works.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://storage.azure.com/").Result;
StorageCredentials storageCredentials = new StorageCredentials(new TokenCredential(accessToken));
CloudStorageAccount cloudStorageAccount = new CloudStorageAccount(storageCredentials, "storage2", "core.windows.net", true);
CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("mycontainer");
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference("hello.txt");
cloudBlockBlob.UploadTextAsync("aaaaaaaa").Wait();
For more details about assign role and get access token you could refer to this article.

Send Message to Amazon SQS using credentials in code

Trying to post a message to an AWS SQS Queue that already exists using .Net Core.
Due to some deployment issues, I don't want to create a separate credentials file, I just want to manually add the credentials and add them to my client or request. I can't see how to do this using the documentation.
I've got a simple console app version of what I am trying to do below... I have created the Credentials, I just can't see how to inject them into the client or request so that it authenticates with my IAM user.
Currently the code just hangs creating the client.
var awsCreds = new BasicAWSCredentials("MYKEYGOESHERE", "MYSECRETGOESHERE");
var amazonSQSConfig = new AmazonSQSConfig();
amazonSQSConfig.ServiceURL = "https://sqs.eu-west-1.amazonaws.com";
var amazonSQSClient = new AmazonSQSClient(amazonSQSConfig);
var sendRequest = new SendMessageRequest();
sendRequest.QueueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]";
sendRequest.MessageBody = "{ 'message' : 'hello world' }";
var sendMessageResponse = amazonSQSClient.SendMessageAsync(sendRequest);
You have to pass the credentials to the AmazonSQSClient like so:
var amazonSQSClient = new AmazonSQSClient(awsCreds, amazonSQSConfig);
Five years later, here is what is working for me:
AmazonSQSClient sqsClient = new AmazonSQSClient("MYKEYGOESHERE", "MYSECRETGOESHERE", RegionEndpoint.USWest2);
No use of BasicAWSCredentials or AmazonSQSConfig.

Aws Cognito: Secret hash with Java SDK (not Android) and ADMIN_NO_SRP_AUTH flow

i try to register a user in my amazon cognito user pool with username and password from my java backend but i always get the error:
Unable to verify secret hash for client
in the documentation i don't found any information how to pass the clientSecret in the register request and i don't like to create an (backend) app without a clientSecret.
My code looks like this
identityProvider = AWSCognitoIdentityProviderClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(awsCreds)).withRegion(Regions.EU_CENTRAL_1).build();
Map<String, String> authParameters = new HashMap<>();
authParameters.put("USERNAME", "username");
authParameters.put("PASSWORD", "password");
authParameters.put("SECRET_HASH", "secret copy and paste from the aws console"); // i read in a forum post, that this should work
AdminInitiateAuthRequest authRequest = new AdminInitiateAuthRequest();
authRequest.withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH);
authRequest.setAuthParameters(authParameters);
authRequest.setClientId("clientId");
authRequest.setUserPoolId("userPoolId");
AdminInitiateAuthResult authResponse = identityProvider.adminInitiateAuth(authRequest);
Thanks
Marcel
To register users you should use the SignUp API. The secret hash can be calculated as follows in Java:
public String calculateSecretHash(String userPoolclientId, String userPoolclientSecret, String userName) {
if (userPoolclientSecret == null) {
return null;
}
SecretKeySpec signingKey = new SecretKeySpec(
userPoolclientSecret.getBytes(StandardCharsets.UTF_8),
HMAC_SHA256_ALGORITHM);
try {
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 Encoding.encodeBase64(rawHmac);
} catch (Exception e) {
throw new RuntimeException("Error while calculating ");
}
}
Can you please elaborate your use case of creating users from your backend instead of directly calling Amazon Cognito from your clients?
Edit: We have updated our documentation to include a section about how to compute the secret hash.
The following code works perfectly:
AdminInitiateAuthRequest adminInitiateAuthRequest = new AdminInitiateAuthRequest().withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH).withClientId("<ID of your client application>").withUserPoolId("<your user pool ID>")
.addAuthParametersEntry("USERNAME", "<your user>").addAuthParametersEntry("PASSWORD", "<your password for the user>");
AdminInitiateAuthResult adminInitiateAuth = identityProvider.adminInitiateAuth(adminInitiateAuthRequest);
System.out.println(adminInitiateAuth.getAuthenticationResult().getIdToken());