Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Impersonate user in AWS Cognito

I have a file server that uses Cognito so users can access by authenticating themselves with basic authentication or the OAuth2.0 authorization code flow.

I'd like external apps to be able to authenticate themselves using the client credentials flow, and then be able to impersonate a user. Is there a way to do this with Cognito?

like image 439
syim Avatar asked Jan 17 '18 16:01

syim


People also ask

Can you change username in Cognito?

The user name is a fixed value that users can't change. If you mark an attribute as an alias, users can sign in with that attribute in place of the user name. You can mark the email address, phone number, and preferred username attributes as aliases.

What is user sub in Cognito?

Cognito sub attribute: When importing the users to a new pool, users will be assigned new Cognito-generated unique IDs (the sub attribute). Federated users: custom attributes for federated users will not be exported and the federated user will get a new value for the sub attribute when they log in to the new user pool.


1 Answers

I was able to do this by creating custom lambdas for the Cognito triggers: Define Auth Challenge, Create Auth Challenge & Verify Auth Challenge.

My requirement was that I wanted my backend to use a secret to then get access & refresh tokens for any Cognito user.

Define Auth Challenge Lambda

exports.handler = async event => {
  if (
    event.request.session &&
    event.request.session.length >= 3 &&
    event.request.session.slice(-1)[0].challengeResult === false
  ) {
    // The user provided a wrong answer 3 times; fail auth
    event.response.issueTokens = false;
    event.response.failAuthentication = true;
  } else if (
    event.request.session &&
    event.request.session.length &&
    event.request.session.slice(-1)[0].challengeResult === true
  ) {
    // The user provided the right answer; succeed auth
    event.response.issueTokens = true;
    event.response.failAuthentication = false;
  } else {
    // The user did not provide a correct answer yet; present challenge
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = 'CUSTOM_CHALLENGE';
  }
  return event;
};

Create Auth Challenge Lambda

exports.handler = async event => {
  if (event.request.challengeName == 'CUSTOM_CHALLENGE') {
    // The value set for publicChallengeParameters is arbitrary for our
    // purposes, but something must be set
    event.response.publicChallengeParameters = { foo: 'bar' };
  }
  return event;
};

Verify Auth Challenge Lambda

exports.handler = async event => {
  if (event.request.challengeName == 'CUSTOM_CHALLENGE') {
    // The value set for publicChallengeParameters is arbitrary for our
    // purposes, but something must be set
    event.response.publicChallengeParameters = { foo: 'bar' };
  }
  return event;
};

I was then able to use some JS, using amazon-cognito-identity-js, to provide the secret and get the tokens:

var authenticationData = {
  Username : 'username'
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = {
  UserPoolId : '...', // Your user pool id here
  ClientId : '...' // Your client id here
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
  Username : 'username',
  Pool : userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);

cognitoUser.setAuthenticationFlowType('CUSTOM_AUTH');

cognitoUser.initiateAuth(authenticationDetails, {
  onSuccess: function(result) {
    // User authentication was successful
  },
  onFailure: function(err) {
    // User authentication was not successful
  },
  customChallenge: function(challengeParameters) {
    // User authentication depends on challenge response
    var challengeResponses = 'secret'
    cognitoUser.sendCustomChallengeAnswer(challengeResponses, this);
  }
});
like image 141
redgeoff Avatar answered Sep 21 '22 19:09

redgeoff