Skip to content

Instantly share code, notes, and snippets.

@mjumbewu
Last active March 20, 2019 15:10
Show Gist options
  • Save mjumbewu/9141814 to your computer and use it in GitHub Desktop.
Save mjumbewu/9141814 to your computer and use it in GitHub Desktop.
WSGI middleware
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
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