AWS Cognito forgot_password Python call - strange behavior - amazon-cognito

Function code:
import json
import boto3
import botocore.exceptions
import hmac
import hashlib
import base64
import uuid
USER_POOL_ID = 'us-east-X_XXX'
CLIENT_ID = 'XXXXXXXXXX'
CLIENT_SECRET = 'XXXXXXXXXXXXX'
def get_secret_hash(username):
msg = username + CLIENT_ID
dig = hmac.new(str(CLIENT_SECRET).encode('utf-8'),
msg=str(msg).encode('utf-8'),
digestmod=hashlib.sha256).digest()
d2 = base64.b64encode(dig).decode()
return d2
def lambda_handler(event, context):
for field in ["username"]:
if not event.get(field):
return {"error": False, "success": True, 'message': f"{field} is not present", "data": None}
client = boto3.client('cognito-idp')
username = event['username']
try:
print('username - ', username)
response = client.forgot_password(
ClientId=CLIENT_ID,
SecretHash=get_secret_hash(username),
Username=username,
)
except client.exceptions.UserNotFoundException:
return {"error": True, "success": False, "message": "Username doesnt exists"}
except client.exceptions.InvalidParameterException:
return {"error": True, "success": False, "data": None, "message": f"User <{username}> is not confirmed yet"}
except Exception as e:
return {"error": True, "success": False, "message": f"Unknown error {e.__str__()} "}
print(response)
return {"error": False, "success": True, "message": f"Please check your Registered email id for validation code", "data": None}
It contains several redundant print statements for debugging.
I call the function:
event = {"username": "exists_in_user_pool_OK"}
handler_response = lambda_handler(event, {})
print(handler_response)
When I submit the real username everything is OK.
It is expected that if I submit the name of a non-existent user, an exception will be thrown. However, when I try it, no exception is thrown. The function seems to work fine and even sends a confirmation code somewhere.
Example 1:
username - non_existent
{'CodeDeliveryDetails': {'Destination': 'n***#y***.com',
'DeliveryMedium': 'EMAIL', 'AttributeName': 'email'},
'ResponseMetadata': {'RequestId':
'87a0b1af-5322-46a2-bf7b-a1afed2639f1', 'HTTPStatusCode': 200,
'HTTPHeaders': {'date': 'Wed, 10 Nov 2021 13:55:51 GMT',
'content-type': 'application/x-amz-json-1.1', 'content-length': '104',
'connection': 'keep-alive', 'x-amzn-requestid':
'87a0b1af-5322-46a2-bf7b-a1afed2639f1'}, 'RetryAttempts': 0}}
{'error': False, 'success': True, 'message': 'Please check your
Registered email id for validation code', 'data': None}
Example 2:
username - some_more_non_existent_user
{'CodeDeliveryDetails': {'Destination': 's***#g***.com',
'DeliveryMedium': 'EMAIL', 'AttributeName': 'email'},
'ResponseMetadata': {'RequestId':
'9b552993-850a-4523-9a88-4160eb5a112c', 'HTTPStatusCode': 200,
'HTTPHeaders': {'date': 'Wed, 10 Nov 2021 14:05:11 GMT',
'content-type': 'application/x-amz-json-1.1', 'content-length': '104',
'connection': 'keep-alive', 'x-amzn-requestid':
'9b552993-850a-4523-9a88-4160eb5a112c'}, 'RetryAttempts': 0}}
{'error': False, 'success': True, 'message': 'Please check your
Registered email id for validation code', 'data': None}
What's going on here? Why isn't an exception thrown?
'Destination': 'n***#y***.com'
'Destination': 's***#g***.com'
What is it? Why did it change?
How do I make the function to throw an exception if the user is not in the User Pool?

Related

React Native fetch for HTTP2 endpoint can not get body

I use React Native fetch to POST to endpoint which is AWS Lambda. By default it's HTTP/2. That works perfectly fine with curl:
% curl -X POST https://yyyyyy.execute-api.eu-central-1.amazonaws.com/Test/stripe_payment -H "x-api-key: xxxxx"
% {"errorCode": "OK", "client_secret": "zzzz"}
But the same from react native:
try {
response = await fetch(`${API_URL}/stripe_payment`, {
method: 'POST',
headers: {
'x-api-key': API_KEY,
},
});
}
catch (error) {
console.error(error);
}
console.log('API response', response);
Returns only Lambda headers, not body:
API response {"_bodyBlob": {"_data": {"__collector": [Object], "blobId": "dce744f2-6755-47e0-9a9d-74921ae64eba", "offset": 0, "size": 100}}, "_bodyInit": {"_data": {"__collector": [Object], "blobId": "dce744f2-6755-47e0-9a9d-74921ae64eba", "offset": 0, "size": 100}}, "bodyUsed": false, "headers": {"map": {"content-length": "100", "content-type": "application/json", "date": "Fri, 11 Nov 2022 19:33:22 GMT", "x-amz-apigw-id": "bc58SFhsFiAFp1A=", "x-amzn-requestid": "fc157dbb-72d2-459e-a391-1ece0ff9680f", "x-amzn-trace-id": "Root=1-636ea381-0c40c8ec31bb9c4f52d0e44b;Sampled=0"}}, "ok": true, "status": 200, "statusText": "", "type": "default", "url": "https://yyyyyy.execute-api.eu-central-1.amazonaws.com/Test/stripe_payment"}
Above response is correct, but it contains only headers, no body.
I do suspect that is because of HTTP/2 binary protocol, looking at some discussions looks like react native did not support it correctly in the past.
Any hints ?
Thanks,
Mark
ok, looks like i have found the answer: https://github.com/facebook/react-native/issues/24520

Customising Axios handling errors

I have an api that in case of errors sends an customized response but axios always shows its own response which is "Request failed with status code 500".
I wonder if there's a way I can receive and handle the api response and not axios's response which is
{"IsSuccess":false,"StatusCode":7,"Message":"User has been registered before"}
What axios returns is:
{
"message": "Request failed with status code 500",
"name": "Error",
"fileName": "http://localhost:8080/js/chunk-vendors.js line 508 > eval",
"lineNumber": 16,
"columnNumber": 15,
"stack": "createError#webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15\nsettle#webpack-internal:///./node_modules/axios/lib/core/settle.js:17:12\nhandleLoad#webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:61:13\n",
"config": {
"url": "http://*******.***/api/v1/User/Create",
"method": "post",
"data": "{\"fullName\":\"aldeonaldeon\",\"email\":\"aldeon#aldj.caljkf\",\"mobile\":\"lkj;adsf;lk\",\"userName\":\"aldeon\",\"password\":\"lk;ajdfs;\"}",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=utf-8"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1
}
}
By using validateStatus I could change the range of error status handled by axios:
const instance = axios.create({
validateStatus: function (status) {
return status >= 200 && status < 501
},
})

Getting values from postman x-www-form-urlencoded to flask-restful

In raw posting, I can get the values of JSON with this below:
[
{
"username": "paul",
"password": "paul1"
},
{
"username": "paul2",
"password": "paul12"
},
{
"username": "paul3",
"password": "paul14"
}
]
And my flask code:
class CreateUser(Resource):
def post(self):
try:
conn = None
json_dict = request.get_json(force=True, silent=True)
x = len(json_dict)
name = str(json_dict[0]['username'])
print(x)
return name
except Exception as e:
x = str(e)
x.replace('\n', '')
return {'status' : 'failed', 'message' : str(x)}
finally:
if conn is not None:
conn.close()
How can I make a POST request in postman with x-www-form-urlencoded selected? I'm getting an error in postman. Also, what code can you suggest to get multiple values in json with x-www-form-urlencoded selected? thanks in advance.

Axios Request Does Not Return a Token

i'm trying to apply token for my request. So i tried to console.log the result of the request, and cannot find any token there inside the object array.
Object {
"config": Object {
"adapter": [Function xhrAdapter],
"data": "ktp=3578270708950002&member=199508070003",
"headers": Object {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/x-www-form-urlencoded",
},
"maxContentLength": -1,
"method": "post",
"timeout": 0,
"transformRequest": Object {
"0": [Function transformRequest],
},
"transformResponse": Object {
"0": [Function transformResponse],
},
"url": "http://103.53.10.122/mobile/LoginCheck.php",
"validateStatus": [Function validateStatus],
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
},
"data": Array [
Object {
"status": "67457",
},
],
"headers": Object {
"connection": "keep-alive",
"content-type": "text/html; charset=UTF-8",
"date": "Fri, 22 Dec 2017 05:38:21 GMT",
"server": "nginx",
"transfer-encoding": "chunked",
"vary": "Accept-Encoding",
},
"request": XMLHttpRequest {
"DONE": 4,
"HEADERS_RECEIVED": 2,
"LOADING": 3,
"OPENED": 1,
"UNSENT": 0,
"_aborted": false,
"_cachedResponse": undefined,
"_hasError": false,
"_headers": Object {
"accept": "application/json, text/plain, */*",
"content-type": "application/x-www-form-urlencoded",
},
"_incrementalEvents": false,
"_lowerCaseResponseHeaders": Object {
"connection": "keep-alive",
"content-type": "text/html; charset=UTF-8",
"date": "Fri, 22 Dec 2017 05:38:21 GMT",
"server": "nginx",
"transfer-encoding": "chunked",
"vary": "Accept-Encoding",
},
"_method": "POST",
"_requestId": null,
"_response": "[{\"status\":\"67457\"}]",
"_responseType": "",
"_sent": true,
"_subscriptions": Array [],
"_timedOut": false,
"_trackingName": "unknown",
"_url": "http://103.53.10.122/mobile/LoginCheck.php",
"readyState": 4,
"responseHeaders": Object {
"Connection": "keep-alive",
"Content-Type": "text/html; charset=UTF-8",
"Date": "Fri, 22 Dec 2017 05:38:21 GMT",
"Server": "nginx",
"Transfer-Encoding": "chunked",
"Vary": "Accept-Encoding",
},
"responseURL": "http://103.53.10.122/mobile/LoginCheck.php",
"status": 200,
"timeout": 0,
"upload": XMLHttpRequestEventTarget {},
"withCredentials": true,
},
"status": 200,
"statusText": undefined,
}
Can someone point me how to add token to authenticate, because i'm still confuse about the concept even after reading it. So if i'm not mistaken, i should do the following in order:
Generate the token when user successfully login
Save the token in local storage
Use the token for each request (How does the backend check the validity of the token?)
Any help would be appreciated
Depending on the way the backend handles API requests you should either use axios.get and append the token to the URL or use axios.post and pass a object as body to the method with your token.
E.g.
axios.post('http://103.53.10.122/mobile/LoginCheck.php', {
username: "test",
password: "1234"
})
.then((res) => {
console.log(res);
/*
In this example I assume that res.data has the token returned from the backend
The res.data should look like this then:
{
token: "1234"
}
*/
let token = res.data.token;
AsyncStorage.setItem("token", token);
})
.catch((err) => {
console.log(err);
});
To use the token for each request save it in AsyncStorage for persistent storage or in the redux state if you are using redux.
On the server side you could generate a JSON web token which contains all data you need for authenticating the user and validating it with the data stored in a database. Due to the fact that you are using PHP I can recommend you this introduction to JSON web tokens in combination with PHP: https://www.sitepoint.com/php-authorization-jwt-json-web-tokens/

how to return a validation property on a hapi reply like the way Joi library does it

I have my own custom validation on a property and I'd like to return a 400 response that is similar to the the JOI.validation that is returned on the other fields. This means that in addition to the error and message I'd like to return a validation property as well - so that the client can know which field to highlight.
So, instead of this
{
"statusCode": 400,
"error": "Bad Request",
"message": "phone validation error: invalid phone number"
}
I'd like to reply with this
{
"statusCode": 400,
"error": "Bad Request",
"message": "phone validation error: invalid phone number"
"validation": {
"source": "payload",
"keys": [
"phone"
]
}
How do I add the validation the the hapi reply?
I've been doing this - which has not been working
e.validation =
{
source: "payload",
keys: [
"phone"
]
}
reply(Boom.badRequest(e));
I'm also assuming that I cannot have custom validators for Joi, otherwise I would have just extended Joi. But, is there a Joi validation error type or object I can use in the reply to get Joi like object structure in my response.
BTW, my phone validation is not a simple regex and has special cases so I cannot use the Joi built in regex validator.
If you inspect the object returned by boom.badRequest('some message'), you'll get:
{ data: null,
isBoom: true,
isServer: false,
output:
{ statusCode: 400,
payload:
{ statusCode: 400,
error: 'Bad Request',
message: 'some message' },
headers: {} },
reformat: [Function] }
So you actually need to do something like
var errObj = Boom.badRequest(e);
errObj.output.payload.validation =
{
source: "payload",
keys: [
"phone"
]
}
reply(errObj);
Try this:
var errObj = Boom.badRequest(e);
errObj.validation =
{
source: "payload",
keys: [
"phone"
]
}
reply(errObj);