I have a simple application consisting of two modules - OAuth2 client (Spring Cloud Gateway) and OAuth2 resource. I use AWS Cognito as an identity provider. Some users with specific roles should be able to create/update/delete other Cognito users.
I'm going to use aws-java-sdk-cognitoidp library for integration with AWS Cognito API, but I need to make this calls as a current logged-in user, to be able to check user's groups and IAM roles. Because users from different groups should have different privileges.
I found AWSSessionCredentialsProvider that seems suitable for this task, but there is no implementation.
I implemented this provider to get access token from the SecurityContext. When I call the API I get an error:
The security token included in the request is invalid
Is it possible to use user's access token as a credentials for AWSCognitoIdentityProvider?
I used to have app to login with given user with his credentials -
AWSCognitoIdentityProvider cognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(getSDKCredentials()))
.withRegion(Regions.fromName(getAwsRegion()))
.build();
Map<String,String> params =new HashMap<>();
params.put("USERNAME", userName);
params.put("PASSWORD", passCode);
AdminInitiateAuthRequest initialRequest=new AdminInitiateAuthRequest()
.withAuthFlow(AuthFlowType.ADMIN_NO_SRP_AUTH)
.withAuthParameters(params)
.withClientId(getClientId())
.withUserPoolId(getUserPoolId());
AdminInitiateAuthResult response = cognitoIdentityProvider.adminInitiateAuth(initialRequest);
this will return your response where you have session. check if it helps-
Related
In my js file, I am accessing my AWS sns, but the main issue is that currently, I am hard coding my IAM access and security keys... Is there a way to avoid doing this by using a temporary key or hiding my keys? I have posted a snippet on how I am updating the config below.
var AWS = require('aws-sdk');
AWS.config.update({
region: < 'My Hard coded region' >,
credentials: {
accessKeyId: < 'My Hard coded Access Key' >,
secretAccessKey: <'My Hard Coded Security Key'>
}
});
...
PLEASE HELP.
It's very hard to comment without knowing more about your code.
The react native is a mobile app. You will need a service to authenticate your mobile app users against the service. One such service is amazon Cognito.
Userpool
Amazon Cognito has a concept called user pool. The user pool is where the users are stored.
When you authenticate a user against a user pool, you will get a authorised token in return. Your app can store this token and send it to your backend services. The backend services can validate the token to confirm the identity of the user.
Identity pool
The identity pool is a concept where temporary AWS credentials are issued in exchange for an authorised token. This is the temporary AWS credentials, using which you can call aws services directly from the mobile app.
Hope this helps.
here is an article for you to read - https://pusher.com/tutorials/serverless-react-native-aws-amplify
Yes there are much more secure ways to handle credentials. Hard coding them is the least secure.
While it is possible to do so, we do not recommend hard-coding your AWS credentials in your application. Hard-coding credentials poses a risk of exposing your access key ID and secret access key
See https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html
Also see From Best Practices for Managing AWS Access Keys:
Don't embed access keys directly into code. The AWS SDKs and the AWS Command Line Tools allow you to put access keys in known locations so that you do not have to keep them in code.
See https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html
The most secure method is to load the credentials from AWS Identity and Access Management (IAM) roles for Amazon EC2.
Each SDK has a way to do this. Check your SDK documentation for loading credentials from IAM.
Here is a good overview for credentials best practices, with examples in Java: https://aws.amazon.com/blogs/developer/credentials-best-practices/
I came across this stackoverflow while googling how to solve this problem. Here's the approach I ended up using to solve this problem in case this helps anyone else. It will expand on the identity pool answer provided earlier.
My setup was this:
Static website hosted on s3, so no way to make AJAX calls back to the server itself to bypass hardcoding credentials.
The solution I ended up using was Cognito identity pools as mentioned. The setup involved creating an identity provider in IAM. We were using an company internal OpenID identity provider. Then the next step was to create an identity pool in cognito that pointed to that identity provider. Next was to provision an IAM role for signed in users of that identity pool to give them access to whatever resources you are trying to secure.
On the s3 website, we had already integrated with the internal OpenID identity provider, so it was just a matter of extracting the token and passing it to Cognito.
The program flow is as follows:
User logs in to open ID internal system.
This system returns a token
Code extracts token and then creates a Cognito Identity Credentials
https://docs.aws.amazon.com/cognito/latest/developerguide/getting-credentials.html
The below is a code snippet copy pasted from the docs linked above. Note that the Logins object is where we will pass the token. The key will be the "provider" field value configured in IAM.
AWS.config.region = 'us-east-1';
// Configure the credentials provider to use your identity pool
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'IDENTITY_POOL_ID',
Logins: { // optional tokens, used for authenticated login
'graph.facebook.com': 'FBTOKEN',
'www.amazon.com': 'AMAZONTOKEN',
'accounts.google.com': 'GOOGLETOKEN',
'appleid.apple.com': 'APPLETOKEN'
}
});
// Make the call to obtain credentials
AWS.config.credentials.get(function(){
// Credentials will be available when this function is called.
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
});
The call to cognito will return temporary credentials including a session token, which you can now pass to your other aws clients.
I have a Java backend service and i want to use AWS Cognito to provide authentication and access to AWS services. This service do not have any information about the AWS account. I see that all the clients required AWS credentials or admin credentials for their creation. How can i give access to this service with only using a user from the user pool without any knowledge of the AWS account?
I have tried the client side and server side but they both need aws credentials to create a user pool and identity pool client which then can get access tokens.
try {
credentials = new ProfileCredentialsProvider("default").getCredentials();
} catch (Exception e) {
throw new AmazonClientException(
"Cannot load the credentials from the credential profiles file. " +
"Please make sure that your credentials file is at the correct " +
"location (/Users/ayushaws/.aws/credentials), and is in valid format.",
e);
}
// Creating Cognito user pool client
AWSCognitoIdentityProvider client = AWSCognitoIdentityProviderClientBuilder.standard()
.withRegion("us-east-1")
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
This is how i am currently creating my client. My question is this requires my credentials initially to create a client. How do we create a client if the app using is outside of AWS and have no knowledge of AWS account.
You need to be using credentials with sufficient privileges to create the Cognito User Pool and the Cognito Identity Pool. Since you're using Cognito you should be able to handle auth and access in your client side application, and your application does not need long term credentials, as Identity Pool will provide the necessary credentials.
In your client application, the user will login to the Cognito User Pool directly. When they successfully login to the User Pool they'll receive a response which includes an IdToken. You then add the IdToken to the credentials map and that will grant the user access to the resources that the Identity Pools Authenticated IAM role permits.
You can read more about how to use Cognito User Pools in conjunction with Cognito Identity Pools in the AWS Cognito docs.
How do I use the token response from SAML authentication with User Pools to retrieve AWS Temporary Access keys and Make API Gateway Calls?
I have configured a Cognito User Pool with an associated App client. I have configured Okta as a 3rd Party SAML Identity provider. Using the Amazon hosted login https://[cognito domain name]/login?response_type=token&client_id=[your App client id]&redirect_uri=[your App client redirect URL] I am able to be redirected to my ReactJS application with the #access_token in the header.
I am trying to now user the #access_token to call API gateway. I have been following this guide as well as aws-amplify. To my understanding I need to use the #access_token to get AWS access keys to make the call to API gateway.
I am trying to do this with the following code:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxx-xxxx-xxxx-xxxx-xxxxxx',
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxx': #access_token
}
});
but not sure how this integrates with aws-amplify, and I have not successfully retrieved AWS temporary access keys to make API Gateway calls.
I previously had this working using users in the Cognito User Pool but now I need to include Okta as an identity provider.
I found I needed the #id_token rather than the #access_token to accomplish what I was trying to do. I enabled the #id_token by selecting the following options in my Cognito Pool App Client Settings:
I was then able to follow Cognito hosted UI.
In an android app, I receive a JWT access_token from http://<domain>.auth.<region>.amazoncognito.com/login once the user is done authenticating to a Cognito User Pool. That User Pool is linked to a Cognito Identity Pool.
What API should I call with that access_token to get an AWSCredentials object.
The closest one I found would be AssumeRoleWithWebIdentity, but that is an STS API, and some of what I've read on the web seems to recommend developers not use STS directly but rely on Cognito.
Moreover, I do not expect the API I need to require specifying a role name. Cognito Identity Pools are already configured to give authenticated users a specific role. And AssumeRoleWithWebIdentity takes a role name as input to the API. Hence that does not look like right.
I've looked at Cognito Identity Pool API Reference, and can't find an API that takes access_token and return AWS credentials.
UPDATE:
The following answer which uses GetCredentialsForIdentity throws ResourceNotFoundException saying it cannot find the specified IdentityId.
string access_token = ...
var jwtAccessToken = System.IdentityModel.Tokens.Jwt.JwtSecurityToken(access_token);
var client = new AmazonCognitoIdentityClient(new AnonymousAWSCredentials(),REGION);
var response = await client.GetCredentialsForIdentityAsync(new GetCredentialsForIdentityRequest
{
IdentityId=String.Format("{0}:{1}", REGION, jwtAccessToken.id),
Logins=new Dictionary<string,string>
{
{String.Format("cognito-idp.{0}.amazonaws.com/{1}", REGION, USER_POOL_ID),
access_token}
}
});
After much investigation, I found the answer.
1- One needs an id_token not an access_token to authenticate to Cognito, as misleading as this might sound. AWS's documentation which says you ask for id_token when you need to have user attributes like name / email etc... and ask for an access_token when you don't need that information and just want to authenticate is wrong, or at the very least misleading.
2- And here's how you use an id-token to get AWS Credentials:
var credentials = CognitoAWSCredentials(<identity pool Id>, region);
credentials.AddLogin(
"cognito-idp.<region>.amazonaws.com/<user_pool_id>",
id_token); // the raw token
Note that you do not need AssumeRoleWithIdentity, or GetCredentialsWithIdentity, you do not even need a AmazonCognitoIdentityClient.
To get the credentials you can use GetCredentialsForIdentity method by passing the JWT token. This method is implemented in AmazonCognitoIdentityClient class in the AWS Android SDK.
IAM Role should be defined in the Cognito Federated Identities. This limits the assuming role to be handled internally, by Cognito not allowing the mobile app to assume any other role than the one configured. In addition you shouldn't give this role IAM permission, allowing the Android SDK to assume different roles (Unless its a superuser kind of a user who is logging in).
I have an API service, which I'm going to deploy using AWS API Gateway with Cognito authorizer + Lambda as backend. This service will be used by our javascript client. Also, it should be exposed to end users as raw endpoints for programmatic access.
While it was quite easy to enable signup/login in js client using federated identities, I can't figure out the way to provide users with private access token to include directly in http headers.
Here are two authentication flows, I'd like to get in the end:
The flow for js client user:
User signs up with Facebook or Google.
User verifies his identity.
After login, user goes to the Profile/API Keys section in the interface.
User copies access token and can include it in http request header in any http client (httpie, curl, language libraries whatever)
The flow for admin created user:
Admin creates user.
Access token is generated for that user.
Admin passes generated access token the user.
User can include it in http headers to make request, as in previous flow.
An access token should be permanent, and can be regenerated by user at any time (think of Stripe API access keys).
The point here is to eliminate additional steps for the user to start using service programmatically. The closest thing in AWS docs so far is developer-authenticated-identities, but user should utilize AWS sdk anyway.
One possible way to accomplish this task is to use Custom authorizer instead of Cognito authorizer in API Gateway. Custom authorizer could implement logic based on e.g. auth header name and decide to either authorize in Cognito or to user API access token in database. I'm not sure, if it is possible, and if it is the major drawback is to reimplement Cognito authentication flow in lambda function.
The question is how can I accomplish such API access token (re)generation using Cognito or API Gateway?
The first flow should be possible with User Pools. Cognito User Pools now has a federation feature where you can federate using Facebook/Google and receive access token/refresh token depending on the flow used.
For admin created user, the user would need to authenticate before tokens are issued but this can be achieved by creating the user with a temporary password and signing the user in with that password, after which it can be changed and logged in again to receive access/refresh token.
The refresh token use case is that it can be used against the Cognito APIs to receive a new access token. When the refresh token expires (default is 30 days but it is configurable), the user would have to authenticate again.