enable autologin after first manual login (#30018)
This commit is contained in:
parent
38ceef6eb4
commit
839620aeee
|
@ -1,7 +1,10 @@
|
|||
from django.utils.translation import gettext_noop
|
||||
from django import forms
|
||||
from django.shortcuts import render
|
||||
|
||||
from authentic2 import constants, utils
|
||||
|
||||
from . import app_settings
|
||||
|
||||
from . import app_settings, utils
|
||||
|
||||
class KerberosAuthenticator(object):
|
||||
def enabled(self):
|
||||
|
@ -13,14 +16,15 @@ class KerberosAuthenticator(object):
|
|||
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'
|
||||
|
||||
def is_hidden(self, request):
|
||||
return 'a2_just_logged_out' not in request.COOKIES
|
||||
def login(self, request, *args, **kwargs):
|
||||
context = kwargs.get('context', {})
|
||||
# autologin is allowed if :
|
||||
# * a Kerberos login has already happened on this terminal
|
||||
# * we do not come from the logout view
|
||||
if (request.COOKIES.get('a2_kerberos_ok') == '1'
|
||||
and 'a2_just_logged_out' not in request.COOKIES):
|
||||
context['autologin'] = True
|
||||
submit = request.method == 'POST' and 'login-kerberos' in request.POST
|
||||
if submit:
|
||||
return utils.redirect_to_login(request, login_url='kerberos-login')
|
||||
return render(request, 'authentic2_auth_kerberos/login.html', context)
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
{% load i18n %}
|
||||
<div>
|
||||
{% include "authentic2_auth_kerberos/autologin.html" %}
|
||||
<form method="post">
|
||||
{% if autologin %}
|
||||
{% include "authentic2_auth_kerberos/autologin.html" %}
|
||||
{% endif %}
|
||||
<form id='kerberos-form' method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" name="{{ submit_name }}" value="{% trans "Login" %}"/>
|
||||
<button name="login-kerberos" value="1">{% trans "Login" %}</button>
|
||||
{% if cancel %}
|
||||
<input type="submit" name="cancel" value="{% trans 'Cancel' %}"/>
|
||||
<input type="submit" name="cancel" value="{% trans 'Cancel' %}"/>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
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)
|
|
@ -2,17 +2,28 @@ import logging
|
|||
|
||||
from django_kerberos.views import NegotiateView
|
||||
|
||||
from authentic2.models import AuthenticationEvent
|
||||
from authentic2 import utils
|
||||
|
||||
__ALL_ = [ 'login' ]
|
||||
__ALL_ = ['login']
|
||||
|
||||
|
||||
class A2NegotiateView(NegotiateView):
|
||||
authentication_successful = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(A2NegotiateView, self).__init__(*args, **kwargs)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def login_user(self, request, user):
|
||||
self.authentication_successful = True
|
||||
utils.login(request, user, 'kerberos')
|
||||
|
||||
def principal_valid(self, request, *args, **kwargs):
|
||||
response = super(A2NegotiateView, self).principal_valid(request, *args, **kwargs)
|
||||
if self.authentication_successful:
|
||||
# set cookie so that automatic login will be tried next time
|
||||
response.set_cookie('a2_kerberos_ok', '1', max_age=86400 * 365)
|
||||
return response
|
||||
|
||||
|
||||
login = A2NegotiateView.as_view()
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# authentic2-auth-kerberos - Kerberos plugin for authentic2
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
|
||||
import pytest
|
||||
import django_webtest
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.a2_rbac.utils import get_default_ou
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app_factory(settings, tmpdir):
|
||||
settings.MEDIA_ROOT = str(tmpdir.mkdir('media'))
|
||||
wtm = django_webtest.WebTestMixin()
|
||||
wtm._patch_settings()
|
||||
try:
|
||||
def factory(hostname='localhost'):
|
||||
return django_webtest.DjangoTestApp(extra_environ={'HTTP_HOST': hostname})
|
||||
yield factory
|
||||
finally:
|
||||
wtm._unpatch_settings()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app(app_factory):
|
||||
return app_factory()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_user():
|
||||
def func(**kwargs):
|
||||
password = kwargs.pop('password', None) or kwargs['username']
|
||||
user, created = User.objects.get_or_create(**kwargs)
|
||||
if password:
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
return user
|
||||
return func
|
|
@ -14,3 +14,5 @@ if 'postgres' in DATABASES['default']['ENGINE']:
|
|||
for key in ('PGPORT', 'PGHOST', 'PGUSER', 'PGPASSWORD'):
|
||||
if key in os.environ:
|
||||
DATABASES['default'][key[2:]] = os.environ[key]
|
||||
|
||||
ALLOWED_HOSTS = ['localhost']
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# authentic2-auth-kerberos - Kerberos plugin for authentic2
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
import pytest
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def kerberos(monkeypatch):
|
||||
import django_kerberos.views
|
||||
|
||||
class MockKerberos(object):
|
||||
server_init_result = 1
|
||||
server_step_result = 1
|
||||
server_response_result = 'x'
|
||||
principal = 'user@REALM'
|
||||
|
||||
def set(self, **kwargs):
|
||||
self.__dict__ = kwargs
|
||||
|
||||
def authGSSServerInit(self, service):
|
||||
return self.server_init_result, {}
|
||||
|
||||
def authGSSServerStep(self, context, authstr):
|
||||
return self.server_step_result
|
||||
|
||||
def authGSSServerResponse(self, context):
|
||||
return self.server_response_result
|
||||
|
||||
def authGSSServerUserName(self, context):
|
||||
return self.principal
|
||||
|
||||
def authGSSServerClean(self, context):
|
||||
pass
|
||||
|
||||
class KrbError(Exception):
|
||||
pass
|
||||
monkeypatch.setattr('django_kerberos.views.kerberos', MockKerberos())
|
||||
return django_kerberos.views.kerberos
|
||||
|
||||
|
||||
def test_default(settings, app, db):
|
||||
settings.A2_AUTH_KERBEROS_DJANGO_BACKEND = True
|
||||
|
||||
assert User.objects.count() == 0
|
||||
assert 'a2_kerberos_ok' not in app.cookies
|
||||
response = app.get('/login/')
|
||||
assert 'login-kerberos' in response.text
|
||||
assert 'autologin' not in response.text
|
||||
response = response.forms['kerberos-form'].submit(name='login-kerberos')
|
||||
assert response.location == '/accounts/kerberos/login/'
|
||||
response = response.follow(headers={'Authorization': 'Negotiate y'})
|
||||
assert app.cookies['a2_kerberos_ok'] == '1'
|
||||
assert response.location == '/'
|
||||
assert User.objects.count() == 1
|
||||
assert User.objects.get(username='user@realm')
|
||||
|
||||
# logout
|
||||
app.session.flush()
|
||||
response = app.get('/login/')
|
||||
assert 'login-kerberos' in response.text
|
||||
assert 'autologin' in response.text
|
3
tox.ini
3
tox.ini
|
@ -6,7 +6,7 @@
|
|||
|
||||
[tox]
|
||||
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/authentic2-auth-kerberos/
|
||||
envlist = py27-coverage-{dj18,dj111}-{oldldap,},pylint
|
||||
envlist = py27-coverage-dj111-{oldldap,},pylint
|
||||
|
||||
[testenv]
|
||||
whitelist_externals =
|
||||
|
@ -42,6 +42,7 @@ deps =
|
|||
ldaptools
|
||||
http://git.entrouvert.org/authentic.git/snapshot/authentic-master.tar.bz2
|
||||
oldldap: python-ldap<3
|
||||
django-webtest
|
||||
commands =
|
||||
./getlasso.sh
|
||||
py.test {env:COVERAGE:} {env:JUNIT:} {posargs:tests}
|
||||
|
|
Loading…
Reference in New Issue