Merge pull request #34 from nitmir/dev
Update version to 0.9.0 v0.9.0 - 2017-11-17 =================== Added ----- * Dutch translation * Protuguese translation (brazilian variant) * Support for ldap3 version 2 or more (changes in the API) All exception are now in ldap3.core.exceptions, methodes for fetching attritutes and dn are renamed. * Possibility to disable service message boxes on the login pages Fixed ----- * Then using the LDAP auth backend with ``bind`` method for password check, do not try to bind if the user dn was not found. This was causing the exception ``'NoneType' object has no attribute 'getitem'`` describe in #21 * Increase the max size of usernames (30 chars to 250) * Fix XSS js injection
This commit is contained in:
commit
4229f871c5
14 changed files with 605 additions and 39 deletions
|
@ -6,6 +6,29 @@ All notable changes to this project will be documented in this file.
|
|||
.. contents:: Table of Contents
|
||||
:depth: 2
|
||||
|
||||
|
||||
v0.9.0 - 2017-11-17
|
||||
===================
|
||||
|
||||
Added
|
||||
-----
|
||||
* Dutch translation
|
||||
* Protuguese translation (brazilian variant)
|
||||
* Support for ldap3 version 2 or more (changes in the API)
|
||||
All exception are now in ldap3.core.exceptions, methodes for fetching attritutes and
|
||||
dn are renamed.
|
||||
* Possibility to disable service message boxes on the login pages
|
||||
|
||||
Fixed
|
||||
-----
|
||||
* Then using the LDAP auth backend with ``bind`` method for password check, do not try to bind
|
||||
if the user dn was not found. This was causing the exception
|
||||
``'NoneType' object has no attribute 'getitem'`` describe in #21
|
||||
* Increase the max size of usernames (30 chars to 250)
|
||||
* Fix XSS js injection
|
||||
|
||||
|
||||
|
||||
v0.8.0 - 2017-03-08
|
||||
===================
|
||||
|
||||
|
|
|
@ -218,7 +218,8 @@ Template settings
|
|||
}
|
||||
|
||||
if you omit some keys of the dictionnary, the default value for these keys is used.
|
||||
|
||||
* ``CAS_SHOW_SERVICE_MESSAGES``: Messages displayed about the state of the service on the login page.
|
||||
The default is ``True``.
|
||||
* ``CAS_INFO_MESSAGES``: Messages displayed in info-boxes on the html pages of the default templates.
|
||||
It is a dictionnary mapping message name to a message dict. A message dict has 3 keys:
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"""A django CAS server application"""
|
||||
|
||||
#: version of the application
|
||||
VERSION = '0.8.0'
|
||||
VERSION = '0.9.0'
|
||||
|
||||
#: path the the application configuration class
|
||||
default_app_config = 'cas_server.apps.CasAppConfig'
|
||||
|
|
|
@ -27,6 +27,7 @@ except ImportError:
|
|||
|
||||
try: # pragma: no cover
|
||||
import ldap3
|
||||
import ldap3.core.exceptions
|
||||
except ImportError:
|
||||
ldap3 = None
|
||||
|
||||
|
@ -297,9 +298,19 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
|||
settings.CAS_LDAP_USER_QUERY % ldap3.utils.conv.escape_bytes(username),
|
||||
attributes=ldap3.ALL_ATTRIBUTES
|
||||
) and len(conn.entries) == 1:
|
||||
user = conn.entries[0].entry_get_attributes_dict()
|
||||
# store the user dn
|
||||
user["dn"] = conn.entries[0].entry_get_dn()
|
||||
# try the new ldap3>=2 API
|
||||
try:
|
||||
user = conn.entries[0].entry_attributes_as_dict
|
||||
# store the user dn
|
||||
user["dn"] = conn.entries[0].entry_dn
|
||||
# fallback to ldap3<2 API
|
||||
except (
|
||||
ldap3.core.exceptions.LDAPKeyError, # ldap3<1 exception
|
||||
ldap3.core.exceptions.LDAPAttributeError # ldap3<2 exception
|
||||
):
|
||||
user = conn.entries[0].entry_get_attributes_dict()
|
||||
# store the user dn
|
||||
user["dn"] = conn.entries[0].entry_get_dn()
|
||||
if user.get(settings.CAS_LDAP_USERNAME_ATTR):
|
||||
self.user = user
|
||||
super(LdapAuthUser, self).__init__(user[settings.CAS_LDAP_USERNAME_ATTR][0])
|
||||
|
@ -308,7 +319,7 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
|||
else:
|
||||
super(LdapAuthUser, self).__init__(username)
|
||||
break
|
||||
except ldap3.LDAPCommunicationError:
|
||||
except ldap3.core.exceptions.LDAPCommunicationError:
|
||||
if retry_nb == 2:
|
||||
raise
|
||||
|
||||
|
@ -321,7 +332,7 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
|||
correct, ``False`` otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
if settings.CAS_LDAP_PASSWORD_CHECK == "bind":
|
||||
if self.user and settings.CAS_LDAP_PASSWORD_CHECK == "bind":
|
||||
try:
|
||||
conn = ldap3.Connection(
|
||||
settings.CAS_LDAP_SERVER,
|
||||
|
@ -336,8 +347,18 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
|||
settings.CAS_LDAP_USER_QUERY % ldap3.utils.conv.escape_bytes(self.username),
|
||||
attributes=ldap3.ALL_ATTRIBUTES
|
||||
) and len(conn.entries) == 1:
|
||||
attributes = conn.entries[0].entry_get_attributes_dict()
|
||||
attributes["dn"] = conn.entries[0].entry_get_dn()
|
||||
# try the ldap3>=2 API
|
||||
try:
|
||||
attributes = conn.entries[0].entry_attributes_as_dict
|
||||
# store the user dn
|
||||
attributes["dn"] = conn.entries[0].entry_dn
|
||||
# fallback to ldap<2 API
|
||||
except (
|
||||
ldap3.core.exceptions.LDAPKeyError, # ldap3<1 exception
|
||||
ldap3.core.exceptions.LDAPAttributeError # ldap3<2 exception
|
||||
):
|
||||
attributes = conn.entries[0].entry_get_attributes_dict()
|
||||
attributes["dn"] = conn.entries[0].entry_get_dn()
|
||||
# cache the attributes locally as we wont have access to the user password
|
||||
# later.
|
||||
user = UserAttributes.objects.get_or_create(username=self.username)[0]
|
||||
|
@ -346,7 +367,10 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
|||
finally:
|
||||
conn.unbind()
|
||||
return True
|
||||
except (ldap3.LDAPBindError, ldap3.LDAPCommunicationError):
|
||||
except (
|
||||
ldap3.core.exceptions.LDAPBindError,
|
||||
ldap3.core.exceptions.LDAPCommunicationError
|
||||
):
|
||||
return False
|
||||
elif self.user and self.user.get(settings.CAS_LDAP_PASSWORD_ATTR):
|
||||
return check_password(
|
||||
|
|
|
@ -185,6 +185,8 @@ CAS_NEW_VERSION_EMAIL_WARNING = True
|
|||
#: You should not change it.
|
||||
CAS_NEW_VERSION_JSON_URL = "https://pypi.python.org/pypi/django-cas-server/json"
|
||||
|
||||
#: If the service message should be displayed on the login page
|
||||
CAS_SHOW_SERVICE_MESSAGES = True
|
||||
|
||||
#: Messages displayed in a info-box on the html pages of the default templates.
|
||||
#: ``CAS_INFO_MESSAGES`` is a :class:`dict` mapping message name to a message :class:`dict`.
|
||||
|
|
BIN
cas_server/locale/pt_BR/django.mo
Normal file
BIN
cas_server/locale/pt_BR/django.mo
Normal file
Binary file not shown.
398
cas_server/locale/pt_BR/django.po
Normal file
398
cas_server/locale/pt_BR/django.po
Normal file
|
@ -0,0 +1,398 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-08-22 08:18-0300\n"
|
||||
"PO-Revision-Date: 2017-08-29 18:09+0200\n"
|
||||
"Language-Team: Roberto Morati <robertomorati@gmail.com>\n"
|
||||
"Language: pt_BR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Last-Translator: Valentin Samir <valentin.samir@crans.org>\n"
|
||||
"X-Generator: Poedit 1.8.11\n"
|
||||
|
||||
#: cas_server/apps.py:25 cas_server/templates/cas_server/base.html:7
|
||||
#: cas_server/templates/cas_server/base.html:26
|
||||
msgid "Central Authentication Service"
|
||||
msgstr "Central de Autenticação de Serviços"
|
||||
|
||||
#: cas_server/default_settings.py:201
|
||||
msgid ""
|
||||
"The Central Authentication Service grants you access to most of our websites by "
|
||||
"authenticating only once, so you don't need to type your credentials again unless your "
|
||||
"session expires or you logout."
|
||||
msgstr ""
|
||||
"A Central de Autenticação de Serviços garante seu acesso à maioria dos nossos sitespor "
|
||||
"meio de uma única autenticação, então você não precisa digitar suas "
|
||||
"credenciaisnovamente, ao menos que sua sessão expire ou seu logout."
|
||||
|
||||
#: cas_server/forms.py:85
|
||||
msgid "Identity provider"
|
||||
msgstr "Provedor de identidade"
|
||||
|
||||
#: cas_server/forms.py:89 cas_server/forms.py:111
|
||||
msgid "Warn me before logging me into other sites."
|
||||
msgstr "Avise-me antes de me registrar em outros sites"
|
||||
|
||||
#: cas_server/forms.py:93
|
||||
msgid "Remember the identity provider"
|
||||
msgstr "Relembrar o provedor de identidade"
|
||||
|
||||
#: cas_server/forms.py:104 cas_server/models.py:638
|
||||
msgid "username"
|
||||
msgstr "usuário"
|
||||
|
||||
#: cas_server/forms.py:108
|
||||
msgid "password"
|
||||
msgstr "senha"
|
||||
|
||||
#: cas_server/forms.py:131
|
||||
msgid "The credentials you provided cannot be determined to be authentic."
|
||||
msgstr "As credenciais que você forneceu não podem ser determinadas como autênticas."
|
||||
|
||||
#: cas_server/forms.py:183
|
||||
msgid "User not found in the temporary database, please try to reconnect"
|
||||
msgstr "Usuário não encontrado na base de dados temporária, por favor, tente se reconectar"
|
||||
|
||||
#: cas_server/forms.py:197
|
||||
msgid "service"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/management/commands/cas_clean_federate.py:20
|
||||
msgid "Clean old federated users"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/management/commands/cas_clean_sessions.py:22
|
||||
msgid "Clean deleted sessions"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/management/commands/cas_clean_tickets.py:22
|
||||
msgid "Clean old tickets"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:71
|
||||
msgid "identity provider"
|
||||
msgstr "provedor de identidade"
|
||||
|
||||
#: cas_server/models.py:72
|
||||
msgid "identity providers"
|
||||
msgstr "provedores de identidade"
|
||||
|
||||
#: cas_server/models.py:78
|
||||
msgid "suffix"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:80
|
||||
msgid "Suffix append to backend CAS returned username: ``returned_username`` @ ``suffix``."
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:87
|
||||
msgid "server url"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:97
|
||||
msgid "CAS protocol version"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:99
|
||||
msgid "Version of the CAS protocol to use when sending requests the the backend CAS."
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:106
|
||||
msgid "verbose name"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:107
|
||||
msgid "Name for this identity provider displayed on the login page."
|
||||
msgstr "Nome para exibir o provedor de identidade na página de login."
|
||||
|
||||
#: cas_server/models.py:113 cas_server/models.py:490
|
||||
msgid "position"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:127
|
||||
msgid "display"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:128
|
||||
msgid "Display the provider on the login page."
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:166
|
||||
msgid "Federated user"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:167
|
||||
msgid "Federated users"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:246
|
||||
msgid "User attributes cache"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:247
|
||||
msgid "User attributes caches"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:271
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:272
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:364
|
||||
#, python-format
|
||||
msgid "Error during service logout %s"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:484
|
||||
msgid "Service pattern"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:485
|
||||
msgid "Services patterns"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:491
|
||||
msgid "service patterns are sorted using the position attribute"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:499 cas_server/models.py:664
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:500
|
||||
msgid "A name for the service"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:508 cas_server/models.py:707 cas_server/models.py:737
|
||||
msgid "pattern"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:510
|
||||
msgid ""
|
||||
"A regular expression matching services. Will usually looks like '^https://some\\.server"
|
||||
"\\.com/path/.*$'.As it is a regular expression, special character must be escaped with a "
|
||||
"'\\'."
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:521
|
||||
msgid "user field"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:522
|
||||
msgid "Name of the attribute to transmit as username, empty = login"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:527
|
||||
msgid "restrict username"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:528
|
||||
msgid "Limit username allowed to connect to the list provided bellow"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:533
|
||||
msgid "proxy"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:534
|
||||
msgid "Proxy tickets can be delivered to the service"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:540
|
||||
msgid "proxy callback"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:541
|
||||
msgid "can be used as a proxy callback to deliver PGT"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:548
|
||||
msgid "single log out"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:549
|
||||
msgid "Enable SLO for the service"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:558
|
||||
msgid ""
|
||||
"URL where the SLO request will be POST. empty = service url\n"
|
||||
"This is usefull for non HTTP proxied services."
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:639
|
||||
msgid "username allowed to connect to the service"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:665
|
||||
msgid "name of an attribute to send to the service, use * for all attributes"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:672 cas_server/models.py:745
|
||||
msgid "replace"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:673
|
||||
msgid ""
|
||||
"name under which the attribute will be show to the service. empty = default name of the "
|
||||
"attribut"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:700 cas_server/models.py:731
|
||||
msgid "attribute"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:701
|
||||
msgid "Name of the attribute which must verify pattern"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:708
|
||||
msgid "a regular expression"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:732
|
||||
msgid "Name of the attribute for which the value must be replace"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:738
|
||||
msgid "An regular expression maching whats need to be replaced"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/models.py:746
|
||||
msgid "replace expression, groups are capture by \\1, \\2 …"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/templates/cas_server/base.html:43
|
||||
#, python-format
|
||||
msgid ""
|
||||
"A new version of the application is available. This instance runs %(VERSION)s and the "
|
||||
"last version is %(LAST_VERSION)s. Please consider upgrading."
|
||||
msgstr ""
|
||||
"Uma nova versão da aplicação está disponível. Está instância usa a versão %(VERSION)s e "
|
||||
"a última versão é %(LAST_VERSION)s. Por favor, considere a atualização."
|
||||
|
||||
#: cas_server/templates/cas_server/logged.html:4
|
||||
msgid ""
|
||||
"<h3>Log In Successful</h3>You have successfully logged into the Central Authentication "
|
||||
"Service.<br/>For security reasons, please Log Out and Exit your web browser when you are "
|
||||
"done accessing services that require authentication!"
|
||||
msgstr ""
|
||||
"<h3>Log In realizado com sucesso</h3>Você foi conectado com sucesso a Central de "
|
||||
"Autenticação de Serviços.<br/>Por razões de segurança, faça o Log Out e saia do seu "
|
||||
"navegador quando você terminar de acessar os serviços que exigem auntenticação!"
|
||||
|
||||
#: cas_server/templates/cas_server/logged.html:8
|
||||
msgid "Log me out from all my sessions"
|
||||
msgstr "Desconecte-me de todas as sessões"
|
||||
|
||||
#: cas_server/templates/cas_server/logged.html:14
|
||||
msgid "Forget the identity provider"
|
||||
msgstr "Esquecer o provedor de identidade"
|
||||
|
||||
#: cas_server/templates/cas_server/logged.html:18
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/templates/cas_server/login.html:6
|
||||
msgid "Please log in"
|
||||
msgstr "Por favor, faça log in"
|
||||
|
||||
#: cas_server/templates/cas_server/login.html:14
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/templates/cas_server/warn.html:9
|
||||
msgid "Connect to the service"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/utils.py:744
|
||||
#, python-format
|
||||
msgid "\"%(value)s\" is not a valid regular expression"
|
||||
msgstr ""
|
||||
|
||||
#: cas_server/views.py:185
|
||||
msgid ""
|
||||
"<h3>Logout successful</h3>You have successfully logged out from the Central "
|
||||
"Authentication Service. For security reasons, close your web browser."
|
||||
msgstr ""
|
||||
"<h3>Logout realizado com sucesso</h3>Você foi desconectado com sucesso da Central de "
|
||||
"Autenticação de Serviços. Por razões de segurança, feche seu navegador."
|
||||
|
||||
#: cas_server/views.py:191
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<h3>Logout successful</h3>You have successfully logged out from %s sessions of the "
|
||||
"Central Authentication Service. For security reasons, close your web browser."
|
||||
msgstr ""
|
||||
"<h3>Logout realizado com sucesso</h3>Você foi desconectado com sucesso da %s sessão da "
|
||||
"Centralde Autenticação de Serviços. Por razões de segurança, feche seu navegador."
|
||||
|
||||
#: cas_server/views.py:198
|
||||
msgid ""
|
||||
"<h3>Logout successful</h3>You were already logged out from the Central Authentication "
|
||||
"Service. For security reasons, close your web browser."
|
||||
msgstr ""
|
||||
"<h3>Logout realizado com sucesso</h3>Você já está desconectado da Central de "
|
||||
"Autenticação de Serviços. Por razões de segurança, feche seu navegador."
|
||||
|
||||
#: cas_server/views.py:378
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Invalid response from your identity provider CAS upon ticket %(ticket)s validation: "
|
||||
"%(error)r"
|
||||
msgstr ""
|
||||
"Resposta inválida do provedor de identidade CAS sobre o ticket %(ticket)svalidação: "
|
||||
"%(error)r"
|
||||
|
||||
#: cas_server/views.py:500
|
||||
msgid "Invalid login ticket, please try to log in again"
|
||||
msgstr "Ticket de login inválido, por favor tente novamente"
|
||||
|
||||
#: cas_server/views.py:693
|
||||
#, python-format
|
||||
msgid "Authentication has been required by service %(name)s (%(url)s)"
|
||||
msgstr "Autenticação requerida pelo serviço %(name)s (%(url)s)"
|
||||
|
||||
#: cas_server/views.py:731
|
||||
#, python-format
|
||||
msgid "Service %(url)s not allowed."
|
||||
msgstr "Serviço %(url)s não permitido"
|
||||
|
||||
#: cas_server/views.py:738
|
||||
msgid "Username not allowed"
|
||||
msgstr "Usuário não permitido"
|
||||
|
||||
#: cas_server/views.py:745
|
||||
msgid "User characteristics not allowed"
|
||||
msgstr "Características de usuário não permitida"
|
||||
|
||||
#: cas_server/views.py:752
|
||||
#, python-format
|
||||
msgid "The attribute %(field)s is needed to use that service"
|
||||
msgstr "O atributo %(field)s é necessário para usar o serviço"
|
||||
|
||||
#: cas_server/views.py:842
|
||||
#, python-format
|
||||
msgid "Authentication renewal required by service %(name)s (%(url)s)."
|
||||
msgstr "Renovação da autenticação requerida pelo serviço %(name)s (%(url)s)."
|
||||
|
||||
#: cas_server/views.py:849
|
||||
#, python-format
|
||||
msgid "Authentication required by service %(name)s (%(url)s)."
|
||||
msgstr "Autenticação requerida pelo serviço %(name)s (%(url)s)."
|
||||
|
||||
#: cas_server/views.py:856
|
||||
#, python-format
|
||||
msgid "Service %s not allowed"
|
||||
msgstr "Serviço %s não permitido"
|
30
cas_server/migrations/0012_auto_20170328_1610.py
Normal file
30
cas_server/migrations/0012_auto_20170328_1610.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.5 on 2017-03-28 14:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cas_server', '0011_auto_20161007_1258'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='federatediendityprovider',
|
||||
name='cas_protocol_version',
|
||||
field=models.CharField(choices=[('1', 'CAS 1.0'), ('2', 'CAS 2.0'), ('3', 'CAS 3.0'), ('CAS_2_SAML_1_0', 'SAML 1.1')], default='3', help_text='Version of the CAS protocol to use when sending requests the the backend CAS.', max_length=30, verbose_name='CAS protocol version'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='servicepattern',
|
||||
name='single_log_out_callback',
|
||||
field=models.CharField(blank=True, default='', help_text='URL where the SLO request will be POST. empty = service url\nThis is usefull for non HTTP proxied services.', max_length=255, verbose_name='single log out callback'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='servicepattern',
|
||||
name='user_field',
|
||||
field=models.CharField(blank=True, default='', help_text='Name of the attribute to transmit as username, empty = login', max_length=255, verbose_name='user field'),
|
||||
),
|
||||
]
|
20
cas_server/migrations/0013_auto_20170329_1748.py
Normal file
20
cas_server/migrations/0013_auto_20170329_1748.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.5 on 2017-03-29 15:48
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cas_server', '0012_auto_20170328_1610'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='username',
|
||||
field=models.CharField(max_length=250),
|
||||
),
|
||||
]
|
|
@ -273,7 +273,7 @@ class User(models.Model):
|
|||
#: The session key of the current authenticated user
|
||||
session_key = models.CharField(max_length=40, blank=True, null=True)
|
||||
#: The username of the current authenticated user
|
||||
username = models.CharField(max_length=30)
|
||||
username = models.CharField(max_length=250)
|
||||
#: Last time the authenticated user has do something (auth, fetch ticket, etc…)
|
||||
date = models.DateTimeField(auto_now=True)
|
||||
#: last time the user logged
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
class="alert alert-danger"
|
||||
{% endif %}
|
||||
{% endspaceless %}>
|
||||
<p>{{message|safe}}</p>
|
||||
<p>{{message}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
<div class="alert alert-success" role="alert">{{logout_msg|safe}}</div>
|
||||
<div class="alert alert-success" role="alert">{{logout_msg}}</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -295,6 +295,24 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
|
|||
) in response.content
|
||||
)
|
||||
|
||||
@override_settings(CAS_SHOW_SERVICE_MESSAGES=False)
|
||||
def test_view_login_get_allowed_service_no_message(self):
|
||||
"""Request a ticket for an allowed service by an unauthenticated client"""
|
||||
# get a bare new http client
|
||||
client = Client()
|
||||
# we are not authenticated and are asking for a ticket for https://www.example.com
|
||||
# which is a valid service matched by self.service_pattern
|
||||
response = client.get("/login?service=https://www.example.com")
|
||||
# the login page should be displayed
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# we warn the user why it need to authenticated
|
||||
self.assertFalse(
|
||||
(
|
||||
b"Authentication required by service "
|
||||
b"example (https://www.example.com)"
|
||||
) in response.content
|
||||
)
|
||||
|
||||
def test_view_login_get_denied_service(self):
|
||||
"""Request a ticket for an denied service by an unauthenticated client"""
|
||||
# get a bare new http client
|
||||
|
@ -306,6 +324,18 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
|
|||
# we warn the user that https://www.example.net is not an allowed service url
|
||||
self.assertTrue(b"Service https://www.example.net not allowed" in response.content)
|
||||
|
||||
@override_settings(CAS_SHOW_SERVICE_MESSAGES=False)
|
||||
def test_view_login_get_denied_service_no_message(self):
|
||||
"""Request a ticket for an denied service by an unauthenticated client"""
|
||||
# get a bare new http client
|
||||
client = Client()
|
||||
# we are not authenticated and are asking for a ticket for https://www.example.net
|
||||
# which is NOT a valid service
|
||||
response = client.get("/login?service=https://www.example.net")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# we warn the user that https://www.example.net is not an allowed service url
|
||||
self.assertFalse(b"Service https://www.example.net not allowed" in response.content)
|
||||
|
||||
def test_view_login_get_auth_allowed_service(self):
|
||||
"""Request a ticket for an allowed service by an authenticated client"""
|
||||
# get a client that is already authenticated
|
||||
|
@ -505,6 +535,40 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
|
|||
# renewing authentication is done in the validate and serviceValidate views tests
|
||||
self.assertEqual(ticket.renew, True)
|
||||
|
||||
@override_settings(CAS_SHOW_SERVICE_MESSAGES=False)
|
||||
def test_renew_message_disabled(self):
|
||||
"""test the authentication renewal request from a service"""
|
||||
# use the default test service
|
||||
service = "https://www.example.com"
|
||||
# get a client that is already authenticated
|
||||
client = get_auth_client()
|
||||
# ask for a ticket for the service but aks for authentication renewal
|
||||
response = client.get("/login", {'service': service, 'renew': 'on'})
|
||||
# we are ask to reauthenticate and tell the user why
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertFalse(
|
||||
(
|
||||
b"Authentication renewal required by "
|
||||
b"service example (https://www.example.com)"
|
||||
) in response.content
|
||||
)
|
||||
# get the form default parameter
|
||||
params = copy_form(response.context["form"])
|
||||
# set valid username/password
|
||||
params["username"] = settings.CAS_TEST_USER
|
||||
params["password"] = settings.CAS_TEST_PASSWORD
|
||||
# the renew parameter from the form should be True
|
||||
self.assertEqual(params["renew"], True)
|
||||
# post the authentication request
|
||||
response = client.post("/login", params)
|
||||
# the request succed, a ticket is created and we are redirected to the service url
|
||||
self.assertEqual(response.status_code, 302)
|
||||
ticket_value = response['Location'].split('ticket=')[-1]
|
||||
ticket = models.ServiceTicket.objects.get(value=ticket_value)
|
||||
# the created ticket is marked has being gottent after a renew. Futher testing about
|
||||
# renewing authentication is done in the validate and serviceValidate views tests
|
||||
self.assertEqual(ticket.renew, True)
|
||||
|
||||
@override_settings(CAS_ENABLE_AJAX_AUTH=True)
|
||||
def test_ajax_login_required(self):
|
||||
"""
|
||||
|
|
|
@ -23,6 +23,7 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
from django.middleware.csrf import CsrfViewMiddleware
|
||||
from django.views.generic import View
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
import re
|
||||
import logging
|
||||
|
@ -181,24 +182,24 @@ class LogoutView(View, LogoutMixin):
|
|||
else:
|
||||
# build logout message depending of the number of sessions the user logs out
|
||||
if session_nb == 1:
|
||||
logout_msg = _(
|
||||
logout_msg = mark_safe(_(
|
||||
"<h3>Logout successful</h3>"
|
||||
"You have successfully logged out from the Central Authentication Service. "
|
||||
"For security reasons, close your web browser."
|
||||
)
|
||||
))
|
||||
elif session_nb > 1:
|
||||
logout_msg = _(
|
||||
logout_msg = mark_safe(_(
|
||||
"<h3>Logout successful</h3>"
|
||||
"You have successfully logged out from %s sessions of the Central "
|
||||
"You have successfully logged out from %d sessions of the Central "
|
||||
"Authentication Service. "
|
||||
"For security reasons, close your web browser."
|
||||
) % session_nb
|
||||
) % session_nb)
|
||||
else:
|
||||
logout_msg = _(
|
||||
logout_msg = mark_safe(_(
|
||||
"<h3>Logout successful</h3>"
|
||||
"You were already logged out from the Central Authentication Service. "
|
||||
"For security reasons, close your web browser."
|
||||
)
|
||||
))
|
||||
|
||||
# depending of settings, redirect to the login page with a logout message or display
|
||||
# the logout page. The default is to display tge logout page.
|
||||
|
@ -835,26 +836,29 @@ class LoginView(View, LogoutMixin):
|
|||
# clean messages before leaving django
|
||||
list(messages.get_messages(self.request))
|
||||
return HttpResponseRedirect(self.service)
|
||||
if self.request.session.get("authenticated") and self.renew:
|
||||
messages.add_message(
|
||||
self.request,
|
||||
messages.WARNING,
|
||||
_(u"Authentication renewal required by service %(name)s (%(url)s).") %
|
||||
{'name': service_pattern.name, 'url': self.service}
|
||||
)
|
||||
else:
|
||||
messages.add_message(
|
||||
self.request,
|
||||
messages.WARNING,
|
||||
_(u"Authentication required by service %(name)s (%(url)s).") %
|
||||
{'name': service_pattern.name, 'url': self.service}
|
||||
)
|
||||
|
||||
if settings.CAS_SHOW_SERVICE_MESSAGES:
|
||||
if self.request.session.get("authenticated") and self.renew:
|
||||
messages.add_message(
|
||||
self.request,
|
||||
messages.WARNING,
|
||||
_(u"Authentication renewal required by service %(name)s (%(url)s).") %
|
||||
{'name': service_pattern.name, 'url': self.service}
|
||||
)
|
||||
else:
|
||||
messages.add_message(
|
||||
self.request,
|
||||
messages.WARNING,
|
||||
_(u"Authentication required by service %(name)s (%(url)s).") %
|
||||
{'name': service_pattern.name, 'url': self.service}
|
||||
)
|
||||
except ServicePattern.DoesNotExist:
|
||||
messages.add_message(
|
||||
self.request,
|
||||
messages.ERROR,
|
||||
_(u'Service %s not allowed') % self.service
|
||||
)
|
||||
if settings.CAS_SHOW_SERVICE_MESSAGES:
|
||||
messages.add_message(
|
||||
self.request,
|
||||
messages.ERROR,
|
||||
_(u'Service %s not allowed') % self.service
|
||||
)
|
||||
if self.ajax:
|
||||
data = {
|
||||
"status": "error",
|
||||
|
|
Loading…
Reference in a new issue