Getting user attributes from Cognito for Pre token generation lambda - aws-lambda

I'm writing a lambda to customize the claims on the accessToken before the token is generated. I need to call an external API with data from my Cognito user pool to get information to customize the claim. This lambda would be triggered before sign in. How do I get a specific field for a particular user from the pool?

Related

Can a Lambda Authorizer function detect when an IAM user has been disabled?

How does a Lambda Authorizer detect if an IAM user has been Disable?
We have a two client servers of Iterable and Punchh. The first one uses a payload of just the base64 token of the username : password while the other server uses the username and password (password is masked).
These 2 servers are pushing (POST method) events down to our API Gateway. To avoid any ,malicious packets being sent down to the gateway, we use an IAM test user (dd_transfer in the example figures below) that can be disbaled once malicious packets are discovered. Thus the IAM test user should now be denied access to the API Gateways where both Punchh and Iterable are pushing their payloads.
When I have an active test user, they are allowed access to the API gateway whenever Punchh or Iterable webhooks push(Post) data. However when that same user is Disabled (password is null) in IAM, that user should not be allowed to access to the gateway. Unfortunately, the 2 external servers are still allowed access once the IAM test user has been deactivated/disabled. I don't want to program and search through a credentials report csv file using boto3 that's encoded to base64. This would expose too much account user info - very risky. Is there another way for the Lambda Authorizer function to determine when an IAM user has been deactivated?
Here are the screen shots below for code, gateway , and servers.
Note that the payloads for the two servers are represented differently. Punchh webhook admin page uses password and username while Iterable webhook admin page uses only the base64 encoded token.
Thanks
Lambda Authorizer Code
API Gateway Method (Note: Post and Get Method Requests are identical)
Lambda Authorizer configuration
Punchh Webhook page
Iterable Webhook Page
I found a safe way to determine whether the dd_transfer user is enabled or not and that is with using the GetLoginProfile API. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.get_login_profile
If there is a valid password for dd_transfer, then a LoginProfile object will be displayed in the response message, a 200 response code is returned, and the access to the API Gateway will be given when the policy is generated (‘Allow’).
However if the password is null because the dd_transfer has been disabled, a NoSuchEntity exception will be returned indicating that the Login Profile for User dd_transfer cannot be found. It’s blunt but at least I don’t have to worry about access being given to allow malicious events to bypass our API Gateway and into S3 buckets.
I have added a try/catch block to gracefully handle the error by calling the generate Policy function passing the ‘Deny’ parameter in order to generate the Deny Access policy.
It’s a lot less work than using the Credential Report API and then BASE 64 decoding each record in the text/csv file to look for dd_transfer’s entry. The csv file doesn’t expose actual raw data like passwords etc but GetLoginProfile takes less to write up. Then in the exception handler, I would make a call to the generate the Deny Policy.

AWS Cognito: Add custom claim/attribute to JWT access token

My app creates a custom attribute "userType" for each new signed-up user. Now I would like this "userType" claim/attribute to be added to the JWT access token whenever the user signs in or the token gets refreshed.
Is there an option to tell cognito to add my custom claim/attribute to the JWT access token? (Without a pre token generation Lambda)
Custom attributes are not available in Cognito access token. Currently it is not possible to inject additional claims in Access Token using Pre Token Generation Lambda Trigger as well. PreToken Generation Lambda Trigger allows you to customize identity token(Id Token) claims only.
You can use ID token to get the token with custom attributes.
Access tokens are not intended to carry information about the user. They simply allow access to certain defined server resources.
You can pass an ID Token around different components of your client, and these components can use the ID Token to confirm that the user is authenticated and also to retrieve information about them.
How to retrieve Id token using amazon cognito identity js
cognitoUser.authenticateUser(authenticationDetails,{
onSuccess: function(result) {
var accessToken = result.getIdToken().getJwtToken();
console.log('accessToken is: ' + accessToken);
},
onFailure: function(err) {
alert(err.message || JSON.stringify(err));
},
});
I have the same problem when I want to create several microservice. There isn't a way I can customize an access token, but only an identity token. However, I use client credentials in the machine-to-machine which needs access token. So, in no way I can customize my token. At last, I decide to add such info(like user type) in the event header. It's not a very secure way compared to customize a token, but there isn't any other easy way to do it right now. Otherwise, I have to rewrite the authorizer in Cognito. Like rewriting a customize authorizer and it's very painful.
I have the same issue with Cognito; exist other tools like "PingFederate"Auth-server of Ping identity and Auth0 Auth-server; I know that the requirement isn't part of the standard, but these applications were my alternatives to fix this issue
The responses suggesting to use the ID Token for authorization in your backend systems are bad security practice. ID Tokens are for determining that the user is in fact logged in and the identity of that user. This is something that should be performed in your frontend. Access Tokens on the other hand are for determining that a request (to your backend) is authorized. ID Tokens do not have the same security controls against spoofing that Access Tokens have (see this blog from Auth0: https://auth0.com/blog/id-token-access-token-what-is-the-difference/).
Instead, I recommend that your backend accept an Access Token as a Bearer token via the Authorization HTTP header. Your backend then calls the corresponding /userinfo endpoint (see: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) on the authorization server that issued the Access Token, passing such said Access Token to that endpoint. This endpoint will return all of the ID Token information and claims, which you can then use to make authorization decisions in your code.

Access user info from lambda

I'm working on a serverless app with aws.
I use AWS Cognito User Pool to manage user : register, login, logout.
Once those users have been confirmed, I use AWS Cognito Identity Pool to get temporary credentials. Then I use those credentials to access the api (the endpoint on my api require AWS_IAM for Auth and call lambda).
All of that work perfectly. But I need to know which user has requested the action. In the lambda I can get the IdentityId from my Identity Pool. But I need to get attributes from my user in User Pool.
So my question is : is there a way to get a user from User Pool using the IdentityId of the Identity attached to it ? Or at least, get the access token ? I know I can send the access token in headers but I would like to only depend on the AWS_IAM auth.
Getting from a federated identity_id back to the user pool user is tricky because there's no guarantee it is a user pool user (it could well be someone from Facebook, or even an unauthenticated user- depending on your configuration).
Given an IdentityId you can use identity:GetOpenIdToken to get a valid OpenId token (you can ignore the logins part of the request if you are just using UserPools).
You can then use this token against the userpools:GetUser end point.
There's a few pitfalls here, like ensuring you authenticate with a scope that allows you to see all the attributes you care about. If you haven't, then you'll need to use the username returned with userpools:AdminGetUser to get the full user profile.

How to store session in AWS lambda

I have a AWS Lambda function which need to talk to an external API to validate the user using bearer token pass in API request header.
Now I want to store that token in session, so I don't want to call external API every time when user send request again with that token.
So which is a best way to do it with AWS lambda.
Thanks
If this request is coming through API Gateway you should look at using a Customer Authorizer. Rather than storing the token in a session, since Lambda APIs are meant to be stateless, you should validate the token in a Custom Authorizer using the necessary keys. The key(s) would typically be set in an environment variable so you can easily access it and validate the token.
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html

How to make AWS Cognito User Data available to Lambda via API Gateway, without an Authorizer?

I have a website that uses AWS Cognito (via Amplify) for user login. The API is on a separate stack that deploys with Serverless.
I am trying to have an API endpoint that can access the current logged-in user's Cognito User Pool data (username, email) if it is available. The only way I've been able to achieve this is by using a cognito user pool authorizer via API Gateway.
Example:
functions:
getMe:
handler: /endpoints/myService.get
events:
- http:
path: /myService
method: GET
cors: true
authorizer:
type: COGNITO_USER_POOLS
authorizerId: ${self:custom.apiGatewayAuthorizerId.${self:custom.stage}}
Where authorizerId is set to the 6-character Authorizer ID found on the AWS Console's API Gateway Authorizers page. However, this blocks all traffic that is not authenticated with Cognito. That isn't what I want, since I have a number of services that should be accessible by both anonymous and logged-in users. I just want to personalize the data for users that are logged-in.
Is there any way to allow traffic and pass the cognito user parameters through the API Gateway to Lambda if they are available?
All resources I've been able to find regarding Cognito + API Gateway + Lambda are specifically about restricting access to endpoints and not layering on data to the requests...
Based on comments above you want Anonymous and Logged-in users pass through same gateway end point ?
You can still use the same setup but remove the authentication from API Gateway and take the logic in your application.
If users try to access your services while being logged in AWS amplify will send through the Authorization header with Id token to API Gateway and API Gateway will pass this header as it is to the application. You will have to check inside your application for this Authorization header and crack open Id token passed to find the user claims/attributes and do your logic. For any other user that doesn't have this token can be considered anonymous.
You still need to Validate the token if you find one in request to make sure it's a valid token and extract claims/Attributes thereafter.

Resources