add Python3 and django 1.11 support (fixes #30321)
Also remove the sample application.
This commit is contained in:
parent
61a8167e9e
commit
e8a1a7221c
|
@ -0,0 +1,50 @@
|
|||
@Library('eo-jenkins-lib@master') import eo.Utils
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
options { disableConcurrentBuilds() }
|
||||
stages {
|
||||
stage('Unit Tests') {
|
||||
steps {
|
||||
sh """
|
||||
rm -rf htmlcov* .coverage* coverage* junit*.xml
|
||||
rm -rf venv
|
||||
virtualenv -p python3 venv
|
||||
. venv/bin/activate
|
||||
pip install tox"""
|
||||
sh './venv/bin/tox -rv'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
utils = new Utils()
|
||||
utils.publish_coverage('coverage.xml')
|
||||
utils.publish_coverage_native('index.html')
|
||||
utils.publish_pylint('pylint.out')
|
||||
}
|
||||
junit 'junit*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Packaging') {
|
||||
steps {
|
||||
script {
|
||||
if (env.JOB_NAME == 'django-kerberos' && env.GIT_BRANCH == 'origin/master') {
|
||||
sh 'sudo -H -u eobuilder /usr/local/bin/eobuilder django-kerberos'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
utils = new Utils()
|
||||
utils.mail_notify(currentBuild, env, 'admin+jenkins-django-kerberos@entrouvert.com')
|
||||
}
|
||||
}
|
||||
success {
|
||||
cleanWs()
|
||||
}
|
||||
}
|
||||
}
|
2
README
2
README
|
@ -3,6 +3,8 @@ Kerberos authentication for Django
|
|||
|
||||
Provide Kerberos authentication to Django applications.
|
||||
|
||||
Python 2 and 3, Django >1.8 are supported.
|
||||
|
||||
Basic usage
|
||||
===========
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Source: python-django-kerberos
|
||||
Maintainer: Benjamin Dauvergne <info@entrouvert.com>
|
||||
Maintainer: Benjamin Dauvergne <bdauvergne@entrouvert.com>
|
||||
Section: python
|
||||
Priority: optional
|
||||
Build-Depends: python-setuptools (>= 0.6b3), python-all (>= 2.6), debhelper (>= 7.4.3),
|
||||
|
@ -10,7 +10,16 @@ X-Python-Version: >= 2.6
|
|||
Package: python-django-kerberos
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${python:Depends},
|
||||
python-django (>= 1.5),
|
||||
python-six,
|
||||
python-django (>= 1.8),
|
||||
python-kerberos
|
||||
Description: Kerberos authentication frontend for Authentic2
|
||||
|
||||
Package: python3-django-kerberos
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${python3:Depends},
|
||||
python3-six,
|
||||
python3-django (>= 1.8),
|
||||
python3-kerberos
|
||||
Description: Kerberos authentication frontend for Authentic2
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e -x
|
||||
env
|
||||
if [ -f /var/lib/jenkins/pylint.django.rc ]; then
|
||||
PYLINT_RC=/var/lib/jenkins/pylint.django.rc
|
||||
elif [ -f pylint.django.rc ]; then
|
||||
PYLINT_RC=pylint.django.rc
|
||||
else
|
||||
echo No pylint RC found
|
||||
exit 0
|
||||
fi
|
||||
pylint -f parseable --rcfile ${PYLINT_RC} "$@" | tee pylint.out || /bin/true
|
|
@ -1 +0,0 @@
|
|||
Rename config.py.example to config.py, and update default settings.
|
|
@ -1,3 +0,0 @@
|
|||
KERBEROS_SERVICE_PRINCIPAL = 'HTTP/fenouil.entrouvert.org@ENTROUVERT.ORG'
|
||||
KERBEROS_DEFAULT_REALM = 'ENTROUVERT.ORG'
|
||||
KERBEROS_BACKEND_ADMIN_REGEXP = '^.*/admin@.*$'
|
|
@ -1,10 +0,0 @@
|
|||
#!/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)
|
|
@ -1,98 +0,0 @@
|
|||
"""
|
||||
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',
|
||||
'django_kerberos.backends.KerberosPasswordBackend',
|
||||
)
|
||||
|
||||
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'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
|
||||
KERBEROS_BACKEND_CREATE = True
|
||||
KERBEROS_BACKEND_ADMIN_REGEXP = r'^.*/admin$'
|
||||
|
||||
execfile('config.py', globals())
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% include "django_kerberos/autologin.html" %}
|
||||
{% if user.is_authenticated %}
|
||||
<p>Hello {{ user }}</p>
|
||||
{% if user.is_superuser %}
|
||||
<p><a href="/admin">Admin</a></p>
|
||||
{% endif %}
|
||||
<p><a href="{% url "logout" %}?next=/">Logout</a></p>
|
||||
{% else %}
|
||||
<p>Please <a href="{% url "kerberos-login" %}">login with kerberos</a> or with your <a href="{% url "login" %}">password</a></p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button>Login</button>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||
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_kerberos.urls')),
|
||||
url('^accounts/', include('django.contrib.auth.urls')),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
def home(request):
|
||||
return render(request, 'index.html')
|
|
@ -1,14 +0,0 @@
|
|||
"""
|
||||
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()
|
27
setup.py
27
setup.py
|
@ -9,7 +9,7 @@ from setuptools.command.sdist import sdist
|
|||
|
||||
class eo_sdist(sdist):
|
||||
def run(self):
|
||||
print "creating VERSION file"
|
||||
print("creating VERSION file")
|
||||
if os.path.exists('VERSION'):
|
||||
os.remove('VERSION')
|
||||
version = get_version()
|
||||
|
@ -17,35 +17,41 @@ class eo_sdist(sdist):
|
|||
version_file.write(version)
|
||||
version_file.close()
|
||||
sdist.run(self)
|
||||
print "removing VERSION file"
|
||||
print("removing VERSION file")
|
||||
if os.path.exists('VERSION'):
|
||||
os.remove('VERSION')
|
||||
|
||||
|
||||
def get_version():
|
||||
'''Use the VERSION, if absent generates a version with git describe, if not
|
||||
tag exists, take 0.0.0- and add the length of the commit log.
|
||||
tag exists, take 0.0- and add the length of the commit log.
|
||||
'''
|
||||
if os.path.exists('VERSION'):
|
||||
with open('VERSION', 'r') as v:
|
||||
return v.read()
|
||||
if os.path.exists('.git'):
|
||||
p = subprocess.Popen(['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE,
|
||||
p = subprocess.Popen(['git', 'describe', '--dirty=.dirty','--match=v*'], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
result = p.communicate()[0]
|
||||
if p.returncode == 0:
|
||||
result = result.split()[0][1:]
|
||||
result = result.decode('ascii').strip()[1:] # strip spaces/newlines and initial v
|
||||
if '-' in result: # not a tagged version
|
||||
real_number, commit_count, commit_hash = result.split('-', 2)
|
||||
version = '%s.post%s+%s' % (real_number, commit_count, commit_hash)
|
||||
else:
|
||||
version = result
|
||||
return version
|
||||
else:
|
||||
result = '0.0.0-%s' % len(subprocess.check_output(
|
||||
['git', 'rev-list', 'HEAD']).splitlines())
|
||||
return result.replace('-', '.').replace('.g', '+g')
|
||||
return '0.0.0'
|
||||
return '0.0.post%s' % len(
|
||||
subprocess.check_output(
|
||||
['git', 'rev-list', 'HEAD']).splitlines())
|
||||
return '0.0'
|
||||
|
||||
setup(name="django-kerberos",
|
||||
version=get_version(),
|
||||
license="AGPLv3 or later",
|
||||
description="Kerberos authentication for Django",
|
||||
long_description=file('README').read(),
|
||||
long_description=open('README').read(),
|
||||
url="http://dev.entrouvert.org/projects/authentic/",
|
||||
author="Entr'ouvert",
|
||||
author_email="info@entrouvert.org",
|
||||
|
@ -53,6 +59,7 @@ setup(name="django-kerberos",
|
|||
maintainer_email="bdauvergne@entrouvert.com",
|
||||
packages=find_packages('src'),
|
||||
install_requires=[
|
||||
'six',
|
||||
'django>1.5',
|
||||
'pykerberos',
|
||||
],
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import re
|
||||
import logging
|
||||
|
||||
from . import app_settings
|
||||
import six
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.encoding import force_bytes
|
||||
|
@ -27,6 +27,8 @@ from django.contrib.auth.backends import ModelBackend
|
|||
|
||||
import kerberos
|
||||
|
||||
from . import app_settings
|
||||
|
||||
|
||||
class KerberosBackend(ModelBackend):
|
||||
def __init__(self):
|
||||
|
@ -74,7 +76,7 @@ class KerberosBackend(ModelBackend):
|
|||
self.provision_user(principal, user)
|
||||
return user
|
||||
|
||||
def authenticate(self, principal=None, **kwargs):
|
||||
def authenticate(self, request=None, principal=None):
|
||||
if principal and self.authorize_principal(principal):
|
||||
return self.lookup_user(principal)
|
||||
|
||||
|
@ -102,22 +104,26 @@ class KerberosPasswordBackend(KerberosBackend):
|
|||
' set')
|
||||
return app_settings.SERVICE_PRINCIPAL
|
||||
|
||||
def authenticate(self, username=None, password=None, **kwargs):
|
||||
def authenticate(self, request=None, username=None, password=None):
|
||||
'''Verify username and password using Kerberos'''
|
||||
if not username:
|
||||
return
|
||||
|
||||
principal = force_bytes(self.principal_from_username(username))
|
||||
password = force_bytes(password)
|
||||
kerb_principal = principal = self.principal_from_username(username)
|
||||
kerb_password = password
|
||||
|
||||
if six.PY2:
|
||||
kerb_principal = force_bytes(kerb_principal)
|
||||
kerb_password = force_bytes(kerb_principal)
|
||||
|
||||
try:
|
||||
if not kerberos.checkPassword(principal, password,
|
||||
if not kerberos.checkPassword(kerb_principal, kerb_password,
|
||||
self.service_principal(),
|
||||
self.default_realm()):
|
||||
return
|
||||
except kerberos.KrbError as e:
|
||||
logging.getLogger(__name__).error(
|
||||
'password validation forprincipal %r failed %s', principal, e)
|
||||
'password validation for principal %r failed %s', principal, e)
|
||||
return
|
||||
else:
|
||||
if principal and self.authorize_principal(principal):
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
urlpatterns = [
|
||||
url(r'^login/$', views.login, name='kerberos-login'),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -52,7 +52,7 @@ class NegotiateView(View):
|
|||
'''Do something with the principal we received'''
|
||||
self.logger.info(u'got ticket for principal %s', self.principal)
|
||||
user = authenticate(principal=self.principal)
|
||||
next_url = request.REQUEST.get(self.NEXT_URL_FIELD) or settings.LOGIN_REDIRECT_URL
|
||||
next_url = request.POST.get(self.NEXT_URL_FIELD) or request.GET.get(self.NEXT_URL_FIELD) or settings.LOGIN_REDIRECT_URL
|
||||
if user:
|
||||
self.login_user(request, user)
|
||||
if request.is_ajax():
|
||||
|
@ -88,8 +88,8 @@ class NegotiateView(View):
|
|||
# ensure context is finalized
|
||||
try:
|
||||
if result != 1:
|
||||
self.logger.warning(u'authGSSServerInit result is non-zero: %s', result)
|
||||
details = u'authGSSServerInit result is non-zero: %s' % result
|
||||
self.logger.warning(u'authGSSServerInit result is non-one: %s', result)
|
||||
details = u'authGSSServerInit result is non-one: %s' % result
|
||||
return TemplateResponse(request, self.error_template_name,
|
||||
context={'details': details}, status=500)
|
||||
try:
|
||||
|
|
|
@ -1,5 +1,42 @@
|
|||
import django
|
||||
import os.path
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': os.environ.get('DB_ENGINE', 'django.db.backends.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(os.path.dirname(__file__), 'templates')],
|
||||
'APP_DIRS': True,
|
||||
},
|
||||
]
|
||||
|
||||
if django.VERSION < (1, 10):
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.http.ConditionalGetMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
)
|
||||
else:
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'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',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
]
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.auth',
|
||||
|
@ -9,3 +46,8 @@ INSTALLED_APPS = (
|
|||
TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), 'templates'),)
|
||||
ROOT_URLCONF = 'django_kerberos.urls'
|
||||
SECRET_KEY = 'xxx'
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'django_kerberos.backends.KerberosBackend',
|
||||
'django_kerberos.backends.KerberosPasswordBackend',
|
||||
)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import logging
|
||||
import pytest
|
||||
import json
|
||||
|
||||
import kerberos
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -11,7 +14,8 @@ def kerberos_mock(request, mocker):
|
|||
'kerberos.authGSSServerStep',
|
||||
'kerberos.authGSSServerResponse',
|
||||
'kerberos.authGSSServerUserName',
|
||||
'kerberos.authGSSServerClean'
|
||||
'kerberos.authGSSServerClean',
|
||||
'kerberos.checkPassword'
|
||||
)
|
||||
for name in d:
|
||||
if hasattr(request, 'param') and name in request.param:
|
||||
|
@ -29,9 +33,143 @@ def test_login_no_header(client, settings, kerberos_mock):
|
|||
@pytest.mark.parametrize('kerberos_mock', ['kerberos.authGSSServerInit'], indirect=True)
|
||||
def test_login_missing_keytab(client, settings, kerberos_mock, caplog):
|
||||
resp = client.get('/login/', HTTP_AUTHORIZATION='Negotiate coin')
|
||||
for key, mock in kerberos_mock.iteritems():
|
||||
for key, mock in kerberos_mock.items():
|
||||
assert mock.call_count == 0
|
||||
assert 'keytab problem' in resp.content
|
||||
assert 'keytab problem' in caplog.text()
|
||||
assert b'keytab problem' in resp.content
|
||||
assert 'keytab problem' in caplog.text
|
||||
|
||||
|
||||
def test_login(client, db, settings, kerberos_mock, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
kerberos_mock['kerberos.authGSSServerInit'].side_effect = kerberos.KrbError('coin')
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 500
|
||||
assert b'exception during authGSSServerInit' in response.content
|
||||
assert 'exception during authGSSServerInit' in caplog.text
|
||||
assert b'coin' in response.content
|
||||
kerberos_mock['kerberos.authGSSServerInit'].side_effect = None
|
||||
caplog.clear()
|
||||
|
||||
kerberos_mock['kerberos.authGSSServerInit'].return_value = 0, None
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 500
|
||||
assert b'authGSSServerInit result is non-one' in response.content
|
||||
assert 'authGSSServerInit result is non-one' in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
kerberos_mock['kerberos.authGSSServerInit'].return_value = 1, None
|
||||
kerberos_mock['kerberos.authGSSServerStep'].side_effect = kerberos.KrbError('coin')
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 500
|
||||
assert b'exception during authGSSServerStep' in response.content
|
||||
assert 'exception during authGSSServerStep' in caplog.text
|
||||
assert b'coin' in response.content
|
||||
kerberos_mock['kerberos.authGSSServerStep'].side_effect = None
|
||||
caplog.clear()
|
||||
|
||||
kerberos_mock['kerberos.authGSSServerStep'].return_value = 0
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 401
|
||||
|
||||
kerberos_mock['kerberos.authGSSServerStep'].return_value = 1
|
||||
kerberos_mock['kerberos.authGSSServerUserName'].side_effect = kerberos.KrbError('coin')
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 500
|
||||
assert b'exception during authGSSServerUserName' in response.content
|
||||
assert 'exception during authGSSServerUserName' in caplog.text
|
||||
assert b'coin' in response.content
|
||||
kerberos_mock['kerberos.authGSSServerUserName'].side_effect = None
|
||||
caplog.clear()
|
||||
|
||||
kerberos_mock['kerberos.authGSSServerUserName'].return_value = 'john.doe@EXAMPLE.COM'
|
||||
kerberos_mock['kerberos.authGSSServerResponse'].return_value = 'yyyy'
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 302
|
||||
assert 'principal john.doe@EXAMPLE.COM has no local user' in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
user = User.objects.create(username='john.doe@example.com')
|
||||
assert '_auth_user_id' not in client.session
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 302
|
||||
assert response['WWW-Authenticate'] == 'Negotiate yyyy'
|
||||
assert 'principal john.doe@EXAMPLE.COM has no local user' not in caplog.text
|
||||
assert client.session['_auth_user_id'] == str(user.id)
|
||||
client.logout()
|
||||
user.delete()
|
||||
assert User.objects.count() == 0
|
||||
caplog.clear()
|
||||
|
||||
settings.KERBEROS_BACKEND_CREATE = True
|
||||
assert '_auth_user_id' not in client.session
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 302
|
||||
assert 'principal john.doe@EXAMPLE.COM has no local user' not in caplog.text
|
||||
assert User.objects.count() == 1
|
||||
user = User.objects.get()
|
||||
assert not user.is_staff
|
||||
assert not user.is_superuser
|
||||
assert client.session['_auth_user_id'] == str(user.id)
|
||||
assert 'got ticket for principal john.doe@EXAMPLE.COM' in caplog.text
|
||||
client.logout()
|
||||
caplog.clear()
|
||||
|
||||
settings.KERBEROS_BACKEND_ADMIN_REGEXP = 'john.doe'
|
||||
assert '_auth_user_id' not in client.session
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx')
|
||||
assert response.status_code == 302
|
||||
assert 'principal john.doe@EXAMPLE.COM has no local user' not in caplog.text
|
||||
assert User.objects.count() == 1
|
||||
user = User.objects.get()
|
||||
assert user.is_staff
|
||||
assert user.is_superuser
|
||||
assert client.session['_auth_user_id'] == str(user.id)
|
||||
assert 'got ticket for principal john.doe@EXAMPLE.COM' in caplog.text
|
||||
assert 'giving superuser power to principal \'john.doe@EXAMPLE.COM\'' in caplog.text
|
||||
client.logout()
|
||||
caplog.clear()
|
||||
|
||||
assert '_auth_user_id' not in client.session
|
||||
response = client.get('/login/', HTTP_AUTHORIZATION='Negotiate xxxx', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.content.decode('ascii')) is True
|
||||
|
||||
|
||||
def test_password_backend(db, settings, kerberos_mock, caplog):
|
||||
from django.contrib.auth import authenticate
|
||||
|
||||
settings.KERBEROS_DEFAULT_REALM = 'EXAMPLE.COM'
|
||||
settings.KERBEROS_SERVICE_PRINCIPAL = 'HTTP/SERVICE.EXAMPLE.COM@EXAMPLE.COM'
|
||||
|
||||
m = kerberos_mock['kerberos.checkPassword']
|
||||
m.return_value = False
|
||||
assert authenticate(username='john.doe', password='password') is None
|
||||
assert User.objects.count() == 0
|
||||
|
||||
m.return_value = True
|
||||
assert authenticate(username='john.doe', password='password') is None
|
||||
assert User.objects.count() == 0
|
||||
|
||||
user = User.objects.create(username='john.doe@example.com')
|
||||
assert authenticate(username='john.doe', password='password') == user
|
||||
user.delete()
|
||||
|
||||
assert User.objects.count() == 0
|
||||
settings.KERBEROS_BACKEND_CREATE = True
|
||||
new_user = authenticate(username='john.doe', password='password')
|
||||
assert new_user
|
||||
assert User.objects.count() == 1
|
||||
assert new_user.username == 'john.doe@example.com'
|
||||
assert not new_user.has_usable_password()
|
||||
|
||||
settings.KERBEROS_KEEP_PASSWORD = True
|
||||
new_user = authenticate(username='john.doe', password='password')
|
||||
assert User.objects.count() == 1
|
||||
assert new_user.username == 'john.doe@example.com'
|
||||
assert new_user.has_usable_password()
|
||||
assert new_user.check_password('password')
|
||||
|
||||
caplog.clear()
|
||||
m.side_effect = kerberos.KrbError('coin')
|
||||
assert authenticate(username='john.doe', password='password') is None
|
||||
assert 'password validation for principal %r failed coin' % u'john.doe@EXAMPLE.COM' in caplog.text
|
||||
|
|
48
tox.ini
48
tox.ini
|
@ -3,40 +3,38 @@
|
|||
# test suite on all supported python versions. To use it, "pip install tox"
|
||||
# and then run "tox" from this directory.
|
||||
|
||||
[testenv:coverage]
|
||||
[tox]
|
||||
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/django-kerberos/{env:BRANCH_NAME:}
|
||||
envlist = py27-coverage-{dj18,dj111}-{pg,sqlite},py3-coverage-{dj18,dj111,dj20,djlast}-{pg,sqlite},pylint
|
||||
|
||||
[testenv]
|
||||
whitelist_externals =
|
||||
/bin/mv
|
||||
/bin/rm
|
||||
setenv =
|
||||
DJANGO_SETTINGS_MODULE=settings
|
||||
PYTHONPATH=tests
|
||||
coverage: COVERAGE=--cov-branch --cov-append --cov=src/ --cov-report=html --cov-report=xml --cov-config .coveragerc
|
||||
sqlite: DB_ENGINE=django.db.backends.sqlite3
|
||||
pg: DB_ENGINE=django.db.backends.postgresql_psycopg2
|
||||
usedevelop = true
|
||||
deps =
|
||||
pytest
|
||||
dj18: django>1.8,<1.9
|
||||
dj18: django-tables2<1.1
|
||||
dj111: django<2.0
|
||||
dj20: django<2.1
|
||||
djlast: django
|
||||
pg: psycopg2-binary
|
||||
pytest<4.2
|
||||
pytest-mock
|
||||
pytest-django
|
||||
pytest-cov
|
||||
pytest-capturelog
|
||||
commands =
|
||||
py.test {posargs:--junit-xml=junit.xml --cov=src --cov-report xml --nomigrations tests}
|
||||
py.test {env:COVERAGE:} --junit-xml=junit-{envname}.xml {posargs:tests}
|
||||
|
||||
[testenv:nocoverage]
|
||||
setenv =
|
||||
DJANGO_SETTINGS_MODULE=settings
|
||||
PYTHONPATH=tests
|
||||
[testenv:pylint]
|
||||
deps =
|
||||
pytest
|
||||
pytest-mock
|
||||
pytest-django
|
||||
pytest-cov
|
||||
pytest-capturelog
|
||||
pylint<1.8
|
||||
pylint-django<0.8.1
|
||||
commands =
|
||||
py.test {posargs:--nomigrations tests}
|
||||
|
||||
[testenv:package]
|
||||
# eobuilder is not on pypi, too bad
|
||||
deps = setuptools
|
||||
pip<8
|
||||
pyasn1
|
||||
ndg-httpsclient
|
||||
pyopenssl
|
||||
commands =
|
||||
pip install -U --find-links https://jenkins.entrouvert.org/packages/ eobuilder
|
||||
sh -c "sudo -u eobuilder -E env HOME=/var/lib/eobuilder PATH=$PATH $VIRTUAL_ENV/bin/eobuilder-ctl -d wheezy,jessie {posargs:django-kerberos}"
|
||||
pylint: ./pylint.sh src/django_kerberos/
|
||||
|
|
Loading…
Reference in New Issue