Search code examples
amazon-cognitoaws-sdk-cpp

authenticate a user using cognito aws-sdk-cpp


I have been trying to create a user login using the aws-sdk-cpp. I essentially would like a user to register using my app as a user (which will add them to the cognito user pool - I have this working), and then log-in. This login will then provide them access to a specific bucket in the account. I have created a policy which should allow cognito users to access the bucket using the below.

http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_cognito-bucket.html

I have created a user pool and a federated identity in the AWS console, and enabled cognito as a identity provider in the user pool, so I think that side is all correct.

I have tried using the SDK to put this authentication together, using the integration tests from identity-management as a starting point.

Aws::SDKOptions options;
Aws::InitAPI(options);
{
    const Aws::String userPool_id = "eu-west-1_xxxxxxxxx";
    const Aws::String client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
    const Aws::String region_id = "eu-west-1";
    const Aws::String identityPool_id = "eu-west-1:xxxxxxxxxxxxxxxxx";
    const Aws::String account_id = "xxxxxxxxxxxx";

    Aws::Client::ClientConfiguration clientConfig;
    clientConfig.region = region_id;

    std::shared_ptr<CustomPersistentCognitoIdentityProvider> persistent_provider = std::make_shared<CustomPersistentCognitoIdentityProvider>();
    persistent_provider->SetAccountId(account_id);
    persistent_provider->SetIdentityPoolId(identityPool_id);

    //Aws::Map<Aws::String, LoginAccessTokens> logins;
    //LoginAccessTokens loginAccessTokens;
    //loginAccessTokens.accessToken = LOGIN_ID;
    //logins[LOGIN_KEY] = loginAccessTokens;
    //persistent_provider->SetLogins("cognito-idp.eu-west-1.amazonaws.com/eu-west-1_xxxxxxx", client_id);

    auto cognito_client = std::make_shared<Aws::CognitoIdentity::CognitoIdentityClient>(clientConfig);

    Aws::CognitoIdentity::Model::GetIdRequest id_request;
    id_request.SetAccountId(account_id);
    id_request.SetIdentityPoolId(identityPool_id);
    id_request.AddLogins("cognito-idp.eu-west-1.amazonaws.com/eu-west-1_xxxxxx", client_id);
    id_request.AddLogins("USERNAME", "tester@xxxxxxxxx");
    id_request.AddLogins("PASSWORD", "xxxxxxxxxxxxx");
    cognito_client->GetId(id_request);

    Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider authenticated_provider(persistent_provider, cognito_client);
    Aws::Auth::AWSCredentials credentials = authenticated_provider.GetAWSCredentials();

    std::cout << "AccessKeyID : " << credentials.GetAWSAccessKeyId() << std::endl;
    std::cout << "SecretKey : " << credentials.GetAWSSecretKey() << std::endl;

    Aws::S3::S3Client s3_client(credentials, clientConfig);

    S3ListObject(s3_client, "cloudtesting");
    // do stuff with the s3 bucket 
}

Aws::ShutdownAPI(options);

The code above returns empty strings for the access keys.

Adding some debug at the GetId call return:

Request error: NotAuthorizedException Invalid login token. Not a valid OpenId Connect identity token.

I've obviously missed something here, or in the setup. Any suggestions/help/code examples would be greatly appreciated!


Solution

  • In order to authenticate with the Cognito User Pool, you have to use the CognitoIdentityProviderClient (see aws/cognito-idp/CognitoIdentityProviderClient.h). It uses the Secure Remote Password protocol (SRP) for authentication, which you unfortunately have to implement yourself. You first make a call to InitiateAuth, which then reply with some info to which you have to respond with RespondToAuthChallenge.

    This is implemented in the Amazon Cognito Identity SDK for JavaScript which you can use as a reference.