authentic/src/authentic2/auth2_auth/auth2_ssl/util.py

87 lines
2.6 KiB
Python

import base64
import six
from . import app_settings
X509_KEYS = {
'subject_dn': 'SSL_CLIENT_S_DN',
'issuer_dn': 'SSL_CLIENT_I_DN',
'serial': ('SSL_CLIENT_M_SERIAL', 'SSL_CLIENT_SERIAL'),
'cert': 'SSL_CLIENT_CERT',
'verify': 'SSL_CLIENT_VERIFY',
}
def normalize_cert(certificate_pem):
'''Normalize content of the certificate'''
base64_content = ''.join(certificate_pem.splitlines()[1:-1])
content = base64.b64decode(base64_content)
return base64.b64encode(content)
def explode_dn(dn):
'''Extract sub element of a DN as displayed by mod_ssl or nginx_ssl'''
dn = dn.strip('/')
parts = dn.split('/')
parts = [part.split('=') for part in parts]
parts = [(part[0], part[1].decode('string_escape').decode('utf-8'))
for part in parts]
return parts
TRANSFORM = {
'cert': normalize_cert,
}
class SSLInfo(object):
"""
Encapsulates the SSL environment variables in a read-only object. It
attempts to find the ssl vars based on the type of request passed to the
constructor. Currently only WSGIRequest and ModPythonRequest are
supported.
"""
def __init__(self, request):
name = request.__class__.__name__
if app_settings.FORCE_ENV:
env = app_settings.FORCE_ENV
elif name == 'WSGIRequest':
env = request.environ
elif name == 'ModPythonRequest':
env = request._req.subprocess_env
else:
raise EnvironmentError('The SSL authentication currently only \
works with mod_python or wsgi requests')
self.read_env(env);
pass
def read_env(self, env):
for attr, keys in X509_KEYS.iteritems():
if isinstance(keys, six.string_types):
keys = [keys]
for key in keys:
if key in env and env[key]:
v = env[key]
if attr in TRANSFORM:
v = TRANSFORM[attr](v)
self.__dict__[attr] = v
else:
self.__dict__[attr] = None
if self.__dict__['verify'] == 'SUCCESS':
self.__dict__['verify'] = True
else:
self.__dict__['verify'] = False
def get(self, attr):
return self.__getattr__(attr)
def __getattr__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
else:
raise AttributeError('SSLInfo does not contain key %s' % attr)
def __setattr__(self, attr, value):
raise AttributeError('SSL vars are read only!')
def __repr__(self):
return '<SSLInfo %s>' % self.__dict__