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
|
.. contents:: Table of Contents
|
||||||
:depth: 2
|
: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
|
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.
|
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.
|
* ``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:
|
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"""
|
"""A django CAS server application"""
|
||||||
|
|
||||||
#: version of the application
|
#: version of the application
|
||||||
VERSION = '0.8.0'
|
VERSION = '0.9.0'
|
||||||
|
|
||||||
#: path the the application configuration class
|
#: path the the application configuration class
|
||||||
default_app_config = 'cas_server.apps.CasAppConfig'
|
default_app_config = 'cas_server.apps.CasAppConfig'
|
||||||
|
|
|
@ -27,6 +27,7 @@ except ImportError:
|
||||||
|
|
||||||
try: # pragma: no cover
|
try: # pragma: no cover
|
||||||
import ldap3
|
import ldap3
|
||||||
|
import ldap3.core.exceptions
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ldap3 = None
|
ldap3 = None
|
||||||
|
|
||||||
|
@ -297,9 +298,19 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
||||||
settings.CAS_LDAP_USER_QUERY % ldap3.utils.conv.escape_bytes(username),
|
settings.CAS_LDAP_USER_QUERY % ldap3.utils.conv.escape_bytes(username),
|
||||||
attributes=ldap3.ALL_ATTRIBUTES
|
attributes=ldap3.ALL_ATTRIBUTES
|
||||||
) and len(conn.entries) == 1:
|
) and len(conn.entries) == 1:
|
||||||
user = conn.entries[0].entry_get_attributes_dict()
|
# try the new ldap3>=2 API
|
||||||
# store the user dn
|
try:
|
||||||
user["dn"] = conn.entries[0].entry_get_dn()
|
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):
|
if user.get(settings.CAS_LDAP_USERNAME_ATTR):
|
||||||
self.user = user
|
self.user = user
|
||||||
super(LdapAuthUser, self).__init__(user[settings.CAS_LDAP_USERNAME_ATTR][0])
|
super(LdapAuthUser, self).__init__(user[settings.CAS_LDAP_USERNAME_ATTR][0])
|
||||||
|
@ -308,7 +319,7 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
||||||
else:
|
else:
|
||||||
super(LdapAuthUser, self).__init__(username)
|
super(LdapAuthUser, self).__init__(username)
|
||||||
break
|
break
|
||||||
except ldap3.LDAPCommunicationError:
|
except ldap3.core.exceptions.LDAPCommunicationError:
|
||||||
if retry_nb == 2:
|
if retry_nb == 2:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -321,7 +332,7 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
||||||
correct, ``False`` otherwise.
|
correct, ``False`` otherwise.
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
if settings.CAS_LDAP_PASSWORD_CHECK == "bind":
|
if self.user and settings.CAS_LDAP_PASSWORD_CHECK == "bind":
|
||||||
try:
|
try:
|
||||||
conn = ldap3.Connection(
|
conn = ldap3.Connection(
|
||||||
settings.CAS_LDAP_SERVER,
|
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),
|
settings.CAS_LDAP_USER_QUERY % ldap3.utils.conv.escape_bytes(self.username),
|
||||||
attributes=ldap3.ALL_ATTRIBUTES
|
attributes=ldap3.ALL_ATTRIBUTES
|
||||||
) and len(conn.entries) == 1:
|
) and len(conn.entries) == 1:
|
||||||
attributes = conn.entries[0].entry_get_attributes_dict()
|
# try the ldap3>=2 API
|
||||||
attributes["dn"] = conn.entries[0].entry_get_dn()
|
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
|
# cache the attributes locally as we wont have access to the user password
|
||||||
# later.
|
# later.
|
||||||
user = UserAttributes.objects.get_or_create(username=self.username)[0]
|
user = UserAttributes.objects.get_or_create(username=self.username)[0]
|
||||||
|
@ -346,7 +367,10 @@ class LdapAuthUser(DBAuthUser): # pragma: no cover
|
||||||
finally:
|
finally:
|
||||||
conn.unbind()
|
conn.unbind()
|
||||||
return True
|
return True
|
||||||
except (ldap3.LDAPBindError, ldap3.LDAPCommunicationError):
|
except (
|
||||||
|
ldap3.core.exceptions.LDAPBindError,
|
||||||
|
ldap3.core.exceptions.LDAPCommunicationError
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
elif self.user and self.user.get(settings.CAS_LDAP_PASSWORD_ATTR):
|
elif self.user and self.user.get(settings.CAS_LDAP_PASSWORD_ATTR):
|
||||||
return check_password(
|
return check_password(
|
||||||
|
|
|
@ -185,6 +185,8 @@ CAS_NEW_VERSION_EMAIL_WARNING = True
|
||||||
#: You should not change it.
|
#: You should not change it.
|
||||||
CAS_NEW_VERSION_JSON_URL = "https://pypi.python.org/pypi/django-cas-server/json"
|
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.
|
#: 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`.
|
#: ``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
|
#: The session key of the current authenticated user
|
||||||
session_key = models.CharField(max_length=40, blank=True, null=True)
|
session_key = models.CharField(max_length=40, blank=True, null=True)
|
||||||
#: The username of the current authenticated user
|
#: 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…)
|
#: Last time the authenticated user has do something (auth, fetch ticket, etc…)
|
||||||
date = models.DateTimeField(auto_now=True)
|
date = models.DateTimeField(auto_now=True)
|
||||||
#: last time the user logged
|
#: last time the user logged
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
class="alert alert-danger"
|
class="alert alert-danger"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endspaceless %}>
|
{% endspaceless %}>
|
||||||
<p>{{message|safe}}</p>
|
<p>{{message}}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if auto_submit %}</noscript>{% endif %}
|
{% if auto_submit %}</noscript>{% endif %}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="alert alert-success" role="alert">{{logout_msg|safe}}</div>
|
<div class="alert alert-success" role="alert">{{logout_msg}}</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -295,6 +295,24 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
|
||||||
) in response.content
|
) 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):
|
def test_view_login_get_denied_service(self):
|
||||||
"""Request a ticket for an denied service by an unauthenticated client"""
|
"""Request a ticket for an denied service by an unauthenticated client"""
|
||||||
# get a bare new http 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
|
# 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)
|
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):
|
def test_view_login_get_auth_allowed_service(self):
|
||||||
"""Request a ticket for an allowed service by an authenticated client"""
|
"""Request a ticket for an allowed service by an authenticated client"""
|
||||||
# get a client that is already authenticated
|
# 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
|
# renewing authentication is done in the validate and serviceValidate views tests
|
||||||
self.assertEqual(ticket.renew, True)
|
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)
|
@override_settings(CAS_ENABLE_AJAX_AUTH=True)
|
||||||
def test_ajax_login_required(self):
|
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.middleware.csrf import CsrfViewMiddleware
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
@ -181,24 +182,24 @@ class LogoutView(View, LogoutMixin):
|
||||||
else:
|
else:
|
||||||
# build logout message depending of the number of sessions the user logs out
|
# build logout message depending of the number of sessions the user logs out
|
||||||
if session_nb == 1:
|
if session_nb == 1:
|
||||||
logout_msg = _(
|
logout_msg = mark_safe(_(
|
||||||
"<h3>Logout successful</h3>"
|
"<h3>Logout successful</h3>"
|
||||||
"You have successfully logged out from the Central Authentication Service. "
|
"You have successfully logged out from the Central Authentication Service. "
|
||||||
"For security reasons, close your web browser."
|
"For security reasons, close your web browser."
|
||||||
)
|
))
|
||||||
elif session_nb > 1:
|
elif session_nb > 1:
|
||||||
logout_msg = _(
|
logout_msg = mark_safe(_(
|
||||||
"<h3>Logout successful</h3>"
|
"<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. "
|
"Authentication Service. "
|
||||||
"For security reasons, close your web browser."
|
"For security reasons, close your web browser."
|
||||||
) % session_nb
|
) % session_nb)
|
||||||
else:
|
else:
|
||||||
logout_msg = _(
|
logout_msg = mark_safe(_(
|
||||||
"<h3>Logout successful</h3>"
|
"<h3>Logout successful</h3>"
|
||||||
"You were already logged out from the Central Authentication Service. "
|
"You were already logged out from the Central Authentication Service. "
|
||||||
"For security reasons, close your web browser."
|
"For security reasons, close your web browser."
|
||||||
)
|
))
|
||||||
|
|
||||||
# depending of settings, redirect to the login page with a logout message or display
|
# 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.
|
# the logout page. The default is to display tge logout page.
|
||||||
|
@ -835,26 +836,29 @@ class LoginView(View, LogoutMixin):
|
||||||
# clean messages before leaving django
|
# clean messages before leaving django
|
||||||
list(messages.get_messages(self.request))
|
list(messages.get_messages(self.request))
|
||||||
return HttpResponseRedirect(self.service)
|
return HttpResponseRedirect(self.service)
|
||||||
if self.request.session.get("authenticated") and self.renew:
|
|
||||||
messages.add_message(
|
if settings.CAS_SHOW_SERVICE_MESSAGES:
|
||||||
self.request,
|
if self.request.session.get("authenticated") and self.renew:
|
||||||
messages.WARNING,
|
messages.add_message(
|
||||||
_(u"Authentication renewal required by service %(name)s (%(url)s).") %
|
self.request,
|
||||||
{'name': service_pattern.name, 'url': self.service}
|
messages.WARNING,
|
||||||
)
|
_(u"Authentication renewal required by service %(name)s (%(url)s).") %
|
||||||
else:
|
{'name': service_pattern.name, 'url': self.service}
|
||||||
messages.add_message(
|
)
|
||||||
self.request,
|
else:
|
||||||
messages.WARNING,
|
messages.add_message(
|
||||||
_(u"Authentication required by service %(name)s (%(url)s).") %
|
self.request,
|
||||||
{'name': service_pattern.name, 'url': self.service}
|
messages.WARNING,
|
||||||
)
|
_(u"Authentication required by service %(name)s (%(url)s).") %
|
||||||
|
{'name': service_pattern.name, 'url': self.service}
|
||||||
|
)
|
||||||
except ServicePattern.DoesNotExist:
|
except ServicePattern.DoesNotExist:
|
||||||
messages.add_message(
|
if settings.CAS_SHOW_SERVICE_MESSAGES:
|
||||||
self.request,
|
messages.add_message(
|
||||||
messages.ERROR,
|
self.request,
|
||||||
_(u'Service %s not allowed') % self.service
|
messages.ERROR,
|
||||||
)
|
_(u'Service %s not allowed') % self.service
|
||||||
|
)
|
||||||
if self.ajax:
|
if self.ajax:
|
||||||
data = {
|
data = {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
|
|
Loading…
Reference in a new issue