Last active
March 20, 2019 15:10
-
-
Save mjumbewu/9141814 to your computer and use it in GitHub Desktop.
WSGI middleware
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import unicode_literals | |
import base64 | |
import binascii | |
import os | |
import re | |
import logging | |
log = logging.getLogger(__name__) | |
def basic_auth_protected(application, exempt=()): | |
username = os.environ.get('BASIC_AUTH_USERNAME') | |
password = os.environ.get('BASIC_AUTH_PASSWORD') | |
is_protected = (username and password) | |
def not_authorized(environ, start_response, msg=None): | |
start_response('401 NOT AUTHORIZED', [('WWW-Authenticate', 'Basic')]) | |
if msg: | |
log.warn('Not authorized: ' + msg) | |
yield (msg.encode() or b'Not Authorized') | |
def protected_application(environ, start_response): | |
auth = environ.pop('HTTP_AUTHORIZATION', '').split() | |
# Check if the path is exempt. Specifying exempt path patterns is useful | |
# when, for example, you're using a proxy to pass information at certain | |
# routes ahead to another service. You don't want to pass the basic auth | |
# credentials along as well, as the auth on the proxied service may be | |
# different. | |
path = environ['PATH_INFO'] | |
for pattern in exempt: | |
if re.match(pattern, path): | |
break | |
# If the path is not exempt, enforce the basic auth. | |
else: | |
if not auth: | |
return not_authorized(environ, start_response, 'No authorization provided.') | |
if auth[0].lower() != 'basic': | |
return not_authorized(environ, start_response, 'Non-basic authorization provided: "' + auth[0] + '".') | |
if len(auth) == 1: | |
return not_authorized(environ, start_response, 'Invalid basic header. No credentials provided.') | |
if len(auth) > 2: | |
return not_authorized(environ, start_response, 'Invalid basic header. Credentials string should not contain spaces.') | |
try: | |
auth_parts = base64.b64decode(auth[1]).decode('iso-8859-1').partition(':') | |
except (TypeError, UnicodeDecodeError, binascii.Error): | |
return not_authorized(environ, start_response, 'Invalid basic header. Credentials not correctly base64 encoded.') | |
if (username, password) != (auth_parts[0], auth_parts[2]): | |
return not_authorized(environ, start_response, 'Invalid username/password.') | |
return application(environ, start_response) | |
return protected_application if is_protected else application |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import unicode_literals | |
import os | |
import logging | |
log = logging.getLogger(__name__) | |
def securely_connected(application): | |
is_secured = (os.environ.get('HTTPS', '').lower() in ('true', 'on', 'yes')) | |
def construct_url(environ): | |
from urllib import quote | |
url = 'https://' | |
if environ.get('HTTP_HOST'): | |
url += environ['HTTP_HOST'] | |
else: | |
url += environ['SERVER_NAME'] | |
url += quote(environ.get('SCRIPT_NAME', '')) | |
url += quote(environ.get('PATH_INFO', '')) | |
if environ.get('QUERY_STRING'): | |
url += '?' + environ['QUERY_STRING'] | |
return url | |
def redirect_to_secure(environ, start_response): | |
secure_url = construct_url(environ) | |
start_response('301 PERMANENT REDIRECT', [('Location', secure_url)]) | |
yield 'This resource requires a secure connection. Use SSL to access %s instead.' % (secure_url,) | |
def secured_application(environ, start_response): | |
if environ.get('wsgi.url_scheme', '').lower() != 'https': | |
return redirect_to_secure(environ, start_response) | |
return application(environ, start_response) | |
return secured_application if is_secured else application |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment