AWS: How to check that credentials are correct? - amazon-web-services

The following function (in Javascript) is supposed to accept accessKey and secretKey and check whether they are correct:
function checkKeys(accessKey, secretKey) {
var cred = new AWS.Credentials(accessKey, secretKey, null);
cred.get(function(err) {
if (err) {
console.log("ERROR!")
} else {
console.log("Keys are OK")
}
})
}
I'd expect that get() method returns an error in case of incorrect credentials. I don't know why, but it doesn't matter what credentials I give, I never get an error, and console always prints "Keys are OK".

You cannot really check that credentials are "correct". Think about user roles. User may be authorized to make one API call, but not another. The only generic thing you can do is make sure that ID+key pair you have are valid AWS credentials with STS.getCallerIdentity() (see SDK docs for details). Note that it will return caller details even if this caller has no access to any of the services, so take the results with a grain of salt.

You're just storing credentials in a local object, and then retrieving them. You need to trigger an actual AWS API call in order to verify if the credentials are valid.

Related

Getting - UserNotFoundException - while calling adminCreateUser - AWS Cognito

I am having a very peculiar issue regarding User creation in AWS Cognito.
When I am in the same region (e.g US-East-AWS and Creating User from NA) then it is working like a charm. But when someone is in other region (e.g US-EAST-AWS and creating user from EU with a slow internet connection) then I am getting UserNotFoundException.
Below is the how I am handling User creation in my Lambda function (JS)
await cognitoidentityserviceprovider.adminCreateUser(params).promise()
if (customer.MFA === true) {
await toggleCognitoUsersMFA(jsonBody.email, true)
}
Check your MessageAction value in your params.
If the value is set to RESEND, and you're creating a new user, you'll get this User Not Found message.
The current AWS docs indicate that either a RESEND or SUPPRESS value is required, this is not true, you can actually omit the value.

Cognito Refresh Token Expires prematurely

We have an app that uses AWS Cognito for authentication. The backend code (using AWS SDK for C# works fine mostly)
After the initial login, we obtain, ID, Access and Refresh TOKEN. Then every hour we try getting a new ID and ACCESS token by calling
public bool ExtendTokens(string userRefreshToken, out AdminInitiateAuthResponse output)
{
output = null;
AdminInitiateAuthRequest request = new AdminInitiateAuthRequest();
AdminInitiateAuthResponse response = new AdminInitiateAuthResponse();
try
{
request.UserPoolId = XXXXXXXXXXX;
request.ClientId = YYYYYYYYYY;
request.AuthFlow = AuthFlowType.REFRESH_TOKEN_AUTH;
request.AuthParameters.Add("REFRESH_TOKEN", userRefreshToken);
response = awsCognito_client.AdminInitiateAuth(request);
if (response != null)
{
output = response;
return true;
}
}
catch (Exception ex)
{
//log the exception and the inner exception!
}
return false;
}
on the backend side and passing them to the client. (The way this app works is that the client makes few calls every 3min to the server, and then server calls Cognito for authentication) then after 60min, renewing tokens the first time (60min after initial login) works fine! However, (after precisely 2hrs) the second time I get this error:
The remote server returned an error: (400) Bad Request.
Refresh Token has been revoked
For several internal/external users this happens right on the dot! 120min after they login using Username/Password. So it cannot be where a user signs out or we call GlobalSignOut accidentally. I have checked my code several places, I don't see where I might have goofed! I even use the same code module in another product and that one does not get kicked out at all! (That one does not make calls every now and then!)
Also, Tracking user devices is OFF. So it cannot be this answer.
Moreover, the Cognito Limitation document does not say anything about the total number of calls per account!
Other useful details: the default expiry of our refresh token is 15days. That's why I call this two hours expiry prematurely!
I am not able to reproduce this on my localhost, but it happens after deploying to IIS. I have checked the settings and the web.configs and I could not find any meaningful difference between the two that would invalidate my refresh tokens!
So, I was able to get around this (I still don't know the root cause) but the way to avoid this is to call the renew function every 45~50 minutes instead of waiting for that 1hr to pass! Doesn't make any sense but Its been 48hrs that my session is active and tokens are being renewed.

AWS API Gateway with custom authorizer returns AuthorizerConfigurationException

I have an AWS API Gateway that uses a custom authorizer, and if the request is authorized, it triggers another lambda function. Since yesterday, whenever I call the API, I get an error saying { "message": null } and a 500 Internal Server Error. In the response headers it says x-amzn-ErrorType →AuthorizerConfigurationException. I can see in the logs that the authorizer is called and returns a valid policy, and that the other lambda function is not triggered. I have not (knowingly) changed the authorizer. Can anyone give me a hint what might be wrong here? I have read this question but there the mistake was that the returned policy was wrongly formatted, while I didn't change my authorizer and it worked before.
The context portion of your policy document can contain only String, Boolean or Numeric values. Arrays and Objects are illegal.
The documentation states:
The returned values are all stringified. Notice that you cannot set a JSON object or array as a valid value of any key in the context map.
Source:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html

send email when user registers - AWS Cognito federated Identities

How can i send an email/trigger a lambda function when a new user registers?
Under "edit identity pool" i only found a sync trigger.
If i understand correctly: This one is triggered every time a user syncs his data...
Is there any way to trigger a lambda function only for the "initial" sync or when a certain dataset is created for the user?
Edit:
To be more specific: I do create the user via lambdas using the JS SDK. I use developer authentication with my own oauth2 flow. I don't know how to distinguish between a user granting access e.g. via Google the first time from someone doing this the second time. The json with the access code seams the same to me... Maybe I am mistaken.
Also using the getOpenIdTokenForDeveloperIdentity call I don't know how to distinguish between an ID that is new to cognito from one cognito already knows.
Edit 2:
To be even more precise:
I am building on this project: https://github.com/laardee/serverless-authentication-boilerplate/blob/master/authentication/lib/storage/usersStorage.js
here is how i do save the User to cognito at the moment.
I do run this code for first time users as well as nth time users. My problem is that i dont know how to distinguish...
const saveCognito = (profile) => new Promise((resolve, reject) => {
if (profile) {
cognitoidentity.getOpenIdTokenForDeveloperIdentity({
IdentityPoolId: process.env.COGNITO_IDENTITY_POOL_ID,
Logins: {
// profile.userId = encrypted id of the e.g. google oauth2 id
[process.env.COGNITO_PROVIDER_NAME]: profile.userId
}
}, (err, dat) => {
if (err) {
reject(err);
} else {
var list_params = {
DatasetName: 'user-data', /* dataset name */
IdentityId: dat.IdentityId, /* cognito id */
IdentityPoolId: process.env.COGNITO_IDENTITY_POOL_ID
};
cognitosync.listRecords(list_params, function(err, data) {
if (err) {
reject(err); // an error occurred
} else {
var RecordPatches = //[Parts of the i want to write to the user]
// SyncSessionToken is returned by the cognitosync.listRecords call
list_params["SyncSessionToken"] = data.SyncSessionToken;
list_params["RecordPatches"] = RecordPatches;
cognitosync.updateRecords(list_params, function(err, update_data) {
if (err){
reject(err);
} else {
resolve();
}
});
}
});
}
});
} else {
reject('Invalid profile');
}
});
So this is something which is not currently supported in Cognito out of the box. You are correct in saying that the only built in Cognito Event that will trigger a Lambda Function is the "Sync Trigger" Event. This Sync event is fired every time that a Cognito IdentityId Synchronizes some of their data to the Cognito Sync cloud data store.
This event is unrelated to the creation of a new IdentityId by Cognito Federated Identity.
You could in theory:
Run a list-identities call on the IdentityPool, before the user logs
in.
Login the user. Check whether the IdentityId which has been given to the user is present in the list you retrieved before they logged
in. This would tell you whether or not the identity that they were
given existed before this login.
Based on this information you could
make a decision whether or not to programatically call the Lambda
Function from your application.
The setup of the above would be complex, as for security reasons you would need to maintain this service, server-side. The list-identities call requires AWS credentials to call. And I doubt you'd want to include permissions for that call in your IAM policy for unauthenticated users.
Aside from the above there is not much you can do at the moment.
In order to do this, you would need to setup a DynamoDB table (or some similar low latency datastore) where you could maintain the state of the IdentityId list, and then query this service/store whenever you login a user to compare new logins to the pre-existing list.
If this is critical to your use case I would suggest heading over to AWS Support, and create a case where you can log this as a feature request.
https://aws.amazon.com/premiumsupport/

How to check if email is valid before send through Amazon SES

I am fresh in implementing Amazon Web services. I am working on implementing an application for sending bulk emails from a queue. I have to check emails and remove non-verified emails from the queue before sending.
My question is: Is there any method available in Amazon to check whether emails are valid or not?
From your question, it is not clear whether you want to:
1-avoid sending messages to malformed email addresses; or
2-avoid sending messages to email addresses which are not verified under your AWS account.
The answer for 1 is spread in different forms accross forums, SO, etc. You either do it simple, i.e., craft a short and clear regular expression which validates roughly 80% of the cases, or you use a very complex regular expression (in order to validate against the full compliance -- good luck, check this example), check whether the domain is not only valid but also up and running, and, last but not least, check if the account is valid under that domain. Up to you. I'd go with a simple regex.
The answer for 2 is available at Verifying Email Addresses in Amazon SES -- the Amazon SES API and SDKs support the operations below, so you should be covered in any case:
Using the Amazon SES API
You can also manage verified email addresses with the Amazon SES API. The following actions are available:
VerifyEmailIdentity
ListIdentities
DeleteIdentity
GetIdentityVerificationAttributes
Note
The API actions above are preferable to the following older API actions, which are deprecated as of the May 15, 2012 release of Domain Verification.
VerifyEmailAddress
ListVerifiedEmailAddresses
DeleteVerifiedEmailAddress
You can use these API actions to write a customized front-end application for email address verification. For a complete description of the API actions related to email verification, go to the Amazon Simple Email Service API Reference.
You can use the "getIdentityVerificationAttributes" operation to check whether emails are valid or not. You can use this as shown below:
var params = {
Identities: arr // It is a required field (array of strings).
};
ses.getIdentityVerificationAttributes(params, function(err, data) {
if(err)
console.log(err, err.stack); // an error occurred
else
console.log(data); // successful response
});
And the Response will be:
{ ResponseMetadata: { RequestId: '7debf2356-ddf94-1dsfe5-bdfeb-efsdfb5b653' },
VerificationAttributes:
{ 'abc#gmail.com': { VerificationStatus: 'Pending' },
'xyz#gmail.com': { VerificationStatus: 'Success' } } }
If there is an email-id which is not sent previously for email verification request, then there is no key present in 'VerificationAttributes' object.
AmazonSimpleEmailServiceClient ses= new AmazonSimpleEmailServiceClient(credentials);
List lids = ses.listIdentities().getIdentities();
if (lids.contains(address)) {
//the address is verified so
return true;
}