Enable CORS for Cloud Run with Cloud Endpoints v1 - google-cloud-endpoints

I have been following an article on Medium to deploy Cloud Endpoints v1 in front of a Cloud Run service hosting a REST API and everything works well.
I now have a requirement to enable CORS support and I've added the below configuration to my endpoints YAML file but get an error saying "This service does not allow CORS traffic" when my browser tries to make a pre-flight request (I've tested this with Postman too with the same error). I know there's a flag to enable CORS --cors_preset=basic using environment variables but I'm not sure what key to set with. Any ideas or help is appreciated.
Endpoints YAML snipper:
swagger: '2.0'
info:
title: Cloud Endpoints with Cloud Run
description: Testing Cloud Endpoints with Cloud Run
version: 1.0.0
host: endpoint-<hash>-uc.a.run.app
x-google-endpoints:
- name: endpoint-<hash>-uc.a.run.app
allowCors: true
schemes:
- https
produces:
- application/json
Error:
{
"code": 7,
"message": "The service does not allow CORS traffic.",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "service_control"
}
]
}
PS: Thanks Guillaum Blaquiere for the awesome article.
UPDATE:
I ended up testing with an incomplete URL and hence received the above error as my backend service wasn't configured to respond to all pre-flight request URLs. Having fixed this, I now get the below error only on the CORS pre-flight configured URL.
{
"code": 13,
"message": "INTERNAL_SERVER_ERROR",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [
],
"detail": "application"
}
]
}
and logs:
invalid URL prefix in "", client: <CLIENT_IP>, server: , request: "OPTIONS /api/v1/<REMAINING_URL> HTTP/1.1", host: "endpoint-<HASH>-uc.a.run.app"

I would say it's necesary to add ESPv2 Config, I've noticed that the note regarding the ESPv2 config was added since last april, and the Medium document was published on 2019, so I think such required step was not mentioned before.
Later in the same section it's mentioned that the flags for cors are passed by the "--set-env-vars" flag of the deploy command.
You can find more about the ESPv2 Beta startup options in here.

I managed to resolve the issue by defining OPTIONS operations in my YAML file with no security, for each path that I had already defined. See below example YAML file for an endpoint path '/api/v1/hello' with GET and OPTIONS operations defined.
swagger: '2.0'
info:
title: Cloud Endpoints with Cloud Run
description: Testing Cloud Endpoints with Cloud Run
version: 1.0.0
host: endpoint-randomhash-uc.a.run.app
x-google-endpoints:
- name: endpoint-randomhash-uc.a.run.app
allowCors: true
schemes:
- https
produces:
- application/json
x-google-backend:
address: https://backend-randomhash-uc.a.run.app
path_translation: APPEND_PATH_TO_ADDRESS
security:
- auth0_jwk: []
paths:
/api/v1/hello:
get:
summary: Say hello
operationId: helloName
parameters:
- name: "name"
in: "query"
description: "Your name"
type: "string"
responses:
'200':
description: Successful operation
schema:
type: string
options:
summary: CORS pre-flight for say hello
operationId: helloNameOptions
parameters:
- name: "name"
in: "query"
description: "Your name"
type: "string"
responses:
'200':
description: Successful operation
schema:
type: string
security: []
securityDefinitions:
auth0_jwk:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://project.auth0.com/"
x-google-jwks_uri: "https://project.auth0.com/.well-known/jwks.json"
x-google-audiences: "firebase-application-host"
As Sergio pointed out in his comment to a SO question, the other option in my case is to use Firebase Hosting proxy to use the same domain and avoid CORS.

Related

WSO2 APIM 4.1.0 (Linux) : REST API testing fails in Publisher : Invalid URL., RESOURCE = /xxxx HEALTH CHECK URL = xxxx

I'm trying to create a simple REST API with a mock back-end in the publisher and test it in the publisher itself, before publishing it to the Dev portal.
Swagger definition
openapi: 3.0.1
info:
title: TestAPI
version: '1.0'
servers:
- url: /
security:
- default: []
paths:
/getMessage:
get:
parameters: []
responses:
'200':
description: ok
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
x-wso2-application-security:
security-types:
- oauth2
optional: false
components:
securitySchemes:
default:
type: oauth2
flows:
implicit:
authorizationUrl: 'https://test.com'
scopes: {}
x-wso2-auth-header: Authorization
x-wso2-cors:
corsConfigurationEnabled: false
accessControlAllowOrigins:
- '*'
accessControlAllowCredentials: false
accessControlAllowHeaders:
- authorization
- Access-Control-Allow-Origin
- Content-Type
- SOAPAction
- apikey
- Internal-Key
accessControlAllowMethods:
- GET
- PUT
- POST
- DELETE
- PATCH
- OPTIONS
x-wso2-production-endpoints:
urls:
- 'https://run.mocky.io/v3/64df2918-ea8d-4fc9-8e6e-1f57d8b07070'
type: http
x-wso2-sandbox-endpoints:
urls:
- 'https://run.mocky.io/v3/64df2918-ea8d-4fc9-8e6e-1f57d8b07070'
type: http
x-wso2-basePath: /test/1.0
x-wso2-transports:
- http
- https
x-wso2-response-cache:
enabled: false
cacheTimeoutInSeconds: 300
Request (generated from the "Test -> Try it out" section )
curl -X 'GET' \
'https://localhost:8243/test/1.0/getMessage' \
-H 'accept: */*' \
-H 'Internal-Key: [key]'
Response (from postman)
{
"code": "404",
"type": "Status report",
"message": "Not Found",
"description": "The requested resource is not available."
}
APIM Log
[2022-06-07 12:02:06,610] INFO - LogMediator STATUS = Message dispatched to the main sequence. Invalid URL., RESOURCE = /test/1.0/getMessage, HEALTH CHECK URL = /test/1.0/getMessage
NOTE: The sample "PizzaShack" API gets deployed correctly and works fine but when I try to create one from scratch it always gives the Invalid URL error. The request URL seems fine to me, what am I doing wrong ?

Nelmio 4 security definitions index not found

I try to configure nelmio/api-doc-bundle to use Authorization header for my Bearer token.
I configure it in nelmio_api_doc.yaml like this
nelmio_api_doc:
documentation:
info:
title: title
version: 1.0.0
securityDefinitions:
Bearer:
type: apiKey
description: 'jwt from oauth prefixed by `Bearer`'
name: Authorization
in: header
security:
- Bearer: []
areas: # to filter documented areas
path_patterns:
- ^/api(?!/doc$|/doc.json$) # Accepts routes under /api except /api/doc and /api/doc.json
But when i got to the ui doc page I got :
Notice: Undefined index: securityDefinitions
Did someone know how to fix it ?
It was changed in version 4, check this docs https://symfony.com/doc/4.x/bundles/NelmioApiDocBundle/index.html#using-the-bundle

There seems to be a mismatch between last deployed API and actually in-use API

According to Google Cloud Console > Endpoints > Services > Deployment History this is the currently deployed API spec:
swagger: "2.0"
info:
title: "JSON Ingester"
description: "Receive JSON files, transform and load them."
version: "1.0.0"
host: "project-id-123.appspot.com"
schemes:
- "https"
paths:
"/upload":
post:
summary: "ETL JSON file."
security:
- api_key: []
operationId: "upload"
consumes:
- multipart/form-data
parameters:
- in: formData
name: file
type: string
responses:
200:
description: "File uploaded."
schema:
type: string
400:
description: "Error during file upload."
securityDefinitions:
api_key:
type: "apiKey"
name: "apikey"
in: "query"
But the key "apikey" is not accepted - instead it requires "key" which was specified in an openapi.yaml that I deployed few hours ago.
This works while it shouldn't:
$ curl -X POST -F "file=#data/file_6.json" https://project-id-123.appspot.com/upload\?key\=AIzaS...Eaoog
And this doesn't work while it should:
$ curl -X POST -F "file=#data/file_6.json" https://project-id-123.appspot.com/upload\?apikey\=AIzaS...Eaoog
{
"code": 16,
"message": "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "service_control"
}
]
}
Do I have to clear a cache or something?
For deploying the API I use:
gcloud endpoints services deploy "./openapi.yaml"
Any ideas?
What rollout_strategy did you use when you deploy ESP? If not specified, default is "fixed". You should use "managed"
Please also check the generated service config by CLI "gcloud endpoints configs describe". Check its system_parameters filed to see if your new "apikey" is created properly.

Swagger doesn't recognize x-www-urleconded parameters

I had a swagger documentation on version 2.0
where i put the path consumes as application/x-www-urlencoded but when i try to request i receive the following error.
{
"message": "Request validation failed: Parameter (username) is required",
"code": "REQUIRED",
"failedValidation": true,
"path": [
"paths",
"/auth/login",
"post",
"parameters",
"0"
],
"paramName": "username"
}
But i already passed the parameter as we can see on this curl
curl -X POST \
http://localhost:10010/v1/auth/login \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'username=LOGIN&password=MYPASS&userType=employee'
I've used the following Swagger.yaml
Here you are the definition of.
definitions:
UserType: &UserType
type: string
enum: [customer, employee, supplier]
description: >
User Type:
* customer.
* employee.
* supplier.
and here the path which is utilized.
paths:
/auth/login:
# binds a127 app logic to a route
x-swagger-router-controller: "authentication"
x-a127-apply: {}
post:
summary: Try to login
description: Try to login with credencials based on username/password. This API will return all "habitant" information if login were successful.
# used as the method name of the controller
operationId: login
consumes:
- application/x-www-form-urlencoded
tags:
- Auth
parameters:
- name: username
in: formData
description: Username to login.
required: true
type: string
- name: password
in: formData
description: Password to login.
required: true
type: string
format: password
- name: userType
in: formData
required: true
default: customer
<<: *UserType
responses:
"200":
description: Success. If there are attributes with empty values they won´t be returned
schema:
# a pointer to a definition
$ref: "#/definitions/AuthResponse"
"401":
description: Unauthorized
schema:
$ref: "#/definitions/ErrorResponse"
"500":
description: Internal Server Error
schema:
$ref: "#/definitions/ErrorResponse"
"501":
description: Not Implemented
schema:
$ref: "#/definitions/ErrorResponse"
Thanks for any help.
I think it could be related to your middleware. Are you using express?
If so you may add something like this "app.use(express.urlencoded());"
You should take a look in this link:
https://www.npmjs.com/package/express-xml-bodyparser

How to change default swagger.json file path?

I have created Ngnix-Consul Docker setup referred https://github.com/nginxinc/NGINX-Demos/tree/master/consul-template-demo.
And have created many microservices. So All the microservices are accessible only after adding the service name for e.g.
http://example.com/service_name/get_data
All is working fine then I wanted to add swagger for all microservices so tried with below snippet
I am able to access swagger ui by using
http://example.com/service_name/ui
But the problem is I am not able to load swagger.json in that ui as its trying to access swagger.json on below url
http://example.com/swagger.json
but the json file is on
http://example.com/service_name/swagger.json
How can I change the default path of swagger.json?
The applications in microservices are created in python-flask
I have tried below snippet
swagger: "2.0"
info:
description: "Add service"
version: "1.0.0"
title: "Add Service"
contact:
email: "abc#efg.com"
license:
name: "s1.0"
url: "http://sample.com"
host: "abc.efg.com"
tags:
- name: "add service"
description: "service"
- name: "delete service"
description: "data"
schemes:
- "http"
paths:
/service_name/get_data:
and even I have tried to add basePath in the swagger.yaml file
then It did not even open swaggerui
swagger: "2.0"
info:
description: "Add service"
version: "1.0.0"
title: "Add Service"
contact:
email: "abc#efg.com"
license:
name: "s1.0"
url: "http://sample.com"
host: "abc.efg.com"
basePath: "service_name"
tags:
- name: "add service"
description: "service"
- name: "delete service"
description: "data"
schemes:
- "http"
paths:
/get_data:
Update:
from flask import Flask
import connexion
app = Flask(__name__)
app = connexion.App(__name__)
app.add_api('swagger.yaml')
//apis
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8090, debug=True)
Had similar problem myself. The solution for me was to disable path rewrite in the NGINX level, so that the microservice would receive the full url:
Before:
Request:
http://example.com/service_name/get_data
Service sees:
/get_data
After:
Request:
http://example.com/service_name/get_data
Service sees:
/service_name/get_data
Only then you can specify basePath as "service_name" in the swagger.yaml file:
swagger: "2.0"
info:
description: "Add service"
version: "1.0.0"
title: "Add Service"
host: "abc.efg.com"
basePath: "service_name"
If file swagger.json is static in NGINX config you can make alias rule like this:
location ^~ /swagger.json {
alias /path_to/swagger.json;
}

Resources