1

I am trying to create a desktop application, which sends user files to Amazon S3, where the users can then sign in to a website to view/download their files. I have the desktop application working, it has the user sign in and upload the files to their own bucket. I also have a webpage where the user can sign in to a Cognito user that has permissions to download files from that bucket. I can't seem to link the Cognito user to their S3 permissions. All of the examples I have found involve linking the website to one bucket, and in this case, that bucket depends on the user they're signed in to. This attempt to list buckets returns "Error: Credential is missing"

AWS amplify authentication (this successfully returns the user when credentials are entered):

export class CognitoService {

  private authenticationSubject: BehaviorSubject<any>;

  constructor() {
    Amplify.configure({
    Auth: environment.cognito,
  });

    this.authenticationSubject = new BehaviorSubject<boolean>(false);
  }


  public signIn(user: IUser): Promise<any> {
    return Auth.signIn(user.username, user.password)
      .then(returnedUser => {
        if (returnedUser.challengeName === 'NEW_PASSWORD_REQUIRED') {
          Auth.completeNewPassword(returnedUser, user.password)
            .then(user => {
              return user
            });
        }
      })
  }
  public getUser(): Promise<any> {
    return Auth.currentUserInfo();
  }
}

Get data (This request is unsuccessful at returning the S3 buckets)

export class DataComponent implements OnInit{
  user: IUser;

 constructor(private cognitoService: CognitoService, private s3Service: S3Service) {
    this.user = {} as IUser;
  }
  public ngOnInit(): void {
    this.cognitoService.getUser()
    .then((user: any) => {
      this.user = user.attributes;
    });
  }
  public getBuckets(): void {
    this.s3Service.getBuckets()
    .then((response: any) => {
      console.log(response)
    })
  }
}

S3 service used to get buckets (I suspect this is where changes are needed):

export class S3Service {
    constructor() {
        Amplify.configure({
            Auth: environment.cognito,
        });
    }

    public async getBuckets() {
        const client = new S3Client({region: 'us-west-2'});
        const input = {};
        const command = new ListBucketsCommand(input);
        const response = await client.send(command);
    }
}

Environment:

export const environment = {
    cognito: {
        userPoolId: 'xxx',
        userPoolWebClientId: 'xxx',
    },
}

2 Answers2

0

You could use Cognito user's role giving permission to access the S3 bucket.

It is possible to assign a role to any/all authenticated user and then use that role's permissions

https://aws.amazon.com/blogs/developer/amazon-cognito-credentials-provider/

Seeing you are using the Amplify lib, it should allow you to get the aws session (temporary) credentials

gusto2
  • 11,210
  • 2
  • 17
  • 36
0

Unfortunately I was having some issues assigning permissions using the temporary credentials. What I ended up doing was this:

  1. Changed the desktop application to upload to a folder inside of a bucket. Their IAM role then had access only to that folder. See below for specifying a folder inside a bucket.
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetBucketTagging",
                "s3:ListBucket",
                "s3:DeleteObject",
                "s3:GetBucketAcl"
            ],
            "Resource": [
                "arn:aws:s3:::{bucket}/{folder}",
                "arn:aws:s3:::{bucket}/{folder}/*"
            ]
        },
  1. The website then has that bucket hard coded in, if they try to download a file from a different folder, then it returns "access denied".