Flask + uWsgi, endpoints not available over HTTPS - python

I'm running a containerized flask API serving with uwsgi and nginx. Now that I am trying to add SSL to my API I'm having some issues.
According to this answer: nginx with uwsgi and flask shows bad request for https connections only I should not change my uwsgi settings when I have NGINX in front of it.
I'm using flask-restplus which provides swagger. On http://domain/api/ I get my normal Swagger documentation and all my endpoints work fine. On https://domain/api/ I get an empty Swagger-page with "No API definition provided" and none of the end-points are present.
In other words, accessing my flask instance over HTTPS works fine. What I cannot figure out is how to get flask to serve my endpoints over HTTPS instead of HTTP (or preferrably, both).
There are several answers here on SO that adds a context to the app.run() function, but this is only valid when using flask's built-in server, which is nonesense in a prod enviornment where you need SSL.
Here's my server.py:
from flask import Flask
from flask_cors import CORS
from flask_restplus import Api
from chatbot.api.v1.dialogflow import dialog_api as v1_dialog_api
from chatbot.api.v1.web import web_api as v1_web_api
from chatbot.api.v2.api import api as v2_api
app = Flask(__name__)
app.register_blueprint(v1_dialog_api)
app.register_blueprint(v1_web_api)
api = Api(app, version='2.1')
api.add_namespace(v2_api)
CORS(app)
Thanks.

Related

How to change the Redirect URI from HTTP to HTTPS within a FastAPI web app using fastapi_msal?

I am trying to setup Azure AD authentication for a web application using FastAPI. I am using the fastapi_msal python package to do this. The problem I am having is that when I go to the web app, I am able to login, but once i am authenticated, it says the redirect URI that the application is using begins with HTTP. However, Azure requires the redirect uri begin with HTTPS unless running the app locally. Does anyone know how I can change the redirect uri to begin with https instead?
The code for my project pretty much exactly resembles the code from this example project here. However, I have found a similar project using Flask instead of FastAPI. And there is a specific portion of the code that addresses this redirect uri problem:
# This section is needed for url_for("foo", _external=True) to automatically
# generate http scheme when this sample is running on localhost,
# and to generate https scheme when it is deployed behind reversed proxy.
# See also https://flask.palletsprojects.com/en/1.0.x/deploying/wsgi-standalone/#proxy-setups
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
Does anyone know how I can do something like this for a web app using FastAPI instead?
The full source code for the Flask app can be found here

Can't serve swagger on remotely hosted server with different url

I'm trying to serve some simple service using flask and flask_restx (a forked project of flask-restplus, that would be eventually served on AWS.
When it is served, I want to generate swagger page for others to test it easily.
from flask import Flask
from flask_restx import Api
from my_service import service_namespace
app = Flask(__name__)
api = Api(app, version='1.0')
api.add_namespace(service_namespace)
if __name__ == '__main__':
app.run(debug=True)
When I test it locally (e.g. localhost:5000), it works just fine. Problem is, when it is hosted on AWS, because it has a specific domain (gets redirected?) (e.g. my-company.com/chris-service to a container), the document page is unable to find its required files like css and so:
What I've looked and tried
Python (Flask + Swagger) Flasgger throwing 404 error
flask python creating swagger document error
404 error in Flask
Also tried adding Blueprint (albeit without knowing exactly what it does):
app = Flask(__name__)
blueprint = Blueprint("api", __name__,
root_path="/chris-service",
# url_prefix="/chris-service", # doesn't work
)
api = Api(blueprint)
app.register_blueprint(blueprint)
...
And still no luck.
Update
So here's more information as per the comments (pseudo, but technically identical)
Access point for the swagger is my-company.com/chris (with or without http:// or https:// doesn't make difference)
When connecting to the above address, the request URL for the assets are my-company.com/swaggerui/swagger-ui.css
You can access the asset in my-company.com/chris/swaggerui/swagger-ui.css
So I my resolution (which didn't work) was to somehow change the root_path (not even sure if it's the correct wording), as shown in What I've looked and tried.
I've spent about a week to solve this but can't find a way.
Any help will be greatful :) Thanks
Swagger parameters defined at apidoc.py file. Default apidoc object also created in this file. So if you want to customize it you have change it before app and api initialization.
In your case url_prefix should be changed (I recommend to use environment variables to be able set url_prefix flexibly):
$ export URL_PREFIX='/chris'
from os import environ
from flask import Flask
from flask_restx import Api, apidoc
if (url_prefix := environ.get('URL_PREFIX', None)) is not None:
apidoc.apidoc.url_prefix = url_prefix
app = Flask(__name__)
api = Api(app)
...
if __name__ == '__main__':
app.run()
Always very frustrating when stuff is working locally but not when deployed to AWS. Reading this github issue, these 404 errors on swagger assets are probably caused by:
Missing javascript swagger packages
Probably not the case, since flask-restx does this for you. And running it locally should also not work in this case.
Missing gunicorn settings
Make sure that you are also setting gunicorn up correctly as well with
--forwarded-allow-ips if deploying with it (you should be). If you are in a kubernetes cluster you can set this to *
https://docs.gunicorn.org/en/stable/settings.html#forwarded-allow-ips
According to this post, you also have to explicitly set
settings.FLASK_SERVER_NAME to something like http://ec2-10-221-200-56.us-west-2.compute.amazonaws.com:5000
If that does not work, try to deploy a flask-restx example, that should definetely work. This rules out any errors on your end.

Using flask to return server side processed URL

I am hosting my web app on my in-house server using flask (100% accessible online - running on host 0.0.0.0), however, I am trying to use flask to navigate to other locally hosted web apps while browsing from a public network .. is it possible? i.e. onclick() i would like to redirect to URLs that are only available on the local network .. is this possible? I am essentially looking to use my flask app to access my LAN .. thanks!
from flask import Flask, redirect
app = Flask(__name__)
#app.route('/<ip>')//local ip
def redirect_to_link(ip):
return redirect('ip') #would like this to be processed server side and displayed through flask
If the other apps are accessible from extern , yes , you can. If not , you can try serving other app pages by making a request to your flask app first. Flask application should download the webpage for you and then serve it to you externally. Basically you want to make a proxy server.
Try this:
import requests
from flask import Flask, redirect
app = Flask(__name__)
#app.route('/<ip>')//local ip
def redirect_to_link(ip):
return redirect('ip') #would like this to be processed server side and displayed through flask
#local url address to serve examples:
#192.168.1.123:8888/whatyouwant
#192.168.1.123:5656/
#192.168.1.123/somepage
#192.168.1.123
#app.route('/lan/<url>')
def serve_from_lan(url):
r = requests.get("http://"+url, allow_redirects=True)
return r.content
So simple it's not secure but can do the job . then you can think about security.
Also consider that all the addresses present in the application pages in lan should refer to your flask app to be navigable-

flask-CORS extension doesn't work. What am I doing wrong? [duplicate]

This question already has an answer here:
CORS Error: “requests are only supported for protocol schemes: http…” etc
(1 answer)
Closed 3 years ago.
I'm developing a website using Flask, Vuejs and Webpack. The server and the client are separated into two folders and in development I'm running the server using flask run and the client (Vuejs) using yarn serve.
So the frontend is coming together nicely, and I now want to start doing some calls to the server. Since the client is served on port 8080, and the server on port 5000 I'm getting CORS errors. To avoid these I'm trying to use the flask-cors extension.
I've copied exactly what they do in the example:
from flask import Flask
from app.config import Config
from flask_cors import CORS, cross_origin
app = Flask(__name__)
app.config.from_object(Config)
CORS(app)
And instead of the last line I also tried the resource specific example:
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
Unfortunately I'm still getting CORS errors in the frontend.
As far as I understand the server side should send along headers which allow cors, but I'm not actually seeing a request in the browser network tab, I just get an error in the console.
Also, it says only the protocol schemes http [...] https are allowed. I'm doing an ordinary http request, so I'm not sure why that wouldn't work.
And from here I'm kinda lost. Does anybody know how I can debug this?
Ok, nevermind. I now realise I didn't add http:// to my request..
Thanks for listening anyway.. :-)

Force HTTPS for heroku app on google domains

I am using the Automated Certificate Management through heroku in order to implement SSL for my application. My application will successfully connect securely using HTTPS if https://www.myapp.com is used, but if www.myapp.com or myapp.com is used, it defaults to HTTP.
In Heroku the domains that have been added are respectively as follows:
Domain Name: myapp.com, www.myapp.com
DNS Target: myapp.com.herokudns.com, www.myapp.com.herokudns.com
In google domains I have a subdomain forward record as follows:
myapp.com -> https://www.myapp.com
and under Custom resource records I have:
Name: www
Type: CNAME
Date: www.myapp.com.herokudns.com
Is there a way to force https through google domains or heroku-cli, or is this something I need to do in my Python app?
The easiest way is to use flask-sslify:
https://github.com/kennethreitz/flask-sslify
It turns every http request to your app into a https request
you only have to add one line of code to you app (or app factory):
from flask import Flask
from flask_sslify import SSLify
app = Flask(__name__)
sslify = SSLify(app)
flask-sslify doesn't seem to be maintained anymore. Heroku suggests looking at flask-talisman. But the csp requirements don't look trivial to me.
There really needs to be a simpler solution for this.

Categories