Credential Provider Not Authorised Exception AWS Android SDK - android

I was trying to Publish and Subscribe using authenticated user on AWS IoT with Federated Identities. Until I keep getting error CognitoCachingCredentialsProvider: Failure to get credentials
I looked up here. But the snippet they provided is not used by Facebook anymore. How can I fix this issue?
Android Code:
public void IntializeAwsIot() {
clientId = "us-east-1:fcbd66e0-***************";
// Initialize the AWS Cognito credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(), // context
AWSConfiguration.AMAZON_COGNITO_IDENTITY_POOL_ID,// Identity Pool ID
AWSConfiguration.AMAZON_COGNITO_REGION // Region
);
Region region = Region.getRegion(AWSConfiguration.AMAZON_COGNITO_REGION);
// MQTT Client
mqttManager = new AWSIotMqttManager(clientId, CUSTOMER_SPECIFIC_ENDPOINT);
// The following block uses IAM user credentials for authentication with AWS IoT.
//awsCredentials = new BasicAWSCredentials("ACCESS_KEY_CHANGE_ME", "SECRET_KEY_CHANGE_ME");
//btnConnect.setEnabled(true);
// The following block uses a Cognito credentials provider for authentication with AWS IoT.
new Thread(new Runnable() {
#Override
public void run() {
awsCredentials = credentialsProvider.getCredentials();
Connect();
}
}).start();
}
Error:
/com.amazon.mysampleapp E/CognitoCachingCredentialsProvider: Failure to get credentials
com.amazonaws.services.cognitoidentity.model.NotAuthorizedException: Access to Identity 'us-east-1:fcbd66e0-**************' is forbidden. (Service: AmazonCognitoIdentity; Status Code: 400; Error Code: NotAuthorizedException; Request ID: 0fa5100d-88a0-11e7-af8c-854a7b8add4d)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:729)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
at com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient.invoke(AmazonCognitoIdentityClient.java:558)
at com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient.getCredentialsForIdentity(AmazonCognitoIdentityClient.java:388)
at com.amazonaws.auth.CognitoCredentialsProvider.populateCredentialsWithCognito(CognitoCredentialsProvider.java:691)
at com.amazonaws.auth.CognitoCredentialsProvider.startSession(CognitoCredentialsProvider.java:617)
at com.amazonaws.auth.CognitoCredentialsProvider.getCredentials(CognitoCredentialsProvider.java:388)
at com.amazonaws.auth.CognitoCachingCredentialsProvider.getCredentials(CognitoCachingCredentialsProvider.java:442)
at com.mysampleapp.AWSIoT.PubSub$1.run(PubSub.java:69)
at java.lang.Thread.run(Thread.java:818)

The problem was there was no credential in the Cognito Cache. So we need to save the appropriate credential so the get credential function can work.
We need to just add the following.
Map<String, String> logins = new HashMap<String, String>();
logins.put("graph.facebook.com", AccessToken.getCurrentAccessToken().getToken());
credentialsProvider.setLogins(logins);

Related

Aws mqtt connection using cognito credential provider in android

I am trying to my app connect with mqtt broker using cognito credentials provider. When I was trying to connect to mqtt broker..app saying identity poolId not found.
CognitoUserSession cognitoUserSession = AppHelper.getCurrSession();
String idToken = cognitoUserSession.getIdToken().getJWTToken();
Map<String,String> logins = new HashMap<String, String>();
logins.put("cognito-idp.ap-south-1.amazonaws.com/XXXX_XXXX", idToken);
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"ap-south-1:XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX", // Identity pool ID
Regions.AP_SOUTH_1 // Region
);
credentialsProvider.setLogins(logins);
AmazonCognitoIdentity cognitoIdentity = new AmazonCognitoIdentityClient(credentialsProvider);
GetIdRequest getIdReq = new GetIdRequest();
getIdReq.setLogins(logins); //or if you have already set provider logins just use credentialsProvider.getLogins()
getIdReq.setIdentityPoolId(credentialsProvider.getIdentityPoolId());
GetIdResult getIdRes = cognitoIdentity.getId(getIdReq);
AttachPrincipalPolicyRequest attachPolicyReq = new AttachPrincipalPolicyRequest(); //in docs it called AttachPolicyRequest but it`s wrong
attachPolicyReq.setPolicyName(AWS_IOT_POLICY_NAME); //name of your IOTAWS policy
attachPolicyReq.setPrincipal(getIdRes.getIdentityId());
new AWSIotClient(credentialsProvider).attachPrincipalPolicy(attachPolicyReq);
mqttManager.connect(credentialsProvider, new AWSIotMqttClientStatusCallback() {
#Override
public void onStatusChanged(final AWSIotMqttClientStatus status, Throwable throwable) {
runOnUiThread(new Runnable() {
#Override
public void run() {
txtStatus.setText(status.toString());
}
});
}
});
}catch(final AmazonClientException e){
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),"exception : "+e,Toast.LENGTH_LONG).show();
}
});
Log.d(LOG_TAG,"Exception : "+e);
}
Log file:
com.amazonaws.services.cognitoidentity.model.ResourceNotFoundException: IdentityPool 'ap-south-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX' not found. (Service: AmazonCognitoIdentity; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: bdd3c355-79b0-48f3-8a18-716fa17c44ce)
Can any one guide me how to resolve this one. What was the wrong in my code.
Thanks in
Advance.
As your log shows, you did not set the Cognito Identity Pool ID and the Region (where your Identity pool is) in your android app. You can find them under sample code of your identity pool in AWS federated identity dashboard.

com.amazonaws.services.cognitoidentity.model.NotAuthorizedException: Invalid login token. Can't pass in a Cognito token

I am using developer authentication in my android app. After successful login, the server sends the client the Cognito token. The intention of this token is to get access to Amazon S3 for uploading images.
I have created a sample project here: TestAWSCognito
Here is the snippet code where I am trying to create AmazonS3Client:
String identityPoolId = "eu-west-1:289fd4a0-2236-4ff4-9c2b-61c93e60bf0a";
AmazonS3Client testClient = null;
Map<String, String> loginsMap = new HashMap<>();
loginsMap.put("cognito-identity.amazonaws.com", "eyJraWQiOiJldS13ZXN0LTExIiwidHlwIjoiSldTIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiJldS13ZXN0LTE6MjkyM2IxYWQtNGNiYS00ZTFmLWEyY2YtZGIyNDVmM2Q3NWJiIiwiYXVkIjoiZXUtd2VzdC0xOjI4OWZkNGEwLTIyMzYtNGZmNC05YzJiLTYxYzkzZTYwYmYwYSIsImFtciI6WyJhdXRoZW50aWNhdGVkIiwiZ3JhcGhxbC5oYXJhaiIsImdyYXBocWwuaGFyYWo6ZXUtd2VzdC0xOjI4OWZkNGEwLTIyMzYtNGZmNC05YzJiLTYxYzkzZTYwYmYwYTo1NjI4NDAiXSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkZW50aXR5LmFtYXpvbmF3cy5jb20iLCJleHAiOjE1NDUxNDgzMTYsImlhdCI6MTU0NTA2MTkxNn0.V-iZeAQdsdMb9LkzYNucka5PEYRMBKKTGm5CzZIJYg8Z5ehcq562JbXGJWr7Yea-w2APsbpVxgP8EjHxSLjsMggk2FdVd-m8YhNFwBYL91oph-wFiAIxLVginD3t3_EhmkPduXZgM1mwH1_yNsGqpBY4nr15cgjqLvfyb4t-QJADFFyjd2qpIUoNzU2EQ5ypEKmbVdgOeLCIe6a-L09yzO-M1xdC0Onc8fs5ELOISR8FA5YFJYIgyqfSz9wDmz929rmCV9EjFdNC3Jd_hSC_Ofp6NYjiW1HRTU0a2C3Z3FCNJFzKppQSUt78MWrJblhHJSEboeMoKhzxmkA0VPgNjg");
CognitoCredentialsProvider cognitoCredentialsProvider = new CognitoCachingCredentialsProvider(getApplicationContext(), identityPoolId, Regions.EU_WEST_1);
cognitoCredentialsProvider.setLogins(loginsMap);
try {
AmazonS3Client testClient = new AmazonS3Client(cognitoCredentialsProvider.getCredentials());
if (testClient != null) {
return testClient;
}
}
catch (Exception e) {
e.printStackTrace();
}
The token and identityPoolId are still valid.
When creating the AmazonS3Client it returns an exception: com.amazonaws.services.cognitoidentity.model.NotAuthorizedException: Invalid login token. Can't pass in a Cognito token. (Service: AmazonCognitoIdentity; Status Code: 400; Error Code: NotAuthorizedException; Request ID: af373152-0452-11e9-b8c4-c3f49006c33b)
Any help would be appreciated. Thanks!

How to set OIDC provider for AWSAssumeRoleWebIdentity

I am developing an android app which uses firebase authentication for signin and uses AWS S3 and dynamodb for managing data/images. I am trying to delegate an access to AWS resource via AWSAssumeRoleWebIdentity. The reason I am doing this is AWS Sign-In UI does not allow enough customization for UI and UI flow. I decided to use firebase authentication only for sign-in and sign-up.
Please find the source code and OIDC Provider setting. With them the error log is
No OpenIDConnect provider found in your account for https://securetoken.google.com/[project-name] (Service: AWSSecurityTokenService; Status Code: 400; Error Code: InvalidIdentityToken; Request ID: 37607060-9e1c-11e8-8ae0-636eae27c3bf)
Identity Provider of AWS IAM has been created with the name of "securetoken.google.com/[my-project-name]/" with the Thumbprint that I created referring to [1] and OAuth 2.0 client IDs obtained in Credentials of Google Cloud Service API & Services.
The source code is shown below.
public void uploadImageFile() {
CustomLog.logI("start of uploadImageFile");
setIDToken();
}
private void setIDToken() {
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
// To get ID Token of the user authenticated by google authentication
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete (#NonNull Task< GetTokenResult > task) {
if (task.isSuccessful()) {
// Token information is set to mIDToken of the global variable
mIDToken = task.getResult().getToken();
AsyncTaskForAssumeRole asyncTaskForAssumeRole = new AsyncTaskForAssumeRole();
asyncTaskForAssumeRole.execute();
} else {
CustomLog.logE(task.getException().getMessage());
}
}
});
}
public class AsyncTaskForAssumeRole extends AsyncTask<Void, Void, BasicSessionCredentials> {
protected BasicSessionCredentials doInBackground(Void... params) {
try {
// set credentials from AssumeRoleWithWebIdentity
BasicSessionCredentials credentials = setAssumeRoleWithWebIdentity();
return credentials;
} catch (Exception e) {
CustomLog.logE(e.getMessage());
return null;
}
}
protected void onPostExecute(BasicSessionCredentials credentials) {
// upload file with S3 connection
connectToS3ForUpload(credentials);
}
}
private BasicSessionCredentials setAssumeRoleWithWebIdentity(){
CustomLog.logD("start of setAssumeRoleWithWebIdentity");
String ROLE_ARN = [my role arn];
// set AssumeRoleWithWebIdentity request with created policy and token information retrieved through Google Sign in information
AssumeRoleWithWebIdentityRequest request = new AssumeRoleWithWebIdentityRequest()
.withWebIdentityToken(mIDToken)
.withRoleArn(ROLE_ARN)
.withRoleSessionName("wifsession");
BasicAWSCredentials basicCreds = new BasicAWSCredentials("", "");
AWSSecurityTokenServiceClient sts = new AWSSecurityTokenServiceClient(basicCreds);
AssumeRoleWithWebIdentityResult result = sts.assumeRoleWithWebIdentity(request);
Credentials stsCredentials = result.getCredentials();
String subjectFromWIF = result.getSubjectFromWebIdentityToken();
BasicSessionCredentials credentials = new BasicSessionCredentials(stsCredentials.getAccessKeyId(),
stsCredentials.getSecretAccessKey(),
stsCredentials.getSessionToken());
return credentials;
}
Great thanks in advance.
[1] http://docs.aws.amazon.com/cli/latest/reference/iam/create-open-id-connect-provider.html
Consider using Amazon Cognito Federated Identities (Identity Pools) to federate (map) the user from your Identity Provider into Amazon Cognito and obtain a Cognito Identity Id, which can be used to authorize access to AWS resources. See https://docs.aws.amazon.com/cognito/latest/developerguide/open-id.html for further details.
Map<String, String> logins = new HashMap<String, String>();
logins.put("login.provider.com", token);
credentialsProvider.setLogins(logins);
Now, you can use the credentialsProvider object with an Amazon S3 client.
AmazonS3 s3Client = new AmazonS3Client(getApplicationContext(), credentialsProvider);

aws cognito user get id token android

I'm trying to get the current logged in user's id token for aws cognito in android.
I found this example:
session.getIdToken().getJWTToken()
where session is a CognitoUserSession object
I can't seem to figure out a way to get the current cognitousersession after the login call has been made.
I'm using the default authenticator activity from the notes tutorial:
https://docs.aws.amazon.com/aws-mobile/latest/developerguide/tutorial-android-aws-mobile-notes-auth.html
It says that the tokens are stored in the shared preferences, but I can't figure out how to retrieve them on future activities so that I can make calls to the api gateway using the id token.
The AWS Android SDK will return the JWT token without a network call when the token is not/will not expire.
The threshold for when a token should be refreshed can be set with the CognitoIdentityProviderClientConfig.setRefreshThreshold(long) method.
If you are stil curious how to retrieve the token yourself, then the code can be found in readCachedTokens() method
https://github.com/aws/aws-sdk-android/blob/master/aws-android-sdk-cognitoidentityprovider/src/main/java/com/amazonaws/mobileconnectors/cognitoidentityprovider/CognitoUser.java#L2116
As nobody has answered yet, this might help you out, be aware this is JS code:
This is my routine to receive the session from an already logged in user.
after this, i'm able to access tokens.
var user_data = {
UserPoolId: AWSConfiguration.UserPoolId,
ClientId: AWSConfiguration.ClientAppId
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(user_data);
if (userPool.getCurrentUser() != null) {
userPool.getCurrentUser().getSession(function (err, session) {
if (err) {
window.location.href = "login.html";
}
var user_params = {
IdentityPoolId: AWSConfiguration.IdPoolId,
Logins: {
'cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXX':session.idToken.jwtToken
}
};
AWS.config.credentials = new AWS.CognitoIdentityCredentials(user_params);
AWS.config.region = AWSConfiguration.region;
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
}
else {
user_is_authenticated();
}
});
});
}

Issue signing into Amazon S3 with Google Sign-in on Android

I'm building an Android app that connects to an Amazon S3 bucket and retrieves mp3 files stored within. This is my first time using Google Sign-in, and it's for a (hopefully) production app, and I want to do it properly.
I've followed all the directions here and have successfully received an ID Token by calling GoogleSignInAccount.getIdToken().
I have then used Amazon's directions for OpenID Connect providers here and used this code:
// Initializing the Amazon Cognito credentials provider
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider (
getApplicationContext(),
"us-east-1:220fe85c-fcc9-4ecc-b923-1357e1380fde", // Example Identity Pool ID
Regions.US_EAST_1 // Example Region
);
Map<String, String> logins = new HashMap<String, String>();
logins.put("accounts.google.com", idToken);
credentialsProvider.setLogins(logins);
to login. However, nothing is showing up in my Identity Pool. I'm wondering whether it's some confusion on my part in regards to which Client ID I am using. When I created the project on the Google Developer console, I received two ID's. One for a Web Application, and one for Android.
As per Google's instructions here, I passed the Web client ID to the requestIdToken method when I created the GoogleSignInOptions object, and the Android ID to the Identity Pool, like this:
I removed all the other numbers after the hyphen, as the example calls for a smaller ID, but for the record, neither version works. The original was like:
1034544032360-77XXXkoq9XXkdXXsj82uhdXXXbqii6t2.apps.googleusercontent.com
Except when I test my app, It seems to be successful, no errors are thrown, but no new identities are logged in my identity pool.
What am I missing? I would really appreciate a nudge in the right direction.
Is that code you gave the extent of your logging in? The Cognito Android SDK gets credentials lazily, setting logins alone won't do anything. Try adding a credentialsProvider.refresh(); after that.
Okay, I solved it finally; there were a few things I missed.
Firstly, as Jeff Bailey mentioned, I wasn't calling credentialsProvider.refresh() after I had set the login token, like this:
private void setCredentials(String token) {
Map<String, String> logins = new HashMap<>();
logins.put("accounts.google.com", token);
credentialsProvider.withLogins(logins);
}
However, that method requires a network request, so that had to be called from an Async task.
Secondly, I used different code to get an ID token from Google, instead of GoogleSignInAccount.getIdToken. See below:
private class GetAndSetGoogleToken extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
try {
GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
AccountManager am = AccountManager.get(getApplicationContext());
Account[] accounts = am.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
token = GoogleAuthUtil.getToken(getApplicationContext(), accounts[0].name,
"audience:server:client_id:" + serverClientId);
} catch(GoogleAuthException ex) {
Log.d(TAG, "GoogleAuthException has been thrown by GetAndSetGoogleToken!");
} catch(IOException ex2) {
Log.d(TAG, "IOException has been thrown by GetAndSetGoogleToken!");
}
return token;
}
#Override
protected void onPostExecute(String token) {
// Passing the ID Token as an Extra to the Intent and starting a new Activity.
goToNextActivity(token);
super.onPostExecute(token);
}
}
Finally, I hadn't modified my IAM Trust Policies to recognise accounts.google.com as a trusted entity. Once doing so, they looked like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": [
"cognito-identity.amazonaws.com",
"accounts.google.com" // I needed to add this
]
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:xxxx2e4a-4cf6-4121-aa16-xxxx53374a49"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
Having done all that, it worked fine.
Hope this helps someone; it doesn't seem to be a well documented use-case unfortunately.

Categories

Resources