How does aws cognito securely persist identityId for unauthenticated users? - amazon-cognito

Using cognito, I'm able to obtain an 'unauthenticated' identityId representing "me". How does cognito prevent someone else from claiming to be "me"?
GetCredentialsForIdentityRequest request = new GetCredentialsForIdentityRequest();
request.setIdentityId("us-west-2:639dc6e0-1f14-4c0a-9a08-a48c742f5395"); //Could I just enter whatever identity Id I want here? Is knowing what the identityId is the security? Is that really secure?
GetCredentialsForIdentityResult result = cognitoIdentityClient.getCredentialsForIdentity(request);
Code shown from AWS JAVA SDK

Related

AWS Cognito - create groups from ADFS as Cognito Groups

An app is communicating via the Open ID Connect protocol with AWS Cognito, which is connected to ADFS, communicating via SAML. Cognito is essentially "proxying" the ADFS server.
ADFS holds a group mapping that the app requires, and I would like to import these groups into Cognito as actual Cognito Group - which will then be read by the app from the cognito:groups from the ID-token Cognito provides.
In the AWS Cognito User Pool setup, I don't see a way to map ADFS groups to Cognito Groups - must I absolutely rely on a custom attribute for my User Pool that I can map to the ADFS-property, or am I missing some piece of configuration that allows Cognito to create new groups on the fly and automatically assign the users to the groups in Cognito?
edit: To clarify, Is it possible to setup Cognito to add/create groups (not as a custom property, but a actual manageable cognito groups) when it imports users?
I had the same issue, and I have not found a static mapping option in Cognito either.
The only way I see is to map the AD groups to custom:adgroups attribute in Cognito, and set up a Cognito "Pre Token Generation" lambda trigger. The lambda reads the value of the custom:adgroups and manually overrides the user's Cognito groups.
NB - this does not change the cognito user's group permanently, only for the current session, but from the application perspective that's exactly what I needed.
Please see a dummy static (non conditional) ADMIN group assignment example here:
def lambda_handler(event, context):
print(f'incoming event: {json.dumps(event)}')
# manual cognito group override
if event['triggerSource'] == "TokenGeneration_HostedAuth":
event['response'] = {
"claimsOverrideDetails": {
"groupOverrideDetails": {
"groupsToOverride": [
"ADMIN"
]
}
}
}
return event
More detailed documentation here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html
Could you use the Post authentication Lambda trigger to update the user's group in the Cognito User Pool based off the group in AD? You could use the APIs: AdminAddUserToGroup and AdminRemoveUserFromGroup. The only issue with this approach is that if you change the user's group in AD, it won't be updated in Cognito until the user authenticates to Cognito again.
How to setup ADFS with Cognito is documented in this link. The section answering your question is the mapping in step 4, item 5. I'm copying the relevant text below:
Choose Attribute mapping. These mappings map the claims from the SAML assertion from AD FS to the user pool attributes.
Make sure that ADFS is sending the groups in the assertions. For setting up the ADFS side for groups this link might be useful.
You could debug the flow with SAML-tracer plugin in Firefox.

Is there a way to know which aad to use for authenticating in advance?

I have a UWP app that needs to authenticate, and I would like to avoid asking the user to choose which national cloud to authenticate with. I could just try them all, but I hope there is a better way to tell which Azure Active Directory the user belongs to (.us or .com)
Native apps can discover the Azure AD endpoint for a national cloud by passing an instance_aware parameter in the authorization request to the global Azure AD endpoint. This is done in the acquireToken call, where you need to pass in instance_aware = true as an extra query parameter when initializing the Authentication context.
From the Authentication result, you can read and store the cloud_instance_host_name attribute to learn the correct Azure AD endpoint. You must pass this value as the authority to re-initialize the Authentication context for the subsequent acquireTokenSilent calls to succeed.
An example ADAL.Net code snippet is below:
var authenticationContext= new AuthenticationContext(Authority, false, new TokenCache());
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource,
clientId,
redirectUri,
platformParameters,
userIdentifier,
"instance_aware=true"
);
Also, here are example OAuth request and responses using the instance_aware parameter:
Request:
https://login.microsoftonline.com/common/oauth2/authorize?
response_type=code&
client_id=f5d01c1c-abe6-4207-ae2d-5bc9af251724&
instance_aware=true&
redirect_uri=http://localhost/appcheck&
resource=00000002-0000-0000-c000-000000000000
Response:
http://localhost/appcheck?
code=AQABAAIAAQDnLpu3ikefR73l_aNlxt5x0ulCIcjaTlOoWp412SJ2Oxlih65_h_Ju3OdOqpEy-mz0giFzZtU2_MbIgSG12e6RjwxpcaXaVPene_lMtmR2DPexUZZ3QhFRl8Vgl76SidX_nJ1CN-hJAejCi139FG_YZit4ePbiNySC3zR9GcP3B3St7HDsdEhMh1Vi1XHSSKfpgVqzLnOiBSO_jXrm1WJVqXSlt4_M_KO92Gdpbpy8H7zpsRg0O6blbuSw_83YUcj0w1gEfByHZP2Hk5AToDy_DWepPqJ0GWOJYeKcfIiEFleNYaeyEJDDuMyFhV16IOT28mq1oNOWL0dnhjwr-OV0JnyajQCT_LZzapxp7Y-8jSPDgW6SR878sgrq6CS2z3Zos8_T31n4DucQaPqv2Ae_jxlGHHSENBFy2RhHy397B7BBohXGqhDj_OdIroimDOJGVewn612gQOA6-9p0llv-PNd7vj9VZL-9Q8kEuYuhTqaBsH3yKm6y9FfgxMWovVkYtDt4YgxbqCV2Wb_lzImtyTHKxazn6YhH6R2pCvFdVSAA&
cloud_instance_name=microsoftonline.us&
cloud_instance_host_name=login.microsoftonline.us&
cloud_graph_host_name=graph.windows.net&
msgraph_host=graph.microsoft.com&
session_state=899b8a55-034f-4dcd-8b4b-888b7874b041
One way to "spot check" which cloud/AAD environment the user belongs to is by making a call to the Azure AD OpenID Connect discovery endpoint:
https://login.microsoftonline.com/place_tenantname_or_tenantid_here/.well-known/openid-configuration
For Azure Government, "USG" or "USGov" as the value in the tenant_region_scope field will indicate tenants that should be using login.microsoftonline.us.
I hope this helps. Let me know if not.
Bernie

How federated Identity ID is populated and sent to IAM policies?

I want to know , from where this value is ${cognito-identity.amazonaws.com:sub} populated . I had checked in cognito Identity JWT token where sub will have username of cognito. I cant able to see federated ID any where in JWT Id token. I can only see the ID generated in federated identity pool.
Does it is a hash of cognito and federated pool ID ?
Because if it is taking from JWT token, i want to pass custom:Attribute1 into this variable dynamically ${cognito-identity.amazonaws.com:custom:Attribute1} in IAM role of dynamodb ?
Thanks
Any help is appreicated
With Cognito Federated Identity, the username from the user pool is not preserved across the federation boundary. Instead it is exchanged for an identity id which is consistent for future interactions with that user. At this time, you will need to maintain your own mapping of username -> identity id. Another option is to not use Federated Identity and proxy your requests to DynamoDB through API Gateway using Cognito User Pool authorizers so you have access to the end user's username.

Why can't we use getUid() to authenticate with your backend server in firebase authentication

In this code snippet (firebase doc) they have mentioned do not use user.getUid() to authenticate with your backend server. use FirebaseUser.getToken() instead.
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// Name, email address, and profile photo Url
String name = user.getDisplayName();
String email = user.getEmail();
Uri photoUrl = user.getPhotoUrl();
// The user's ID, unique to the Firebase project. Do NOT use this value to
// authenticate with your backend server, if you have one. Use
// FirebaseUser.getToken() instead.
String uid = user.getUid();
}
getUid() // A unique user ID, intended as the user's unique key across all providers.
getToken() // The Firebase authentication token for this session.
My requirement is.
First I will register user with firebase authentication method (Email and password).
I will save String uid = user.getUid(); in my own backend server once registration is successful.
User credit information say user balance is saved in my own backend server as key user.getUid().
User sign-in with Email and password and ask for his balance.
I will get user.getUid() from firebase and match with my records, if match found returns balance to user.
They said getUid() is unique user id but Do NOT use this value to authenticate with your backend server.
Why so? Why can't we use getUid() to authenticate with your backend server??
The uid is a unique identifier for the user. So, while it identifies the user, it does not authenticate them.
A simple corollary is that my Stack Overflow ID is 209103. Knowing that, you can identify me. But to prove to Stack Overflow that you are Frank van Puffelen, requires that you know my credentials.
The ID of a user is quite often exposed in the interface. For example, if you click on my profile, you will see my ID. This is necessary for identifying me. If you would also use that same ID to authenticate, everyone who had seen your profile once could impersonate you on the site. Not a good idea when it comes to security.
Take your requirements as an example, if you using [GET] https://your-domain.com/api/users/$uid/balance to retrieve user's data, then this API is not secured at all, anybody could get other user's data with a random $uid.
As the comment(firebase doc) recommends, FirebaseUser.getToken() will get a JWT token, you should validate the token with firebase Admin SDK in your backend, and that is the data you could trust.
And the method client-side method should update to user.getIdToken() by now.
https://firebase.google.com/docs/auth/admin/verify-id-tokens is the reference for more detail.

Amazon AWS for Android not accepts Google token Id, as identity provider

I acquire the Google tokenId and pass it to the CredentialsProvider instance based on the instructions here.
String token = AccountUtils.getAuthToken(this);
Map<String, String> logins = new HashMap<>();
logins.put("accounts.google.com", token);
getCredentialsProvider().withLogins(logins);
Then I refresh the CredentialsProvider instance by calling below line in an AsyncTask:
getCredentialsProvider().refresh();
I get no exceptions, I expect too see a new Google Authenticated user in the cognito control panel. But I only get a new unauthenticated user. sigh
I checked that the token I am receiving from Google is just fine and that I have set the clientId in the cognito settings.
Any help is highly appreciated
After 2 days of trying to make it work, and tempted a lot to forget AWS 4ever and run my own server, I was able to find the solution with the help of this guy.
If you follow the Google instructions to integrate sign in, you will receive 2 client ids in step 2 and 4. You need to put first one in your cognito pool and the second one in your app.
Apparently Amazon has mentioned this nowhere in their documentations