How to fetch user information from aws SSO - node.js

I am trying to fetch the users using my VPN setup. So in the AWS SSO / AWS IAM Identity Center, I have a group called __ with 2 users. Both users have attribute information such as email, phone number, first name.. etc.
As I try to fetch the information, on lambda I use the below code.
const AWS = require("aws-sdk");
async function getUserInformation(){
const identityStore = new AWS.IdentityStore({
accessKeyId: process.env.accessKeyId,
secretAccessKey: process.env.secretAccessKey,
region: process.env.region,
});
let params = {
IdentityStoreId: process.env.identityStoreId
};
const userIdPromise = () => {
return new Promise((resolve, reject) => {
identityStore.listUsers(params, (err, data) => {
if (err) {
return reject(err);
}
return resolve(data.Users);
});
});
};
const userInfoPromise = (Users) => {
const usersInfo = [];
return new Promise((resolve, reject) => {
Users.map(({ UserId }) => {
let params = {
IdentityStoreId: process.env.identityStoreId,
UserId: UserId,
};
identityStore.describeUser(params, function (err, data) {
if (err) {
return reject(err);
}
usersInfo.push(data);
if (usersInfo.length == Users.length) {
return resolve(usersInfo);
}
});
});
});
};
const Users = await userIdPromise();
const usersInfo= await userInfoPromise(Users);
return usersInfo;
}
exports.handler = async (event) => {
try {
const users = await getUserInformation();
return users;
} catch (err) {
return err;
}
};
The output i get from this is the following response, but I was expecting a response as in the documentation .
Response
[
{
"UserName": "jakob-2",
"UserId": "a34498c2-4011-70bd-1a24-*"
},
{
"UserName": "JakobCI",
"UserId": "2334c812-6051-70cd-a983-*"
}
]
i hope you can help as i have now tried for 3 days to get the correct responce information

Related

(nodejs gmail-api) Store messages in array?

I have a function that prints in the console all the unread messages. I'd like to store these messages in an array that I could use again later in the code. Is that possible ?
async function listMessages(auth, query) {
return new Promise((resolve, reject) => {
const gmail = google.gmail({version: 'v1', auth});
gmail.users.messages.list(
{
userId: 'me',
q: query,
}, (err, res) => {
if (err) {
reject(err);
return;
}
if (!res.data.messages) {
resolve([]);
return;
}
console.log(res.data.messages);
resolve(res.data.messages);
}
);
})
;}```
myNewMessage as your message:
var myArray = [];
myArray.push(myNewMessage)

upload files to aws s3 from node js

I am using aws sdk to uplod user input image and then get the image link from aws and i will store the link in mongoDB. In that case when i run .upload() it is async.
const imgSRC = [];
for (let img of image) {
console.log(img);
const params = {
Bucket: process.env.AWS_BUCKET,
Key: `${img.originalname}_${userID}`,
Body: img.buffer,
};
s3.upload(params, (error, data) => {
if (error) {
console.log(error);
res.status(500).json({ msg: "server error" });
}
imgSRC.push(data.Location);
console.log(imgSRC);
});
}
const newPost = new Post({
userID: userID,
contentID: contentID,
posts: [
{
caption: caption,
data: imgSRC,
},
],
});
const post = await newPost.save();
in that case when the .save to mongodb run, there is no imgLinks from aws yet. How can i fix that things.
I've already tried async and it didn't work
You need to use Promise.all() in this manner
const uploadImage = (obj) => {
return new Promise((resolve, reject) => {
const params = {
Bucket: process.env.AWS_BUCKET,
Key: obj.key,
Body: obj.body,
}
s3.upload(params, (error, data) => {
if (error) {
console.log(error);
return reject(error);
}
return data;
});
})
}
const mainFunction = async () => {
const promises = [];
for (let img of image) {
const options = {
key: `${img.originalname}_${userID}`,
body: img.buffer
};
promises.push(uploadImage(options));
}
const result = await Promise.all(promises);
const imgSRC = result.map((r) => { return r.Location });
return imgSRC;
}
If you use await on s3.upload method you should remove the callback for this method.
try {
const data = await s3.upload(params);
imgSRC.push(data.Location);
console.log(imgSRC);
} catch(e) {
console.log(error);
res.status(500).json({ msg: "server error" });
}
Let me know if it works.

Node Lambda returns null for AWS console

The following code works great locally, but after deploying it to AWS Lambda and running it my records are not saving to DynamoDB and I'm getting a return of null from Lambda.
I know it's not a permissions issue with the Lambda execution role because I can successfully insert one individual record into DynamoDB from the AWS console.
I think the issue has to do with the .forEach loop and how the aws-sdk works. I'm not sure I'm completely wrapping my head around how to properly use JavaScript promises with Lambda. Any help is greatly appreciated!
module.exports.handler = async event => {
const getItems = () => {... // return items //...}
const addToDb = (items) => {
items.forEach(item => {
var params = {
Item: {"id": {S: item.id}, "title": {S: item.title}},
ReturnConsumedCapacity: "TOTAL",
TableName: "my-table"
};
dynamodb.putItem(params, (err, data) => {
if (err) console.log(err, err.stack);
else console.log(data);
});
});
};
const getItemsPromise = new Promise((resolve) => {
const items = getItems();
const itemsAddedToDb = addToDb(items);
resolve(itemsAddedToDb);
});
return getItemsPromise
.catch(err => console.log(err));
};
This should work!
exports.handler = (event) => {
const getItems = () => {...} // assuming getItems returns promise
const addToDb = (items) => {
asyncForEach(items, async (item) => {
const params = {
Item: {
id: {
S: item.id
},
title: {
S: item.title
}
},
ReturnConsumedCapacity: 'TOTAL',
TableName: 'my-table'
}
await dynamodb.putItem(params, (err, data) => {
if (err) console.log(err, err.stack)
else console.log(data)
})
})
}
const getItemsPromise = new Promise(async (resolve) => { // rule eslintno-async-promise-executor - use then instead
const items = await getItems()
const itemsAddedToDb = await addToDb(items)
resolve(itemsAddedToDb)
})
const asyncForEach = async (array, callback) => {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array)
}
}
return getItemsPromise.catch((err) => console.log(err))
}
Notice:
async for export.handler has no use. use async only if function has await inside it.
async await doesn't support for forEach try for loop instead

async/await for aws sdk function

I am using a custom auth challenge to get the otp as response, with below code I am able to get the OTP. But, instead of promise how can I use async/await to get the response from intiateAuth.
const params = {
AuthFlow: ".......",
ClientId: "*********",
AuthParameters: {
"USERNAME": req.userName,
}
};
return new Promise((resolve, reject) => {
new AWS.CognitoIdentityServiceProvider().initiateAuth(params, (err, data) => {
if (err) {
console.log("Error in adminInitiateAuth: %s", err.message);
reject(false);
} else {
const otpResponse: IOTPResponseDetails = {
session: data.Session,
userName: data.ChallengeParameters.USERNAME,
}
resolve(otpResponse);
}
});
});
}```
Create an async function. Use "await" inside a try/catch block to capture any errors.
const params = {
AuthFlow: ".......",
ClientId: "*********",
AuthParameters: {
"USERNAME": req.userName,
}
};
// Async function using await
const execute = async(parameters) => {
try {
const data = await new AWS.CognitoIdentityServiceProvider().initiateAuth(parameters);
const otpResponse: IOTPResponseDetails = {
session: data.Session,
userName: data.ChallengeParameters.USERNAME,
};
return otpResponse;
} catch (err) {
console.log("Error in adminInitiateAuth: %s", err.message);
throw new Error(err.message);
}
}
// Call async function with params as argument
await execute(params);

SQS to Lambda + SES

I'm new with Lambda & SQS and I'm trying to create a function to send emails, queued in an SQS service, but I don't understand how to call the process function that contains the send + delete queue methods.
Here bellow I paste my code:
'use strict';
const AWS = require('aws-sdk');
const SQS = new AWS.SQS({ apiVersion: '2012-11-05' });
const Lambda = new AWS.Lambda({ apiVersion: '2015-03-31' });
const ses = new AWS.SES({ accessKeyId: "xxxxxxxx", secretAccesskey: "xxxxxxx/xxxxxxxxx" });
const s3 = new AWS.S3({ apiVersion: "2006-03-01", region: "us-west-2" });
const QUEUE_URL = 'https://sqs.us-west-2.amazonaws.com/xxxxxxx/queue';
const PROCESS_MESSAGE = 'process-message';
function getPieceOfMail (path, mapObj, replace) {
return new Promise(function (resolve, reject) {
s3.getObject({
Bucket: "myBucket",
Key: "myKey/" + path
}, function (err, data) {
if (err) {
reject(err);
} else {
if (replace === true) {
var re = new RegExp(Object.keys(mapObj).join("|"), "gi");
data = data.Body.toString().replace(re, function (matched) {
return mapObj[matched.toLowerCase()];
});
resolve(data);
} else {
resolve(data.Body.toString());
}
}
});
});
}
function getRegisterSource (nickname, activate_link) {
var activate_link, pieces;
pieces = [
getPieceOfMail("starts/start.html", {}, false),
getPieceOfMail("headers/a.html", {}, false),
getPieceOfMail("footers/a.html", {}, false),
];
return Promise.all(pieces)
.then(function (data) {
return (data[0] + data[1] + data[2]);
})
.catch(function (err) {
return err;
});
}
function sendEmail (email, data) {
return new Promise(function (resolve, reject) {
var params = {
Destination: { ToAddresses: [email] },
Message: {
Body: {
Html: {
Data: data
},
Text: {
Data: data
}
},
Subject: {
Data: "myData"
}
},
Source: "someone <noreply#mydomain.co>",
};
ses.sendEmail(params, function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
function process(message, callback) {
console.log(message);
// process message
getRegisterSource(event['nickname'], event['user_id'])
.then(function (data) {
return sendEmail(event["email"], data);
})
.catch(function (err) {
console.log("==ERROR==");
callback(err, err);
})
.finally(function () {});
// delete message
const params = {
QueueUrl: QUEUE_URL,
ReceiptHandle: message.ReceiptHandle,
};
SQS.deleteMessage(params, (err) => callback(err, message));
}
function invokePoller(functionName, message) {
const payload = {
operation: PROCESS_MESSAGE,
message,
};
const params = {
FunctionName: functionName,
InvocationType: 'Event',
Payload: new Buffer(JSON.stringify(payload)),
};
return new Promise((resolve, reject) => {
Lambda.invoke(params, (err) => (err ? reject(err) : resolve()));
});
}
function poll(functionName, callback) {
const params = {
QueueUrl: QUEUE_URL,
MaxNumberOfMessages: 10,
VisibilityTimeout: 10,
};
// batch request messages
SQS.receiveMessage(params, (err, data) => {
if (err) {
return callback(err);
}
// for each message, reinvoke the function
const promises = data.Messages.map((message) => invokePoller(functionName, message));
// complete when all invocations have been made
Promise.all(promises).then(() => {
const result = `Messages received: ${data.Messages.length}`;
callback(null, result);
});
});
}
exports.handler = (event, context, callback) => {
try {
if (event.operation === PROCESS_MESSAGE) {
console.log("Invoked by poller");
process(event.message, callback);
} else {
console.log("invoked by schedule");
poll(context.functionName, callback);
}
} catch (err) {
callback(err);
}
};
can somebody throw me some light to this?
Thanks in advice.
UPDATE
After so much misconception, I've decided to start looking on how the example of polling-SQS works provided by AWS.
There I've found that I lacked some basic SQS permissions, but solved now by adding the right policy:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": ["*"]
}]
}
This allows Lambda.invoke() to call process().
When the process(message, callback) is called, if I console.log(message);, it seems that there's no message, although the queue is being cleared by the line SQS.deleteMessage(params, (err) => callback(err, message));
What I was trying was to combine my sendMail function that is currently working with a SQS service so I only have to push each message to the queue.
This is a common requirement where AWS SES has its own limitations in sending emails at once. If these limitations are violated, the SES account will sandbox itself. It seems like you have solved the problem using proper access credentials.
This code contains a Python3 Lambda code that can be used to handle a situation like this, where a Lambda polls from SQS using threading, and sends emails using SES, without exceeding the given limitations.
Link to Github Project.
You can also consider using the new feature in SQS, which is capable of invoking lambdas, when a new message is placed within SQS. But, be careful not to exceed the maximum number of lambda functions within the AWS Account region. (See this document)

Resources