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