How to reject sign-up trigger with GoLang - amazon-web-services

I've successfully created a lambda function using Go for the pre sign-up trigger of AWS Cognito.
My problem is that I'm not being able to deny/reject the user if a custom field is not valid (based on custom logic).
I'm returning an error as described in AWS Cognito trigger's guide:
return event, fmt.Errorf("Invalid value for field 'custom:myField'")
also I've tried this options:
returning an empty event (nil is not allowed for the event):
var emptyEvent events.CognitoEventUserPoolsPreSignup
return emptyEvent, fmt.Errorf("Invalid value for field 'custom:myField'")
changing ValidationData in the original event:
event.Request.ValidationData = map[string]string{"custom:myField": "Invalid value for field 'custom:myField."}
return event, fmt.Errorf("Invalid value for field 'custom:myField'")
changing UserAttributes in the original event
event.Request.UserAttributes["email"] = ""
return event, fmt.Errorf("Invalid value for field 'custom:myField'")
All those methods are failing, the user is always created in the User Pool.
What should be the correct way to reject the sign-up request using GoLang lambda function?

Looks like something changed on AWS Cognito Lambda triggers, since today I tried the following source code and it worked as expected:
func handler(event events.CognitoEventUserPoolsPreSignup) (events.CognitoEventUserPoolsPreSignup, error) {
fmt.Println(event)
return event, fmt.Errorf("TESTING LAMBDA ERRORS WITH GOLANG")
}
Also, the previous source code that was not working as expected when I posted this question is currently working (with no changes on my side).

Related

In Aws Lex - using lambda can we change the slot values?

say for example there is a non-required slot present in intent and value I entered on Lex is A and then I need to change the value of slot to B.
It is possible to achieve this through the use of your custom Lambda function.
My suggestion would be to use the sessionAttributes to store the modified slot values. Use your Lambda function to change the slot's raw value and then save this to the sessionAttributes.
Ensure that you set these sessionAttributes correctly on the response from the Lambda function.
Please refer to the developer guide for the full schemas of the request and response formats.
Lambda Function Input Event and Response Format
If you want to edit the raw value, you can do so as well. The below is a snippet from a Python Lambda function that I have supporting a V1 Lex bot:
if first_name is not None:
originalValue = event['currentIntent']['slotDetails']['firstName']['originalValue']
originalValue = originalValue.replace("-"," ")
slot_values["firstName"] = originalValue
I then include the modifed slot_values in the response to Lex:
'dialogAction': {
'type': 'ElicitSlot',
'intentName': ...,
'slots': slot_values,
'slotToElicit': ...,
'message': ...
}
You can modify the response to perform your desired dialog action by setting the correct value for type.

AWS Lambda function context.identity.cognito_identity_id returns null

For a web app, I am making an AWS Lambda function which is triggered by the api gateway. I have the api gateway linked to a cognito user pool so you need to sign in before triggering the function. The "Options" part has no authorization enabled and the "post" method has the cognito user pool as the authorizer. When I press a button on the front end to trigger it, the function runs correctly. My problem is that context.identity.cognito_identity_id always returns a null value and not a sub uuid as expected. I don't know why this is. I tried enabling "Invoke with caller credentials" but when I mouse over the check box is says I can't enable it. This is my current lambda function:
import json
def lambda_handler(event, context):
UniqueUser = context.identity.cognito_identity_id
if not UniqueUser:
UniqueUser = "fail"
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps('Hello from Lambda ' + UniqueUser + "!")
};
How can I make it so that context.identity.cognito_identity_id (or something similar) returns the user's uuid as I believe it should?
Looks like sub and/or email are in event['requestContext']['authorizer']['claims']

AWS Cognito - Custom email message with Lambda trigger being overwritten

I'm using a lambda function to customize confirmation emails with AWS Cognito. My lambda function seems to work fine and looks like this:
exports.handler = async (event, context, callback) => {
const sampleTemplate = `<html>
<body>
<div>${event.request.codeParameter}</div>
<div>${event.userName}</div>
</body>
</html>`
if (event.triggerSource === "CustomMessage_AdminCreateUser") {
event.response.emailSubject = 'Lets hope this works'
event.response.emailMessage = sampleTemplate
console.log(event.response) // Logs look as expected
}
callback(null, event);
};
The problem is that when the emails arrive the message body is being overwritten by the content in the User Pools > Message Customizations tab. The subject line is working fine, but the email body is being overwritten. For example, the cognito settings look like this:
And the emails look like this:
As you can see, the lambda function worked for setting the email's subject line, but not the actual content. I can't find any setting to turn off that content and it can't be left blank... Any help is much appreciated.
For anyone finding this, I was able to find the answer. When using the CustomMessage_AdminCreateUser event, cognito will silently throw an error if you use event.userName in the template. Instead use event.request.usernameParameter and it will work
If after doing everything, your custom email template doesn't show up then check the following:
Verification type is set to "code" not "link". ( Your Pool > General settings > message customizations ) Ref: https://github.com/amazon-archives/amazon-cognito-identity-js/issues/521#issuecomment-358383440
Email HTML template shouldn't exceed more than 20,000 UTF characters. Ref: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-message.html#aws-lambda-triggers-custom-message-example
Check this tutorial - https://medium.com/#hasnat_33856/customize-your-cognito-verification-emails-with-html-pages-using-lambda-function-e6fff7ebfb94
We MUST include both the "{username}" and "{####}" placeholder for the custom template for CustomMessage_AdminCreateUser to work. We can place this ourselves in the html file or via the event object's values for the keys event.request.usernameParameter and event.request.codeParameter respectively.
In summary, the html file for CustomMessage_AdminCreateUser must include these two values:
event.request.usernameParameter (has value "{username}") and
event.request.codeParameter (has value "{####}")

Cognito Custom Message Trigger doesn't have any effect

I am trying to customize the message sent to the user pre-verification by using the custom message trigger, I verified that the data returned from the lambda is valid and the modifications are as I want them to be, however it seems that those changes are not taking any effect as I get the standard verification details to my email
I failed to find any solutions in aws docs, anyone had the same issue ?
package main
import (
"fmt"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
// Handler will handle our request comming from the API gateway
func Handler(event events.CognitoEventUserPoolsCustomMessage) (events.CognitoEventUserPoolsCustomMessage, error) {
if event.TriggerSource == "CustomMessage_SignUp" {
event.Response.EmailMessage = "Welcome to myapp, please click the following link to verify your email, this is a custom message"
event.Response.EmailMessage = fmt.Sprintf(`Please click the link below to verify your email address. https://apigateway.myapp.com/auth/validate?client_id=%s&user_name=%s&confirmation_code=%s`, event.CallerContext.ClientID, event.UserName, event.Request.CodeParameter)
}
return event, nil
}
func main() {
lambda.Start(Handler)
}
It seems that in the cognito panel under message customizations verification type code needs to be checked (not link), after I did that the trigger does change the message
It works also for verification link, but you have to use the code parameter as {##Verify email##} and not {####} in your User Pool - Message customization settings. And then also use {##Verify email##} keyword in your html template.

How to get the HTTP method in AWS Lambda?

In an AWS Lambda code, how can I get the HTTP method (e.g. GET, POST...) of an HTTP request coming from the AWS Gateway API?
I understand from the documentation that context.httpMethod is the solution for that.
However, I cannot manage to make it work.
For instance, when I try to add the following 3 lines:
if (context.httpMethod) {
console.log('HTTP method:', context.httpMethod)
}
into the AWS sample code of the "microservice-http-endpoint" blueprint as follows:
exports.handler = function(event, context) {
if (context.httpMethod) {
console.log('HTTP method:', context.httpMethod)
}
console.log('Received event:', JSON.stringify(event, null, 2));
// For clarity, I have removed the remaining part of the sample
// provided by AWS, which works well, for instance when triggered
// with Postman through the API Gateway as an intermediary.
};
I never have anything in the log because httpMethod is always empty.
The context.httpMethod approach works only in templates. So, if you want to have access to the HTTP method in your Lambda function, you need to find the method in the API Gateway (e.g. GET), go to the Integration Request section, click on Mapping Templates, and add a new mapping template for application/json. Then, select the application/json and select Mapping Template and in the edit box enter something like:
{
"http_method": "$context.httpMethod"
}
Then, when your Lambda function is called, you should see a new attribute in the event passed in called http_method which contains the HTTP method used to invoke the function.
API Gateway now has a built-in mapping template that passes along stuff like http method, route, and a lot more. I can't embed because I don't have enough points, but you get the idea.
Here is a screenshot of how you add it in the API Gateway console:
To get there navigate to AWS Console > API Gateway > (select a resource, IE - GET /home) > Integration Request > Mapping Templates > Then click on application/json and select Method Request Passthrough from dropdown shown in the screenshot above
I had this problem when I created a template microservice-http-endpoint-python project from functions.
Since it creates an HTTP API Gateway, and only REST APIs have Mapping template I was not able to put this work. Only changing the code of Lambda.
Basically, the code does the same, but I am not using the event['httpMethod']
Please check this:
import boto3
import json
print('Loading function')
dynamo = boto3.client('dynamodb')
def respond(err, res=None):
return {
'statusCode': '400' if err else '200',
'body': err.message if err else json.dumps(res),
'headers': {
'Content-Type': 'application/json',
},
}
def lambda_handler(event, context):
'''Demonstrates a simple HTTP endpoint using API Gateway. You have full
access to the request and response payload, including headers and
status code.
To scan a DynamoDB table, make a GET request with the TableName as a
query string parameter. To put, update, or delete an item, make a POST,
PUT, or DELETE request respectively, passing in the payload to the
DynamoDB API as a JSON body.
'''
print("Received event: " + json.dumps(event, indent=2))
operations = {
'DELETE': lambda dynamo, x: dynamo.delete_item(**x),
'GET': lambda dynamo, x: dynamo.scan(**x),
'POST': lambda dynamo, x: dynamo.put_item(**x),
'PUT': lambda dynamo, x: dynamo.update_item(**x),
}
operation = event['requestContext']['http']['method']
if operation in operations:
payload = event['queryStringParameters'] if operation == 'GET' else json.loads(event['body'])
return respond(None, operations[operation](dynamo, payload))
else:
return respond(ValueError('Unsupported method "{}"'.format(operation)))
I changed the code from:
operation = event['httpMethod']
to
operation = event['requestContext']['http']['method']
How do I get this solution?
I simply returned the entire event, checked the JSON and put it to work with the correct format.
If event appears an empty object, make sure you enabled proxy integration for the method. Proxy integration for an HTTP method adds request information into event.
See Use Lambda Proxy integration on API Gateway page.
If you are using API gateway, http method will be automatically passed to the event parameter when the lambda is triggered.
export const handler: Handler<APIGatewayProxyEvent> = async (
event: APIGatewayEvent,
context: Context
): Promise<APIGatewayProxyResult> => {
const httpMethod = event.httpMethod;
...
}