4
  • The user uploads an image to his/her subfolder on S3. The only way this can be enforced with policy is by using identity id:

    arn:aws:s3:::thebucket/${cognito-identity.amazonaws.com:sub}/avatar.jpg
    
  • A lambda that transforms that image, is triggered, and saves the transformations to a different S3.

  • But now, with the identity id on disposal, that lambda needs to update the user's db record with the references to the avatar transformations. This is where the issue is evident, I only have the identity id, and from it, I need to get to the cognito user's details so i can look for the user in my users table which has user:sub as identifier.

How do I correlate those two? Is there an api in cognito that would give me the sub based on the identity id?

Is there maybe a more reasonable way?

Daniel Birowsky Popeski
  • 8,752
  • 12
  • 60
  • 125

1 Answers1

0

I have not been able to find a way to do this. Also, you should only get a Cognito Identity Id passed to Lambda if you are using the Mobile SDK, which you can access using 'context.identity.cognitoIdentityId'. Although one user user at least seems to be defying the AWS documention set by getting it to work with Javascript.

It looks like you are using the sub in your s3 object key, so have you thought about taking it form there? You get loads of information passed about the s3 object in your event, including the key, which in your case includes your sub.

Your S3 event should look something like this

{  
   "Records":[  
      {  
         "eventVersion":"2.0",
         "eventSource":"aws:s3",
         "awsRegion":"us-east-1",
         "eventTime":"1970-01-01T00:00:00.000Z",
         "eventName":"ObjectCreated:Put",
         "userIdentity":{  
            "principalId":"AIDAJDPLRKLG7UEXAMPLE"
         },
         "requestParameters":{  
            "sourceIPAddress":"127.0.0.1"
         },
         "responseElements":{  
            "x-amz-request-id":"C3D13FE58DE4C810",
            "x-amz-id-2":"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"
         },
         "s3":{  
            "s3SchemaVersion":"1.0",
            "configurationId":"testConfigRule",
            "bucket":{  
               "name":"mybucket",
               "ownerIdentity":{  
                  "principalId":"A3NL1KOZZKExample"
               },
               "arn":"arn:aws:s3:::mybucket"
            },
            "object":{  
               "key":"HappyFace.jpg",
               "size":1024,
               "eTag":"d41d8cd98f00b204e9800998ecf8427e",
               "versionId":"096fKKXTRTtl3on89fVO.nfljtsv6qko",
               "sequencer":"0055AED6DCD90281E5"
            }
         }
      }
   ]
}

You could parse the S3 object key, which should have your sub in it.

EDIT: After sharing some comments I think your situation is this:

  • You have a user who has logged into using an external identity (e.g. google)
  • This user also has a user pool identity
  • The identities have not been linked using admin-link-provider-for-user
  • You want to lookup the user pool identity from the external identity after some action

Im assuming the thing that links these accounts is an email address? One option is to link the accounts when they signup, using a cognito pre-signup trigger and the admin-link-provider-for-user function.

The other thing you could do is take the current (externally provided) identity email, then do ListUsers based on that email. You will get a list of UserType back, then choose the one where the provider is Cognito, which should give you the sub you want.

Is that the sort of thing your after?

EDIT: Another idea we discussed in the comments was calling your Lambda function directly from your application, rather than relying on the S3 event. The benefit of this approach is that you could include any information you like in the call, like the correct user sub.

F_SO_K
  • 13,640
  • 5
  • 54
  • 83
  • Ah.. you have no idea how happy i would've been if that `sub` is actually the user's `sub` from the id token. That is a sub of the identity id. But then I wonder, if identity id completely identifies the user, maybe that's the one i should use in my `user` table. But how would I obtain it on successful user registration? Another thing: can I be sure that all user's external and internal identities (cognito user pool, fb, g, t) are merged into the same identity id? Just brainfarting here. Maybe we'll solve this together. – Daniel Birowsky Popeski Dec 05 '17 at 11:43
  • Can I check something; are you saying your user has logged in with an external provider (like google), they also have a userpool account, and its the userpool account sub you want, not the external provider one? – F_SO_K Dec 05 '17 at 12:19
  • Well, just imagine how for every new external provider account i'm creating a user in my cognito user pool. And with the id of that user(the `sub`), i'm identifying a user record in my user table. Get it? :} So yeah, i need to somehow get to the user record in my user table. If you think i should identify the table with a different identifier, please, take a shot. – Daniel Birowsky Popeski Dec 08 '17 at 13:08
  • I have found admin-link-provider-for-user very difficult to implement, for example see this [see this thread](https://github.com/aws/amazon-cognito-identity-js/issues/560) and [this one](https://forums.aws.amazon.com/message.jspa?messageID=814706). But its possible. TBH I think Cognito is in poor shape compared to most other AWS services. – F_SO_K Dec 08 '17 at 13:32
  • Got some feedback: let's say we succeed linking identities in all cases. What I still cannot figure out is when the images-transformations-lambda is triggered, it only knows of an identity id. But i need to glue the transformed images to the user's db record. That record is identified with cognito user pool sub field(the record is being created on user registration). So in short: how to get the user:sub field given the user's identity id. – Daniel Birowsky Popeski Dec 08 '17 at 17:27
  • You could create your own custom event in your application. Then you could just put the sub in the event. The event would be triggered on a succesful S3 action. – F_SO_K Dec 08 '17 at 17:33
  • I dont know how to go from principalId to cognito sub though. – F_SO_K Dec 08 '17 at 17:33
  • Could you elaborate what do you mean by custom event? What triggers it? – Daniel Birowsky Popeski Dec 08 '17 at 17:36
  • Sure. Rather than using the event generated by S3 on your behalf, you could write your own event to an AWS SNS topic. This is super easy - SNS is a great service. You can then pass a custom payload to Lambda on your event. [This is worth reading](http://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html) – F_SO_K Dec 08 '17 at 17:40
  • Sure but.. what triggers this custom event? Where is it produced? – Daniel Birowsky Popeski Dec 08 '17 at 17:41
  • You would create the SNS topic, form that you copy a topic ID. Then in your application code, when something happens, like saving something to S3, you post to the SNS topic. You have Lambda listen to that topic, so it receives the message. – F_SO_K Dec 08 '17 at 17:43
  • So you generate it in your application. Thats fine, as along as your application is the only thing that is saving to S3. – F_SO_K Dec 08 '17 at 17:43
  • So a lambda listens to s3 and then pushes to sns? But even so, the lambda doesn't have enough information to push to the topic. The lambda wouldn't have the cognito sub.. right? – Daniel Birowsky Popeski Dec 08 '17 at 17:44
  • Don't mind us.. working on the longest SO comment stream here. – Daniel Birowsky Popeski Dec 08 '17 at 17:45
  • No. Your application pushes to SNS, then Lambda is listening to that topic. – F_SO_K Dec 08 '17 at 17:45
  • Haha, thats what its here for I suppose. – F_SO_K Dec 08 '17 at 17:46
  • So im assuming you have an 'application' running that does something to S3. Maybe this is bad assumption? – F_SO_K Dec 08 '17 at 17:47
  • How does the user get their item into S3 exactly? – F_SO_K Dec 08 '17 at 17:48
  • I would say so, yes. The clients are the ones doing the stuff (uploads) to s3. And then our backend (lambdas) responds to s3. The users put their stuff up on s3 by getting aws temp credentials based on their cognito authentication. – Daniel Birowsky Popeski Dec 08 '17 at 17:49
  • Ok but they are not doing that through the AWS console, right? There is some kind of application they are logging into? Can you add code to that application? – F_SO_K Dec 08 '17 at 17:55
  • 1
    OK, great, so in that application, when the code gets called to save the item in S3, at that point you could add some code to publish a custom message to SNS. – F_SO_K Dec 08 '17 at 17:57
  • If the client is the one notifying the backend of the new upload, there is no need of SNS as indirection. Once the upload is done, the client can just call a lambda directly. And that would solve things. But given that it's not the client's responsibility to connect the dots, i consider this approach a workaround. Despite, you just thought of a workaround. And if there is no other way, i might just use it. – Daniel Birowsky Popeski Dec 08 '17 at 18:12
  • Yes, that's true. – F_SO_K Dec 08 '17 at 18:13
  • Put this in the answer so I can accept it. And please, if you think of something, do not hesitate :} there is still room in this chat stream. – Daniel Birowsky Popeski Dec 08 '17 at 18:15