first commit
This commit is contained in:
commit
cb05f9eb2a
|
@ -0,0 +1,2 @@
|
||||||
|
cmsplugin-blurp is entirely under the copyright of Entr'ouvert and distributed
|
||||||
|
under the license AGPLv3 or later.
|
|
@ -0,0 +1,3 @@
|
||||||
|
include COPYING
|
||||||
|
recursive-include sample *.py *.html
|
||||||
|
recursive-include src/django_kerberos/templates *.html
|
|
@ -0,0 +1,55 @@
|
||||||
|
Kerberos authentication for Django
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Provide Kerberos authentication to Django applications.
|
||||||
|
|
||||||
|
Basic usage
|
||||||
|
===========
|
||||||
|
|
||||||
|
Add this to your project `urls.py`::
|
||||||
|
|
||||||
|
url('^accounts/kerberos/', include('django_auth_kerb.urls')),
|
||||||
|
|
||||||
|
And use the default authentication backend, by adding that to your `settings.py` file::
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'django_auth_kerberos.backends.KerberosBackend',
|
||||||
|
)
|
||||||
|
|
||||||
|
Settings
|
||||||
|
========
|
||||||
|
|
||||||
|
`KERBEROS_HOSTNAME`
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Hostname for retrieving the service key, the correspondig principal will be
|
||||||
|
`HTTP/{KERBEROS_HOSTNAME}@DEFAULT_REAML`, default is `None`. If `None` the hostname
|
||||||
|
from the request will be used.
|
||||||
|
|
||||||
|
`KERBEROS_KEYTAB`
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
File path of the keytab containing the key for the service principal, default
|
||||||
|
is `None`. If `None` the default host keytab will be tried, which should fails
|
||||||
|
since it's usually only readable by root.
|
||||||
|
|
||||||
|
`KERBEROS_BACKEND_CREATE`
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Whether to create user if no existing model can be found, default is `False`.
|
||||||
|
|
||||||
|
`KERBEROS_BACKEND_ADMIN_REGEXP`
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
A regular expression that the principal must match to get superuser privileges,
|
||||||
|
default is `None`. A classic example could be `r'^.*/admin$'`.
|
||||||
|
|
||||||
|
Custom backend
|
||||||
|
==============
|
||||||
|
|
||||||
|
A custom authentication backend can be used, in this case the signature of the
|
||||||
|
authenticate method must be::
|
||||||
|
|
||||||
|
class CustomKerberosBackend(object):
|
||||||
|
def authenticate(self, principal=None):
|
||||||
|
pass
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings")
|
||||||
|
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
execute_from_command_line(sys.argv)
|
|
@ -0,0 +1,94 @@
|
||||||
|
"""
|
||||||
|
Django settings for sample project.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.6/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/1.6/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
import os
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 's0xb*2mi0#pi48tri&x6cwr96k30mmdu%e6pa28_=n9^4eh-3='
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
TEMPLATE_DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'django_kerberos',
|
||||||
|
)
|
||||||
|
|
||||||
|
MIDDLEWARE_CLASSES = (
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
)
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'django_kerberos.backends.KerberosBackend',
|
||||||
|
)
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'sample.urls'
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'sample.wsgi.application'
|
||||||
|
|
||||||
|
TEMPLATE_DIRS = ( os.path.join(BASE_DIR, 'sample', 'templates'), )
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/1.6/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/1.6/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
LOGIN_URL = 'kerberos-login'
|
||||||
|
|
||||||
|
KERBEROS_BACKEND_CREATE = True
|
||||||
|
KERBEROS_BACKEND_ADMIN_REGEXP = r'^.*/admin$'
|
|
@ -0,0 +1,7 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
from django.conf.urls import patterns, include, url
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
admin.autodiscover()
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
# Examples:
|
||||||
|
url(r'^$', views.home, name='home'),
|
||||||
|
# url(r'^blog/', include('blog.urls')),
|
||||||
|
|
||||||
|
url('^accounts/kerberos/', include('django_auth_kerberos.urls')),
|
||||||
|
url('^accounts/', include('django.contrib.auth.urls')),
|
||||||
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django import http
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def home(request):
|
||||||
|
return http.HttpResponse(u'It worked ' + request.user.username + u'!', content_type='text/plain')
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""
|
||||||
|
WSGI config for sample project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings")
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
application = get_wsgi_application()
|
|
@ -0,0 +1,62 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
''' Setup script for django-kerberos
|
||||||
|
'''
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
setup(name="django-kerberos",
|
||||||
|
version=get_version(),
|
||||||
|
license="AGPLv3 or later",
|
||||||
|
description="",
|
||||||
|
long_description=file('README').read(),
|
||||||
|
url="http://dev.entrouvert.org/projects/authentic/",
|
||||||
|
author="Entr'ouvert",
|
||||||
|
author_email="info@entrouvert.org",
|
||||||
|
maintainer="Benjamin Dauvergne",
|
||||||
|
maintainer_email="bdauvergne@entrouvert.com",
|
||||||
|
packages=find_packages('src'),
|
||||||
|
install_requires=[
|
||||||
|
'django>1.5',
|
||||||
|
],
|
||||||
|
package_dir={
|
||||||
|
'': 'src',
|
||||||
|
},
|
||||||
|
package_data={
|
||||||
|
'django_kerberos': [
|
||||||
|
'templates/django_kerberos/*.html',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
dependency_links=[],
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
__version__ = '1.0.0'
|
|
@ -0,0 +1,20 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class AppSettings(object):
|
||||||
|
__PREFIX = 'KERBEROS_'
|
||||||
|
__DEFAULTS = {
|
||||||
|
'HOSTNAME': None,
|
||||||
|
'KEYTAB': None,
|
||||||
|
'BACKEND_CREATE': False,
|
||||||
|
'BACKEND_ADMIN_REGEXP': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
from django.conf import settings
|
||||||
|
if name not in self.__DEFAULTS:
|
||||||
|
raise AttributeError
|
||||||
|
return getattr(settings, self.__PREFIX + name, self.__DEFAULTS[name])
|
||||||
|
|
||||||
|
app_settings = AppSettings()
|
||||||
|
app_settings.__name__ = __name__
|
||||||
|
sys.modules[__name__] = app_settings
|
|
@ -0,0 +1,34 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from . import app_settings
|
||||||
|
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.backends import ModelBackend
|
||||||
|
|
||||||
|
class KerberosBackend(ModelBackend):
|
||||||
|
def authenticate(self, principal=None):
|
||||||
|
'''Match principal username with Django user model username'''
|
||||||
|
if not principal:
|
||||||
|
return
|
||||||
|
User = get_user_model()
|
||||||
|
username = principal.split('@')[0]
|
||||||
|
username_field = getattr(User, 'USERNAME_FIELD', 'username')
|
||||||
|
kwargs = {username_field: username}
|
||||||
|
if app_settings.BACKEND_CREATE:
|
||||||
|
user, created = User.objects.get_or_create(**kwargs)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
user = User.objects.get(**kwargs)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return
|
||||||
|
# basic authorization
|
||||||
|
if app_settings.BACKEND_ADMIN_REGEXP:
|
||||||
|
if re.match(app_settings.BACKEND_ADMIN_REGEXP, username):
|
||||||
|
if not user.is_staff or not user.is_superuser:
|
||||||
|
user.is_staff = True
|
||||||
|
user.is_superuser = True
|
||||||
|
user.save()
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
An error occurred during initialization of the GSSAPI context, verify that a properly initialized keytab is accessible
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
Access unauthorized please refresh your ticket cache
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^login/$', views.login, name='kerberos-login'),
|
||||||
|
)
|
|
@ -0,0 +1,52 @@
|
||||||
|
import kerberos
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django import http
|
||||||
|
from django.template.response import TemplateResponse
|
||||||
|
from django.contrib.auth import authenticate, login as auth_login
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from . import app_settings
|
||||||
|
|
||||||
|
def www_authenticate(request):
|
||||||
|
response = TemplateResponse(request, 'django_kerberos/unauthorized.html', status=401)
|
||||||
|
response['WWW-Authenticate'] = 'Negotiate'
|
||||||
|
return response
|
||||||
|
|
||||||
|
def login(request):
|
||||||
|
'''Try to authenticate the user using SPNEGO and Kerberos'''
|
||||||
|
next_url = request.REQUEST.get('next') or settings.LOGIN_REDIRECT_URL
|
||||||
|
if app_settings.KEYTAB:
|
||||||
|
old = os.environ.get('KRB5_KTNAME')
|
||||||
|
os.environ['KRB5_KTNAME'] = app_settings.KEYTAB
|
||||||
|
try:
|
||||||
|
host = app_settings.HOSTNAME or request.get_host().split(':')[0]
|
||||||
|
service = 'HTTP@%s' % host
|
||||||
|
|
||||||
|
if 'HTTP_AUTHORIZATION' in request.META:
|
||||||
|
kind, authstr = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
|
||||||
|
print authstr
|
||||||
|
if kind == 'Negotiate':
|
||||||
|
result, context = kerberos.authGSSServerInit(service)
|
||||||
|
if result != 1:
|
||||||
|
return TemplateResponse(request, 'django_kerberos/error.html')
|
||||||
|
r = kerberos.authGSSServerStep(context, authstr)
|
||||||
|
if r == 1:
|
||||||
|
gssstring = kerberos.authGSSServerResponse(context)
|
||||||
|
else:
|
||||||
|
return www_authenticate(request)
|
||||||
|
principal = kerberos.authGSSServerUserName(context)
|
||||||
|
kerberos.authGSSServerClean(context)
|
||||||
|
user = authenticate(principal=principal)
|
||||||
|
if user:
|
||||||
|
auth_login(request, user)
|
||||||
|
response = http.HttpResponseRedirect(next_url)
|
||||||
|
response['WWW-Authenticate'] = 'Negotiate %s' % gssstring
|
||||||
|
return response
|
||||||
|
return www_authenticate(request)
|
||||||
|
finally:
|
||||||
|
if app_settings.KEYTAB:
|
||||||
|
if old:
|
||||||
|
os.environ['KRB5_KTNAME'] = old
|
||||||
|
else:
|
||||||
|
del os.environ['KRB5_KTNAME']
|
Loading…
Reference in New Issue