get the state of the user (DISABLED/ENABLED) when triggers lamda function of pre sign in - amazon-cognito

I have an user with the state Disabled in his account:
I have this lamda function in the event of pre sign in:
exports.handler = (event, context, callback) => {
console.log(event);
callback(null, event);
};
when the user try to sign in, I can get this response of the lamda that I have created
console.log of event:
{
version: '1',
region: 'us-east-1',
userPoolId: 'us-east-1_XXXXXXXXX',
userName: 'XXXXXXX-XXXX-XXXX-XXXXXX-XXXXXXXXXX',
callerContext: {
awsSdkVersion: 'aws-sdk-unknown-unknown',
clientId: 'XXXXXXXXXXXXXXXXXXXXXXXXXX'
},
triggerSource: 'PostAuthentication_Authentication',
request: {
userAttributes: {
sub: 'XXXXXXX-XXXX-XXXXX-aXX-XXXXXXXXXXX',
'custom:city_id': '141',
'cognito:email_alias': 'gaby#hotmail.com',
'cognito:user_status': 'CONFIRMED',
birthdate: '1998-08-18',
email_verified: 'false',
gender: 'male',
phone_number_verified: 'true',
'custom:uid': 'XXXXXXXXXXXXXXXXXXXXXXX',
given_name: 'Gabo',
'custom:document_number': '1053817459',
'custom:status': 'activo',
phone_number: '+999999999',
family_name: 'Amaya',
email: 'gaby#hotmail.com',
'custom:document_type_id': '1',
'custom:country_code': 'CO'
},
newDeviceUsed: false
},
response: {}
}
How can I get in my lamda function the status of his account? (the status is Disabled)

You can use AdminGetUser method to pass the username and user pool ID and get their details as response. This method also returns if the user is enabled or disabled in the form of boolean. eg: Enabled : True

Related

Invalid credentials postman

I hard coded the users in my seed file
I can view the the users in the database
But when i try to test the details in the database i get an error "invalid credentials"
I don't know why it says that when the user is already in the database
This is the seeds file
const noPassword = "$2a$12$ZQwXBTq7UMgmugpy5zz9SOdG4JvEa3Bj5MofQl9fIMFb1wTSGU9.C"; exports.seed = function (knex) { // Deletes ALL existing entries return knex("users") .truncate() .then(function () { // Inserts seed entries return knex("users").insert([ { email: "danielAsuquo15#gmail.com", first_name: "Daniel", last_name: "Asuquo", password:noPassword, }, { email: "josiahdamiwilliams#gmail.com", first_name: "josiah", last_name: "williams", password:noPassword, }, ]); }); };

Should a new Collection be created upon Model.create()

Am working with mongoose and have two models. The User model and the Service model, when a user logs in the method will findOne() user if one exists or create() a new user based on the what's passed in from req.body.
My Service Schema is like this:
const serviceSchema = new mongoose.Schema({
name: {
type: String,
default: 'contentEditor'
},
display: {
type: String,
default: 'Content Editor'
},
accessLevel: {
type: Number,
min: 0,
max: 4,
default: 4
}
});
My User Schema is a bit bigger, I've removed some of the field/value pairs but the part where I embed the Service Schema looks like this:
const userSchema = new mongoose.Schema(
{
email: {
type: String,
required: [true, 'Must have a email address'],
trim: true,
unique: true,
},
firstName: {
type: String,
},
lastName: {
type: String,
},
services: {
type: [serviceSchema],
ref: 'Services',
default: [serviceSchema],
},
},
);
When I hit the /api/v1/login endpoint a new user will be created with the Service document correctly but within the Mongoose database only a User collection exists. How do I make it so that both a Users collection and Services collection are created?
Edit: Below is the function that I create/find the user with when they login. When an existing User is found, by their email it will return that user if the user is not found then it will create a new one...
Both behaviours are as expected including adding the Services to the newly created User. What isn't expected is that only ONE collection is added to the DB.
const login = catchAsync(async ({ body: { email, password } }, res, next) => {
if (!email || !password) {
return next(new AppError('Please provide email and password', 400));
}
const { Success } = await webApi(email, password);
const mongoUser = await User.findOne({ email });
if (Success && mongoUser) {
return createSendtoken(mongoUser, 200, res);
}
if (Success && !mongoUser) {
const newUser = await User.create({ email });
return createSendtoken(newUser, 201, res);
}
return next(new AppError('User not found', 404));
});
Make sure you are making the serviceSchema a mongoose model.
const Services = mongoose.model('Service', serviceSchema)
You also have to save it using mongooses model.save() function

How to set a session from a GraphQL Resolver in NestJS?

I have a GraphQL mutation that handling authentication for my NestJS app. It's set a login information inside an express-session. This method works fine in 'vanilla express'. But, when i do this in NestJS, the session is not changed. I wonder where did i go wrong?
I've tried using guard to set the express-session, but it doesnt work too.
#Mutation('doLogin')
async doLogin(#Parent() parent: any, #Args() args: any, #Context() context: any, #Info() info: any) {
const login: Login = await authenticationService.doLogin(args.loginInput);
context.session.session.login = login;
console.log(context.session.session);
return login;
}
When i check the terminal, the session is changed just like i wanted
Session {
cookie:
{ path: '/',
_expires: 2019-07-15T04:48:50.599Z,
originalMaxAge: 3600000,
httpOnly: true,
secure: true },
login:
Login {
id: 1,
username: 'admin',
name: 'admin',
email: 'admin#email.com',
role: 'ADMIN',
active: true
}
But when it's leave the resolver, the login part is not there anymore

AWS Cognito - User stuck in CONFIRMED and email_verified = false

How do I go about email verifying a user who is CONFIRMED yet email_verified is false?
The scenario is roughly an agent signs up user on their behalf, and I confirm the user through the admin call adminConfirmSignUp. At that point, the user cannot change their password because of the email_verified flag being false.
I can't call resendConfirmationCode because the user is already confirmed.
I can't call forgotPassword because the email_verified flag is false.
The best I can think of is deleting the user account and calling signUp (prompting them to re-enter their password or a new password), hence recreating their account.
Using the AWS CLI you can update the email_verified attribute:
aws cognito-idp admin-update-user-attributes
--user-pool-id eu-west-xxxxxx
--username xxxxyyyy#example.com
--user-attributes Name=email_verified,Value=true
Here is the official documentation: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cognito-idp/admin-update-user-attributes.html
You can change email_verified, phone_number_verified and other attributes by calling adminUpdateUserAttributes without any lambdas and triggers:
'use strict'
var AWS = require('aws-sdk')
AWS.config.update({
accessKeyId: 'YOUR_ACCESS_KEY_HERE',
secretAccessKey: 'YOUR_SECRET_ACCESS_KEY_HERE',
region: 'us-east-1' // change region if required
});
var CognitoIdentityServiceProvider = AWS.CognitoIdentityServiceProvider
var client = new CognitoIdentityServiceProvider({
apiVersion: '2016-04-19',
region: 'us-east-1' // change region if required
})
client.adminUpdateUserAttributes({
UserAttributes: [{
Name: 'phone_number_verified',
Value: 'true'
}, {
Name: 'email_verified',
Value: 'true'
}
// other user attributes like phone_number or email themselves, etc
],
UserPoolId: 'COGNITO_USER_POOL_ID_HERE',
Username: 'USERNAME'
}, function(err) {
if (err) {
console.log(err, err.stack)
} else {
console.log('Success!')
}
})
Currently, Cognito does not allow an external agent to update the email_verified and phone_verified attributes on behalf of the user. The only way these can be marked as true is through a code verification process which can be done by the end user. The exception to this is with admin level APIs, as answers below describe, but those shouldn't be done from client side.
The process is this: user signs-in and gets an access token. They then call GetUserAttrbuteVerificationCode API with the attribute they want to verify. This will deliver a code to the user, which can be used by calling VerifyUserAttribute which will flip the attribute as verified.
You can now programmatically set email_verified to true using the Pre-Signup lambda trigger and modifying the returned event with event.response.autoVerifyEmail = true;
It's not in the docs yet but referenced on this github issue. Also read working with cognito lambda triggers.
Here is the Another Approach you can use to create users by Agents.
You can Use AdminCreateUser on the Behalf of user. By calling this API user will be created with a temp Password which will be sent to the user Email Address. (i.e. User will be in Force_Change_Password state). Now use RespondToAuthChallenge API to change the Password.
Note: You need to set "email_verified" attribute in attribute List. to make sure user email will be verified.
Here is the Code Example in NodeJS:
var params = {
UserPoolId: process.env.userPoolId, /* required */
Username: email,//'STRING_VALUE', /* required */
DesiredDeliveryMediums: [
"EMAIL",
/* more items */
],
ForceAliasCreation: false,
UserAttributes: [{
Name: 'email_verified',
Value: 'True'
},/* any other Attributes*/],
};
cognitoidentityserviceprovider.adminCreateUser(params, function (err, data) {
if (err) {
console.log(err, err.stack);
reject(err); // an error occurred
}
else {
console.log(data);
resolve(data);
}// successful response
});
});
It was giving an error message: 'No email provided but email_verified was true', code: 'InvalidParameterException'.
So I added also email attribute into attributes list.
const params = {
UserPoolId: this.userPoolId /* required */,
Username: username /* required */,
TemporaryPassword: password,
DesiredDeliveryMediums: ['EMAIL'],
ForceAliasCreation: false,
UserAttributes: [
{
Name: 'email_verified' /* required */,
Value: 'true',
},
{
Name: 'email' /* required */,
Value: email,
},
],
};
then create the user with these params
cognitoidentityserviceprovider.adminCreateUser(
params,
(err, data) => {
console.log(data);
if (err) {
console.log(err);
reject(err);
throw new BadRequestException(err);
}
// an error occurred
else resolve(data); // successful response
},
);
Trigger on pre-registration this lambda function (Node.js v6):
exports.handler = function(event, context) {
event.response.autoConfirmUser = true;
event.response.autoVerifyEmail = true;
event.response.autoVerifyPhone = true;
context.done(null, event);
};
Using the "Configure test event" you can test it first with this payload
{
"version": 1,
"triggerSource": "PreSignUp_SignUp",
"region": "<region>",
"userPoolId": "<userPoolId>",
"userName": "<userName>",
"callerContext": {
"awsSdk": "<calling aws sdk with version>",
"clientId": "<apps client id>"
},
"request": {
"userAttributes": {
"email": "usertestsns06#yopmail.com"
},
"validationData": {
"k1": "v1",
"k2": "v2"
}
},
"response": {
"autoConfirmUser": false,
"autoVerifyEmail": false,
"autoVerifyPhone": false
}
}
Now when you create the user from the API those verifications flags should be true.
verify user email on aws cognito with python using boto3
response =client.get_user_attribute_verification_code(AccessToken='eyJraWQiOiJtTEM4Vm......',AttributeName='email')
response = client.verify_user_attribute( AccessToken='eyJraWQiOiJtTEM......', AttributeName='email', Code='230433')
Here is the Official Documentation.
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp.html

How can I override builtin login method in Loopback?

I've created a new User model, based on builtin one. I'm trying this:
module.exports = function(TiUser) {
TiUser.on('dataSourceAttached', function(obj) {
var login = TiUser.login;
TiUser.login = function(credentials, include, cb) {
var result = login.apply(this, credentials);
// Do my stuff
cb(null, my_data);
};
});
};
But I can't get it working... What is wrong? or how could this be done right?
Thanks
You may want to consider adding an afterRemote() hook to login(). Now you can achieve to add role( using Role model ) to user. For example:
TiUser.afterRemote('login', function(ctx, next) {
//add role to the user.
next();
});
At the end I've created a new method instead of overriding a current one:
module.exports = function(TiUser) {
TiUser.auth = function(credentials, include, fn) {
var self = this;
self.login(credentials, include, function(err, token) {
authInfo = {
token: token
};
fn(err, authInfo);
});
};
TiUser.remoteMethod(
'auth',
{
description: 'Login method with Role data information embedded in return',
accepts: [
{arg: 'credentials', type: 'object', required: true, http: {source: 'body'}},
{arg: 'include', type: ['string'], http: {source: 'query' },
description: 'Related objects to include in the response. ' +
'See the description of return value for more details.'}
],
returns: {
arg: 'accessToken', type: 'object', root: true,
description: 'User Model'
},
http: {verb: 'post'}
}
);
};