CopyPastor

Detecting plagiarism made easy.

Score: 0.8024179409273888; Reported for: String similarity Open both answers

Possible Plagiarism

Reposted on 2021-03-03
by F\_SO\_K

Original Post

Original - Posted on 2020-11-14
by F\_SO\_K



            
Present in both answers; Present only in the new answer; Present only in the old answer;

There is a way to do this but you will need to write some code - there is no out-of-the-box solution.
You will need to write a lambda and connect it to the Cognito Pre-Signup trigger. https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html The trigger has three different sources of event; `PreSignUp_SignUp`, `PreSignUp_AdminCreateUser` and `PreSignUp_ExternalProvider`.
Your lambda should check you have the `PreSignUp_ExternalProvider` event. For these events, use the Cognito SDK to look the use up in your existing pool. If the user exists, return the event. If the user does not exist, return a string (error message).
I will paste my own Pre-Signup trigger here. It does not do what you need it to, but all the main components you need are there. You can basically hack it into doing what you require.
const AWS = require("aws-sdk"); const cognito = new AWS.CognitoIdentityServiceProvider(); exports.handler = (event, context, callback) => { function checkForExistingUsers(event, linkToExistingUser) { console.log("Executing checkForExistingUsers"); var params = { UserPoolId: event.userPoolId, AttributesToGet: ['sub', 'email'], Filter: "email = \"" + event.request.userAttributes.email + "\"" }; return new Promise((resolve, reject) => cognito.listUsers(params, (err, result) => { if (err) { reject(err); return; } if (result && result.Users && result.Users[0] && result.Users[0].Username && linkToExistingUser) { console.log("Found existing users: ", result.Users); if (result.Users.length > 1){ result.Users.sort((a, b) => (a.UserCreateDate > b.UserCreateDate) ? 1 : -1); console.log("Found more than one existing users. Ordered by createdDate: ", result.Users); } linkUser(result.Users[0].Username, event).then(result => { resolve(result); }) .catch(error => { reject(err); return; }); } else { resolve(result); } }) ); } function linkUser(sub, event) { console.log("Linking user accounts with target sub: " + sub + "and event: ", event); //By default, assume the existing account is a Cognito username/password var destinationProvider = "Cognito"; var destinationSub = sub; //If the existing user is in fact an external user (Xero etc), override the the provider if (sub.includes("_")) { destinationProvider = sub.split("_")[0]; destinationSub = sub.split("_")[1]; } var params = { DestinationUser: { ProviderAttributeValue: destinationSub, ProviderName: destinationProvider }, SourceUser: { ProviderAttributeName: 'Cognito_Subject', ProviderAttributeValue: event.userName.split("_")[1], ProviderName: event.userName.split("_")[0] }, UserPoolId: event.userPoolId }; console.log("Parameters for adminLinkProviderForUser: ", params); return new Promise((resolve, reject) => cognito.adminLinkProviderForUser(params, (err, result) => { if (err) { console.log("Error encountered whilst linking users: ", err); reject(err); return; } console.log("Successfully linked users."); resolve(result); }) ); } console.log(JSON.stringify(event)); if (event.triggerSource == "PreSignUp_SignUp" || event.triggerSource == "PreSignUp_AdminCreateUser") { checkForExistingUsers(event, false).then(result => { if (result != null && result.Users != null && result.Users[0] != null) { console.log("Found at least one existing account with that email address: ", result); console.log("Rejecting sign-up"); //prevent sign-up callback("An external provider account alreadys exists for that email address", null); } else { //proceed with sign-up callback(null, event); } }) .catch(error => { console.log("Error checking for existing users: ", error); //proceed with sign-up callback(null, event); }); } if (event.triggerSource == "PreSignUp_ExternalProvider") { checkForExistingUsers(event, true).then(result => { console.log("Completed looking up users and linking them: ", result); callback(null, event); }) .catch(error => { console.log("Error checking for existing users: ", error); //proceed with sign-up callback(null, event); }); } };
The solution I created handles, I think, all cases. It also tackles some common issues with Cognito.
- If the user is signing up with an external provider, link them to any existing account, including Cognito (username/password) or external provider account. - When linking to existing accounts, link only to the oldest account. This is important is you have more than 2 login options. - If the user is signing up with Cognito (username/password), if an external provider already exists, reject the signup with a custom error message (because the accounts cannot be linked).
Note that when linking accounts, the Cognito pre-signup trigger returns an "Already found an entry for username" error. Your client should handle this and reattempt authentication, or ask the user to sign in again. More info on this here:
https://stackoverflow.com/q/47815161/4985580
Here is my lambda, executed on the Cognito pre-signup trigger
``` lang-js const AWS = require("aws-sdk"); const cognito = new AWS.CognitoIdentityServiceProvider();
exports.handler = (event, context, callback) => {
function checkForExistingUsers(event, linkToExistingUser) {
console.log("Executing checkForExistingUsers");
var params = { UserPoolId: event.userPoolId, AttributesToGet: ['sub', 'email'], Filter: "email = \"" + event.request.userAttributes.email + "\"" };
return new Promise((resolve, reject) => cognito.listUsers(params, (err, result) => { if (err) { reject(err); return; } if (result && result.Users && result.Users[0] && result.Users[0].Username && linkToExistingUser) { console.log("Found existing users: ", result.Users); if (result.Users.length > 1){ result.Users.sort((a, b) => (a.UserCreateDate > b.UserCreateDate) ? 1 : -1); console.log("Found more than one existing users. Ordered by createdDate: ", result.Users); } linkUser(result.Users[0].Username, event).then(result => { resolve(result); }) .catch(error => { reject(err); return; }); } else { resolve(result); }
}) );
}
function linkUser(sub, event) { console.log("Linking user accounts with target sub: " + sub + "and event: ", event);
//By default, assume the existing account is a Cognito username/password var destinationProvider = "Cognito"; var destinationSub = sub; //If the existing user is in fact an external user (Xero etc), override the the provider if (sub.includes("_")) { destinationProvider = sub.split("_")[0]; destinationSub = sub.split("_")[1]; } var params = { DestinationUser: { ProviderAttributeValue: destinationSub, ProviderName: destinationProvider }, SourceUser: { ProviderAttributeName: 'Cognito_Subject', ProviderAttributeValue: event.userName.split("_")[1], ProviderName: event.userName.split("_")[0] }, UserPoolId: event.userPoolId }; console.log("Parameters for adminLinkProviderForUser: ", params); return new Promise((resolve, reject) => cognito.adminLinkProviderForUser(params, (err, result) => { if (err) { console.log("Error encountered whilst linking users: ", err); reject(err); return; } console.log("Successfully linked users."); resolve(result); }) ); }
console.log(JSON.stringify(event));
if (event.triggerSource == "PreSignUp_SignUp" || event.triggerSource == "PreSignUp_AdminCreateUser") {
checkForExistingUsers(event, false).then(result => { if (result != null && result.Users != null && result.Users[0] != null) { console.log("Found at least one existing account with that email address: ", result); console.log("Rejecting sign-up"); //prevent sign-up callback("An external provider account alreadys exists for that email address", null); } else { //proceed with sign-up callback(null, event); } }) .catch(error => { console.log("Error checking for existing users: ", error); //proceed with sign-up callback(null, event); });
}
if (event.triggerSource == "PreSignUp_ExternalProvider") {
checkForExistingUsers(event, true).then(result => { console.log("Completed looking up users and linking them: ", result); callback(null, event); }) .catch(error => { console.log("Error checking for existing users: ", error); //proceed with sign-up callback(null, event); });
}
};
```

        
Present in both answers; Present only in the new answer; Present only in the old answer;