I have created a get function in my flask application which looks something similar below.
flask_app.py
_cloudenv='dev.net'
app = Flask(__name__)
csrf = CSRFProtect()
csrf.init_app(app)
#app.route('/')
#app.route('/index')
def index():
project = "Project 1"
framework = "Publish Framework"
version = '0.1'
# May require to change
hostname = 'farid.net'
# return render_template('index.html', title=project , description=f'{project} : {framework} v - {version}' , hostname=hostname , get_env=_cloudenv)
test_flask.py
import flask_app as flk_app
from flask_app import app
class test_tbrp_case(unittest.TestCase):
def test_home_page_getenv(self):
response = app.test_client().get('/')
assert response.status_code == 200
assert response.get_env == 'dev.net'
def test_home_page_gettitle(self):
response = app.test_client().get('/')
assert response.status_code == 200
assert response.title== 'Project 1'
when i run my test cases , it failed, anything that i did wrong here ?
Related
I am trying to implement Superset using Keycloak for authentication. Following the post here: Using KeyCloak(OpenID Connect) with Apache SuperSet, the login part works fine.
I also have a timeout set on the session (security requirement) using the Superset Docs: https://superset.apache.org/docs/installation/configuring-superset#flask-app-configuration-hook
The part that doesn't work, when a user is logged out, they are not redirected to the login page. It's just a bunch of errors thrown on the screen, and the user can't see anything. Anyone have a hint as to how I get the user redirected to the login page?
Worth noting, the whole thing is behind an nginx reverse proxy.
Here's the full superset_config.py, in case it's helpful...
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_oidc import OpenIDConnect
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import ModelView, SimpleFormView, expose
import logging
class AuthOIDCView(AuthOIDView):
#expose('/login/', methods=['GET', 'POST'])
def login(self, flag=True):
sm = self.appbuilder.sm
oidc = sm.oid
#self.appbuilder.sm.oid.require_login
def handle_login():
user = sm.auth_user_oid(oidc.user_getfield('email'))
if user is None:
info = oidc.user_getinfo(['preferred_username', 'given_name', 'family_name', 'email'])
user = sm.add_user(info.get('preferred_username'), info.get('given_name'), info.get('family_name'), info.get('email'), sm.find_role('Gamma'))
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return handle_login()
#expose('/logout/', methods=['GET', 'POST'])
def logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/') + self.appbuilder.get_url_for_login
return redirect(oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout?redirect_uri=' + quote(redirect_url))
class OIDCSecurityManager(SupersetSecurityManager):
authoidview = AuthOIDCView
def __init__(self,appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
SQLALCHEMY_DATABASE_URI = 'a sting'
MENU_HIDE_USER_INFO = True
FEATURE_FLAGS = {
"ROW_LEVEL_SECURITY": True,
"DASHBOARD_RBAC": True,
}
ENABLE_PROXY_FIX = True
PROXY_FIX_CONFIG = {"x_for": 1, "x_proto": 0, "x_host": 1, "x_port": 0, "x_prefix": 0}
class ReverseProxied(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
# print(environ)
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '')
print(scheme)
if scheme:
environ['wsgi.url_scheme'] = scheme
return self.app(environ, start_response)
ADDITIONAL_MIDDLEWARE = [ReverseProxied, ]
def role_mapper(role_list):
# not exposing our roles
# Auth Settings
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS = '/a/path' #real config contains correct path
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
# Webserver Setting
SUPERSET_WEBSERVER_PROTOCOL = "http"
SUPERSET_WEBSERVER_ADDRESS = "127.0.0.1"
SUPERSET_WEBSERVER_PORT = 8088
# Flask Application Builder Settings
SILENCE_FAB = False
FAB_ADD_SECURITY_VIEWS = True
FAB_ADD_SECURITY_PERMISSION_VIEW = True
FAB_ADD_SECURITY_VIEW_MENU_VIEW = True
FAB_ADD_SECURITY_PERMISSION_VIEWS_VIEW = True
# Session Timeout
from flask import session
from flask import Flask
from datetime import timedelta
def make_session_permanent():
session.permanent = True
# Set up max age of session to 1 minute for testing
PERMANENT_SESSION_LIFETIME = timedelta(minutes=1)
def FLASK_APP_MUTATOR(app: Flask) -> None:
app.before_request_funcs.setdefault(None, []).append(make_session_permanent)```
I am also facing same issue, when user is trying to login agin after logout once its throwing 502 error, Because when user made logout only from superset he is getting logout but in keykloak status kept as login , How to logout from keykloak also when user logout from superset dashboard
I am in the first part of TDD fastapi, docker and pytest course. I got a strange issue, that I need your help with.
When I created the first test that used torotoise it works fine, adds the record to the DB, and gets it from fastapi with no issue.
The minute I add another test (the one that adds, then reads the record), I get this error:
tortoise.exceptions.OperationalError: relation "textsummery" does not exist
(please ignore the typo in the word summary, it started as a mistake, but I use it as a way to force myself to not mindlessly copy paste everything)
If I remove the first test, this error is now gone, and the test goes without a hitch
Any reason why it won't just use the tables already created? I'm kinda at a loss on this one.
Code:
# C:\src\tdd-fastapi\project\test\conftest.py
#pytest.fixture(scope="module")
def test_app_with_db():
# set up
app = create_applications()
app.dependency_overrides[get_settings] = get_settings_override
register_tortoise(
app,
db_url=os.environ.get("DATABASE_TEST_URL"),
modules={"models": ["app.models.tortoise"]},
generate_schemas=True,
add_exception_handlers=True,
)
And
# C:\src\tdd-fastapi\project\test\test_summeries.py
def test_create_summery(test_app_with_db):
response = test_app_with_db.post("/summeries/", data=json.dumps({"url": "https://foo.bar"}))
assert response.status_code == 201
assert response.json()["url"] == "https://foo.bar"
assert response.json()["id"] != 0
# ...
def test_read_summery(test_app_with_db):
response = test_app_with_db.post("/summeries/", data=json.dumps({"url": "https://foo.bar"}))
assert response.status_code == 201
assert response.json()["url"] == "https://foo.bar"
assert response.json()["id"] != 0
summery_id = response.json()["id"]
response = test_app_with_db.get(f"/summeries/{summery_id}/")
assert response.status_code == 200
response_dict = response.json()
assert response_dict["id"] == summery_id
assert response_dict["url"] == "https://foo.bar"
assert response_dict["summery"]
assert response_dict["created_at"]
Per a comment suggestion, I added torotoise and testconf
from tortoise import fields, models
from tortoise.contrib.pydantic import pydantic_model_creator
# C:\src\tdd-fastapi\project\app\models\tortoise.py
class TextSummery(models.Model):
url = fields.TextField()
summery = fields.TextField()
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True)
def __str__(self):
return self.url
SummerySchema = pydantic_model_creator(TextSummery)
And
# C:\src\tdd-fastapi\project\test\conftest.py
import os
import pytest
from starlette.testclient import TestClient
from app.main import create_applications
from app.config import get_settings, Settings
from tortoise.contrib.fastapi import register_tortoise
def get_settings_override() -> Settings:
return Settings(testing=1, database_url=os.environ.get('DATABASE_TEST_URL'))
#pytest.fixture(scope='module')
def test_app():
# setup
app = create_applications()
app.dependency_overrides[get_settings] = get_settings_override
with TestClient(app) as test_client:
yield test_client
#pytest.fixture(scope="module")
def test_app_with_db():
# set up
app = create_applications()
app.dependency_overrides[get_settings] = get_settings_override
register_tortoise(
app,
db_url=os.environ.get("DATABASE_TEST_URL"),
modules={"models": ["app.models.tortoise"]},
generate_schemas=True,
add_exception_handlers=True,
)
with TestClient(app) as test_client:
# testing
yield test_client
# tear down
Found it!
The problem wasn't in any of the files I included, but in main.py
Inside the create application I had this code:
def create_applications() -> FastAPI:
application = FastAPI()
register_tortoise(
application,
db_url = os.environ.get("DATABASE_URL"),
modules = {"models": ["app.models.tortoise"]},
generate_schemas=False, # updated
add_exception_handlers = True
)
application.include_router(ping.router)
application.include_router(summeries.router, prefix="/summeries", tags=['summeries'])
return application
This was in a previous part of the course, and I forgot to remove it.
I'm not sure why it affected only the 2nd test, but I had a function that should have handled it, called init_db. After removing register_tortoise, all tests work as expected.
I have a python script that I start from flask:
from flask import Flask, render_template, request, redirect, url_for
from transcode_audio_manual_stag_funct import get_epguid
application = Flask(__name__)
#application.route('/audiotranscode')
def homepage():
html = render_template('homepage.html')
return html
#application.route('/transcode', methods=['GET','POST'])
def transcode():
dmguid = request.form['mediaid']
get_epguid(dmguid)
return redirect(url_for('homepage'))
if __name__ == '__main__':
application.run(host='0.0.0.0')
At the end of the script, the status can be failed or successful.
...
def register_lowres_depot(dmguid, url_register_audio):
r = safegeturl(url_register_audio)
root = ET.fromstring(r.content)
jobID = root.text
status = ''
while not (status == '2' or status == '4'):
url_status = url %jobID
r = safegeturl(url_status)
root = ET.fromstring(r.content)
status = root.text
print(dmguid, status)
time.sleep(10)
if status == '2':
logger.info('{} successfully registered in depot'.format(dmguid))
else:
logger.warning('Failed to register audio lowres for {}'.format(dmguid))
if __name__ == '__main__':
get_epguid(dmguid)
How can I return that status back to my flask script and present it to the user?
You can make use of make_resopnse() method. What ever you need to present it to user, pass it as parameter to this method. Like below:
# case : Successful
resp = make_resopnse('{} successfully registered in depot'.format(dmguid))
resp.status_code = 200
return resp
# case : Failure
resp = make_resopnse('Failed to register audio lowres for {}'.format(dmguid))
resp.status_code = 500
return resp
Note : The above is very generic.
This question already has an answer here:
Why not generate the secret key every time Flask starts?
(1 answer)
Closed 4 years ago.
I'm currently super stumped. I have a large flask application that I recently deployed to my production ec2 server that's not functioning properly. It works fine in dev/test. It looks like, maybe, apache is hanging. When I first deployed it, it worked a few times. Then, after that I started getting 500 server errors. When I restart apache, it works fine again for a session but the 500 server errors come back. Each time, on a different page of the application. This is reoccurring. How would I go about fixing this? Here's my routes/app.py:
from flask import Flask, render_template,redirect,request,url_for, flash, session
from Index_generator import index_generator
from Yelp_api import request_yelp
from plaid import auth
from search_results import search,search1
from Options import return_data
from datetime import timedelta
import os
import urllib2
import time
from path import path_data
#from writer import create_config_file
import logging
from logging_path import log_dir
logger = logging.getLogger("Routing")
logger.setLevel(logging.INFO)
foodie_log = log_dir()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - % (message)s')
foodie_log.setFormatter(formatter)
logger.addHandler(foodie_log)
app = Flask(__name__)
app.secret_key = os.urandom(24)
go = path_data()
#app.before_request
def make_session_permanent():
session.permanent = False
app.permanent_session_lifetime = timedelta(seconds=300)
##app.route('/setup',methods=['GET','POST'])
#def setup():
# if request.method == 'POST':
# Username=request.form['username']
# Password=request.form['password']
# Port=request.form['port']
# Host=request.form['host']
# C_Key=request.form['CONSUMER_KEY']
# C_Sec=request.form['CONSUMER_SECRET']
# Tok=request.form['TOKEN']
# Tok_Sec=request.form['TOKEN_SECRET']
# clientid=request.form['client_id']
# Sec=request.form['secret']
# create_config_file(Username,Password,Port,Host,C_Key,C_Sec,Tok,Tok_Sec,clientid,Sec)
# return 'complete'
# elif request.method == 'GET':
#
# return render_template('setup.html')
#app.route('/')
def home():
store = index_generator()
session['store'] = store
return render_template('home.html')
#app.route('/about')
def about():
return render_template('about.html')
#app.route('/home_city',methods = ['POST'])
def home_city():
try:
CITY=request.form['city']
store = session.get('store')
request_yelp(DEFAULT_LOCATION=CITY,data_store=store)
return render_template('bank.html')
except Exception as e:
logger.error(e)
error = 'Sorry, no results. Is' + ' ' +CITY + ' '+ 'your hometown? If not, try again and if so, we have been made aware of the issue and is working to resolve it'
return render_template('home.html',error=error)
#app.route('/traveling',methods = ['POST'])
def travel():
store = session.get('store')
answer=request.form['Travel']
if answer == 'yes':
#time.sleep(2)
return render_template('destination.html')
else:
results_home = search(index=store)
time.sleep(2)
return return_data(results_home)
#app.route('/dest_city',methods = ['POST'])
def dest_city():
store = session.get('store')
try:
DESTINATION=request.form['dest_city']
request_yelp(DEFAULT_LOCATION=DESTINATION, data_store=store,sourcetype='dest_city')
results_dest = search1(index=store)
time.sleep(2)
return return_data(results_dest)
except urllib2.HTTPError:
error = 'Sorry, no results. Is your destination city? If not, try again and if so, we have been made aware of the issue and is working to resolve it'
return render_template('destination.html',error=error)
#app.route('/bank',methods = ['POST'])
def bank():
try:
store = session.get('store')
print store
Bank=request.form['Fin_Bank']
Username=request.form['username']
Password=request.form['password']
Test = auth(account=Bank,username=Username,password=Password,data_store=store)
if Test == 402 or Test ==401:
error = 'Invalid credentials'
return render_template('bank.html',error=error)
else :
return render_template('travel.html')
except:
logger.error(e)
if __name__ == '__main__':
app.run(debug=True)
app.secret_key=os.urandom(24)
Not completely sure if this causes your errors but you should definitely change this:
You have to set app.secret_key to a static value rather than os.urandom(24), e.g.:
app.secret_key = "/\xfa-\x84\xfeW\xc3\xda\x11%/\x0c\xa0\xbaY\xa3\x89\x93$\xf5\x92\x9eW}"
With your current code, each worker thread of your application will have a different secret key, which can result in errors or session inconsistency depending on how you use the session object in your application.
I'm using Flask OauthLib following this tutorial, trying to make a basic OAuth2 client to use with Foursquare.com: https://flask-oauthlib.readthedocs.org/en/latest/client.html#oauth2-client
After I grant permission to use the app, I get redirected to a page with this text:
{
"meta": {
"code": 400,
"errorDetail": "Missing access credentials. See https://developer.foursquare.com/docs/oauth.html for details.",
"errorType": "invalid_auth"
},
"response": {}
}
What is wrong? How do I fix this? Thanks.
Foursquare app settings:
Redirect URI(s):
https://127.0.0.1:5000/login/authorized
github.py (A slightly modified version of https://github.com/lepture/flask-oauthlib/blob/master/example/github.py )
from flask import Flask, redirect, url_for, session, request, jsonify
from flask_oauthlib.client import OAuth
app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
oauth = OAuth()
foursquare = oauth.remote_app(
'foursquare',
app_key='FOURSQUARE',
consumer_key='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
)
app.config['FOURSQUARE'] = dict(
consumer_key='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
base_url='https://api.foursquare.com/',
request_token_url=None,
access_token_url='https://foursquare.com/oauth2/access_token',
authorize_url='https://foursquare.com/oauth2/authenticate',
)
oauth.init_app(app)
#app.route('/')
def index():
if 'foursquare_token' in session:
me = foursquare.get('v2/users/self')
return jsonify(me.data)
return redirect(url_for('login'))
#app.route('/login')
def login():
return foursquare.authorize(callback=url_for('authorized', _external=True))
#app.route('/logout')
def logout():
session.pop('foursquare_token', None)
return redirect(url_for('index'))
#app.route('/login/authorized')
def authorized():
resp = foursquare.authorized_response()
if resp is None:
return 'Access denied: reason=%s error=%s' % (
request.args['error'],
request.args['error_description']
)
session['foursquare_token'] = (resp['access_token'], '')
me = foursquare.get('v2/users/self')
return jsonify(me.data)
#foursquare.tokengetter
def get_foursquare_oauth_token():
return session.get('foursquare_token')
if __name__ == '__main__':
app.run('127.0.0.1', debug=True, port=5000, ssl_context=('/Users/XXXXX/Development/Certificates/server.crt', '/Users/XXXXX/Development/Certificates/server.key'))
You need to define a scope too: for example:
request_token_params={
'scope': [
'https://mail.google.com/',
'https://www.googleapis.com/auth/admin.directory.user.readonly',
'https://www.googleapis.com/auth/admin.directory.orgunit.readonly',
'https://www.googleapis.com/auth/admin.directory.group.readonly',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/plus.profile.emails.read',
]