AWS Pinpoint updating user attributes when unauthenticated - security issue? - amazon-web-services

I'm looking at using AWS Pinpoint to send push notifications to my react native app. However it seems that unauthenticated users are able to update user attributes for any user they wish, ie there is no access control. I'm new to mobile development, but isn't putting stuff like that into the frontend a security issue? If it were a web application, people would be able to inspect network calls to obtain credentials and make any call they wish to updateEndpoint. Is this not applicable to mobile apps or am I misunderstanding something?
Details:
There's a step in the setup that says Edit the IAM policy document for unauthenticated identities to allow permissions for the mobiletargeting:PutEvents and mobiletargeting:UpdateEndpoint actions
And react native code snippet provided goes as follows:
import Analytics from '#aws-amplify/analytics';
import Auth from '#aws-amplify/auth';';
const amplifyConfig = {
Auth: {
identityPoolId: 'COGNITO_IDENTITY_POOL_ID',
region: 'ap-south-1'
}
}
//Initialize Amplify
Auth.configure(amplifyConfig);
const analyticsConfig = {
AWSPinpoint: {
// Amazon Pinpoint App Client ID
appId: 'cd73a57d200e49e2bc4b97d6ebf63cd4',
// Amazon service region
region: 'ap-south-1',
mandatorySignIn: false,
}
}
Analytics.configure(analyticsConfig)
Analytics.updateEndpoint({
attributes: {
interests: ['science', 'politics', 'travel'],
//..
},
userId: 'UserIdValue',
userAttributes: {
username: 'ilovethecloud'
}
});

I'm not sure if this will help,
But you have 2 IAM policies (in Cognito Identity-pool), 1 for authenticated users and 1 for unauth. users.
You should restrict the IAM policy for unauth users, so they can't edit other users info.
Also, the credentials that you are given by Cognito, are temporal, they expire (and get renewed by your react-native app), so in that way you are safe.

Related

AWS Amplify 'currentUserCredentials()' returns unexpected authenticated value, bug?

When calling Auth.currentUserCredentials() after Auth.signIn() I get valid valid credentials, but for an unauthenticated user, why?
Code:
async signIn({ dispatch, state }, { email, password }) {
try {
const user = await Auth.signIn(email, password);
console.log("User state after login")
const userCredentialsAfterLogin = await Auth.currentUserCredentials();
console.log(userCredentialsAfterLogin)
} catch (error) {
console.log("error")
console.log(error)
return
}
await dispatch('fetchUser')
},
Expected behaviour:
After signing in with a valid user, Auth.currentUserCredentials() should return an authenticated set of Credentials.
Actual behaviour:
Auth.currentUserCredentials() returns an unauthenticated user with the authenticated property set to false and a 400 error, "ResourceNotFoundException: IdentityPool 'eu-west-1:62dab5ed-5a84-4064-a7a2-87d1d0df511b'
System:
authenticationFlowType: "USER_SRP_AUTH"
Versions: "aws-amplify": "^3.3.14", "aws-amplify-vue": "^2.1.4", amplify version 4.42.0
config
{
"authSelections": "userPoolOnly",
"resourceName": "testapp89e81d50",
"serviceType": "imported",
"region": "eu-west-1"
}
I understand where you're coming from, and honestly I can't really show you clear documentation that exactly states why this won't work. AWS documentation on Cognito and Amplify is difficult to piece together, both because the Amplify framework still uses an old library under the hood ('amazon-cognito-identity-js') and Cognito is the name for both a connect-login-with-IAM and signup/signin-as-a-service offering. Cognito is super powerful and rock solid in terms of security if done right, but the setup is a bit of a pain.
There's a bit of documentation, e.g. the API docs of Amplify Auth here. You can see there that currentCredentials / currentUserCredentials gives you some object which contains among other things an 'identitiId'. Credentials, in the Amplify Auth framework, refer to AWS IAM credentials that refer to an Cognito Identity.
You seem to be using Amplify to login to a Cognito User Pool, using email/password. A Cognito User Pool can be connected to a Cognito Identify pool, to 'exchange' a Cognito JWT token for some credentials that can be used to use AWS resources (IAM credentials). This is not needed to have a normal sign in / sign up flow working though.
So, the question is: what do you want?
Do you want to know about the currently logged in Cognito User Pool user, e.g. his email, JWT token and other fields that are stored in the JWT token? Use 'currentUserInfo' or 'currentUserSession'
Do you actually want to have some IAM credentials to invoke AWS resources? Make sure to create and connect your Cognito User Pool with a Cognito Identity Pool and configure your Identity Pool id in your frontend settings. If you've done that, you should be able to use 'currentCredentials'.

Accessing AWS AppSync without using API Keys in React Native

In my React Native App I am using API Keys with AWS AppSync and I want to move to using Cognito or IAM but with no user sign in.
My React Native app that just uses AWS Appsync to read to and write from DyanmoDB.
I initially set up the app to use API keys as it was easier to understand and I'm now attempting to transition to using AWS Cognito or IAM.
To do this in my AWS Console I changed the "Appsync->MyAppAPI->Settings->Default authorisation mode"/"API-level" from "API key" to "AWS Identity and Access Management (IAM)".
I then created an Identity Pool and allowed "Enable access to unauthenticated identities".
My aws-exports file is
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_appsync_graphqlEndpoint": "https://xxxxx.appsync-api.eu-west-x.amazonaws.com/graphql",
"aws_appsync_region": "eu-west-X",
"aws_appsync_authenticationType": "AWS_IAM",
"aws_appsync_apiKey": "xxx-xxxxxxxxxxxxxxxxxxxxxxxxxx",
};
export default awsmobile;
In my App.js file I have attempted to get the identityPoolId to be used and I have created this:
Amplify.configure({
url: config.aws_appsync_graphqlEndpoint,
region: config.aws_appsync_region,
auth: {
type: config.aws_appsync_authenticationType,
apiKey: config.aws_appsync_apiKey,
region: 'eu-west-x',
identityPoolId: 'eu-west-x:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
}
})
When I use the app to read from DynamoDB I get this error
[WARN] 04:51.835 API - ensure credentials error, No Cognito Federated Identity pool provided
I then went back to the Cognito Manage Identity Pool page and changed my identity pool to use Cognito as an authentication source and provided a User Pool ID and an App client id. But I still get the same error.
I am fundamentally missunderstanding something, could you offer any insight?

How to create custom user pool on cognito, and connect this to your application

I would like to use the out-of-the-box user account creation with cognito, and am able to do that. But I would like to add custom attributes.
Now, is there a way, using the terminal, that you can ask amplify to use the user pool you have created, instead of the default one that it generates for you?
Indeed, you do not have to create a Cognito User/Identity Pools when using AWS Amplify (simply, do not run amplify add auth).
And even if you have one created by default, you can still manually configure Amplify to use desired resources for authentication as:
Amplify.configure({
Auth: {
identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
region: 'XX-XXXX-X',
identityPoolRegion: 'XX-XXXX-X',
userPoolId: 'XX-XXXX-X_abcd1234',
userPoolWebClientId: 'a1b2c3d4e5f6g7h8i9j0k1l2m3',
mandatorySignIn: false
}
});
Just put the proper values of your project. For further options for manual configuration, you can have a glance at the Amplify Auth docs.

How to delete a user from the user pool in the NodeJS lambda by admin

I faced a problem when a user has signed up but doesn't want to confirm his email. The solution is to delete an unconfirmed user from AWS Cognito.
So as I don't know his password, I am trying to write a Lambda function which I will trigger through API Gateway. This lambda should remove Cognito user.
I wrote this code but it doesn't work.
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({
apiVersion: '2016-03-18',
});
var params = {
UserPoolId: 'us-east-1_123456',
Username: 'user#mail.com' // I want to remove this user
};
cognitoidentityserviceprovider.adminDeleteUser(params, function (err, data) {
if (err) {
callback(err, err.stack);
} else {
callback(data);
}
});
I get an error:
user is not authorized to perform ...
Because of security, I don't want to set my admin credentials on frontend part and I want to do all work in this lambda... How to do it?
Any ideas?
Any solutions to prevent this problem?
You can assign a role to the lambda function and make a call to cognito api without passing any argument to the library you use to access aws services, that way the credential provider would fallback to the assumed role and have the lambda execution role's identity.
Usually roles are the way to go with amazon related authorizations.
Btw, this means that you have to create an iam role, a policy with the right cognito actions allowed and attach it to said role.
const cisp = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' })
cisp.adminDeleteUser().promise() //delete current user as admin

Getting AWS IAM user by access key id using sdk

I'm trying to verify that an IAM user exists with an access key using the AWS SDK(js).
I am trying to build an access control module for an API. I can't deploy it on AWS. Instead of trying to build the whole thing, I want to handle user management using IAM but will need to build a custom module to check if current IAM user has access to resources.
I've checked the docs and looks like you can only get user by username. I thought maybe I can list the users and filter the user array by access key but obviously the list does not have access key info.
The AWS Identity and Access Management (IAM) service is designed specifically for granting access to AWS resources. It is not designed as an authentication system for applications.
A more appropriate product would be Amazon Cognito:
Amazon Cognito lets you easily add user sign-up and sign-in and manage permissions for your mobile and web apps. You can create your own user directory within Amazon Cognito. You can also choose to authenticate users through social identity providers such as Facebook, or Amazon; with SAML identity solutions; or by using your own identity system. In addition, Amazon Cognito enables you to save data locally on users' devices, allowing your applications to work even when the devices are offline. You can then synchronize data across users' devices so that their app experience remains consistent regardless of the device they use.
With Amazon Cognito, you can focus on creating great app experiences instead of worrying about building, securing, and scaling a solution to handle user management, authentication, and synchronization across devices.
You can check whether the user exist or not by IAM User's credentials using AWS CLI/SDK
Attach iam:GetUser and iam:SimulatePrincipalPolicy policies to your IAM user.
Here iam:GetUser will be used to check the user existence and iam:SimulatePrincipalPolicy will be used to check the resource access.
1. Check existence:
You can use getUser() function of AWS-IAM to verify whether user exist or not
const iam = new AWS.IAM({
// Iam User access and secret Key
})
iam.getUser({}, (err,data)=>{
if(err)
console.log("User not exist");
else
console.log("User exist ", data);
})
if user exists:=>
`{
"User": {
"Path": "/",
"UserName": "userName",
"UserId": "AIDAY357ZXJ7ADSEWNGWA3",
"Arn": "arn:aws:iam::60977878822:user/userName", // required this in simulator
"CreateDate": "2020-08-05T14:48:49Z"
}
}`
2. For resource access you can use simulatePrincipalPolicy() function of AWS-IAM.
let params = {
PolicySourceArn = "Paste IAM user arn", // arn:aws:iam::60977878822:user/userName
ActionNames = ["ec2:RunInstances"]
}
iam.simulatePrincipalPolicy(params, (err, data)=> {
if(err)
console.log("Error", err);
else
console.log("Data ", data);
})
output:=>
`{
ResponseMetadata: { RequestId: '3e7cbc9a-ed7b-472a-b054-a6f3f37bf8c4' },
EvaluationResults:
[ { EvalActionName: 'iam:SimulatePrincipalPolicy',
EvalResourceName: '*',
**EvalDecision: 'allowed',** // check this
MatchedStatements: [Array],
MissingContextValues: [],
ResourceSpecificResults: [] },
],
IsTruncated: false
}`
If the EvalDecision is 'allowed' means your IAM User have the access to create new instances.