3

I was wondering if someone can help me with the following concept in android. I want users to create an account and login on my application, using amazon cognito, to identify their identity. Once a user is logged in this user can download a personal file from Amazon S3.

I implemented the code provided by the AWS Mobile Hub regarding the login and everything seems to work nicely: I was able to create a test account through my app and login without errors. Obviously I cannot test the backend because the S3 part is causing me troubles. The code for the login is very basic and looks like this:

public class AuthenticatorActivity_old extends Activity {
    @Override    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AWSMobileClient.getInstance().initialize(this, new AWSStartupHandler() {
            SignInUI signin = (SignInUI) AWSMobileClient.getInstance().getClient(AuthenticatorActivity_old.this, SignInUI.class);
            signin.login(AuthenticatorActivity_old.this, home.class).execute();
        }).execute();        
    }
}

This code works with a bunch of Amazon libraries and the awsconfiguration.json file, and I assume it declares the credentialsProvider

Regarding the personal file that user can download, every user gets their own file in the application's bucket (only one bucket, because I do not want to create a separate bucket for every user), and only this logged in user has the rights to download this file. I have written (adopted and adapted from someone else) an IAM policy which looks like this, which if I understand correctly, only allows users to download a file which has a name [bucket]/cognito/[username]/fixedfilename.jpg :

{
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": ["s3:ListBucket"],
              "Resource": ["arn:aws:s3:::<BUCKET-NAME>"],
              "Condition": {"StringLike": {"s3:prefix": ["cognito/<APPLICATION-NAME>/"]}}
            },
            {
              "Effect": "Allow",
              "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
              ],
              "Resource": [
                "arn:aws:s3:::<BUCKET-NAME>/cognito/<APPLICATION-NAME>/${cognito-identity.amazonaws.com:sub}",
                "arn:aws:s3:::<BUCKET-NAME>/cognito/<APPLICATION-NAME>/${cognito-identity.amazonaws.com:sub}/*"
              ]
            }
          ]
}

I think I am so far so good (have not been able to test it all, so I am not sure). But now comes the tricky part. To download a file from S3 the following steps need to be taken:

  1. You first create AWS Credentials for accessing S3 using BasicAWSCredentails class
  2. Pass AWS Credentials to AmazonS3 instance
  3. You then pass AmazonS3 object to TransferUtility class

So if I understand correctly, the signing in process mentioned before should save AWS Credentials. This credential file is tailored to my bucket and to the credentials of the signed in user.

The AWS Mobile Hub simply tells me to go to https://docs.aws.amazon.com/aws-mobile/latest/developerguide/add-aws-mobile-user-data-storage.html#add-aws-mobile-user-data-storage-app and implement this. Even though I use the exact code provided, I still get the error: AmazonS3 client is required please set using .s3Client(yourClient).

It seems Amazon provides a broken code. Looking at what this AmazonS3client is, AmazonS3 s3 = new AmazonS3Client(credentialsProvider);, I again see the credentialsProvider. The one that is created (I assume) during the login process but which I cannot extract because it is hidden in Amazon's libraries and awsconfiguration.json (again I assume. There are many black boxes here for me).

I get lost in the many many many documentation/tutorials/sample apps provided by Amazon, and it seems they recently did an update making some texts online irrelevant.

Is there anyone who can help me with this???

-------------------------------- UPDATE ---------------------------

some additional information for the people not too familiar with this topic but still wanting to help me out :)

This is the code that is provided by Amazon for the upload to S3 (in combination with the awsconfiguration.json file):

public class YourActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uploadData();
    }

   public void uploadData() {

   TransferUtility transferUtility =
         TransferUtility.builder()
               .context(getApplicationContext())
               .awsConfiguration(awsConfig)
               .build();

   TransferObserver uploadObserver =
         transferUtility.upload(
               "s3Folder/s3Key.txt",
               new File("/path/to/file/localFile.txt"));

   uploadObserver.setTransferListener(new TransferListener() {

     ..... some more code

The error occurs in Transferutility.builder, and I expect to change it as follows:

AmazonS3 s3Client = new AmazonS3Client(credentialsProvider);

                      TransferUtility.builder()
                        .s3Client(s3Client) <------------this one
                        .context(getApplicationContext())
                        .awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
                        .build();

The point is that I cannot have a S3Client (or can I???) using the credentials of the user login (without having to build the sign in activity from the ground up, rather than using Amazon's code, because that is a bit out of my league!)

daan166
  • 300
  • 1
  • 10

1 Answers1

1

You can create an object of CredentialsProvider like this:

CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
            getApplicationContext(),
            &quot;us-east-1:dbacd6aa-9393-475e-b687-xxxxxxxxx&quot;, // Your Identity Pool ID
            Regions.US_EAST_1 // Your Region
    );

If you dont want to create this every time then you can write this code inside a separate class and use setter and getter methods to use it.

Rahul Kumar
  • 340
  • 1
  • 3
  • 12
  • Somewhere in the process of setting up the transferutility information of the user needs to be included. Does this happen in the getApplicationContext() part of creating the credentialsprovider? Or is my fundamental understanding of the credentialsprovider wrong? – daan166 Nov 23 '17 at 08:24
  • No. I think you are misunderstanding the credentialProvider. credentialProvider is used to authorize the connection req of your app to your aws server and not to verify the user signin credentials – Rahul Kumar Nov 23 '17 at 11:58
  • Ah I see that now, thanks for your explanation. I got rid of the error. So after the sign in process 'john's' credentials (user john1234) are stored locally (I believe in the shared preferences). Where in the process does the app send a message to the server, "hey this is john1234, and it is me who wants to store file x on the server, and not mike4321"? Because this is quite important for me as john should only be able to store a file named /john/filex and should only be possible to retrieve the file starting with /john/. Mike4321 should not be allowed to access this file or write with /john/ – daan166 Nov 23 '17 at 22:12
  • Sorry, for the late reply. In case you still wondering how to store those files on S3, you can provide the upload path in your code above: `transferUtility.upload( "s3Folder/s3Key.txt", new File("/path/to/file/localFile.txt"));` your destination path can be like this: `"s3Folder/username/fileName.txt"` – Rahul Kumar Nov 25 '17 at 00:48
  • If I helped in solving your problem, I would really appreciate if you could mark this answer as accepted. – Rahul Kumar Nov 25 '17 at 00:54