first commit
This commit is contained in:
commit
3778e18202
|
@ -0,0 +1,2 @@
|
|||
authentic2-auth-kerberos is entirely under the copyright of Entr'ouvert and
|
||||
distributed under the license AGPLv3 or later.
|
|
@ -0,0 +1,3 @@
|
|||
include COPYING
|
||||
recursive-include src/authentic2_auth_kerberos/templates *.html
|
||||
recursive-include src/authentic2_auth_kerberos/static *.js *.css *.png
|
|
@ -0,0 +1,35 @@
|
|||
Authentic2 Auth Kerberos
|
||||
==========================
|
||||
|
||||
It provides basic implementation of the HTTP Negotiate authentication mechanism
|
||||
and autologin support using Javascript and a cookie.
|
||||
|
||||
The django-kerberos_ project is used as a basis for this plugin.
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
You just have to install the package in your virtualenv and relaunch, it will
|
||||
be automatically loaded by authentic2.
|
||||
|
||||
You must define the KRB5_KTNAME environment to the path of a keytab file
|
||||
containing the key for your service principal. See django-kerberos_
|
||||
documentation for details.
|
||||
|
||||
Settings
|
||||
--------
|
||||
|
||||
- A2_AUTH_KERBEROS_ENABLED: enable the authentication module, default is True.
|
||||
- A2_AUTH_KERBEROS_CREATE_USER: whether to create users for Kerberos
|
||||
principals, default is True.
|
||||
- A2_AUTH_KERBEROS_REALM: default reaml to attribute to user, default is None.
|
||||
If not None, the Kerberos realm is replaced by this one. It's incompatible
|
||||
with support for multiple realms.
|
||||
|
||||
.. _django-kerberos: https://pypi.python.org/pypi/django-kerberos
|
||||
|
||||
Roadmap
|
||||
-------
|
||||
|
||||
- LDAP support (think AD support)
|
||||
- Linking Kerberos principals to existing users
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/python
|
||||
from setuptools import setup, find_packages
|
||||
import os
|
||||
|
||||
def get_version():
|
||||
import glob
|
||||
import re
|
||||
import os
|
||||
|
||||
version = None
|
||||
for d in glob.glob('src/*'):
|
||||
if not os.path.isdir(d):
|
||||
continue
|
||||
module_file = os.path.join(d, '__init__.py')
|
||||
if not os.path.exists(module_file):
|
||||
continue
|
||||
for v in re.findall("""__version__ *= *['"](.*)['"]""",
|
||||
open(module_file).read()):
|
||||
assert version is None
|
||||
version = v
|
||||
if version:
|
||||
break
|
||||
assert version is not None
|
||||
if os.path.exists('.git'):
|
||||
import subprocess
|
||||
p = subprocess.Popen(['git','describe','--dirty','--match=v*'],
|
||||
stdout=subprocess.PIPE)
|
||||
result = p.communicate()[0]
|
||||
assert p.returncode == 0, 'git returned non-zero'
|
||||
new_version = result.split()[0][1:]
|
||||
assert new_version.split('-')[0] == version, '__version__ must match the last git annotated tag'
|
||||
version = new_version.replace('-', '.')
|
||||
return version
|
||||
|
||||
README = file(os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'README')).read()
|
||||
|
||||
setup(name='authentic2-auth-kerberos',
|
||||
version=get_version(),
|
||||
license='AGPLv3',
|
||||
description='Authentic2 Auth Kerberos',
|
||||
long_description=README,
|
||||
author="Entr'ouvert",
|
||||
author_email="info@entrouvert.com",
|
||||
packages=find_packages('src'),
|
||||
package_dir={
|
||||
'': 'src',
|
||||
},
|
||||
package_data={
|
||||
'authentic2_auth_kerberos': [
|
||||
'templates/authentic2_auth_kerberos/*.html',
|
||||
'static/authentic2_auth_kerberos/js/*.js',
|
||||
'static/authentic2_auth_kerberos/css/*.css',
|
||||
'static/authentic2_auth_kerberos/img/*.png',
|
||||
],
|
||||
},
|
||||
install_requires=[
|
||||
'authentic2',
|
||||
'django-kerberos',
|
||||
],
|
||||
entry_points={
|
||||
'authentic2.plugin': [
|
||||
'authentic2-auth-kerberos = authentic2_auth_kerberos:Plugin',
|
||||
],
|
||||
},
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
__version__ = '1.0.0'
|
||||
|
||||
class Plugin(object):
|
||||
def get_before_urls(self):
|
||||
from . import urls
|
||||
return urls.urlpatterns
|
||||
|
||||
def get_apps(self):
|
||||
return [__name__, 'django_kerberos']
|
||||
|
||||
def get_authentication_backends(self):
|
||||
return ['authentic2_auth_kerberos.backends.A2KerberosBackend']
|
||||
|
||||
def get_auth_frontends(self):
|
||||
return ['authentic2_auth_kerberos.auth_frontends.KerberosFrontend']
|
|
@ -0,0 +1,25 @@
|
|||
class AppSettings(object):
|
||||
__DEFAULTS = {
|
||||
'ENABLED': True,
|
||||
'CREATE_USER': True,
|
||||
'REALM': None,
|
||||
}
|
||||
|
||||
def __init__(self, prefix):
|
||||
self.prefix = prefix
|
||||
|
||||
def _setting(self, name, dflt):
|
||||
from django.conf import settings
|
||||
return getattr(settings, self.prefix+name, dflt)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in self.__DEFAULTS:
|
||||
raise AttributeError(name)
|
||||
return self._setting(name, self.__DEFAULTS[name])
|
||||
|
||||
# Ugly? Guido recommends this himself ...
|
||||
# http://mail.python.org/pipermail/python-ideas/2012-May/014969.html
|
||||
import sys
|
||||
app_settings = AppSettings('A2_AUTH_KERBEROS_')
|
||||
app_settings.__name__ = __name__
|
||||
sys.modules[__name__] = app_settings
|
|
@ -0,0 +1,23 @@
|
|||
from django.utils.translation import gettext_noop
|
||||
from django import forms
|
||||
|
||||
from . import app_settings, utils
|
||||
|
||||
class KerberosFrontend(object):
|
||||
def enabled(self):
|
||||
return app_settings.ENABLED
|
||||
|
||||
def name(self):
|
||||
return gettext_noop('Kerberos')
|
||||
|
||||
def id(self):
|
||||
return 'kerberos'
|
||||
|
||||
def form(self):
|
||||
return forms.Form
|
||||
|
||||
def post(self, request, form, nonce, next):
|
||||
return utils.redirect_next(request, 'kerberos-login', nonce=nonce)
|
||||
|
||||
def template(self):
|
||||
return 'authentic2_auth_kerberos/login.html'
|
|
@ -0,0 +1,28 @@
|
|||
from django_kerberos.backends import KerberosBackend
|
||||
|
||||
import logging
|
||||
|
||||
from . import app_settings
|
||||
|
||||
class A2KerberosBackend(KerberosBackend):
|
||||
def __init__(self):
|
||||
super(A2KerberosBackend, self).__init__()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def username_from_principal(self, principal):
|
||||
if app_settings.REALM:
|
||||
username, domain = principal.rsplit('@', 1)
|
||||
return '{0}@{1}'.format(username, app_settings.REALM)
|
||||
return super(A2KerberosBackend, self).username_from_principal(principal)
|
||||
|
||||
def should_create_user(self):
|
||||
return app_settings.CREATE_USER
|
||||
|
||||
def provision_user(self, principal, user):
|
||||
pass
|
||||
|
||||
def authenticate(self, principal=None, **kwargs):
|
||||
if not app_settings.ENABLED:
|
||||
return
|
||||
return super(A2KerberosBackend, self).authenticate(principal=principal,
|
||||
**kwargs)
|
|
@ -0,0 +1,11 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from admin_tools.dashboard import modules
|
||||
|
||||
|
||||
def get_admin_modules():
|
||||
'''Show Client model in authentic2 admin'''
|
||||
model_list = modules.ModelList(_('Authentic2 Auth Kerberos'),
|
||||
models=('authentic2_auth_kerberos.models.*',))
|
||||
return (model_list,)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import functools
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
from . import app_settings
|
||||
|
||||
def plugin_enabled(view):
|
||||
'''If plugin is not enabled, return 404'''
|
||||
@functools.wraps(view)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not app_settings.ENABLED:
|
||||
raise Http404
|
||||
return view(*args, **kwargs)
|
||||
return wrapper
|
|
@ -0,0 +1,3 @@
|
|||
from django import forms
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
{% comment %}placeholder{% endcomment %}
|
|
@ -0,0 +1,11 @@
|
|||
{% load i18n %}
|
||||
<div>
|
||||
{% include "django_kerberos/autologin.html" %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" name="{{ submit_name }}" value="{% trans "Login" %}"/>
|
||||
{% if cancel %}
|
||||
<input type="submit" name="cancel" value="{% trans 'Cancel' %}"/>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
from django.conf.urls import patterns, url, include
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^accounts/kerberos/login/$', views.login, name='kerberos-login'),
|
||||
)
|
|
@ -0,0 +1,28 @@
|
|||
import urlparse
|
||||
import urllib
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
def redirect_next(request, url, **kwargs):
|
||||
'''Redirect to URL, add or replace parameters with kwargs
|
||||
|
||||
You can use relative or fully qualifier, or view names. You can provide
|
||||
view args and kwargs using named argument args and kwargs.
|
||||
'''
|
||||
# specialize on the next url parameter as it is so frequent
|
||||
if 'next' in request.REQUEST:
|
||||
next_url = request.REQUEST.get('next')
|
||||
kwargs['next'] = next_url
|
||||
if not url.startswith('/') and not url.startswith('http:') and not url.startswith('https:'):
|
||||
view_args = kwargs.pop('args', None)
|
||||
view_kwargs = kwargs.pop('kwargs', None)
|
||||
url = reverse(url, args=view_args, kwargs=view_kwargs)
|
||||
parsed = urlparse.urlparse(url)
|
||||
params = urlparse.parse_qs(parsed.query)
|
||||
for key in kwargs.keys():
|
||||
if kwargs[key] is None:
|
||||
del kwargs[key]
|
||||
params.update(kwargs)
|
||||
url = urlparse.urlunparse(parsed[:4] + (urllib.urlencode(params),) + parsed[5:])
|
||||
return HttpResponseRedirect(url)
|
|
@ -0,0 +1,34 @@
|
|||
import logging
|
||||
|
||||
from django_kerberos.views import NegotiateView
|
||||
|
||||
from authentic2.models import AuthenticationEvent
|
||||
|
||||
__ALL_ = [ 'login' ]
|
||||
|
||||
class A2NegotiateView(NegotiateView):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
super(A2NegotiateView, self).__init__(*args, **kwargs)
|
||||
|
||||
def user_found(self, request, user, *args, **kwargs):
|
||||
response = super(A2NegotiateView, self).user_found(request, user,
|
||||
*args, **kwargs)
|
||||
nonce = request.REQUEST.get('nonce', '')
|
||||
if nonce:
|
||||
self.logger.info('logged in %r as %r (nonce %r)', self.principal,
|
||||
user, nonce)
|
||||
else:
|
||||
self.logger.info('logged in %r as %r', self.principal, user)
|
||||
AuthenticationEvent.objects.create(
|
||||
who=unicode(user),
|
||||
how='kerberos',
|
||||
nonce=nonce)
|
||||
return response
|
||||
|
||||
def user_not_found(self, request, user, *args, **kwargs):
|
||||
self.logger.debug('unable to log in %r', self.principal)
|
||||
return super(A2NegotiateView, self).user_not_found(request, user,
|
||||
*args, **kwargs)
|
||||
|
||||
login = A2NegotiateView.as_view()
|
Loading…
Reference in New Issue