3
votes

I am trying to use amazon cognito with developer authenticated identities. My API is successfully returning an id and token. However, when I use these tokens to upload content to S3 I receive the following error:

Not authorized to perform sts:AssumeRoleWithWebIdentity

Below is my code for setting up the credentials provider.

ZGAWSIdentityProvider *identityProvider = [ZGAWSIdentityProvider new];
[identityProvider setIdentityPoolId:AWS_IDENTITY_POOL_ID];

AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
                                           initWithRegionType:AWSRegionUSEast1
                                           identityProvider:identityProvider
                                           unauthRoleArn:AWS_UNAUTH_ROLE_ARN
                                           authRoleArn:AWS_AUTH_ROLE_ARN];


AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSWest1
                                                                      credentialsProvider:credentialsProvider];

[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;

And I am using the template provided at http://docs.aws.amazon.com/mobile/sdkforios/developerguide/cognito-auth.html#create-an-identity-pool-that-supports-developer-authenticated-identities to create the identity provider.

@implementation ZGAWSIdentityProvider
@synthesize identityPoolId=_identityPoolId;
@synthesize identityId=_identityId;
@synthesize token=_token;


- (BFTask *)getIdentityId {
    // Should ensure that identityId property is valid. The below code can probably
    // be used for most use cases.

    if (self.identityId) {
        return [BFTask taskWithResult:nil];
    } else {
        return [[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
            if (!self.identityId) {
                return [self refresh];
            }
            return nil;
        }];
    }
}

- (BFTask *)refresh {

    BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
    __weak __typeof(self)weakSelf = self;
    [[ZGAccountController sharedInstance] getAWSCredentialsWithCompletion:^(NSDictionary *credentials) {

        if (credentials && [credentials objectForKey:@"identity_id"] && [credentials objectForKey:@"identity_id"]) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
            strongSelf.identityId = [credentials objectForKey:@"identity_id"];
            strongSelf.token = [credentials objectForKey:@"token"];
            [task setResult:nil];
        } else {
            NSError *error = [NSError errorWithDomain:@"com.##.##" code:-1 userInfo:nil];
            [task setError:error];
        }

    }];

    return task.task;
}

@end

It appears to be an issue with Role Trust. I created the identity pool using the amazon web interface and have double checked that the identity pool id is correct. I have been able to successfully upload w unauthenticated identities, so I believe is not a role permissions issue.

2
Maybe a bit off the topic but I want to ask what is the reason to have return [[BFTask ...]; in else block of -getIdentityID method instead of simple return [self refresh]; ?slava

2 Answers

6
votes

Sorry for all the trouble.

There is a small issue with how the identity provider and credentials provider interact that is not properly documented or handled well. The credentials provider pivots using the unauth or auth role arn based on whether or not there are logins attached on the provider. If you aren’t storing any additional logins on the provider, it will treat it as unauthenticated and use the unauth role and result in the STS error you are seeing. You can work around this by doing something like the following in your identity provider’s refresh:

// add login to the map to make sure CredentialsProvider treats us as authenticated
NSMutableDictionary *temp = [NSMutableDictionary dictionaryWithDictionary:self.logins];
[temp setObject:@"temp" forKey:@"myprovider"];
self.logins = temp;

Update 2015-03-10: You may want to consider looking at our end-to-end example for a better method for handling this.

This the sample, we include the the actual values for the user identifier, then pass the entire contents of the logins property to the backend.

3
votes

If you're successfully able to do this while unauthenticated, there are a few possibilities here.

First of all, make sure your unauthenticated role arn is different from your authenticated role arn. Additionally, ensure that, in the trust policy (accessible via the appropriate role from this link), the amr points to "authenticated".

If you have any other questions, this blog post goes over the process at a high level.