From 14a459b1280e1441ee0d870cc91fcfe2ede7037d Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Sun, 21 Aug 2016 09:03:32 +0200 Subject: [PATCH 01/14] Add a validator to models CharField that should be regular expressions --- cas_server/models.py | 9 ++++++--- cas_server/tests/test_utils.py | 6 ++++++ cas_server/utils.py | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/cas_server/models.py b/cas_server/models.py index 22aae24..02b705e 100644 --- a/cas_server/models.py +++ b/cas_server/models.py @@ -466,7 +466,8 @@ class ServicePattern(models.Model): "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 '\\'." - ) + ), + validators=[utils.regexpr_validator] ) #: Name of the attribute to transmit as username, if empty the user login is used user_field = models.CharField( @@ -660,7 +661,8 @@ class FilterAttributValue(models.Model): pattern = models.CharField( max_length=255, verbose_name=_(u"pattern"), - help_text=_(u"a regular expression") + help_text=_(u"a regular expression"), + validators=[utils.regexpr_validator] ) #: ForeignKey to a :class:`ServicePattern`. :class:`FilterAttributValue` instances for a #: :class:`ServicePattern` are accessible thought its :attr:`ServicePattern.filters` @@ -689,7 +691,8 @@ class ReplaceAttributValue(models.Model): pattern = models.CharField( max_length=255, verbose_name=_(u"pattern"), - help_text=_(u"An regular expression maching whats need to be replaced") + help_text=_(u"An regular expression maching whats need to be replaced"), + validators=[utils.regexpr_validator] ) #: The replacement to what is mached by :attr:`pattern`. groups are capture by \\1, \\2 … replace = models.CharField( diff --git a/cas_server/tests/test_utils.py b/cas_server/tests/test_utils.py index 79c3cb2..add692d 100644 --- a/cas_server/tests/test_utils.py +++ b/cas_server/tests/test_utils.py @@ -255,3 +255,9 @@ class UtilsTestCase(TestCase): self.assertIsInstance(result, dict) self.assertIn('applied', result) self.assertIsInstance(result['applied'], datetime.datetime) + + def test_regexpr_validator(self): + """test the function regexpr_validator""" + utils.regexpr_validator("^a$") + with self.assertRaises(utils.ValidationError): + utils.regexpr_validator("[") diff --git a/cas_server/utils.py b/cas_server/utils.py index eb04a31..19957c8 100644 --- a/cas_server/utils.py +++ b/cas_server/utils.py @@ -18,7 +18,10 @@ from django.contrib import messages from django.contrib.messages import constants as DEFAULT_MESSAGE_LEVELS from django.core.serializers.json import DjangoJSONEncoder from django.utils import timezone +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ +import re import random import string import json @@ -700,3 +703,19 @@ def logout_request(ticket): 'datetime': timezone.now().isoformat(), 'ticket': ticket } + + +def regexpr_validator(value): + """ + Test that ``value`` is a valid regular expression + + :param unicode value: A regular expression to test + :raises ValidationError: if ``value`` is not a valid regular expression + """ + try: + re.compile(value) + except re.error: + raise ValidationError( + _('"%(value)s" is not a valid regular expression'), + params={'value': value} + ) From 816156fa598fa9a4cfef60fddefa04096bddccab Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Mon, 22 Aug 2016 15:07:15 +0200 Subject: [PATCH 02/14] Allow the user defined CAS_COMPONENT_URLS to omit not changed values --- README.rst | 5 +++-- cas_server/default_settings.py | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 6c57a7f..f4bc027 100644 --- a/README.rst +++ b/README.rst @@ -208,7 +208,7 @@ Template settings Default is a key icon. Set it to ``False`` to disable it. * ``CAS_SHOW_POWERED``: Set it to ``False`` to hide the powered by footer. The default is ``True``. * ``CAS_COMPONENT_URLS``: URLs to css and javascript external components. It is a dictionnary - and it must have the five following keys: ``"bootstrap3_css"``, ``"bootstrap3_js"``, + having the five following keys: ``"bootstrap3_css"``, ``"bootstrap3_js"``, ``"html5shiv"``, ``"respond"``, ``"jquery"``. The default is:: { @@ -218,6 +218,7 @@ Template settings "respond": "//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js", "jquery": "//code.jquery.com/jquery.min.js", } + if you omit some keys of the dictionnary, the default value for these keys is used. * ``CAS_LOGIN_TEMPLATE``: Path to the template showed on ``/login`` then the user is not autenticated. The default is ``"cas_server/login.html"``. @@ -597,7 +598,7 @@ You could for example do as bellow : .. code-block:: - 10 0 * * * cas-user /path/to/project/manage.py cas_clean_federate + 10 0 * * * cas-user /path/to/project/manage.py cas_clean_federate diff --git a/cas_server/default_settings.py b/cas_server/default_settings.py index 8474d0b..0ee1749 100644 --- a/cas_server/default_settings.py +++ b/cas_server/default_settings.py @@ -182,11 +182,17 @@ CAS_NEW_VERSION_JSON_URL = "https://pypi.python.org/pypi/django-cas-server/json" GLOBALS = globals().copy() for name, default_value in GLOBALS.items(): - # get the current setting value, falling back to default_value - value = getattr(settings, name, default_value) - # set the setting value to its value if defined, ellse to the default_value. - setattr(settings, name, value) + # only care about parameter begining by CAS_ + if name.startswith("CAS_"): + # get the current setting value, falling back to default_value + value = getattr(settings, name, default_value) + # set the setting value to its value if defined, ellse to the default_value. + setattr(settings, name, value) +# Allow the user defined CAS_COMPONENT_URLS to omit not changed values +MERGED_CAS_COMPONENT_URLS = CAS_COMPONENT_URLS.copy() +MERGED_CAS_COMPONENT_URLS.update(settings.CAS_COMPONENT_URLS) +settings.CAS_COMPONENT_URLS = MERGED_CAS_COMPONENT_URLS # if the federated mode is enabled, we must use the :class`cas_server.auth.CASFederateAuth` auth # backend. From f0e1aa8d7de912d572a45272744766adc5e51872 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Mon, 22 Aug 2016 15:10:18 +0200 Subject: [PATCH 03/14] README.rst typos --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f4bc027..a40713f 100644 --- a/README.rst +++ b/README.rst @@ -218,6 +218,7 @@ Template settings "respond": "//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js", "jquery": "//code.jquery.com/jquery.min.js", } + if you omit some keys of the dictionnary, the default value for these keys is used. * ``CAS_LOGIN_TEMPLATE``: Path to the template showed on ``/login`` then the user @@ -272,7 +273,7 @@ New version warnings settings * ``CAS_NEW_VERSION_HTML_WARNING``: A boolean for diplaying a warning on html pages then a new version of the application is avaible. Once closed by a user, it is not displayed to this user until the next new version. The default is ``True``. -* ``CAS_NEW_VERSION_EMAIL_WARNING``: A bolean sot sending a email to ``settings.ADMINS`` when a new +* ``CAS_NEW_VERSION_EMAIL_WARNING``: A boolean for sending a email to ``settings.ADMINS`` when a new version is available. The default is ``True``. From 6412ee5e090c18be981329cd9c2ae31604be1188 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Mon, 22 Aug 2016 15:17:48 +0200 Subject: [PATCH 04/14] Remove code-blocks and use double ` in README.rst --- README.rst | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index a40713f..6a32ef3 100644 --- a/README.rst +++ b/README.rst @@ -174,13 +174,11 @@ Quick start inactive since more than ``SESSION_COOKIE_AGE``. The default value for is ``1209600`` seconds (2 weeks). You probably should reduce it to something like ``86400`` seconds (1 day). - You could for example do as bellow : + You could for example do as bellow:: - .. code-block:: - - 0 0 * * * cas-user /path/to/project/manage.py clearsessions - */5 * * * * cas-user /path/to/project/manage.py cas_clean_tickets - 5 0 * * * cas-user /path/to/project/manage.py cas_clean_sessions + 0 0 * * * cas-user /path/to/project/manage.py clearsessions + */5 * * * * cas-user /path/to/project/manage.py cas_clean_tickets + 5 0 * * * cas-user /path/to/project/manage.py cas_clean_sessions 5. Run ``python manage.py createsuperuser`` to create an administrator user. @@ -230,7 +228,7 @@ Template settings authenticated. The default is ``"cas_server/logged.html"``. * ``CAS_LOGOUT_TEMPLATE``: Path to the template showed on ``/logout`` then to user is being disconnected. The default is ``"cas_server/logout.html"`` -* ``CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT``: Should we redirect users to `/login` after they +* ``CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT``: Should we redirect users to ``/login`` after they logged out instead of displaying ``CAS_LOGOUT_TEMPLATE``. The default is ``False``. @@ -547,10 +545,10 @@ A service pattern has 4 associated models: an email address to connect to it. To do so, put ``email`` in ``Attribute`` and ``.*`` in ``pattern``. Then a user ask a ticket for a service, the service URL is compare against each service patterns -sorted by `position`. The first service pattern that matches the service URL is chosen. -Hence, you should give low `position` to very specific patterns like -``^https://www\.example\.com(/.*)?$`` and higher `position` to generic patterns like ``^https://.*``. -So the service URL `https://www.examle.com` will use the service pattern for +sorted by ``position``. The first service pattern that matches the service URL is chosen. +Hence, you should give low ``position`` to very specific patterns like +``^https://www\.example\.com(/.*)?$`` and higher ``position`` to generic patterns like ``^https://.*``. +So the service URL ``https://www.examle.com`` will use the service pattern for ``^https://www\.example\.com(/.*)?$`` and not the one for ``^https://.*``. @@ -574,7 +572,7 @@ An identity provider comes with 5 fields: * ``Suffix``: the suffix that will be append to the username returned by the identity provider. It must be unique. * ``Server url``: the URL to the identity provider CAS. For instance, if you are using - ``https://cas.example.org/login`` to authenticate on the CAS, the `server url` is + ``https://cas.example.org/login`` to authenticate on the CAS, the ``server url`` is ``https://cas.example.org`` * ``CAS protocol version``: the version of the CAS protocol to use to contact the identity provider. The default is version 3. @@ -595,11 +593,9 @@ Then using federate mode, you should add one command to a daily crontab: ``cas_c This command clean the local cache of federated user from old unused users. -You could for example do as bellow : +You could for example do as bellow:: -.. code-block:: - - 10 0 * * * cas-user /path/to/project/manage.py cas_clean_federate + 10 0 * * * cas-user /path/to/project/manage.py cas_clean_federate From c0604337eb2634a8ee503f4114c2d9bf44c32cc9 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 23 Aug 2016 12:49:09 +0200 Subject: [PATCH 05/14] Add a CHANGELOG.rst file --- CHANGELOG.rst | 416 +++++++++++++++++++++++++++++++++++++++++++++ docs/CHANGELOG.rst | 1 + docs/index.rst | 5 + 3 files changed, 422 insertions(+) create mode 100644 CHANGELOG.rst create mode 100644 docs/CHANGELOG.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000..ad7f4e8 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,416 @@ +Change Log +########## + +All notable changes to this project will be documented in this file. + +.. contents:: Table of Contents + :depth: 2 + +Unreleased +========== + +Added +----- +* Add a CHANGELOG.rst file. +* Add a validator to models CharField that should be regular expressions checking that user input + are valids regular expressions. + +Changed +------- +* Allow the user defined CAS_COMPONENT_URLS to omit not changed values. +* replace code-block without language indication by literal blocks. + +Fixed +----- +* Some README.rst typos. + + +v0.6.4 - 2016-08-14 +=================== + +commit: 282e3a831b3c0b0818881c2f16d056850d572b89 + +Added +----- +* Add a forgotten migration (only change help_text) + + +v0.6.3 - 2016-08-14 +=================== + +commit: 07a537b403c5c5e39a4ddd084f90e3a4de88a54e + +Added +----- +* Add powered by footer +* Add a github version badge +* documents templatetags + +Changed +------- +* Usage of the documented API for models _meta in auth.DjangoAuthUser +* set warn cookie using javascript if possible +* Unfold many to many attributes in auth.DjangoAuthUser attributes + +Fixed +----- +* typos in README.rst +* w3c validation + +Cleaned +------- +* Code factorisation (models.py, views.py) + + +v0.6.2 - 2016-08-02 +=================== + +commit: 773707e6c3c3fa20f697c946e31cafc591e8fee8 + +Added +----- +* Support authentication renewal in federate mode +* Add new version email and info box then new version is available +* Add SqlAuthUser and LdapAuthUser auth classes. + Deprecate the usage of MysqlAuthUser in favor of SqlAuthUser. +* Add pytest-warning to tests +* Add a checkbox to forget the identity provider if we checked "remember the identity provider" +* Add dependancies correspondance between python pypi, debian and centos packages in README + +Changed +------- +* Move coverage computation last in travis +* Enable logging to stderr then running tests +* Remember "warn me before…" using a cookie +* Put favicon (shortcut icon) URL in settings + +Deprecated +---------- +* The auth class MysqlAuthUser is deprecated in favor of the SqlAuthUser class. + +Fixed +----- +* Use custom templatetags instead settings custom attributes to Boundfields + (As it do not work with django 1.7) +* Display an error message on bad response from identity provider in federate mode + instead of crashing. (e.g. Bad XML document) +* Catch base64 decode error on b64decode to raise our custom exception BadHash +* Add secret as sensitive variables/post parameter for /auth +* Only set "remember my provider" in federated mode upon successful authentication +* Since we drop django-boostrap3 dependancies, Django default minimal version is 1.7.1 +* [cas.py] Append renew=true when validating tickets + +Cleaned +------- +* code factorization (cas.py, forms.py) + + +v0.6.1 - 2016-07-27 +=================== + +commit: b168e0a6423c53de31aae6c444fa1d1c5083afa6 + +Added +----- +* Add sphinx docs + autodoc +* Add the possibility to run tests with "setup.py test" +* Include docs, Makefile, coverage config and tests config to source package +* Add serviceValidate ProxyTicket tests +* Add python 3.5 tox/travis tests + +Changed +------- +* Use https://badges.genua.fr for badges + +Fixed +----- +* Keep LoginTicket list upon fail authentication + (It prevent the next login attemps to fail because of bad LT) + +Cleaned +------- +* Compact federated mode migration +* Reformat default_settings.py for documentation using sphinx autodoc +* Factorize some code (from views.py to Ticket models class methods) +* Update urlpattern for django 1.10 +* Drop dependancies django-picklefield and django-bootstrap3 + + +v0.6.0 - 2016-07-06 +=================== + +commit: 4ad4d13baa4236c5cd72cc5216d7ff08dd361476 + +Added +----- +* Add a section describing service patterns options to README.rst +* Add a federation mode: + When the settings CAS_FEDERATE is True, django-cas-server will offer to the user to choose its + CAS backend to authenticate. Hence the login page do not display anymore a username/password form + but a select form with configured CASs backend. + This allow to give access to CAS supported applications to users from multiple organization + seamlessly. + + It was originally developped to mach the need of https://ares.fr (Federated CAS at + https://cas.ares.fr, example of an application using it as https://chat.myares.fr) + +Fixed +----- +* Then a ticket was marked as obtained with the user entering its credentials (aka not by SSO), and + the service did not require it, ticket validation was failing. Now, if the service do not require + authentication to be renewed, both ticket with renewed authentication and non renewed + authentication validate successfully. + + + +v0.5.0 - 2016-07-01 +=================== + +commit: e3ab64271b718a17e4cbbbabda0a2453107a83df + +Added +----- +* Add more password scheme support to the mysql authentication backend: ldap user + attribute scheme encoding and simple password hash in hexa for md5, sha1, sha224, + sha256, sha384, sha512. +* Add a main heading to template "Central Authentication Service" with a logo controled + by CAS_LOGO_URL +* Add logos to the project (svg, png) +* Add coverage computation +* link project to codacy +* Update doc: add debian requirement, correct typos, correct links + +Changed +------- +* Use settings to set tests username password and attributes +* Tweak the css and html for small screens +* Update travis cache for faster build +* clean Makefile, use pip to install, add target for tests + +Fixed +----- +* Fix "warn me": we generate the ticket after the user agree to be connected to the service. + we were generating first and the connect button was a link to the service url with the ?ticket= + this could lead to situation where the ticket validity expire if the user is slow to click the + connect button. +* Fix authentication renewal: the renew parameter were not transmited when POST the login request + and self.renew (aks for auth renewal) was use instead of self.renewed (auth was renewd) + when generating a ticket. +* Fix attribute value replacement when generating a ticket: we were using the 'name' attribute + instead of the 'attribut' attribut on ReplaceAttributValue +* Fix attribute value replacement when generating a ticket then the value is a list: iterate over + each element of the list. +* Fix a NameError in utils.import_attr +* Fix serviceValidate and samlValidate when user_field is an attribute that is a list: we use + the first element of the list as username. we were serializing the list before that. +* Correct typos + + +Cleaned +------- +* Clean some useless conditional branches found with coverage +* Clean cas.js: use compact object declararion +* Use six for python{2|3} compatibility +* Move all unit tests to cas_server.tests and use django primitive. We also have a 100% tests + coverage now. Using the django classes for tests, we do not need to use our own dirty mock. +* Move mysql backend password check to a function in utils + + +v0.4.4 - 2016-04-30 +=================== + +commit: 77d1607b0beefe8b171adcd8e2dcd974e3cdc72a + +Added +----- +* Add sensitive_post_parameters and sensitive_variables for passwords, so passwords are anonymised + before django send an error report. + +Fixed +----- +* Before commit 77fc5b5 the User model had a foreign key to the Session model. After the commit, + Only the session_key is store, allowing to use different backend than the Session SQL backend. + So the first migration (which is 21 migrations combined) was creating the User model with the + foreign key, then delete it and add the field session_key. Somehow, MySQL did not like it. + Now the first migration directly create the User model with the session_key and without the + foreign key to the Session SQL backend. +* Evaluate attributes variables in the template samlValidate.xml. the {{ }} was missing causing + the variable name to be displyed instead of the variable content. +* Return username in CAS 1.0 on the second ligne of the CAS response as specified. + + +Changed +------- +* Update tests + + +v0.4.3 - 2016-03-18 +=================== + +commit: f6d436acb49f8d32b5457c316c18c4892accfd3b + +Fixed +----- +* Currently, one of our dependancy, django-boostrap3, do not support django 1.7 in its last version. + So there is some detection of the current django installed version in setup.py to pin + django-boostrap3 to a version supported by django 1.7 if django 1.7 is installed, or to require + at least django 1.8. + The detection did not handle the case where django was not installed. +* [PEP8] Put line breaks after binary operator and not before. + + +v0.4.2 - 2016-03-18 +=================== + +commit: d1cd17d6103281b03a8c57013671057eab80d21c + +Added +----- +* On logout, display the number of sessions we are logged out from. + +Fixed +----- +* One of our dependancy, django-boostrap3, do not support django 1.7 in its last version. + Some django version detection is added to setup.py to handle that. +* Some typos +* Make errors returned by utils.import_attr clearer (as they are likely to be displayed to the + django admin) + + +v0.4.1 - 2015-12-23 +=================== + +commit: 5e63f39f9b7c678a300ad2f8132166be34d1d35b + +Added +----- +* Add a run_test_server target to make file. Running make run_test_server will build a virtualenv, + create a django projet with django-cas-server and lauch ./management.py runserver. It is quite + handy to test developement version. +* Add verbose name for cas_server app and models +* Add Makefile clean targets for tox tests and test virtualenv. +* Add link on license badge to the GPLv3 + +Changed +------- +* Make Makefile clean targets modular +* Use img.shields.io for PyPi badges +* Get django-cas-server version in Makefile directly from setup.py (so now, the version is only + written in one place) + +Fixed +----- +* Fix MysqlAuthUser when number of results != 1: In that case, call super anyway this the provided + username. + + +v0.4.0 - 2015-12-15 +=================== + +commit: 7b4fac575449e50c2caff07f5798dba7f4e4857c + +Added +----- +* Add a help_text to pattern of ServicePattern +* Add a timeout to SLO requests +* Add logging capabilities (see README.rst for instruction) +* Add management commands that should be called on a regular basis to README.rst + + +v0.3.5 - 2015-12-12 +=================== + +commit: 51fa0861f550723171e52d58025fa789dccb8cde + +Added +----- +* Add badges to README.rst +* Document settings parameter in README.rst +* Add a "Features" section in README.rst + +Changed +------- +* Add a AuthUser auth class and use it as auth classes base class instead of DummyAuthUser + +Fixed +----- +* Fix minor errors and typos in README.rst + + + +v0.3.4 - 2015-12-12 +=================== + +commit: 9fbfe19c550b147e8d0377108cdac8231cf0fb27 + +Added +----- +* Add static files, templates and locales to the PyPi release by adding them to MANIFEST.in +* Add a Makefile with the build/install/clean/dist targets + + +v0.3.3 - 2015-12-12 +=================== + +commit: 16b700d0127abe33a1eabf5d5fe890aeb5167e5a + +Added +----- +* Add management commands and migrations to the package by adding there packages to setup.py + packages list. + + +v0.3.2 - 2015-12-12 [YANKED] +============================ + +commit: eef9490885bf665a53349573ddb9cbe844319b3e + +Added +----- +* Add migrations to setup.py package_data + + +v0.3.1 - 2015-12-12 +=================== + +commit: d0f6ed9ea3a4b3e2bf715fd218c460892c32e39f + +Added +----- +* Add a forgotten migration (remove auto_now_add=True from the User model) + + +v0.3.0 - 2015-12-12 +=================== + +commit: b69769d71a99806a69e300eca0d7c6744a2b327e + +Added +----- +* Django 1.9 compatibility (add tox and travis tests and fix some decrecated) + + +v0.2.1 - 2015-12-12 +=================== + +commit: 90e077dedb991d651822e9bb283470de8bddd7dd + +First github and PyPi release + +Fixed +----- +* Prune .tox in MANIFEST.in +* add dist/ to .gitignore +* typo in setup.cfg + + +v0.2.0 - 2015-12-12 [YANKED] +============================ + +commit: a071ad46d7cd76fc97eb86f2f538d330457c6767 + + +v0.1.0 - 2015-05-22 [YANKED] +============================ + +commit: 6981433bdf8a406992ba0c5e844a47d06ccc08fb diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst new file mode 100644 index 0000000..565b052 --- /dev/null +++ b/docs/CHANGELOG.rst @@ -0,0 +1 @@ +.. include:: ../CHANGELOG.rst diff --git a/docs/index.rst b/docs/index.rst index 7062ab0..7ad7ed1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,6 +14,11 @@ Contents: README package/cas_server +.. toctree:: + :maxdepth: 2 + + CHANGELOG + Indices and tables ================== From 8874a20292a3e2e2f66c735c24414b7112fc98ab Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 23 Aug 2016 12:50:04 +0200 Subject: [PATCH 06/14] Add link to the Authentication backend section in README.rst --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6a32ef3..2058cc3 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ CAS Server is a Django application implementing the `CAS Protocol 3.0 Specificat `_. By default, the authentication process use django internal users but you can easily -use any sources (see auth classes in the auth.py file) +use any sources (see the `Authentication backend`_ section and auth classes in the auth.py file) .. contents:: Table of Contents @@ -38,7 +38,7 @@ Dependencies Minimal version of packages dependancy are just indicative and meens that ``django-cas-server`` has been tested with it. Previous versions of dependencies may or may not work. -Additionally, denpending of the authentication backend you plan to use, you may need the following +Additionally, denpending of the `Authentication backend`_ you plan to use, you may need the following python packages: * ldap3 From 656a207e4737fe2c3933d26caac2dae187e61c48 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 23 Aug 2016 12:57:18 +0200 Subject: [PATCH 07/14] Add CHANGELOG.rst to MANIFEST.in --- MANIFEST.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MANIFEST.in b/MANIFEST.in index 3f968f7..47669dd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ include tox.ini include LICENSE include README.rst +include CHANGELOG.rst include .coveragerc include Makefile include pytest.ini @@ -15,6 +16,7 @@ include docs/conf.py include docs/index.rst include docs/Makefile include docs/README.rst +include docs/CHANGELOG.rst recursive-include docs/_ext * recursive-include docs/package * recursive-include docs/_static * From 6a55769e50aa2dc33aa23f7215965501f6790f3b Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 23 Aug 2016 12:57:42 +0200 Subject: [PATCH 08/14] Add CHANGELOG.rst test in tox check_rst --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 401c249..4ab3f52 100644 --- a/tox.ini +++ b/tox.ini @@ -101,6 +101,7 @@ deps= skip_install=True commands= rst2html.py --strict {toxinidir}/README.rst /dev/null + rst2html.py --halt=warning {toxinidir}/CHANGELOG.rst /dev/null {[post_cmd]commands} whitelist_externals={[post_cmd]whitelist_externals} From 097a7e32adf43be06f0fc8c05e220c3c11b77413 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Wed, 24 Aug 2016 17:20:57 +0200 Subject: [PATCH 09/14] Fix some english typos and update french translation --- cas_server/locale/fr/LC_MESSAGES/django.mo | Bin 9460 -> 10143 bytes cas_server/locale/fr/LC_MESSAGES/django.po | 169 +++++++++--------- .../management/commands/cas_clean_tickets.py | 2 +- cas_server/models.py | 2 +- cas_server/views.py | 8 +- 5 files changed, 93 insertions(+), 88 deletions(-) diff --git a/cas_server/locale/fr/LC_MESSAGES/django.mo b/cas_server/locale/fr/LC_MESSAGES/django.mo index d0f80edbb5787b491eb6c002ad9d48a14579dcbb..603a6db75044837325395944d89391c04108e251 100644 GIT binary patch delta 2486 zcmZA1TWl0n7{Kwfg>sQwEiEm#a%h24C@nVup_W?_K?o7T%}Bzqd%6q`Gt0~@w`kTV z52!?lBl;jp35i+~<+30c6E$oI4?^Mtkq6@~5+O^gU%trSWD@4z#_!l$wOE<25{shw)Hvr4C?QAEn;J%Qytr z_f_g`%-|{P@t9IG@pEj)TO}v;Q)-4%IpuIt#ScfZ4$q-XbQOon1Nb=h>0i7)3>z6w z!C|-_<+%{$1tOIDPvAs6j~nn7K84E$C^ZV-z;f1C$2j4o)Cp|Ev-l+5DUDkOD%HyP zMdXrtA17fq%EDJs7QTnF@xgOX?tUtNH->Q^z^TI_ELBh?9$) zY{UVB2{XDV5AG<9b0`b%EnR;Lr!#&RW#VsQ8LaU96F1J5vCRio5L*teFj;|Y{dKTm-i$8C5EM^g|TSTS6w z=WsPHz>jeb{((HI#*wdjoI8T}kLF|(7n*SoN>QCe)>M~Jisl-Q#Ci^GI1golmr?HP z!i9JaZTt(@VJ8JL4!=f8&F@J1)opwlRgO}W2^V7$_n_qT2FgaNbg@`kQ6@4d)xQsA z}R(Ui7R*rYZ{c|!&14^oXCRT;99(i8au|21~j-C zeVmRzplqySY%!M;aW>=WrLl(+k)0@??*Z(A$M9MF442}4Wd595#A}svVI@j&tSgNz zlntbDE`~@@)M?~PQ&&)m^f#0Z{8<{0BRo=+EhXone9kLTBD4<)j4Gqc`theQlhb*0 znW%$4pDv3rr+S7?-NgBloy)f`)htmX&2gJnQi@F8_Cb@JH__#LpHjN`6v~UmjrG-3 z`T)A7&!9__oi2&biU-mbhhIi~RdGb*d>LInB|e;oZ5C(pb&RKz&A8yCMkFnh>GHop zYHk5N*Umwjd=?|3^<&3xx16kL3hK2TXx9t1rMY6Kv~SW`$MUt=nej~!*q)o; z*lR<1{;Pg>%Z75B<9Itvszt3b{&qWQ^w{|E=+eN~q9eWPayso>ZW!oYURGPlBs1vH z(_6hD)Ly6dvcBG7HU)NQ0=;RMwzA=7U2G2=Ikl6qAv#PhlBjDg9jyQ{u?p3(eOGME6~~KWbLs2 zao~(<+dQp(VRU53xT>V*x+WPGy2qO)-ZA4BJ_({%Y8uPiHum$FcU1PGg zmrP8n(>(8at3mP^pLdv<)6Z$gVzm_GE4w&SdH+A_NdbET_WsV}A= zVu8`g&DOSTaYZdB@%Fjsrg<0cl0};JmTa&s+sG~`vEp4a{r~eyIsH4sBLTI|?iLl@ t9kow__^Mu8O$5?~Znx0wTaM0#wqpl{?))!$ri3|P+wds?jxLO8{Rf&3wvhk; delta 1869 zcmYk+Z%kEn9LMqRfeV^f!^=fLKsbto8S%$|2nvcAiNyLtW{Wk&>m6Q4m*RphR^5p` zDJosZGUpbn2W6WY{?)U5`V!-Ji5@V7<2D1dmYPg z1}|VU?q6iqj&B8ihnrXzhs}!2($>qQk_`t?Cpw19bpRIPOtAe+tY!T@mSJdd_P8q4 zjkjY2`|%!p3ZKL?*oL>U3O6n>%fmgG&-JaJ$yPQTz!sbe*4MCsb@82MOsxy=#Ya&$ zJb}9KJE$AKj0HG{x{;r;4{zf}>|y5)Jcfty3k-36YglUL;s)%%JxFToH0n;zV=vC2 zo=j)g{yHSf)`9idgH*-Fkw2T@M;SbYs^Fah!|y!KCH!fb z*?V|~e13r2OR}l`4KK2GO3iNIH15PH8s%ZUj!Nw&8eet5nO@OsGhirIzgC1>;LMp6T2{hFXQ7lk9T1&2dgBbs9tyhyYMyK zigOslLK;XnawN@!hqiZ7P4Y47L^n{~zN{*H=WR&&Z6A_ldm5j?-UHG37G z$1sL@Y+a}X_hKiq%g&-ok^Y3qAtqN)HD1T#k|i5N)oub?aWYtch04S?sMqvY%tfc# zY&YfwK7_i!SyV5bL!Iwpu>L5!KW(2f*~X5qk%zEFtIc?0Y%QuOTTnO95v-p>HQ|ea zZ{lXw=TMpX5gp7Wnh1>$v6IjZDcdTEMy=j|4W(Se&HQG6)IiF}8bVK?r&CJxEucD? zr-4jo%SJ*sprJ3^7J_oyc0%6`y`t?z8=)TQBpQP2GtCaYpH#wlLo(UOZlx^2L_Kgn zLBAQjnQ1bWLnYfmXzU`IGc&#s*g@z6rJ+nJdn7y4kZGkZpXet3KU7=2<0^p~=x(Bi zXd!Y4m8gc$Amf=qE7#t&L6IT#@_V!vDLd!11O_tG&9?2`^Mq=?wU*OXhQ&0k5p=PiM@Jl)vrx(-o(4 zIODFW*=TQkB$jXw#@$rhjSVN0@z|(e=XN;W$yJjaw4!?Ng0a!WP$CugU#f2AJpSi3 S7aZ?IWyHHy5%ylGjs63$n9-jA diff --git a/cas_server/locale/fr/LC_MESSAGES/django.po b/cas_server/locale/fr/LC_MESSAGES/django.po index bdcc3a7..644f814 100644 --- a/cas_server/locale/fr/LC_MESSAGES/django.po +++ b/cas_server/locale/fr/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: cas_server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-08-01 12:01+0200\n" -"PO-Revision-Date: 2016-08-01 12:01+0200\n" +"POT-Creation-Date: 2016-08-24 17:18+0200\n" +"PO-Revision-Date: 2016-08-24 17:18+0200\n" "Last-Translator: Valentin Samir \n" "Language-Team: django \n" "Language: fr\n" @@ -18,8 +18,8 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 1.8.8\n" -#: apps.py:25 templates/cas_server/base.html:9 -#: templates/cas_server/base.html:27 +#: apps.py:25 templates/cas_server/base.html:7 +#: templates/cas_server/base.html:26 msgid "Central Authentication Service" msgstr "Service Central d'Authentification" @@ -27,61 +27,61 @@ msgstr "Service Central d'Authentification" msgid "Identity provider" msgstr "fournisseur d'identité" -#: forms.py:92 forms.py:111 +#: forms.py:88 forms.py:107 msgid "Warn me before logging me into other sites." msgstr "Prévenez-moi avant d'accéder à d'autres services." -#: forms.py:96 +#: forms.py:92 msgid "Remember the identity provider" msgstr "Se souvenir du fournisseur d'identité" -#: forms.py:106 models.py:600 +#: forms.py:102 models.py:594 msgid "username" msgstr "nom d'utilisateur" -#: forms.py:108 +#: forms.py:104 msgid "password" msgstr "mot de passe" -#: forms.py:130 +#: forms.py:126 msgid "The credentials you provided cannot be determined to be authentic." msgstr "Les informations transmises n'ont pas permis de vous authentifier." -#: forms.py:182 +#: forms.py:178 msgid "User not found in the temporary database, please try to reconnect" msgstr "" "Utilisateur non trouvé dans la base de donnée temporaire, essayez de vous " "reconnecter" -#: forms.py:196 +#: forms.py:192 msgid "service" msgstr "service" #: management/commands/cas_clean_federate.py:20 msgid "Clean old federated users" -msgstr "Nettoyer les anciens utilisateurs fédéré" +msgstr "Nettoyer les anciens utilisateurs fédérés" #: management/commands/cas_clean_sessions.py:22 msgid "Clean deleted sessions" msgstr "Nettoyer les sessions supprimées" #: management/commands/cas_clean_tickets.py:22 -msgid "Clean old trickets" +msgid "Clean old tickets" msgstr "Nettoyer les vieux tickets" -#: models.py:46 +#: models.py:71 msgid "identity provider" msgstr "fournisseur d'identité" -#: models.py:47 +#: models.py:72 msgid "identity providers" msgstr "fournisseurs d'identités" -#: models.py:53 +#: models.py:78 msgid "suffix" msgstr "suffixe" -#: models.py:55 +#: models.py:80 msgid "" "Suffix append to backend CAS returned username: ``returned_username`` @ " "``suffix``." @@ -89,46 +89,46 @@ msgstr "" "Suffixe ajouté au nom d'utilisateur retourné par le CAS du fournisseur " "d'identité : `nom retourné`@`suffixe`." -#: models.py:62 +#: models.py:87 msgid "server url" msgstr "url du serveur" -#: models.py:72 +#: models.py:97 msgid "CAS protocol version" msgstr "Version du protocole CAS" -#: models.py:74 +#: models.py:99 msgid "" "Version of the CAS protocol to use when sending requests the the backend CAS." msgstr "" "Version du protocole CAS à utiliser lorsque l'on envoie des requête au CAS " "du fournisseur d'identité." -#: models.py:81 +#: models.py:106 msgid "verbose name" msgstr "Nom du fournisseur" -#: models.py:82 +#: models.py:107 msgid "Name for this identity provider displayed on the login page." msgstr "Nom affiché pour ce fournisseur d'identité sur la page de connexion." -#: models.py:88 models.py:446 +#: models.py:113 models.py:446 msgid "position" msgstr "position" -#: models.py:102 +#: models.py:127 msgid "display" msgstr "afficher" -#: models.py:103 +#: models.py:128 msgid "Display the provider on the login page." msgstr "Afficher le fournisseur d'identité sur la page de connexion." -#: models.py:233 +#: models.py:245 msgid "User" msgstr "Utilisateur" -#: models.py:234 +#: models.py:246 msgid "Users" msgstr "Utilisateurs" @@ -149,7 +149,7 @@ msgstr "Motifs de services" msgid "service patterns are sorted using the position attribute" msgstr "Les motifs de service sont trié selon l'attribut position" -#: models.py:455 models.py:626 +#: models.py:455 models.py:620 msgid "name" msgstr "nom" @@ -157,7 +157,7 @@ msgstr "nom" msgid "A name for the service" msgstr "Un nom pour le service" -#: models.py:464 models.py:669 models.py:698 +#: models.py:464 models.py:663 models.py:693 msgid "pattern" msgstr "motif" @@ -172,108 +172,108 @@ msgstr "" "expression rationnelle, les caractères spéciaux doivent être échappés avec " "un '\\'." -#: models.py:476 +#: models.py:477 msgid "user field" msgstr "champ utilisateur" -#: models.py:477 +#: models.py:478 msgid "Name of the attribute to transmit as username, empty = login" msgstr "" "Nom de l'attribut devant être transmis comme nom d'utilisateur au service. " "vide = nom de connexion" -#: models.py:482 +#: models.py:483 msgid "restrict username" msgstr "limiter les noms d'utilisateurs" -#: models.py:483 +#: models.py:484 msgid "Limit username allowed to connect to the list provided bellow" msgstr "" "Limiter les noms d'utilisateurs autorisé à se connecter à la liste fournie " "ci-dessous" -#: models.py:488 +#: models.py:489 msgid "proxy" msgstr "proxy" -#: models.py:489 +#: models.py:490 msgid "Proxy tickets can be delivered to the service" msgstr "des proxy tickets peuvent être délivrés au service" -#: models.py:495 +#: models.py:496 msgid "proxy callback" msgstr "" -#: models.py:496 +#: models.py:497 msgid "can be used as a proxy callback to deliver PGT" msgstr "peut être utilisé comme un callback pour recevoir un PGT" -#: models.py:503 +#: models.py:504 msgid "single log out" msgstr "" -#: models.py:504 +#: models.py:505 msgid "Enable SLO for the service" msgstr "Active le SLO pour le service" -#: models.py:512 +#: models.py:513 msgid "single log out callback" msgstr "" -#: models.py:513 +#: models.py:514 msgid "" "URL where the SLO request will be POST. empty = service url\n" "This is usefull for non HTTP proxied services." msgstr "" -"URL a laquelle la requête de déconnexion sera postée. vide = l'url du " +"URL à laquelle la requête de déconnexion sera postée. vide = l'url du " "service\n" -"Ceci n'est utilise que pour des services non HTTP proxifiés" +"Ceci n'est en général utilisé que pour des services non HTTP proxifiés" -#: models.py:601 +#: models.py:595 msgid "username allowed to connect to the service" -msgstr "noms d'utilisateurs autorisé à se connecter au service" +msgstr "noms d'utilisateurs autorisés à se connecter au service" -#: models.py:627 +#: models.py:621 msgid "name of an attribute to send to the service, use * for all attributes" msgstr "" -"nom d'un attribut a envoyer au service, utiliser * pour tous les attributs" +"nom d'un attribut à envoyer au service, utiliser * pour tous les attributs" -#: models.py:634 models.py:705 +#: models.py:628 models.py:701 msgid "replace" msgstr "remplacement" -#: models.py:635 +#: models.py:629 msgid "" -"name under which the attribute will be showto the service. empty = default " +"name under which the attribute will be show to the service. empty = default " "name of the attribut" msgstr "" "nom sous lequel l'attribut sera rendu visible au service. vide = inchangé" -#: models.py:662 models.py:692 +#: models.py:656 models.py:687 msgid "attribute" msgstr "attribut" -#: models.py:663 +#: models.py:657 msgid "Name of the attribute which must verify pattern" msgstr "Nom de l'attribut devant vérifier un motif" -#: models.py:670 +#: models.py:664 msgid "a regular expression" msgstr "une expression régulière" -#: models.py:693 +#: models.py:688 msgid "Name of the attribute for which the value must be replace" -msgstr "nom de l'attribut pour lequel la valeur doit être remplacé" +msgstr "Nom de l'attribut pour lequel la valeur doit être remplacé" -#: models.py:699 +#: models.py:694 msgid "An regular expression maching whats need to be replaced" -msgstr "une expression régulière reconnaissant ce qui doit être remplacé" +msgstr "Une expression régulière reconnaissant ce qui doit être remplacé" -#: models.py:706 +#: models.py:702 msgid "replace expression, groups are capture by \\1, \\2 …" msgstr "expression de remplacement, les groupe sont capturé par \\1, \\2" -#: templates/cas_server/base.html:38 +#: templates/cas_server/base.html:43 #, python-format msgid "" "A new version of the application is available. This instance runs " @@ -282,7 +282,7 @@ msgid "" msgstr "" "Une nouvelle version de l'application est disponible. Cette instance utilise " "la version %(VERSION)s et la dernière version est %(LAST_VERSION)s. Merci de " -"vous mettre a jour." +"vous mettre à jour." #: templates/cas_server/logged.html:4 msgid "" @@ -291,10 +291,10 @@ msgid "" "your web browser when you are done accessing services that require " "authentication!" msgstr "" -"

Déconnexion réussie

Vous vous êtes déconnecté(e) du Service Central " -"d'Authentification. Pour des raisons de sécurité, veuillez fermer votre " -"navigateur après avoir fini d'accéder a des services demandant une " -"authentification !" +"

Connexion réussie

Vous vous êtes connecté(e) auprès du Service " +"Central d'Authentification.
Pour des raisons de sécurité, veuillez vous " +"déconnecter et fermer votre navigateur après avoir fini d'accéder à des " +"services demandant une authentification !" #: templates/cas_server/logged.html:8 msgid "Log me out from all my sessions" @@ -310,7 +310,7 @@ msgstr "Se déconnecter" #: templates/cas_server/login.html:6 msgid "Please log in" -msgstr "Merci de se connecter" +msgstr "Veuillez vous authentifier" #: templates/cas_server/login.html:14 msgid "Login" @@ -320,7 +320,12 @@ msgstr "Connexion" msgid "Connect to the service" msgstr "Se connecter au service" -#: views.py:168 +#: utils.py:736 +#, python-format +msgid "\"%(value)s\" is not a valid regular expression" +msgstr "\"%(value)s\" n'est pas une expression rationnelle valide" + +#: views.py:185 msgid "" "

Logout successful

You have successfully logged out from the Central " "Authentication Service. For security reasons, exit your web browser." @@ -329,7 +334,7 @@ msgstr "" "d'Authentification. Pour des raisons de sécurité, veuillez fermer votre " "navigateur." -#: views.py:174 +#: views.py:191 #, python-format msgid "" "

Logout successful

You have successfully logged out from %s sessions " @@ -340,7 +345,7 @@ msgstr "" "Service Central d'Authentification. Pour des raisons de sécurité, veuillez " "fermer votre navigateur." -#: views.py:181 +#: views.py:198 msgid "" "

Logout successful

You were already logged out from the Central " "Authentication Service. For security reasons, exit your web browser." @@ -349,7 +354,7 @@ msgstr "" "d'Authentification. Pour des raisons de sécurité, veuillez fermer votre " "navigateur." -#: views.py:361 +#: views.py:378 #, python-format msgid "" "Invalid response from your identity provider CAS upon ticket %(ticket)s " @@ -358,48 +363,48 @@ msgstr "" "Réponse invalide du CAS du fournisseur d'identité lors de la validation du " "ticket %(ticket)s: %(error)r" -#: views.py:483 +#: views.py:500 msgid "Invalid login ticket, please retry to login" msgstr "Ticket de connexion invalide, merci de réessayé de vous connecter" -#: views.py:675 +#: views.py:692 #, python-format msgid "Authentication has been required by service %(name)s (%(url)s)" msgstr "" "Une demande d'authentification a été émise pour le service %(name)s " "(%(url)s)." -#: views.py:713 +#: views.py:730 #, python-format -msgid "Service %(url)s non allowed." +msgid "Service %(url)s not allowed." msgstr "le service %(url)s n'est pas autorisé." -#: views.py:720 -msgid "Username non allowed" +#: views.py:737 +msgid "Username not allowed" msgstr "Nom d'utilisateur non authorisé" -#: views.py:727 -msgid "User characteristics non allowed" +#: views.py:744 +msgid "User characteristics not allowed" msgstr "Caractéristique utilisateur non autorisée" -#: views.py:734 +#: views.py:751 #, python-format msgid "The attribute %(field)s is needed to use that service" msgstr "L'attribut %(field)s est nécessaire pour se connecter à ce service" -#: views.py:824 +#: views.py:841 #, python-format msgid "Authentication renewal required by service %(name)s (%(url)s)." msgstr "Demande de réauthentification pour le service %(name)s (%(url)s)." -#: views.py:831 +#: views.py:848 #, python-format msgid "Authentication required by service %(name)s (%(url)s)." msgstr "Authentification requise par le service %(name)s (%(url)s)." -#: views.py:838 +#: views.py:855 #, python-format -msgid "Service %s non allowed" +msgid "Service %s not allowed" msgstr "Le service %s n'est pas autorisé" #~ msgid "Logged" diff --git a/cas_server/management/commands/cas_clean_tickets.py b/cas_server/management/commands/cas_clean_tickets.py index 87d802e..3111016 100644 --- a/cas_server/management/commands/cas_clean_tickets.py +++ b/cas_server/management/commands/cas_clean_tickets.py @@ -19,7 +19,7 @@ from ... import models class Command(BaseCommand): """Clean old trickets""" args = '' - help = _(u"Clean old trickets") + help = _(u"Clean old tickets") def handle(self, *args, **options): models.User.clean_old_entries() diff --git a/cas_server/models.py b/cas_server/models.py index 02b705e..d13f553 100644 --- a/cas_server/models.py +++ b/cas_server/models.py @@ -626,7 +626,7 @@ class ReplaceAttributName(models.Model): max_length=255, blank=True, verbose_name=_(u"replace"), - help_text=_(u"name under which the attribute will be show" + help_text=_(u"name under which the attribute will be show " u"to the service. empty = default name of the attribut") ) #: ForeignKey to a :class:`ServicePattern`. :class:`ReplaceAttributName` instances for a diff --git a/cas_server/views.py b/cas_server/views.py index f9be770..c2b18b4 100644 --- a/cas_server/views.py +++ b/cas_server/views.py @@ -727,21 +727,21 @@ class LoginView(View, LogoutMixin): messages.add_message( self.request, messages.ERROR, - _(u'Service %(url)s non allowed.') % {'url': self.service} + _(u'Service %(url)s not allowed.') % {'url': self.service} ) except models.BadUsername: error = 2 messages.add_message( self.request, messages.ERROR, - _(u"Username non allowed") + _(u"Username not allowed") ) except models.BadFilter: error = 3 messages.add_message( self.request, messages.ERROR, - _(u"User characteristics non allowed") + _(u"User characteristics not allowed") ) except models.UserFieldNotDefined: error = 4 @@ -852,7 +852,7 @@ class LoginView(View, LogoutMixin): messages.add_message( self.request, messages.ERROR, - _(u'Service %s non allowed') % self.service + _(u'Service %s not allowed') % self.service ) if self.ajax: data = { From e8d893beeb4fef60003ee08a7c7412ad754dd2fa Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Wed, 24 Aug 2016 17:57:02 +0200 Subject: [PATCH 10/14] Add a CAS_INFO_MESSAGES and CAS_INFO_MESSAGES_ORDER settings allowing to display messages --- README.rst | 24 +++++++++++++++++++ cas_server/default_settings.py | 27 ++++++++++++++++++++++ cas_server/locale/fr/LC_MESSAGES/django.po | 13 ++++++++++- cas_server/static/cas_server/functions.js | 10 ++++---- cas_server/templates/cas_server/base.html | 24 +++++++++++++++---- cas_server/templates/cas_server/login.html | 4 ++-- cas_server/utils.py | 23 ++++++++++++++++++ 7 files changed, 112 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index 2058cc3..d67a3e0 100644 --- a/README.rst +++ b/README.rst @@ -219,6 +219,30 @@ Template settings if you omit some keys of the dictionnary, the default value for these keys is used. +* ``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: + + * ``message``: A unicode message to display, potentially wrapped around ugettex_lazy + * ``discardable``: A boolean, specify if the users can close the message info-box + * ``type``: One of info, success, info, warning, danger. The type of the info-box. + + ``CAS_INFO_MESSAGES`` contains by default one message, ``cas_explained``, which explain + roughly the purpose of a CAS. The default is:: + + { + "cas_explained": { + "message":_( + u"The Central Authentication Service grants you access to most of our websites by " + u"authenticating only once, so you don't need to type your credentials again unless " + u"your session expires or you logout." + ), + "discardable": True, + "type": "info", # one of info, success, info, warning, danger + }, + } + +* ``CAS_INFO_MESSAGES_ORDER``: A list of message names. Order in which info-box messages are + displayed. Use an empty list to disable messages display. The default is ``[]``. * ``CAS_LOGIN_TEMPLATE``: Path to the template showed on ``/login`` then the user is not autenticated. The default is ``"cas_server/login.html"``. * ``CAS_WARN_TEMPLATE``: Path to the template showed on ``/login?service=...`` then diff --git a/cas_server/default_settings.py b/cas_server/default_settings.py index 0ee1749..238fc0a 100644 --- a/cas_server/default_settings.py +++ b/cas_server/default_settings.py @@ -12,6 +12,7 @@ """Default values for the app's settings""" from django.conf import settings from django.contrib.staticfiles.templatetags.staticfiles import static +from django.utils.translation import ugettext_lazy as _ from importlib import import_module @@ -180,6 +181,32 @@ 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" + +#: 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`. +#: A message :class:`dict` has 3 keys: +#: * ``message``: A :class:`unicode`, the message to display, potentially wrapped around +#: ugettex_lazy +#: * ``discardable``: A :class:`bool`, specify if the users can close the message info-box +#: * ``type``: One of info, success, info, warning, danger. The type of the info-box. +#: ``CAS_INFO_MESSAGES`` contains by default one message, ``cas_explained``, which explain +#: roughly the purpose of a CAS. +CAS_INFO_MESSAGES = { + "cas_explained": { + "message": _( + u"The Central Authentication Service grants you access to most of our websites by " + u"authenticating only once, so you don't need to type your credentials again unless " + u"your session expires or you logout." + ), + "discardable": True, + "type": "info", # one of info, success, info, warning, danger + }, +} +#: :class:`list` of message names. Order in which info-box messages are displayed. +#: Let the list empty to disable messages display. +CAS_INFO_MESSAGES_ORDER = [] + + GLOBALS = globals().copy() for name, default_value in GLOBALS.items(): # only care about parameter begining by CAS_ diff --git a/cas_server/locale/fr/LC_MESSAGES/django.po b/cas_server/locale/fr/LC_MESSAGES/django.po index 644f814..049921a 100644 --- a/cas_server/locale/fr/LC_MESSAGES/django.po +++ b/cas_server/locale/fr/LC_MESSAGES/django.po @@ -23,7 +23,18 @@ msgstr "" msgid "Central Authentication Service" msgstr "Service Central d'Authentification" -#: forms.py:88 +#: default_settings.py:197 +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 "" +"Le Service Central d'Authentification permet, en vous authentifiant une " +"seule fois, d'accéder à la plupart de nos sites sans avoir à retaper votre " +"identifiant et votre mot de passe chaque fois que vous changez de site, " +"jusqu'à ce que votre session expire ou que vous vous déconnectiez." + +#: forms.py:84 msgid "Identity provider" msgstr "fournisseur d'identité" diff --git a/cas_server/static/cas_server/functions.js b/cas_server/static/cas_server/functions.js index 81a4add..8bbbeaa 100644 --- a/cas_server/static/cas_server/functions.js +++ b/cas_server/static/cas_server/functions.js @@ -31,14 +31,14 @@ function eraseCookie(name) { createCookie(name,"",-1); } -function alert_version(last_version){ +function discard_and_remember(id, cookie_name, token, days=10*365){ jQuery(function( $ ){ - $("#alert-version").click(function( e ){ + $(id).click(function( e ){ e.preventDefault(); - createCookie("cas-alert-version", last_version, 10*365); + createCookie(cookie_name, token, days); }); - if(readCookie("cas-alert-version") === last_version){ - $("#alert-version").parent().hide(); + if(readCookie(cookie_name) === token){ + $(id).parent().hide(); } }); } diff --git a/cas_server/templates/cas_server/base.html b/cas_server/templates/cas_server/base.html index 8a491ca..2a2d8e1 100644 --- a/cas_server/templates/cas_server/base.html +++ b/cas_server/templates/cas_server/base.html @@ -31,10 +31,16 @@
{% if auto_submit %}
{% endfor %} {% if auto_submit %}{% endif %} @@ -71,9 +77,17 @@ - {% if settings.CAS_NEW_VERSION_HTML_WARNING and upgrade_available %} - - {% endif %} + {% block javascript %}{% endblock %} diff --git a/cas_server/templates/cas_server/login.html b/cas_server/templates/cas_server/login.html index ff98c03..51aa19c 100644 --- a/cas_server/templates/cas_server/login.html +++ b/cas_server/templates/cas_server/login.html @@ -15,7 +15,7 @@ {% if auto_submit %}{% endif %} {% endblock %} -{% block javascript %}{% endblock %} +{% endblock %} diff --git a/cas_server/utils.py b/cas_server/utils.py index 19957c8..17ec5f9 100644 --- a/cas_server/utils.py +++ b/cas_server/utils.py @@ -64,6 +64,7 @@ def context(params): """ params["settings"] = settings params["message_levels"] = DEFAULT_MESSAGE_LEVELS + if settings.CAS_NEW_VERSION_HTML_WARNING: LAST_VERSION = last_version() params["VERSION"] = VERSION @@ -72,6 +73,28 @@ def context(params): params["upgrade_available"] = decode_version(VERSION) < decode_version(LAST_VERSION) else: params["upgrade_available"] = False + + if settings.CAS_INFO_MESSAGES_ORDER: + params["CAS_INFO_RENDER"] = [] + for msg_name in settings.CAS_INFO_MESSAGES_ORDER: + if msg_name in settings.CAS_INFO_MESSAGES: + try: + msg = settings.CAS_INFO_MESSAGES[msg_name].copy() + except AttributeError: + continue + if "message" in msg: + msg["name"] = msg_name + # use info as default infox type + msg["type"] = msg.get("type", "info") + # make box discardable by default + msg["discardable"] = msg.get("discardable", True) + msg_hash = ( + six.text_type(msg["message"]).encode("utf-8") + + msg["type"].encode("utf-8") + ) + # hash depend of the rendering language + msg["hash"] = hashlib.md5(msg_hash).hexdigest() + params["CAS_INFO_RENDER"].append(msg) return params From cd57f101bcca7d3dfd4f3e6ec312329d80ab4766 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Wed, 24 Aug 2016 18:01:59 +0200 Subject: [PATCH 11/14] Fix english typos in tests --- cas_server/tests/test_view.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cas_server/tests/test_view.py b/cas_server/tests/test_view.py index 1297e4a..6cf0b14 100644 --- a/cas_server/tests/test_view.py +++ b/cas_server/tests/test_view.py @@ -234,7 +234,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): 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.assertTrue(b"Service https://www.example.net non allowed" in response.content) + self.assertTrue(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""" @@ -280,7 +280,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): self.assertEqual(response.status_code, 200) # we warn the user that https://www.example.net is not an allowed service url # NO ticket are created - self.assertTrue(b"Service https://www.example.org non allowed" in response.content) + self.assertTrue(b"Service https://www.example.org not allowed" in response.content) def test_user_logged_not_in_db(self): """If the user is logged but has been delete from the database, it should be logged out""" @@ -314,7 +314,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): response = client.get("/login", {'service': self.service_restrict_user_fail}) self.assertEqual(response.status_code, 200) # the ticket is not created and a warning is displayed to the user - self.assertTrue(b"Username non allowed" in response.content) + self.assertTrue(b"Username not allowed" in response.content) # same but with the tes user username being one of the allowed usernames response = client.get("/login", {'service': self.service_restrict_user_success}) @@ -337,7 +337,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): response = client.get("/login", {'service': service}) # the ticket is not created and a warning is displayed to the user self.assertEqual(response.status_code, 200) - self.assertTrue(b"User characteristics non allowed" in response.content) + self.assertTrue(b"User characteristics not allowed" in response.content) # same but with rectriction that a valid upon the test user attributes response = client.get("/login", {'service': self.service_filter_success}) @@ -546,7 +546,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): self.assertEqual(data["messages"][0]["level"], "error") self.assertEqual( data["messages"][0]["message"], - "Service https://www.example.org non allowed." + "Service https://www.example.org not allowed." ) @override_settings(CAS_ENABLE_AJAX_AUTH=True) From 6b007f39604d3d01e39957b88de095ddd8755ddc Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Wed, 24 Aug 2016 18:20:12 +0200 Subject: [PATCH 12/14] Add CAS_INFO_MESSAGES tests --- cas_server/tests/test_view.py | 39 +++++++++++++++++++++++++++++++++++ cas_server/utils.py | 5 ++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/cas_server/tests/test_view.py b/cas_server/tests/test_view.py index 6cf0b14..c623a27 100644 --- a/cas_server/tests/test_view.py +++ b/cas_server/tests/test_view.py @@ -75,6 +75,45 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): response = client.get("/login") self.assertNotIn(b"A new version of the application is available", response.content) + @override_settings(CAS_INFO_MESSAGES_ORDER=["cas_explained"]) + def test_messages_info_box_enabled(self): + """test that the message info-box is displayed then enabled""" + client = Client() + response = client.get("/login") + self.assertIn( + b"The Central Authentication Service grants you access to most of our websites by ", + response.content + ) + + @override_settings(CAS_INFO_MESSAGES_ORDER=[]) + def test_messages_info_box_disabled(self): + """test that the message info-box is not displayed then disabled""" + client = Client() + response = client.get("/login") + self.assertNotIn( + b"The Central Authentication Service grants you access to most of our websites by ", + response.content + ) + + # test1 and test2 are malformed and should be ignored, test3 is ok, test5 do not + # exists and should be ignored + @override_settings(CAS_INFO_MESSAGES_ORDER=["test1", "test2", "test3", "test5"]) + @override_settings(CAS_INFO_MESSAGES={ + "test1": "test", # not a dict, should be ignored + "test2": {"type": "success"}, # not "message" key, should be ignored + "test3": {"message": "test3"}, + "test4": {"message": "test4"}, + }) + def test_messages_info_box_bad_messages(self): + """test that mal formated messages dict are ignored""" + client = Client() + # not errors should be raises + response = client.get("/login") + # test3 is ok est should be there + self.assertIn(b"test3", response.content) + # test4 is not in CAS_INFO_MESSAGES_ORDER and should not be there + self.assertNotIn(b"test4", response.content) + def test_login_view_post_goodpass_goodlt(self): """Test a successul login""" # we get a client who fetch a frist time the login page and the login form default diff --git a/cas_server/utils.py b/cas_server/utils.py index 17ec5f9..8817b22 100644 --- a/cas_server/utils.py +++ b/cas_server/utils.py @@ -78,10 +78,9 @@ def context(params): params["CAS_INFO_RENDER"] = [] for msg_name in settings.CAS_INFO_MESSAGES_ORDER: if msg_name in settings.CAS_INFO_MESSAGES: - try: - msg = settings.CAS_INFO_MESSAGES[msg_name].copy() - except AttributeError: + if not isinstance(settings.CAS_INFO_MESSAGES[msg_name], dict): continue + msg = settings.CAS_INFO_MESSAGES[msg_name].copy() if "message" in msg: msg["name"] = msg_name # use info as default infox type From 13cf8cf95b4d7f3df3b7392557dc6006d6788f04 Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Wed, 24 Aug 2016 18:40:08 +0200 Subject: [PATCH 13/14] Update CHANGELOG.rst --- CHANGELOG.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ad7f4e8..3a27965 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,15 +14,19 @@ Added * Add a CHANGELOG.rst file. * Add a validator to models CharField that should be regular expressions checking that user input are valids regular expressions. +* Add a CAS_INFO_MESSAGES and CAS_INFO_MESSAGES_ORDER settings allowing to display messages in + info-boxes on the html pages of the default templates. Changed ------- * Allow the user defined CAS_COMPONENT_URLS to omit not changed values. * replace code-block without language indication by literal blocks. +* Update french translation Fixed ----- * Some README.rst typos. +* some english typos v0.6.4 - 2016-08-14 From 5b2795ae44dacd600c272d71dab8f85bdd03f88b Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Wed, 24 Aug 2016 23:03:21 +0200 Subject: [PATCH 14/14] Update version to 0.7.0 --- CHANGELOG.rst | 4 ++-- cas_server/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3a27965..0bd4d8b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,8 +6,8 @@ All notable changes to this project will be documented in this file. .. contents:: Table of Contents :depth: 2 -Unreleased -========== +v0.7.0 - 2016-08-24 +=================== Added ----- diff --git a/cas_server/__init__.py b/cas_server/__init__.py index 5fcbed0..3936504 100644 --- a/cas_server/__init__.py +++ b/cas_server/__init__.py @@ -11,7 +11,7 @@ """A django CAS server application""" #: version of the application -VERSION = '0.6.4' +VERSION = '0.7.0' #: path the the application configuration class default_app_config = 'cas_server.apps.CasAppConfig'