From 583d24c18ddb23326ebf0b4d362f98d72582d192 Mon Sep 17 00:00:00 2001 From: Conrad Date: Mon, 15 May 2017 10:43:51 -0400 Subject: [PATCH 01/14] Add lazy parameter to uwsgi config to fix database connections while multithreading --- app/config/uwsgi.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/config/uwsgi.ini b/app/config/uwsgi.ini index c996d6b..5790769 100644 --- a/app/config/uwsgi.ini +++ b/app/config/uwsgi.ini @@ -20,3 +20,7 @@ logger = file:$UWSGIERR # cd into the app directory chdir = $CODEROOT module = wsgi:app + +# For multithreading use +lazy = true +lazy-apps = true -- GitLab From ee137ec69bcdff28b186f9ddf0b95ef6380199fc Mon Sep 17 00:00:00 2001 From: Conrad Date: Tue, 22 Aug 2017 10:30:39 -0400 Subject: [PATCH 02/14] Remove userservice and check auth0 token instead --- app/config/development.default.py | 9 ++-- app/config/local.default.py | 9 ++-- app/config/production.default.py | 9 ++-- app/config/staging.default.py | 9 ++-- app/config/test.default.py | 9 ++-- app/permissions/auth.py | 89 +++++++++++++------------------ 6 files changed, 61 insertions(+), 73 deletions(-) diff --git a/app/config/development.default.py b/app/config/development.default.py index 8d06722..e421eed 100644 --- a/app/config/development.default.py +++ b/app/config/development.default.py @@ -17,15 +17,16 @@ SERVICE_CONFIG = { 'app_secret': 'x-blocpower-app-secret'}, 'urls': { 'app': 'http://dev.appservice.blocpower.io/', - 'user': 'http://dev.userservice.blocpower.io/'} + } } # AppService APP_CACHE_EXPIRY = 60 * 60 # One hour. -# UserService -GOOGLE_AUTH_HEADER = 'x-blocpower-google-token' -USER_CACHE_EXPIRY = 60 * 60 # One Hour. +# Auth0 Authentication +AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' +AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] +AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/local.default.py b/app/config/local.default.py index 9d611c0..e80477b 100644 --- a/app/config/local.default.py +++ b/app/config/local.default.py @@ -14,15 +14,16 @@ SERVICE_CONFIG = { 'app_secret': 'x-blocpower-app-secret'}, 'urls': { 'app': 'http://127.0.0.1:5400', - 'user': 'http://127.0.0.1:5401'} + } } # AppService APP_CACHE_EXPIRY = 60 * 60 # One hour. -# UserService -GOOGLE_AUTH_HEADER = 'x-blocpower-google-token' -USER_CACHE_EXPIRY = 60 * 60 # One Hour. +# Auth0 Authentication +AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' +AUTH0_DOMAIN = '$AUTH0_DOMAIN' +AUTH0_AUDIENCE = '$AUTH0_AUDIENCE' # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/production.default.py b/app/config/production.default.py index f135fcd..8005d7b 100644 --- a/app/config/production.default.py +++ b/app/config/production.default.py @@ -17,15 +17,16 @@ SERVICE_CONFIG = { 'app_secret': 'x-blocpower-app-secret'}, 'urls': { 'app': 'http://app.s.blocpower.us', - 'user': 'http://user.s.blocpower.us'} + } } # AppService APP_CACHE_EXPIRY = 60 * 60 # One hour. -# UserService -GOOGLE_AUTH_HEADER = 'x-blocpower-google-token' -USER_CACHE_EXPIRY = 60 * 60 # One Hour. +# Auth0 Authentication +AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' +AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] +AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/staging.default.py b/app/config/staging.default.py index 9a06abb..e26e9e6 100644 --- a/app/config/staging.default.py +++ b/app/config/staging.default.py @@ -17,15 +17,16 @@ SERVICE_CONFIG = { 'app_secret': 'x-blocpower-app-secret'}, 'urls': { 'app': 'http://staging.app.s.blocpower.us/', - 'user': 'http://staging.user.s.blocpower.us/'} + } } # AppService APP_CACHE_EXPIRY = 60 * 60 # One hour. -# UserService -GOOGLE_AUTH_HEADER = 'x-blocpower-google-token' -USER_CACHE_EXPIRY = 60 * 60 # One Hour. +# Auth0 Authentication +AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' +AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] +AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/test.default.py b/app/config/test.default.py index 6231e62..59f560e 100644 --- a/app/config/test.default.py +++ b/app/config/test.default.py @@ -15,7 +15,7 @@ SERVICE_CONFIG = { 'app_secret': 'x-blocpower-app-secret'}, 'urls': { 'app': 'http://127.0.0.1:5400', - 'user': 'http://127.0.0.1:5401'} + } } # App @@ -50,9 +50,10 @@ TEST_CLIENTS = { } } -# Auth -GOOGLE_AUTH_HEADER = 'x-blocpower-google-token' -USER_CACHE_EXPIRY = 60 * 60 # One Hour. +# Auth0 Authentication +AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' +AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] +AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/permissions/auth.py b/app/permissions/auth.py index 6b4b20c..007bb25 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -1,5 +1,8 @@ """Permissions to check authentication.""" from werkzeug.exceptions import Unauthorized +from jose import jwt +import json +import requests from ..lib.red import redis from ..lib.service import services @@ -8,62 +11,42 @@ from .application import app_need class AuthNeed(Permission): - """Checks the user service for a valid login.""" + """Check if the access token is valid.""" def is_met(self): - """Check for authentication with the user service.""" from flask import session, request, current_app - # Check the cache. - key = session.get('user_key') - token = session.get('user_token') - cached_token = redis.users.get(key) - if ( - key and token and cached_token and - cached_token.decode('utf-8') == token - ): + """Check for authentication with Auth0.""" + auth0_header = current_app.config.get('AUTH0_AUTH_HEADER') + auth0_token = request.headers.get(auth0_header) + + AUTH0_DOMAIN = current_app.config['AUTH0_DOMAIN'] + API_AUDIENCE = current_app.config['AUTH0_AUDIENCE'] + ALGORITHMS = ["RS256"] + r = requests.get("https://"+AUTH0_DOMAIN+"/.well-known/jwks.json") + jwks = json.loads(r.text) + unverified_header = jwt.get_unverified_header(auth0_token) + rsa_key = {} + for key in jwks["keys"]: + if key["kid"] == unverified_header["kid"]: + rsa_key = { + "kty": key["kty"], + "kid": key["kid"], + "use": key["use"], + "n": key["n"], + "e": key["e"] + } + if rsa_key: + try: + payload = jwt.decode( + auth0_token, + rsa_key, + algorithms=ALGORITHMS, + audience=API_AUDIENCE, + issuer="https://"+AUTH0_DOMAIN+"/" + ) + except Exception: + return False return True - - # Hit the user service. - google_header = current_app.config.get('GOOGLE_AUTH_HEADER') - google_token = request.headers.get(google_header) - response = services.user.get( - '/session/', headers={google_header: google_token}) - - if not response.status_code == 200: - return False - data = response.json() - if 'data' not in data: - return False - data = data['data'] - if ( - 'user' not in data or - 'token' not in data or - 'key' not in data['user'] - ): - return False - - key = data['user']['key'] - token = data['token'] - - # Add to the cache and get the token from the cache. - # - # If there was already a token for this user (e.g from a different - # login), then we can trust that token, the command above did nothing, - # and we should respond with the cached token. - # - # These two are run atomically together to prevent the race condition - # where there is already a token and it expires before we retrieve it. - _, token = redis.users.pipeline()\ - .set(key, token, - ex=current_app.config.get('USER_CACHE_EXPIRY'), - nx=True)\ - .get(key)\ - .execute() - - # Add to the session. - session['user_key'] = key - session['user_token'] = token - - return True + return False auth_need = AuthNeed() -- GitLab From d122566e77d5de7e7dd5d009f3730637da5920fe Mon Sep 17 00:00:00 2001 From: Conrad Date: Tue, 22 Aug 2017 11:03:43 -0400 Subject: [PATCH 03/14] Update nginx config --- app/config/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/nginx.conf b/app/config/nginx.conf index 8bbb09a..27988b5 100644 --- a/app/config/nginx.conf +++ b/app/config/nginx.conf @@ -28,7 +28,7 @@ http { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'HEAD, GET, POST, PUT, DELETE, OPTIONS' always; - add_header 'Access-Control-Allow-Headers' 'x-blocpower-app-key,x-blocpower-app-secret,x-blocpower-app-token,x-blocpower-auth-key,x-blocpower-auth-token,x-blocpower-google-token' always; + add_header 'Access-Control-Allow-Headers' 'x-blocpower-app-key,x-blocpower-app-secret,x-blocpower-app-token,x-blocpower-auth-key,x-blocpower-auth-token,x-blocpower-auth0-token'' always; } } } -- GitLab From 1d4b287d38f1be2ba1b8d80b0d0a377ebcbc710e Mon Sep 17 00:00:00 2001 From: Conrad Date: Tue, 22 Aug 2017 11:25:57 -0400 Subject: [PATCH 04/14] Catch exception if no access_token is given --- app/permissions/auth.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/permissions/auth.py b/app/permissions/auth.py index 007bb25..5b3c67b 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -23,19 +23,19 @@ class AuthNeed(Permission): ALGORITHMS = ["RS256"] r = requests.get("https://"+AUTH0_DOMAIN+"/.well-known/jwks.json") jwks = json.loads(r.text) - unverified_header = jwt.get_unverified_header(auth0_token) - rsa_key = {} - for key in jwks["keys"]: - if key["kid"] == unverified_header["kid"]: - rsa_key = { - "kty": key["kty"], - "kid": key["kid"], - "use": key["use"], - "n": key["n"], - "e": key["e"] - } - if rsa_key: - try: + try: + unverified_header = jwt.get_unverified_header(auth0_token) + rsa_key = {} + for key in jwks["keys"]: + if key["kid"] == unverified_header["kid"]: + rsa_key = { + "kty": key["kty"], + "kid": key["kid"], + "use": key["use"], + "n": key["n"], + "e": key["e"] + } + if rsa_key: payload = jwt.decode( auth0_token, rsa_key, @@ -43,9 +43,9 @@ class AuthNeed(Permission): audience=API_AUDIENCE, issuer="https://"+AUTH0_DOMAIN+"/" ) - except Exception: - return False - return True + return True + except Exception: + pass return False auth_need = AuthNeed() -- GitLab From 78aa4fe5cf1e7b45c784796af37272ac8ed5270e Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 23 Aug 2017 12:14:48 -0400 Subject: [PATCH 05/14] Add a permission check for a list of inputted permissions --- app/config/development.default.py | 1 + app/config/local.default.py | 1 + app/config/production.default.py | 1 + app/config/staging.default.py | 1 + app/config/test.default.py | 1 + app/permissions/auth.py | 15 +++++++++++++-- 6 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/config/development.default.py b/app/config/development.default.py index e421eed..9333a24 100644 --- a/app/config/development.default.py +++ b/app/config/development.default.py @@ -27,6 +27,7 @@ APP_CACHE_EXPIRY = 60 * 60 # One hour. AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] +AUTH0_CLAIMS_NAMESPACE = os.environ['AUTH0_CLAIMS_NAMESPACE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/local.default.py b/app/config/local.default.py index e80477b..d3e4d2b 100644 --- a/app/config/local.default.py +++ b/app/config/local.default.py @@ -24,6 +24,7 @@ APP_CACHE_EXPIRY = 60 * 60 # One hour. AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' AUTH0_DOMAIN = '$AUTH0_DOMAIN' AUTH0_AUDIENCE = '$AUTH0_AUDIENCE' +AUTH0_CLAIMS_NAMESPACE = '$AUTH0_CLAIMS_NAMESPACE' # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/production.default.py b/app/config/production.default.py index 8005d7b..b382b44 100644 --- a/app/config/production.default.py +++ b/app/config/production.default.py @@ -27,6 +27,7 @@ APP_CACHE_EXPIRY = 60 * 60 # One hour. AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] +AUTH0_CLAIMS_NAMESPACE = os.environ['AUTH0_CLAIMS_NAMESPACE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/staging.default.py b/app/config/staging.default.py index e26e9e6..c8a4b81 100644 --- a/app/config/staging.default.py +++ b/app/config/staging.default.py @@ -27,6 +27,7 @@ APP_CACHE_EXPIRY = 60 * 60 # One hour. AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] +AUTH0_CLAIMS_NAMESPACE = os.environ['AUTH0_CLAIMS_NAMESPACE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/config/test.default.py b/app/config/test.default.py index 59f560e..6639a96 100644 --- a/app/config/test.default.py +++ b/app/config/test.default.py @@ -54,6 +54,7 @@ TEST_CLIENTS = { AUTH0_AUTH_HEADER = 'x-blocpower-auth0-token' AUTH0_DOMAIN = os.environ['AUTH0_DOMAIN'] AUTH0_AUDIENCE = os.environ['AUTH0_AUDIENCE'] +AUTH0_CLAIMS_NAMESPACE = os.environ['AUTH0_CLAIMS_NAMESPACE'] # Blocpower auth information. HEADER_AUTH_KEY = 'x-blocpower-auth-key' diff --git a/app/permissions/auth.py b/app/permissions/auth.py index 5b3c67b..3475fcf 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -43,11 +43,22 @@ class AuthNeed(Permission): audience=API_AUDIENCE, issuer="https://"+AUTH0_DOMAIN+"/" ) + # Check permissions + required_permissions = self.bool_ + # The self.bool_ variable is a boolean if no value is passed in + if type(required_permissions) is list: + CLAIMS_NAMESPACE = current_app.config['AUTH0_CLAIMS_NAMESPACE'] + actual_permissions = payload['{}permissions'.format(CLAIMS_NAMESPACE)] + for permission in required_permissions: + if permission not in actual_permissions: + return False return True except Exception: pass return False -auth_need = AuthNeed() -standard_login_need = app_need & auth_need +standard_login_need = app_need & AuthNeed() +# An example permission need decorator. This decorator requires that the user +# has the 'view::developer' permission +developer_view_need = app_need & AuthNeed(['view::developer']) -- GitLab From 4837f290e351285748b6ee01bf67db439cad35e9 Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 23 Aug 2017 12:16:57 -0400 Subject: [PATCH 06/14] Add back auth_need --- app/permissions/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/permissions/auth.py b/app/permissions/auth.py index 3475fcf..e1d25c3 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -57,8 +57,8 @@ class AuthNeed(Permission): pass return False - -standard_login_need = app_need & AuthNeed() +auth_need = AuthNeed() +standard_login_need = app_need & auth_need # An example permission need decorator. This decorator requires that the user # has the 'view::developer' permission developer_view_need = app_need & AuthNeed(['view::developer']) -- GitLab From 27ba4b84baf398eceb0d476aa99b6ed4d87b0698 Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 23 Aug 2017 14:43:23 -0400 Subject: [PATCH 07/14] Add python-jose requirement --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 932bb87..0a28abd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,6 +27,7 @@ pyasn1==0.1.9 pyasn1-modules==0.0.8 pycparser==2.14 python-dateutil==2.4.2 +python-jose==1.3.2 PyYAML==3.11 redis==2.10.5 requests==2.6.2 -- GitLab From c44a954dceeb29361713316407256a18d05115fb Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 24 Aug 2017 10:54:32 -0400 Subject: [PATCH 08/14] Catch specific exceptions and print them out --- app/permissions/auth.py | 60 ++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/app/permissions/auth.py b/app/permissions/auth.py index e1d25c3..5f9e9fa 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -23,19 +23,19 @@ class AuthNeed(Permission): ALGORITHMS = ["RS256"] r = requests.get("https://"+AUTH0_DOMAIN+"/.well-known/jwks.json") jwks = json.loads(r.text) - try: - unverified_header = jwt.get_unverified_header(auth0_token) - rsa_key = {} - for key in jwks["keys"]: - if key["kid"] == unverified_header["kid"]: - rsa_key = { - "kty": key["kty"], - "kid": key["kid"], - "use": key["use"], - "n": key["n"], - "e": key["e"] - } - if rsa_key: + unverified_header = jwt.get_unverified_header(auth0_token) + rsa_key = {} + for key in jwks["keys"]: + if key["kid"] == unverified_header["kid"]: + rsa_key = { + "kty": key["kty"], + "kid": key["kid"], + "use": key["use"], + "n": key["n"], + "e": key["e"] + } + if rsa_key: + try: payload = jwt.decode( auth0_token, rsa_key, @@ -43,18 +43,28 @@ class AuthNeed(Permission): audience=API_AUDIENCE, issuer="https://"+AUTH0_DOMAIN+"/" ) - # Check permissions - required_permissions = self.bool_ - # The self.bool_ variable is a boolean if no value is passed in - if type(required_permissions) is list: - CLAIMS_NAMESPACE = current_app.config['AUTH0_CLAIMS_NAMESPACE'] - actual_permissions = payload['{}permissions'.format(CLAIMS_NAMESPACE)] - for permission in required_permissions: - if permission not in actual_permissions: - return False - return True - except Exception: - pass + # For now we will print and return unauthorized. In the future + # we will log these errors and the requester + except jwt.ExpiredSignatureError: + print('Token is expired') + return False + except jwt.JWTClaimsError: + print('Incorrect claims. Please check the audience and the issuer') + return False + except Exception: + print('Invalid header. Unable to parse the token') + return False + + # Check permissions + required_permissions = self.bool_ + # The self.bool_ variable is a boolean if no value is passed in + if type(required_permissions) is list: + CLAIMS_NAMESPACE = current_app.config['AUTH0_CLAIMS_NAMESPACE'] + actual_permissions = payload['{}permissions'.format(CLAIMS_NAMESPACE)] + for permission in required_permissions: + if permission not in actual_permissions: + return False + return True return False auth_need = AuthNeed() -- GitLab From e246a5676de39bcf1686e3fb41743445af336ac4 Mon Sep 17 00:00:00 2001 From: Conrad Schloer Date: Thu, 24 Aug 2017 14:35:37 -0400 Subject: [PATCH 09/14] Add a required_permissions argument to the Auth class (#30) --- app/permissions/auth.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/permissions/auth.py b/app/permissions/auth.py index 5f9e9fa..d6bbeaf 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -12,6 +12,11 @@ from .application import app_need class AuthNeed(Permission): """Check if the access token is valid.""" + + def __init__(self, required_permissions=[]): + self.required_permissions = required_permissions + super().__init__() + def is_met(self): from flask import session, request, current_app """Check for authentication with Auth0.""" @@ -56,14 +61,12 @@ class AuthNeed(Permission): return False # Check permissions - required_permissions = self.bool_ # The self.bool_ variable is a boolean if no value is passed in - if type(required_permissions) is list: - CLAIMS_NAMESPACE = current_app.config['AUTH0_CLAIMS_NAMESPACE'] - actual_permissions = payload['{}permissions'.format(CLAIMS_NAMESPACE)] - for permission in required_permissions: - if permission not in actual_permissions: - return False + CLAIMS_NAMESPACE = current_app.config['AUTH0_CLAIMS_NAMESPACE'] + actual_permissions = payload['{}permissions'.format(CLAIMS_NAMESPACE)] + for permission in self.required_permissions: + if permission not in actual_permissions: + return False return True return False -- GitLab From d12f83187114c596c4fe347b8cf06105400ba6b9 Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 24 Aug 2017 17:20:41 -0400 Subject: [PATCH 10/14] Fix typo in nginx config --- app/config/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/nginx.conf b/app/config/nginx.conf index 27988b5..af53850 100644 --- a/app/config/nginx.conf +++ b/app/config/nginx.conf @@ -28,7 +28,7 @@ http { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'HEAD, GET, POST, PUT, DELETE, OPTIONS' always; - add_header 'Access-Control-Allow-Headers' 'x-blocpower-app-key,x-blocpower-app-secret,x-blocpower-app-token,x-blocpower-auth-key,x-blocpower-auth-token,x-blocpower-auth0-token'' always; + add_header 'Access-Control-Allow-Headers' 'x-blocpower-app-key,x-blocpower-app-secret,x-blocpower-app-token,x-blocpower-auth-key,x-blocpower-auth-token,x-blocpower-auth0-token' always; } } } -- GitLab From eb0ac6af608ef563b087d00e82ae7e8c7a2f7339 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 6 Sep 2017 10:32:05 -0400 Subject: [PATCH 11/14] Setup logging for app --- app/__init__.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index cbd49e1..efb3706 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,11 +1,27 @@ +import logging +from logging.handlers import RotatingFileHandler from flask import Flask +MEGABYTE = 10**6 +LOG_FORMAT = '[%(asctime)s] %(pathname)s:%(lineno)d %(levelname)s - %(message)s' +LOG_PATH = '/var/log/flask.log' def create_app(config): """Set up the application.""" app = Flask(__name__) app.config.from_pyfile(config) + if config != 'config/local.py': + handler = RotatingFileHandler(LOG_PATH, maxBytes=MEGABYTE, backupCount=1) + + handler.setLevel(logging.INFO) + handler.setFormatter(logging.Formatter(LOG_FORMAT)) + + app.logger.addHandler(handler) + app.logger.setLevel(logging.INFO) + + app.logger.info('Setting up application...') + from .lib import database database.register(app) @@ -27,4 +43,4 @@ def create_app(config): with app.app_context(): database.db.create_all() - return app + return app \ No newline at end of file -- GitLab From a3f76a398a3910dd8bc0cb5986698fccdb3c77e0 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 6 Sep 2017 15:37:17 -0400 Subject: [PATCH 12/14] Add newline to init --- app/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index efb3706..b7bfff9 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -43,4 +43,4 @@ def create_app(config): with app.app_context(): database.db.create_all() - return app \ No newline at end of file + return app -- GitLab From ed06b4bfc7b2db58a1aaa9609c640c8cc8728cea Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Thu, 7 Sep 2017 09:37:15 -0400 Subject: [PATCH 13/14] Format loggging date --- app/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index b7bfff9..da6671a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,7 +15,7 @@ def create_app(config): handler = RotatingFileHandler(LOG_PATH, maxBytes=MEGABYTE, backupCount=1) handler.setLevel(logging.INFO) - handler.setFormatter(logging.Formatter(LOG_FORMAT)) + handler.setFormatter(logging.Formatter(LOG_FORMAT, datefmt='%Y-%m-%d %H:%M:%S')) app.logger.addHandler(handler) app.logger.setLevel(logging.INFO) -- GitLab From 2f63fa139e3d1d43558c6a3b53932db5d8f58a68 Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 7 Sep 2017 16:10:09 -0400 Subject: [PATCH 14/14] Add logging for user authentication --- app/permissions/auth.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/permissions/auth.py b/app/permissions/auth.py index d6bbeaf..360b77c 100644 --- a/app/permissions/auth.py +++ b/app/permissions/auth.py @@ -1,4 +1,5 @@ """Permissions to check authentication.""" +from flask import current_app from werkzeug.exceptions import Unauthorized from jose import jwt import json @@ -51,13 +52,13 @@ class AuthNeed(Permission): # For now we will print and return unauthorized. In the future # we will log these errors and the requester except jwt.ExpiredSignatureError: - print('Token is expired') + current_app.logger.info('Token is expired') return False except jwt.JWTClaimsError: - print('Incorrect claims. Please check the audience and the issuer') + current_app.logger.info('Incorrect claims. Please check the audience and the issuer') return False except Exception: - print('Invalid header. Unable to parse the token') + current_app.logger.info('Invalid header. Unable to parse the token') return False # Check permissions -- GitLab