I'm using the apollo-server-lambda module to create a lambda that connects to RDS database. The only way I can properly connect to the RDS is the following
exports.graphqlHandler = function(event, context, callback) {
context.callbackWaitsForEmptyEventLoop = false;
sequelize.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
callback(null, "just stop!");
})
.catch(err => {
console.error('Unable to connect to the database:', err);
callback("error");
});
How can I do this using the Apollo server lambda createHandler method
someone answered my question on github issues.
const server = new ApolloServer({
context: ({ context, event }) => {
context. callbackWaitsForEmptyEventLoop = false;
}
})
https://github.com/apollographql/apollo-server/issues/1479
Related
I am trying to attach an angular application to a .NET core API utilizing the JWT token. At this point i have the local angular app authenticating with Cognito and getting the user account.
I've followed this to get the token attached to the request.
https://medium.com/#umashankar.itn/aws-cognito-hosted-ui-with-angular-and-asp-net-core-5ddf351680a5
Amplify.Configure({
Auth: {
region: 'us-west-2',
userPoolId: 'us-west-MY POOL',
userPoolWebClientId: 'MY APP CLIENT ID'
}
}
});
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
if (request.url.indexOf(environment.api.baseUrl) == 0) {
return this.getToken().pipe(mergeMap(token => {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next.handle(request);
}));
}
return next.handle(request);
}
}
getToken() {
return from(
new Promise((resolve, reject) => {
Auth.currentSession()
.then((session) => {
if (!session.isValid()) {
resolve(null);
} else {
resolve(session.getIdToken().getJwtToken());
}
})
.catch(err => {
return resolve(null)
});
})
);
}
And i can confirm that it is adding the token to the request.
Interesting thing to note is that i'm using the session.getIdToken().getJwtToken() but there also is session.getAccessToken().getJwtToken() and they are different. I can't find anything telling me what the difference is, but i've tried both and they both have the same issue.
For the server side i've followed this answer to setup the .net core site and i can confirm that it is appropriately downloading the keys from /.well-known/jwks.json. It however just keeps rejecting the request with authentication failure.
How to validate AWS Cognito JWT in .NET Core Web API using .AddJwtBearer()
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
// get JsonWebKeySet from AWS
var json = new WebClient().DownloadString(parameters.ValidIssuer + "/.well-known/jwks.json");
// serialize the result
return JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
},
ValidateIssuer = true,
ValidIssuer = $"https://cognito-idp.us-west-2.amazonaws.com/us-west-MYID",
ValidateLifetime = true,
LifetimeValidator = (before, expires, token, param) => expires > DateTime.UtcNow,
ValidateAudience = true,
ValidAudience = "MY APP CLIENT ID"
};
});
app.UseAuthentication();
[HttpGet]
[Authorize]
public IEnumerable<Device> Get()
{
return 'my devices...';
}
The angular app is running at http://localhost:4200 and the .net core is running at https://localhost:44300.
So the question i have is, am i missing some sort of setup in my cognito app client? What am i missing to get the .NET core app to take the JWT?
Turns out i actually did have everything correct as far as Cognito goes.
What i did have was this.
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Which is not the correct order for things to work... this is..
app.UseRouting();
app.UseAuthentication(); <-- Authentication before authorization
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
I created 2 tables in RDS aurora:
test-table in aurora db with values id(PK), tasknumber, status , contactid(FK)
contact-table in same db with values contactid(PK), email, phone
I created a trigger in 'test-table' that whenever a 'status' changes, the trigger should call AWS-Lambda ARN.
The Lambda function and Aurora has all the permissions, and security cleared, still on testing from Lambda I get below image error and on updating the 'status' field manually in aurora(via Workbench Sql query) it shows:
Operation failed: There was an error while applying the SQL script to the database.
ERROR 2013: 2013: Lost connection to MySQL server during query
I have attached my Lambda Node.Js code too.
var AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
const mysql = require('mysql');
var con = mysql.createConnection({
host: 'correct value',
user: 'root',
password: 'correct value',
port: correct value,
database: 'correct value'
});
exports.handler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
var fk = event.contact_id;
console.log('FOREIGN KEY=', fk)
con.connect(function(err) {
if (err) throw err;
var sql = `SELECT * FROM db.contacts where contact_id=${fk}`
con.query(sql, function(err, result) {
if (err) throw err;
var email = result[0].email;
console.log(email);
var sns = new AWS.SNS();
var params = {
Message: email,
Subject: "Test SNS From Lambda",
TopicArn: "arn:correct value"
};
sns.publish(params, function(err, data) {
if (err) console.log(err, err.stack);
else {
console.log(data);
callback(null, 'Success');
}
});
});
});
};
Image1ErrorMySqlWorkbench
Image2ErrorLambdaaws
Also followed for NodeJs package: https://github.com/isaacs
you have to close the connection if you want the instant response otherwise it will take the default time to close the connection, please let me know if makes sense
I'm trying to connect to AWS documentDB from Lambda function but, not able to connect.
MongoClient.connect never calls the callback function connected.
TLS is off on documentDB Cluster. I'm able to connect via mongo shell.
Lambda & documentDB are in same VPC & Security group.
'use strict';
module.exports.search = async (event, context, callback) => {
const MongoClient = require('mongodb').MongoClient;
const url = "mongodb://xxx:xxxx#xxx-db.cluster-xxx.us-east-2.docdb.amazonaws.com:27017";
console.log("Starting");
MongoClient.connect(url,
{
useNewUrlParser: true
},
function(err, client) {
if(err)
throw err;
console.log("Connected");
db = client.db('mydb');
col = db.collection('mycollection');
col.find({}).toArray().then(result => {
console.log(result);
return { statusCode: 200, body: result };
}).catch(err => {
console.log('=> an error occurred: ', err);
return { statusCode: 500, body: 'error' };
});
});
};
Output only prints starting which was consoled before calling Mongo.Connect.
How to identify or debug the issue ?
Just from looking at the current code I am pretty sure your function exit before it is able to complete. Therefore, your callback is not executed
Because MongoClient.connect runs asynchronously
Try to take a look at some resource around async/await/promise and Lambda
https://medium.com/tensult/async-await-on-aws-lambda-function-for-nodejs-2783febbccd9
How to wait for async actions inside AWS Lambda?
I am using the AWS Amplify library with MobileHub.
I have a Cognito User Pool connected, and an API Gateway (which communicates with Lambda functions). I'd like my users to sign before accessing resources, so I've enabled "mandatory sign-in" in MobileHub User Sign-In page, and the Cloud Logic page.
Authentication works fine, but when I send a GET request to my API, I receive this error:
"[WARN] 46:22.756 API - ensure credentials error": "cannot get guest credentials when mandatory signin enabled"
I understand that Amplify generates guest credentials, and has put these in my GET request. Since I've enabled "mandatory signin", this doesn't work.
But why is it use guest credentials? I've signed in -- shouldn't it use those credentials? How do I use the authenticated user's information?
Cheers.
EDIT: Here is the code from the Lambda function:
lambda function:
import { success, failure } from '../lib/response';
import * as dynamoDb from '../lib/dynamodb';
export const main = async (event, context, callback) => {
const params = {
TableName: 'chatrooms',
Key: {
user_id: 'user-abc', //event.pathParameters.user_id,
chatroom_id: 'chatroom-abc',
}
};
try {
const result = await dynamoDb.call('get', params);
if (result.Item) {
return callback(null, success(result.Item, 'Item found'));
} else {
return callback(null, failure({ status: false }, 'Item not found.'));
}
} catch (err) {
console.log(err);
return callback(null, failure({ status: false }), err);
}
}
And these small helper functions:
response.js:
export const success = (body, message) => buildResponse(200, body, message)
export const failure = (body, message) => buildResponse(500, body, message)
const buildResponse = (statusCode, body, message=null) => ({
statusCode: statusCode,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true
},
body: JSON.stringify({
...body,
message: message
})
});
dynamodb.js:
import AWS from 'aws-sdk';
AWS.config.update({ region: 'ap-southeast-2' });
export const call = (action, params) => {
const dynamoDb = new AWS.DynamoDB.DocumentClient();
return dynamoDb[action](params).promise();
}
I'm following the guide "serverless-stack" and was prompt with the same warning message, I was logging in correctly and logging out correctly and did not understand why the warning message.
In my case, in the Amplify.configure I skip to add the identity pool id, and that was the problem, User pools and federated identities are not the same.
(English is not my native language)
Have you tried checking why your SignIn request is being rejected/error prone?
Auth.signIn(username, password)
.then(user => console.log(user))
.catch(err => console.log(err));
// If MFA is enabled, confirm user signing
// `user` : Return object from Auth.signIn()
// `code` : Confirmation code
// `mfaType` : MFA Type e.g. SMS, TOTP.
Auth.confirmSignIn(user, code, mfaType)
.then(data => console.log(data))
.catch(err => console.log(err));
You can try this, then it would be easier for you to debug.
From the suggestions on the aws-amplify issues tracker, add an anonymous user to your cognito user pool and hard code the password in your app. Seems like there are other options but this is the simplest in my opinion.
You have to use your credentials at each request to use AWS Services :
(sample code angular)
SignIn :
import Amplify from 'aws-amplify';
import Auth from '#aws-amplify/auth';
Amplify.configure({
Auth: {
region: ****,
userPoolId: *****,
userPoolWebClientId: ******,
}
});
//sign in
Auth.signIn(email, password)
Request
import Auth from '#aws-amplify/auth';
from(Auth.currentCredentials())
.pipe(
map(credentials => {
const documentClient = new AWS.DynamoDB.DocumentClient({
apiVersion: '2012-08-10',
region: *****,
credentials: Auth.essentialCredentials(credentials)
});
return documentClient.query(params).promise()
}),
flatMap(data => {
return data
})
)
I have this scenario in which a service hosted on IIS must be used by my AWS lambda function. When I try adding it as a service reference, I'm getting "An error occurred while attempting to discover services in the solution: No services found in the solution.. " error. I don't find any issue with the service, and it is working fine.
Is there any link that I'm missing to make my service available to be used by AWS?
If you are using node.js for Lambda then please do like below,
var soap = require('soap');
var url = 'YouServiceURL.svc?wsdl';
var soapOptions = {
forceSoap12Headers: true
};
var soapHeader = {
'wsa:Action': 'http://tempuri.org/MyBinding/MyOperation',
'wsa:To': 'YouServiceURL.svc'
};
exports.handler = function(event, context, callback) {
var params = {
param1: event.param1,
param2: event.param2
};
soap.createClient(url, soapOptions, function(err, client) {
if (err) callback(err);
client.addSoapHeader(soapHeader, '', 'wsa', 'http://www.w3.org/2005/08/addressing');
client.MyOperation(params, function(err, data) {
if (err) callback(err);
callback(null, data);
});
});
}
Please find sample code here