auth2_ssl: simplify and adapt for nginx

This commit is contained in:
Benjamin Dauvergne 2014-02-25 10:00:04 +01:00
parent dc16ce9e81
commit 833191a3df
4 changed files with 72 additions and 48 deletions

View File

@ -103,6 +103,22 @@ Reload Apache.
Configure Authentic
===================
Key Description
-------------------------- ----------------------------------------
ACCEPT_SELF_SIGNED accept certificate for which the validation failed,
default: False
STRICT_MATCH do a binary compare to match certificate and users,
default: False
SUBJECT_MATCH_KEYS SSL information to use to match recorded
certificates. default: ('subject_dn', 'issuer_dn'),
possible values: serial, subject_dn, issuer_dn, cert.
CREATE_USERNAME_CALLBACK function receiving a SSLInfo object as first
parameter and returning a username, default: None
CREATE_USER function receiving a SSLInfo object as first
parameter and returning a user, default: None
USE_COOKIE to be described
in settings.py:
Set AUTH_SSL = True
To create a user with the mail adress as identifier:
@ -117,3 +133,48 @@ def myusernamegen(ssl_info):
SSLAUTH_CREATE_USERNAME_CALLBACK = myusernamegen
Nginx configuration
===================
You must be able to retrieve SSL environment variable, for example with the
SCGI backend you must add those lines to /etc/nginx/scgi_params::
scgi_param SSL_CLIENT_CERT $ssl_client_cert;
scgi_param SSL_CLIENT_RAW_CERT $ssl_client_raw_cert;
scgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
scgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
scgi_param SSL_CLIENT_SERIAL $ssl_client_serial;
scgi_param SSL_CLIENT_M_SERIAL $ssl_client_serial;
scgi_param SSL_CLIENT_VERIFY $ssl_client_verify;
It would be the same with FCGI but using the fcgi_param directive in the
fcgi_params file. It does not currently work when using proxy_pass.
A virtualhost configuration example::
server {
listen 80;
server_name authentic.localhost;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443;
server_name authentic.localhost;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_verify_client optional_no_ca;
location / {
include scgi_params;
scgi_pass localhost:8000;
}
}
The serveur must be run using the SCGI protocol, with this command line for
example::
./manage.py runfcgi protocol=scgi method=threaded daemonize=false host=localhost port=8000

View File

@ -6,10 +6,12 @@ import sys
class AppSettings(object):
'''Thanks django-allauth'''
__DEFAULTS = dict(
# settings for TEST only, make it easy to simulate the SSL
# environment
FORCE_ENV={},
ACCEPT_SELF_SIGNED=False,
STRICT_MATCH=False,
SUBJECT_MATCH_KEYS=(),
SUBJECT_MATCH_KEYS=('subject_dn', 'issuer_dn'),
CREATE_USERNAME_CALLBACK=None,
USE_COOKIE=False,
CREATE_USER=False,

View File

@ -53,14 +53,8 @@ settings')
return None
query = Q(cert=ssl_info.cert)
else:
# compare according to SSLAUTH_SUBJECT_MATCH_KEYS
if app_settings.SUBJECT_MATCH_KEYS:
match_keys = app_settings.SUBJECT_MATCH_KEYS
else:
match_keys = ( 'subject_dn', 'issuer_dn')
query_args = {}
for key in match_keys:
for key in app_settings.SUBJECT_MATCH_KEYS:
if not ssl_info.get(key):
logging.error('SSLAuth: key %s is missing from ssl_info' \
% key)
@ -103,14 +97,7 @@ settings')
user = build_user(username, ssl_info)
# create the certificate record and save
cert = models.ClientCertificate()
cert.user = user
cert.subject_dn = ssl_info.subject_dn
cert.issuer_dn = ssl_info.issuer_dn
cert.cert = ssl_info.cert
cert.serial = ssl_info.serial
cert.save()
self.link_user(ssl_info, user)
return user
@transaction.commit_on_success
@ -120,9 +107,6 @@ settings')
for the passed certificate info. It does not create an issuer record,
just a subject for the ClientCertificate.
"""
if not user:
return None
# create the certificate record and save
cert = models.ClientCertificate()
cert.user = user
@ -134,14 +118,6 @@ settings')
return user
def build_username(self, ssl_info):
"""
create a valid django username from the certificate info. this method
can be "overwritten" by using the SSLAUTH_CREATE_USERNAME_CALLBACK
setting
"""
raise NotImplementedError
def build_user(self, username, ssl_info):
"""

View File

@ -1,8 +1,7 @@
from django.contrib.auth import authenticate, login, get_user
from django.contrib.auth.models import AnonymousUser
from django.contrib.auth import authenticate, login
from . import util, app_settings, backends
from . import util, app_settings
class SSLAuthMiddleware(object):
@ -10,23 +9,9 @@ class SSLAuthMiddleware(object):
attempts to find a valid user based on the client certificate info
"""
def process_request(self, request):
USE_COOKIE = app_settings.USE_COOKIE
if USE_COOKIE:
request.user = get_user(request)
if request.user.is_authenticated():
return
if app_settings.USE_COOKIE and request.user.is_authenticated():
return
ssl_info = util.SSLInfo(request)
user = authenticate(ssl_info=ssl_info) or AnonymousUser()
if not user.is_authenticated() and ssl_info.verify \
and app_settings.CREATE_USER:
if backends.SSLAuthBackend().create_user(ssl_info):
user = authenticate(ssl_info=ssl_info) or AnonymousUser()
if user.is_authenticated() and USE_COOKIE:
user = authenticate(ssl_info=ssl_info)
if user and request.user != user:
login(request, user)
else:
request.user = user