AWS API Gateway 'Access-Control-Allow-Origin' header is not present - python-3.x

So, like many before me, I'm also facing the CORS error with AWS API gateway+Lambda(python) for a POST request.
Let me explain the Homeworks I did.
Followed the links and got a basic idea of how CORS works.
Tried enabling lambda proxy integration and tried without it as well.
During the manual configuration attempt I added the "Access-Control-Allow-Origin":'*' manually in API gateway method configurations.
At all times my lambda function is set to return the headers like below:
'headers': {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
}
Postman is working fine as it worked for most of the people who had issues.
When I check the network traffic in chrome, I get the 'Access-Control-Allow-Origin': '*' as part of the header for OPTIONS. But when POST request has none of these headers I have added in the lambda.
The destination page is hosted in my local and AWS Amplify and both has the same issue.
Few images for reference.
Looking forward to all of your inputs.
Edit:
Adding my lambda code as requested:
import json
import urllib.parse
import boto3
import configparser
import os
import datetime
import json
print('Loading function')
# some more code here...
def lambda_handler(event, context):
logfilename = log(json.dumps(event, indent=2), "Debug")
response = {
'headers': {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
},
"statusCode": 200,
"body": "{\"result\": \"Success.\"}"
}
return response

You need to add "Secure; SameSite=None" to the cookie you send with the lambda response and add withCredentials: true to your axios request.
Important! The cookie will not be accessible with JS inside you app (as it is httpOnly one). But it will be added to external HTTP requests (execute with axios withCredentials: true)

Related

REST API Post method Recursive run returning Different data-probably data with error in Azure Functions

I am using REST API Post method and deployed to Azure functions .The First Run[immediate run post changes and deployment to azure] is success and subsequent runs are showing error in data and counts are not same as the first Run.Following is the code snippet that I am using.
` def __init__(self):
url = "https://login.microsoftonline.com/abcdefgh12345/oauth2/v2.0/token"
payload = 'grant_type=client_credentials&scope=api%AB1234567890CDE%.default'
headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + "ABCDEFG",
'Cookie': 'XYZMANOP'
}
response = requests.request("POST", url, headers=headers, data=payload)
self.auth = response.json()`
Then I am using self.auth in other methods
Why is this happening and what is the solution???PS:When I try the code in local it works like a charm.
I tried extracting the access_token and added it in subsequent functions. But the result is also the same. Also I changed the schedule since access_token is valid only for 3600s and rescheduled to execute post 2 hours.But its returning same result

Python - How to manipulate FastAPI request headers to be mutable?

I am trying to change my request headers in my api code. Its immutable right now oob with fastapi starlette. how can i change it so my request headers are mutable? i would like to add, remove, and delete request headers. i tried to instantiate a new request and directly modify the request using
request.headers["authorization"] = "XXXXXX"
but I get the following error
TypeError: ‘Headers’ object does not support item assignment
Thanks!
I'm assuming you want to do something with the header in a middleware. Because FastAPI is Starlette underneath, Starlette has a data structure where the headers can be modified. You can instantiate MutableHeaders with the original header values, modify it, and then set request._headers to the new mutable one. Here is an example below:
from starlette.datastructures import MutableHeaders
from fastapi import Request
#router.get("/test")
def test(request: Request):
new_header = MutableHeaders(request._headers)
new_header["xxxxx"]="XXXXX"
request._headers = new_header
print(request.headers)
return {}
Now you should see "xxxxx" is in the print output of your request.headers object:
MutableHeaders({'host': '127.0.0.1:8001', 'user-agent': 'insomnia/2021.5.3', 'content-type': 'application/json', 'authorization': '', 'accept': '*/*', 'content-length': '633', 'xxxxx': 'XXXXX'})

Unable to verify Discord signature for bot on AWS Lambda Python 3 (Interactions_Endpoint_URL)

I am attempting to validate the signature for my bot application using discord's "INTERACTIONS ENDPOINT URL" in a lambda function running python 3.7. Using the documentation here under the "Security and Authorization" section, I still seem to be unable to get a valid return on the signature, with the exception being triggered each time. I'm unsure which aspect of the validation is incorrect. I am using AWS API Gateway to forward the headers to the lambda function in order to access them. Any help with pointing me in the right direction would be appreciated.
Edit:
Here is the output of the event in lambda for reference. I removed some of the values for security marked by <>.
{'body': {'application_id': '<AppID>', 'id': '<ID>', 'token': '<Token>', 'type': 1, 'user': {'avatar': '4cbeed4cdd11cac74eec2abf31086e59', 'discriminator': '9405', 'id': '340202973932027906', 'public_flags': 0, 'username': '<username>'}, 'version': 1}, 'headers': {'accept': '*/*', 'content-type': 'application/json', 'Host': '<AWS Lambda address>', 'User-Agent': 'Discord-Interactions/1.0 (+https://discord.com)', 'X-Amzn-Trace-Id': 'Root=1-60a570b8-00381f6e26f023df5f9396b1', 'X-Forwarded-For': '<IP>', 'X-Forwarded-Port': '443', 'X-Forwarded-Proto': 'https', 'x-signature-ed25519': 'de8c8e64be2058f40421e9ff8c7941bdabbf501a697ebcf42aa0419858c978e19c5fb745811659b41909c0117fd89430c720cbf1da33c9dcfb217f669c496c00', 'x-signature-timestamp': '1621455032'}}
import json
import os
from nacl.signing import VerifyKey
from nacl.exceptions import BadSignatureError
def lambda_handler(event, context):
# Your public key can be found on your application in the Developer Portal
PUBLIC_KEY = os.environ['DISCORD_PUBLIC_KEY']
verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY))
signature = event['headers']["x-signature-ed25519"]
timestamp = event['headers']["x-signature-timestamp"]
body = event['body']
try:
verify_key.verify(f'{timestamp}{body}'.encode(), bytes.fromhex(signature))
except BadSignatureError:
return (401, 'invalid request signature')
I was able to diagnose the issue. I was unable to verify the signature because AWS API Gateway was altering the body into JSON before it got to my lambda function. This made the signature verification come up as invalid each time. I solved this by checking Lambda Proxy Integration in the Integration Request section in API Gateway. Lambda Proxy Check Box. This allowed an unaltered body being sent to Lambda, which I could then verify my discord outgoing webhook. Below is my final code.
import json
import os
from nacl.signing import VerifyKey
from nacl.exceptions import BadSignatureError
def lambda_handler(event, context):
PUBLIC_KEY = os.environ['DISCORD_PUBLIC_KEY']
verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY))
signature = event['headers']["x-signature-ed25519"]
timestamp = event['headers']["x-signature-timestamp"]
body = event['body']
try:
verify_key.verify(f'{timestamp}{body}'.encode(), bytes.fromhex(signature))
body = json.loads(event['body'])
if body["type"] == 1:
return {
'statusCode': 200,
'body': json.dumps({'type': 1})
}
except (BadSignatureError) as e:
return {
'statusCode': 401,
'body': json.dumps("Bad Signature")
}

Error calling CF API login one time passcode

I am working with the CF API RESTful services. Trying to get an access token from cloud foundry's UAA API using https://login..../oauth/token web method.
I have verified that headers & body content is correct, but calling the api always returns a 400 error code with message missing grant type.
I have implemented this call in Objective-C, Swift & now Python. All tests return the same result. Here is my code example in Python:
import json
import requests
import urllib
params = {"grant_type": "password",
"passcode": "xxx"
}
url = "https://login.system.aws-usw02-pr.ice.predix.io/oauth/token"
headers = {"Authorization": "Basic Y2Y6", "Content-Type": "application/json", "Accept": "application/x-www-form-urlencoded"}
encodeParams = urllib.parse.urlencode(params)
response = requests.post(url, headers=headers, data=encodeParams)
rjson = response.json()
print(rjson)
Each time I run this, I get the response
error invalid request, Missing grant type
Any help would be greatly appreciated.
Your code mostly worked for me, although I used a different UAA server.
I had to make only one change. You had the Accept and Content-Type headers flipped around. Accept should be application/json because that's the format you want back, and Content-Type should be application/x-www-form-urlencoded because that's the format you are sending.
See the API Docs for reference.
import json
import requests
import urllib
import getpass
UAA_SERVER = "https://login.run.pivotal.io"
print("go to {}/passcode".format(UAA_SERVER))
params = {
"grant_type": "password",
"passcode": getpass.getpass(),
}
url = "https://login.run.pivotal.io/oauth/token"
headers = {
"Authorization": "Basic Y2Y6",
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
}
encodeParams = urllib.parse.urlencode(params)
response = requests.post(url, headers=headers, data=encodeParams)
rjson = response.json()
print(json.dumps(rjson, indent=4, sort_keys=True))
I made a couple other minor changes, but they should affect the functionality.
Use getpass.getpass() to load the passcode.
Set the target server as a variable.
Pretty print the JSON response.
The only other thing to note, is that the OAuth2 client you use must be allowed to use the password grant type. It looks like you're using the same client that the cf cli uses, so if your UAA server is part of a standard Cloud Foundry install that is likely to be true, but if it still doesn't work for you then you may need to talk with an administrator and make sure the client is set up to allow this.

URLFetch does not support granular timeout settings, reverting to total or default URLFetch timeout

We have an application (app-a) that is on python2.7 standard google app engine. We are attempting to do programmatic authentication to access another application (app-b) using service account based on the example here. App-b is on python3.7 standard google app engine.
When we do the iap authenticated call we get the following error in the logs of App-A.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
google_open_id_connect_token)}, **kwargs)
AppEnginePlatformWarning: urllib3 is using URLFetch on Google App Engine sandbox instead of sockets. To use sockets directly instead of URLFetch see https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.
AppEnginePlatformWarning: URLFetch does not support granular timeout settings, reverting to total or default URLFetch timeout.
The requests.request errors with
Exception("Bad response from application: 500 / {'content-type': 'text/html', 'x-cloud-trace-context':
In App-B we are trying to receive the data sent from app-a.
json.loads(request.data)
We get the following error in the logs of app-b.
in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/opt/python3.7/lib/python3.7/json/decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
This leads me to believe that app-a is able to call app-b successfully. But for some reason it is not able to pass the data. Please help.
UPDATE -
Per suggestion to use HTTPlib we tried this.
payload = {
'test_data' : "data_test"
}
payload_json_dumps = json.dumps(payload)
conn = httplib.HTTPConnection(host)
conn.request("POST", path, payload_json_dumps, request_headers)
resp = conn.getresponse()
Added the following to app.yaml.
env_variables:
GAE_USE_SOCKETS_HTTPLIB : 'true'
In App-B we changed to
from flask import request
#app.route('url', methods = ['GET','POST'])
def content_from_client():
if (request.data):
data_received = request.get_json()
We are still not able to get the data on App-B. We get
AttributeError("'NoneType' object has no attribute 'get'")
UPDATE -
Changed the header formation and got it working.
request_headers = {
"Content-Type": 'application/json',
"follow_redirects": False,
"X-Appengine-Inbound-Appid": "app-A.appspot.com",
"Connection": "keep-alive",
'Authorization': 'Bearer {}'.format(google_open_id_connect_token)
}
AppEnginePlatformWarning is raised by urllib3 which is used by the requests library.
Urllib3 provides a pool manager that uses URL Fetch API by default. Sometimes though may not be the best option for your use case. A solution is to use sockets instead. In order to do that you have to configure your app.yamland include the following field:
env_variables:
GAE_USE_SOCKETS_HTTPLIB : 'true'
You may also find this documented in Google documentation.
As of the error on your app-B I would use response.json() method, requests builtin method instead of json.loads() as it detects automatically which decoder to use.
Let me know if this was helpful.
Per suggestion above the following helped solve the issue. Changed to httplib instead of urlfetch.
conn = httplib.HTTPConnection(host)
conn.request("POST", path, payload_json_dumps, request_headers)
resp = conn.getresponse()
Added the following to app.yaml -
env_variables:
GAE_USE_SOCKETS_HTTPLIB : 'true'
Changed header formation to -
request_headers = {
"Content-Type": 'application/json',
"follow_redirects": False,
"X-Appengine-Inbound-Appid": "app-A.appspot.com",
"Connection": "keep-alive",
'Authorization': 'Bearer {}'.format(google_open_id_connect_token)
}

Resources