Enable CORS on API Gateway with Python CDK - python

I have an API Gateway defined in the python cdk that will accept CURL Restful requests to upload / read / delete files from an S3 bucket:
api = api_gw.RestApi(self, "file-api",
rest_api_name="File REST Service")
file = api.root.add_resource("{id}")
get_files_integration = api_gw.LambdaIntegration(handler,
request_templates={"application/json": '{ "statusCode": "200" }'})
post_file_integration = api_gw.LambdaIntegration(handler)
get_file_integration = api_gw.LambdaIntegration(handler)
delete_file_integration = api_gw.LambdaIntegration(handler)
api.root.add_method("GET", get_files_integration, authorization_type=api_gw.AuthorizationType.COGNITO, authorizer=auth)
file.add_method("POST", post_file_integration); # POST /{id}
file.add_method("GET", get_file_integration); # GET /{id}
file.add_method("DELETE", delete_file_integration); # DELETE /{id}
Is it possible to enable CORS on the API Gateway so that it will perform pre-flight checks and allow external access from a localhost on another machine?
I have attempted to use the existing add_core_preflight() method defined in the documentation I can find but believe this may no longer be valid as of CDK 2.0.

Yes, IResource.add_cors_preflight() does exactly this.
You can also specify default CORS config with the default_cors_preflight_options attribute of RestApi.
Here are the examples from the docs. They're in Typescript, but it will work the same in Python.
The following example will enable CORS for all methods and all origins on all resources of the API:
new apigateway.RestApi(this, 'api', {
defaultCorsPreflightOptions: {
allowOrigins: apigateway.Cors.ALL_ORIGINS,
allowMethods: apigateway.Cors.ALL_METHODS // this is also the default
}
})
The following example will add an OPTIONS method to the myResource API resource, which only allows GET and PUT HTTP requests from the origin https://amazon.com.
declare const myResource: apigateway.Resource;
myResource.addCorsPreflight({
allowOrigins: [ 'https://amazon.com' ],
allowMethods: [ 'GET', 'PUT' ]
});

Related

How to add GCP bucket to the Firestore with Python SDK?

I am trying to upload the file to the custom Google Cloud Storage bucket with a Flutter web app.
final _storage = FirebaseStorage.instanceFor(bucket: bucketName);
Reference documentRef = _storage.ref().child(filename);
await documentRef.putData(await data);
The code works fine for a default bucket but fails with a new custom GCP bucket.
Error: FirebaseError: Firebase Storage: An unknown error occurred, please check the error payload for server response. (storage/unknown)
The HTTP POST response causing this error says:
{
"error": {
"code": 400,
"message": "Your bucket has not been set up properly for Firebase Storage. Please visit 'https://console.firebase.google.com/project/{my_project_name}/storage/rules' to set up security rules."
}
}
So apparently, I need to add a new bucket to Firestore and set up access rules before I can upload the file there.
Since these buckets are created automatically by my backend microservice, is there a way to add them to Firestore and set up the rules with Python SDK? Alternatively, is there any other way to upload data to GCP buckets with Flutter besides Firebase Storage?
Thank you.
So far I think this is not possible to be done using an SDK, nevertheless this can done making a request to the Firebase API. Here's how it would be done using curl:
curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
https://firebasestorage.clients6.google.com/v1alpha/projects/[PROJECT_NUMBER]/buckets/[BUCKET_NAME]:addFirebase
So you can make a similar request using requests and creating the token as explained here:
import google.auth
import google.auth.transport.requests
creds, project = google.auth.default()
# creds.valid is False, and creds.token is None
# Need to refresh credentials to populate those
auth_req = google.auth.transport.requests.Request()
creds.refresh(auth_req)
# Now you can use creds.token

add properties to api gateway using python cdk

hi I want to add few properties to my api-gateway code like response body . I have added this using aws panel like this manual configurations done using aws panel
basically want to add a response body of 200 response and it's content type would be application/json and Models will be empty. so any way to do this using cdk python ?
see apigateway.MethodResponse in docs
from aws_cdk import aws_apigateway as apigateway
# model: apigateway.Model
method_response = apigateway.MethodResponse(
status_code="statusCode",
# the properties below are optional
response_models={
"response_models_key": model
},
response_parameters={
"response_parameters_key": False
})

Flask OIDC: oauth2client.client.FlowExchangeError

The Problem:
The library flask-oidc includes the scope parameter into the authorization-code/access-token exchange request, which unsurprisingly throws the following error:
oauth2client.client.FlowExchangeError: invalid_request Scope parameter is not supported on an authorization code access_token exchange request. Scope parameter should be supplied to the authorized request.
The Question:
Is this a configuration problem or a library problem?
My Configurations:
Flask Application:
app.config.update({
'DEBUG': True,
'TESTING': True,
'SECRET_KEY': 'secret',
'SERVER_NAME' : 'flask.example.com:8000',
'OIDC_COOKIE_SECURE': False,
'OIDC_REQUIRE_VERIFIED_EMAIL': False,
'OIDC_CALLBACK_ROUTE': '/oidc/callback',
'OIDC_CLIENT_SECRETS': 'client_secrets.json'
})
oidc = OpenIDConnect(app)
client_secrets.json
{
"web": {
"auth_uri": "http://openam.example.com:8080/openam/oauth2/realms/root/authorize",
"issuer": "http://openam.example.com:8080/openam/oauth2/realms/root/",
"userinfo_uri": "http://openam.example.com:8080/openam/oauth2/realms/root/userinfo",
"client_id": "MyClientID",
"client_secret": "password",
"redirect_uris": [
"http://flask.example.com:8000/oidc/callback"
],
"token_uri": "http://openam.example.com:8080/openam/oauth2/realms/root/token",
"token_introspection_uri": "http://openam.example.com:8080/openam/oauth2/realms/root/introspect"
}
}
Access Manager
For the access manager I use OpenAM. I configured an OpenAM client agent as follows:
Client ID = MyClientID
Client Secret = password
Response Type = code
Token Endpoint Authentication Method = client_secret_post
Redirect URI = http://flask.example.com:8000/oidc/callback
Context:
I use flask-oidc for the logic on the application side and OpenAM for the identity and access management - both applications run in docker containers. When using simple curl commands I can retrieve an authorization grant as well as an authentication token (grant type: Authorization Code Grant). However, using the mentioned library, after logging in to OpenAM and granting authorization to the application (endpoint 'oauth2/authorize'), flask-oidc sends the following GET request:
GET /oidc/callback?code=<some code> \
&scope=openid%20email \
&iss=http%3A%2F%2Fopenam.example.com%3A8080%2Fopenam%2Foauth2 \
&state=<some state> \
&client_id=MyClientID
Which leads to the error mentioned above.
While this does not directly answer the question, the best answer I could find was to use pyJWT or oauthlib instead of using flask-oidc. I found pyjwt was very straightforward in most respects, and there is an excellent tutorial here:
SSO Using Flask Request Oauthlib and pyjwt
I am not sure of this, but because the error is generated by oauth2client, not flask-oidc, it is possible the error is actually just related to the deprecated oathlib2clientlib.
There was a detailed request to mark the entire flask-oidc project as deprecated, but that request was made several years after the flask-oidc project was stopped being maintained. I hope one day flask will roove this link from their site because it is misleading to think that it is a main part of flask.

Redirect from a Python AWS Lambda with AWS Gateway API Proxy

Posting here because I just can't get a redirect working. Using AWS API Gateway linked to a Python Lambda function as a proxy just returns the response and header json. Here is the code
import json
def lambda_handler(event, context):
response = {}
response["statusCode"]=301
response["headers"]=[{"key": 'Location',"value":
'https://www.google.com'}]
data = {}
response["body"]=json.dumps(data)
return response
Any help will be appreciated?
Thanks
Mixed documentation on the web which was confusing. The syntax for specifying the redirect using Location needs to be the following when using Python:
import json
def lambda_handler(event, context):
response = {}
response["statusCode"]=302
response["headers"]={'Location': 'https://www.google.com'}
data = {}
response["body"]=json.dumps(data)
return response
I'll prefix this by saying that when I copied this code into a Lambda function, added an API Gateway to it using the settings that made sense to me, and tested from a browser and curl, I got the correct redirect. Which is expected, the code looks right and conforms to the specification in the documentation.
So I spent some time fiddling with settings in Lambda and in API Gateway to try to break it; plus searching the web to see how others have had it not work.
The general Internet consensus in 2021 (time of original post) is that there was a setting "Use Lambda proxy integration" in the API Gateway that needed to be turned on for API Gateway to interpret the returned JSON correctly, and this was not the default. I can't find that setting in the console today in that format, but when you create an API Gateway "API" you select integrations, the first one in the list is Lambda. Selecting that sets up the integration correctly for interpreting the JSON (in either v1 or v2 format).
If you are working in an older already-configured API Gateway endpoint, I'd suggest looking for the "Use Lambda proxy integration" setting, followed by setting up the API Gateway with the "Lambda" integration setting if it is the new-style interface.
a bit less line, with the same output
def handler(event, context):
response = {
"headers": {"Location": "https://www.google.com", },
"statusCode": 301,
}
return response

How to enable CORS on Google App Engine Python Server?

I am see the following error on Javascript console:
VM31:1 XMLHttpRequest cannot load '<some-url>'. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '<my-url>' is therefore not allowed access.
How do I enable Cross-Origin Resource Sharing with Google App Engine (Python) to access ?
You'll have to use the Access-Control-Allow-Origin http header in your yaml configuration
handlers:
- url: /
...
http_headers:
Access-Control-Allow-Origin: http://my-url
Find more under CORS Support in the docs
For a python script you can add the following line near other self.response.header lines.
self.response.headers['Access-Control-Allow-Origin'] = '*'
This worked for me. The idea was taken from a php issue listed in the notes of another answer.
For those who are wondering how to basically allow all origins for the AppEngine instance in Springboot:
use the #CrossOrigin(origins = "*") annotation on the #RestController classes your project has
or use use the same annotation above for any of your specific resource methods that has one of the #GetMapping, #PostMapping, etc annotations.
No need to set any of the handlers in the app.yaml. Actually it didn't work when changing the app.yaml file as explained in the docs
...
...
...
#SpringBootApplication
#RestController
#CrossOrigin(origins = "*") // <--- here
public class SpringbootApplication {
...
...
#GetMapping("/")
#CrossOrigin(origins = "*"). // <--- or here
public String hello() {
.....
}
}
If you want to serve a script, you cannot use Jeffrey Godwyll's answer, unfortunately. The documentation, somewhat hidden in the second sentence of the http_headers states: "If you need to set HTTP headers in your script handlers, you should instead do that in your app's code."
Another possibility is to allow your app to handle pre-flight requests by "prematurely" returning the headers. GOTCHA: If you are building a POST endpoint, make it so that it returns the allow cross site origin request headers on everything BUT your desired request method. Sometimes there may be a pre-flight GET as well (for some odd reason):
from flask import Flask, request
HEADERS = {
"Access-Control-Allow-Origin": "*",
}
app = Flask(__name__)
#app.route("/", methods=["GET", "POST"])
def main():
if request.method != "POST":
return ("", 204, HEADERS)
return "After the POST"
If you are building an app for GET only, you can instead write if request.method == "OPTIONS":..., like in the Cloud Functions documentation

Categories

Resources