Merge pull request #83 from nitmir/dev

Update to version 2.0.0

v2.0.0 - 2022-10-17
===================

Added
-----
* Support for Django 4.0 and 4.1
* Add locale for zh_Hans
* Add a unit test with a non ascii char in service url
* Add settings to allow deletings Django cookies upon logout

Changed
-------
* Update CI: require pytest >= 7 and remove pytest-pythonpath dependancy

Fixes
-----
* Fix unicode sandwich issue in cas_server.utils.update_url
* Fix DeprecationWarning about default_app_config in Django 3.2
* Fix DeprecationWarning about USE_L10N in Django 4.0

Removed
-------
* Drop support for python 2.7 (now deprecated for more than 2 years,
  expect it to break now or in a near future)
* Drop support for python 3.5 (but it should keep working for a while.
  pytest >= 7 do not support python 3.5 and Debian Stretch support ended)
This commit is contained in:
Valentin Samir 2022-10-17 20:07:46 +02:00 committed by GitHub
commit 0025a3772b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 601 additions and 54 deletions

View file

@ -1,3 +1,4 @@
dist: focal
language: python language: python
matrix: matrix:
include: include:
@ -8,13 +9,7 @@ matrix:
env: TOX_ENV=check_rst env: TOX_ENV=check_rst
- python: "3.9" - python: "3.9"
env: TOX_ENV=coverage env: TOX_ENV=coverage
# Debian strech support # REHL 7 support and Ubuntu bionic
- python: "3.5"
env: TOX_ENV=py35-django111
- python: "3.5"
env: TOX_ENV=py35-django111
arch: ppc64le
# Ubuntu bionic and EPEL 7 support
- python: "3.6" - python: "3.6"
env: TOX_ENV=py36-django111 env: TOX_ENV=py36-django111
- python: "3.6" - python: "3.6"
@ -38,17 +33,25 @@ matrix:
- python: "3.8" - python: "3.8"
env: TOX_ENV=py38-django22 env: TOX_ENV=py38-django22
arch: ppc64le arch: ppc64le
# Debian bullseye and Ubuntu hirsute support # Debian bullseye and Ubuntu hirsute and impish support
- python: "3.9" - python: "3.9"
env: TOX_ENV=py39-django22 env: TOX_ENV=py39-django22
- python: "3.9" - python: "3.9"
env: TOX_ENV=py39-django22 env: TOX_ENV=py39-django22
arch: ppc64le arch: ppc64le
# Ubuntu jammy and kinetic support
- python: "3.10"
env: TOX_ENV=py310-django32
- python: "3.10"
env: TOX_ENV=py310-django32
arch: ppc64le
# Django additional supported version # Django additional supported version
- python: "3.9"
env: TOX_ENV=py39-django31
- python: "3.9" - python: "3.9"
env: TOX_ENV=py39-django32 env: TOX_ENV=py39-django32
- python: "3.10"
env: TOX_ENV=py310-django40
- python: "3.10"
env: TOX_ENV=py310-django41
cache: cache:
directories: directories:

View file

@ -6,6 +6,34 @@ All notable changes to this project will be documented in this file.
.. contents:: Table of Contents .. contents:: Table of Contents
:depth: 2 :depth: 2
v2.0.0 - 2022-10-17
===================
Added
-----
* Support for Django 4.0 and 4.1
* Add locale for zh_Hans
* Add a unit test with a non ascii char in service url
* Add settings to allow deletings Django cookies upon logout
Changed
-------
* Update CI: require pytest >= 7 and remove pytest-pythonpath dependancy
Fixes
-----
* Fix unicode sandwich issue in cas_server.utils.update_url
* Fix DeprecationWarning about default_app_config in Django 3.2
* Fix DeprecationWarning about USE_L10N in Django 4.0
Removed
-------
* Drop support for python 2.7 (now deprecated for more than 2 years,
expect it to break now or in a near future)
* Drop support for python 3.5 (but it should keep working for a while.
pytest >= 7 do not support python 3.5 and Debian Stretch support ended)
v1.3.1 - 2021-07-03 v1.3.1 - 2021-07-03
=================== ===================

View file

@ -21,15 +21,15 @@ Features
* Possibility to rename/rewrite attributes per service * Possibility to rename/rewrite attributes per service
* Possibility to require some attribute values per service * Possibility to require some attribute values per service
* Federated mode between multiple CAS * Federated mode between multiple CAS
* Supports Django 1.11, 2.2, 3.1 and 3.2 * Supports Django 1.11, 2.2, 3.2, 4.0 and 4.1
* Supports Python 3.5+ * Supports Python 3.6+
Dependencies Dependencies
============ ============
``django-cas-server`` depends on the following python packages: ``django-cas-server`` depends on the following python packages:
* Django >= 1.11 < 3.3 * Django >= 1.11 < 4.2
* requests >= 2.4 * requests >= 2.4
* requests_futures >= 0.9.5 * requests_futures >= 0.9.5
* lxml >= 3.4 * lxml >= 3.4
@ -285,6 +285,17 @@ Authentication settings
* ``CAS_SLO_TIMEOUT``: Timeout for a single SLO request in seconds. The default is ``5``. * ``CAS_SLO_TIMEOUT``: Timeout for a single SLO request in seconds. The default is ``5``.
* ``CAS_REMOVE_DJANGO_SESSION_COOKIE_ON_LOGOUT``: If `True` Django session cookie will be removed
on logout from CAS server (default `False`). Note that Django session middleware will generate
a new session cookie.
* ``CAS_REMOVE_DJANGO_CSRF_COOKIE_ON_LOGOUT``: If `True` Django csrf cookie will be removed on
logout from CAS server (default `False`). Note that Django csrf middleware will generate a new
csrf token cookie.
* ``CAS_REMOVE_DJANGO_LANGUAGE_COOKIE_ON_LOGOUT``: If `True` Django language cookie will be
removed on logout from CAS server (default `False`).
Federation settings Federation settings
------------------- -------------------

View file

@ -9,9 +9,14 @@
# #
# (c) 2015-2016 Valentin Samir # (c) 2015-2016 Valentin Samir
"""A django CAS server application""" """A django CAS server application"""
try:
import django
except ModuleNotFoundError:
django = None
#: version of the application #: version of the application
VERSION = '1.3.1' VERSION = '2.0.0'
if django is None or django.VERSION < (3, 2):
#: 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'

View file

@ -239,6 +239,13 @@ CAS_INFO_MESSAGES = {
#: Let the list empty to disable messages display. #: Let the list empty to disable messages display.
CAS_INFO_MESSAGES_ORDER = [] CAS_INFO_MESSAGES_ORDER = []
#: :class:`bool` If `True` Django session cookie will be removed on logout from CAS server
CAS_REMOVE_DJANGO_SESSION_COOKIE_ON_LOGOUT = False
#: :class:`bool` If `True` Django csrf cookie will be removed on logout from CAS server
CAS_REMOVE_DJANGO_CSRF_COOKIE_ON_LOGOUT = False
#: :class:`bool` If `True` Django language cookie will be removed on logout from CAS server
CAS_REMOVE_DJANGO_LANGUAGE_COOKIE_ON_LOGOUT = False
GLOBALS = globals().copy() GLOBALS = globals().copy()
for name, default_value in GLOBALS.items(): for name, default_value in GLOBALS.items():

Binary file not shown.

View file

@ -0,0 +1,421 @@
# 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.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-08-01 22:18+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: apps.py:30 templates/cas_server/bs3/base.html:7
#: templates/cas_server/bs3/base.html:26 templates/cas_server/bs4/base.html:6
#: templates/cas_server/bs4/base.html:17
msgid "Central Authentication Service"
msgstr "认证中心服务"
#: default_settings.py:230
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 ""
"您仅需在认证中心认证一次,就可以访问您的多数网站, "
"这样您不再需要重复输入认证,除非您的会话过期,或者您登出了."
#: forms.py:93
msgid "Identity provider"
msgstr "身份提供者"
#: forms.py:97 forms.py:119
msgid "Warn me before logging me into other sites."
msgstr "登录到其它网站时警告我"
#: forms.py:101
msgid "Remember the identity provider"
msgstr "记住此身份提供者"
#: forms.py:112 models.py:646
msgid "username"
msgstr "用户名"
#: forms.py:116
msgid "password"
msgstr "密码"
#: forms.py:139
msgid "The credentials you provided cannot be determined to be authentic."
msgstr "您提供的令牌不能通过鉴权"
#: forms.py:191
msgid "User not found in the temporary database, please try to reconnect"
msgstr "在临时数据库找不到此用户,请尝试重新连接"
#: forms.py:205
msgid "service"
msgstr "服务"
#: management/commands/cas_clean_federate.py:25
msgid "Clean old federated users"
msgstr "清除过期联盟用户"
#: management/commands/cas_clean_sessions.py:27
msgid "Clean deleted sessions"
msgstr "清除被删除的会话"
#: management/commands/cas_clean_tickets.py:27
msgid "Clean old tickets"
msgstr "清除过期凭证"
#: models.py:79
msgid "identity provider"
msgstr "身份提供者"
#: models.py:80
msgid "identity providers"
msgstr "身份证供者"
#: models.py:86
msgid "suffix"
msgstr "后缀"
#: models.py:88
msgid ""
"Suffix append to backend CAS returned username: ``returned_username`` @ "
"``suffix``."
msgstr "后端 CAS 附加后缀返回的用户名: ``returned_username`` @ "
"``suffix``."
#: models.py:95
msgid "server url"
msgstr "服务 url"
#: models.py:105
msgid "CAS protocol version"
msgstr "CAS 协议版本"
#: models.py:107
msgid ""
"Version of the CAS protocol to use when sending requests the the backend CAS."
msgstr ""
"后端 CAS 发送请求时使用的 CAS 协议版本"
#: models.py:114
msgid "verbose name"
msgstr "详细名称"
#: models.py:115
msgid "Name for this identity provider displayed on the login page."
msgstr "在登录页显示的身份提供者的名字"
#: models.py:121 models.py:498
msgid "position"
msgstr "位置"
#: models.py:135
msgid "display"
msgstr "显示"
#: models.py:136
msgid "Display the provider on the login page."
msgstr "在登录页显示提供者"
#: models.py:174
msgid "Federated user"
msgstr "联盟用户"
#: models.py:175
msgid "Federated users"
msgstr "联盟用户"
#: models.py:254
msgid "User attributes cache"
msgstr "用户属性缓存"
#: models.py:255
msgid "User attributes caches"
msgstr "用户属性缓存"
#: models.py:279
msgid "User"
msgstr "用户"
#: models.py:280
msgid "Users"
msgstr "用户"
#: models.py:372
#, python-format
msgid "Error during service logout %s"
msgstr "服务登出中的异常 %s"
#: models.py:492
msgid "Service pattern"
msgstr "服务范式"
#: models.py:493
msgid "Services patterns"
msgstr "服务范式"
#: models.py:499
msgid "service patterns are sorted using the position attribute"
msgstr "服务范式会按照位置属性排序"
#: models.py:507 models.py:676
msgid "name"
msgstr "名称"
#: models.py:508
msgid "A name for the service"
msgstr "服务的名称"
#: models.py:516 models.py:723 models.py:757
msgid "pattern"
msgstr "范式"
#: models.py:518
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 ""
"用一个正则表示式来匹配服务。一般如 '^https://"
"some\\.server\\.com/path/.*$'. 在正则表达式中,特殊"
"字符必须用 '\\' 转码."
#: models.py:529
msgid "user field"
msgstr "用户字段"
#: models.py:530
msgid "Name of the attribute to transmit as username, empty = login"
msgstr "被转译作为用户名的属性字段,空 = login"
#: models.py:535
msgid "restrict username"
msgstr "用户名限制"
#: models.py:536
msgid "Limit username allowed to connect to the list provided bellow"
msgstr "只允许下面列表提供的用户名连接"
#: models.py:541
msgid "proxy"
msgstr "代理"
#: models.py:542
msgid "Proxy tickets can be delivered to the service"
msgstr "可以对服务分发的代理凭证"
#: models.py:548
msgid "proxy callback"
msgstr "代理回调"
#: models.py:549
msgid "can be used as a proxy callback to deliver PGT"
msgstr "可以作为代理回调来分发PGT"
#: models.py:556
msgid "single log out"
msgstr "单点登出"
#: models.py:557
msgid "Enable SLO for the service"
msgstr "为服务启用 SLO"
#: models.py:565
msgid "single log out callback"
msgstr "单点登出回调"
#: models.py:566
msgid ""
"URL where the SLO request will be POST. empty = service url\n"
"This is usefull for non HTTP proxied services."
msgstr ""
"SLO 的 POST 请求使用的 URL. 空 = 服务地址\n"
"在为非 HTTP 代理服务时有用"
#: models.py:647
msgid "username allowed to connect to the service"
msgstr "允许连接到服务的用户名"
#: models.py:677
msgid "name of an attribute to send to the service, use * for all attributes"
msgstr "发给服务的属性名, 使用 * 表示所有属性"
#: models.py:684 models.py:765
msgid "replace"
msgstr "替换"
#: models.py:685
msgid ""
"name under which the attribute will be show to the service. empty = default "
"name of the attribut"
msgstr ""
"展示给服务的属性的名字. 空 = default"
"属性的名字"
#: models.py:716 models.py:751
msgid "attribute"
msgstr "属性"
#: models.py:717
msgid "Name of the attribute which must verify pattern"
msgstr "必须校验范式的属性的名字"
#: models.py:724
msgid "a regular expression"
msgstr "一个正则表达式"
#: models.py:752
msgid "Name of the attribute for which the value must be replace"
msgstr "必须被替换的值的属性的名字"
#: models.py:758
msgid "An regular expression maching whats need to be replaced"
msgstr "一个正则表达式,符合的将要被替换"
#: models.py:766
msgid "replace expression, groups are capture by \\1, \\2 …"
msgstr "替换表达式, 用 \\`, \\2 等等来替换组"
#: templates/cas_server/bs3/base.html:43 templates/cas_server/bs4/base.html:28
#, 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 ""
"此应用有一个新版本可用. 此实例运行于 %(VERSION)s, 最新的版本是 %(LAST_VERSION)s. 请考虑升级"
#: templates/cas_server/bs3/logged.html:4
#: templates/cas_server/bs4/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>登入成功</h3>您已经成功登入认证中心."
"<br/>出于安全考虑, 当您用完需要认证的服务时,请您登出并退出您的浏览器!"
#: templates/cas_server/bs3/logged.html:8
#: templates/cas_server/bs4/logged.html:8
msgid "Log me out from all my sessions"
msgstr "从我的所有会话中登出"
#: templates/cas_server/bs3/logged.html:14
#: templates/cas_server/bs4/logged.html:14
msgid "Forget the identity provider"
msgstr "忘掉身份提供者"
#: templates/cas_server/bs3/logged.html:18
#: templates/cas_server/bs4/logged.html:18
msgid "Logout"
msgstr "登出"
#: templates/cas_server/bs3/login.html:6 templates/cas_server/bs4/login.html:7
msgid "Please log in"
msgstr "请登录"
#: templates/cas_server/bs3/login.html:14
#: templates/cas_server/bs4/login.html:17
msgid "Login"
msgstr "登录"
#: templates/cas_server/bs3/warn.html:9 templates/cas_server/bs4/warn.html:9
msgid "Connect to the service"
msgstr "连接到服务"
#: utils.py:753
#, python-format
msgid "\"%(value)s\" is not a valid regular expression"
msgstr "\"%(value)s\" 不是一个有效的正则表达式"
#: views.py:197
msgid ""
"<h3>Logout successful</h3>You have successfully logged out from the Central "
"Authentication Service. For security reasons, close your web browser."
msgstr ""
"<h3>登出成功</h3>您成功从认证中心登出."
"安全起见,请关闭您的浏览器"
#: views.py:203
#, python-format
msgid ""
"<h3>Logout successful</h3>You have successfully logged out from %d sessions "
"of the Central Authentication Service. For security reasons, close your web "
"browser."
msgstr ""
"<h3>登出成功</h3>您已经从认证中心服务的会话 %d 中成功登出"
"为安全起见,请关闭您的浏览器"
#: views.py:210
msgid ""
"<h3>Logout successful</h3>You were already logged out from the Central "
"Authentication Service. For security reasons, close your web browser."
msgstr ""
"<h3>登出成功</h3>您已经从认证中心服务登出. "
"为安全起见,请关闭您的浏览器"
#: views.py:391
#, python-format
msgid ""
"Invalid response from your identity provider CAS upon ticket %(ticket)s "
"validation: %(error)r"
msgstr ""
"您的身份提供者 CAS 对凭证 %(ticket)s 返回了无效响应"
"校验: %(error)r"
#: views.py:513
msgid "Invalid login ticket, please try to log in again"
msgstr "无效登录凭证, 请尝试重新登录"
#: views.py:706
#, python-format
msgid "Authentication has been required by service %(name)s (%(url)s)"
msgstr "服务 %(name)s (%(url)s) 需要认证"
#: views.py:744
#, python-format
msgid "Service %(url)s not allowed."
msgstr "不允许的服务 %(url)s"
#: views.py:751
msgid "Username not allowed"
msgstr "不允许的用户名"
#: views.py:758
msgid "User characteristics not allowed"
msgstr "不允许的用户特征"
#: views.py:765
#, python-format
msgid "The attribute %(field)s is needed to use that service"
msgstr "使用那个服务需要属性 %(field)s"
#: views.py:857
#, python-format
msgid "Authentication renewal required by service %(name)s (%(url)s)."
msgstr "服务 %(name)s (%(url)s) 需要更新认证"
#: views.py:864
#, python-format
msgid "Authentication required by service %(name)s (%(url)s)."
msgstr "服务 %(name)s (%(url)s) 需要认证."
#: views.py:872
#, python-format
msgid "Service %s not allowed"
msgstr "不允许的服务 %s"

View file

@ -90,6 +90,7 @@ TIME_ZONE = 'UTC'
USE_I18N = True USE_I18N = True
if django.VERSION < (4, 0):
USE_L10N = True USE_L10N = True
USE_TZ = True USE_TZ = True

View file

@ -10,6 +10,7 @@
# #
# (c) 2016 Valentin Samir # (c) 2016 Valentin Samir
"""Tests module for utils""" """Tests module for utils"""
import django
from django.test import TestCase, RequestFactory from django.test import TestCase, RequestFactory
from django.db import connection from django.db import connection
@ -173,6 +174,7 @@ class UtilsTestCase(TestCase):
utils.import_attr('cas_server.utils.toto') utils.import_attr('cas_server.utils.toto')
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
utils.import_attr('toto') utils.import_attr('toto')
if django.VERSION < (3, 2):
self.assertEqual( self.assertEqual(
utils.import_attr('cas_server.default_app_config'), utils.import_attr('cas_server.default_app_config'),
'cas_server.apps.CasAppConfig' 'cas_server.apps.CasAppConfig'

View file

@ -262,7 +262,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
# check that the service pattern registered on the ticket is the on we use for tests # check that the service pattern registered on the ticket is the on we use for tests
self.assertEqual(ticket.service_pattern, self.service_pattern) self.assertEqual(ticket.service_pattern, self.service_pattern)
def assert_service_ticket(self, client, response): def assert_service_ticket(self, client, response, service="https://www.example.com"):
"""check that a ticket is well emited when requested on a allowed service""" """check that a ticket is well emited when requested on a allowed service"""
# On ticket emission, we should be redirected to the service url, setting the ticket # On ticket emission, we should be redirected to the service url, setting the ticket
# GET parameter # GET parameter
@ -270,7 +270,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
self.assertTrue(response.has_header('Location')) self.assertTrue(response.has_header('Location'))
self.assertTrue( self.assertTrue(
response['Location'].startswith( response['Location'].startswith(
"https://www.example.com?ticket=%s-" % settings.CAS_SERVICE_TICKET_PREFIX "%s?ticket=%s-" % (service, settings.CAS_SERVICE_TICKET_PREFIX)
) )
) )
# check that the value of the ticket GET parameter match the value of the ticket # check that the value of the ticket GET parameter match the value of the ticket
@ -337,6 +337,19 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin):
self.assertFalse(b"Service https://www.example.net not allowed" in response.content) 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 containing
non ascii char in url
"""
# get a client that is already authenticated
client = get_auth_client()
# ask for a ticket for https://www.example.com
response = client.get("/login?service=https://www.example.com/é")
# as https://www.example.com/é is a valid service a ticket should be created and the
# user redirected to the service url
self.assert_service_ticket(client, response, service="https://www.example.com/%C3%A9")
def test_view_login_get_auth_allowed_service_non_ascii(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
client = get_auth_client() client = get_auth_client()

View file

@ -249,15 +249,25 @@ def update_url(url, params):
:return: The URL with an updated querystring :return: The URL with an updated querystring
:rtype: unicode :rtype: unicode
""" """
if not isinstance(url, bytes): def to_unicode(data):
url = url.encode('utf-8') if isinstance(data, bytes):
for key, value in list(params.items()): return data.decode('utf-8')
if not isinstance(key, bytes): else:
del params[key] return data
key = key.encode('utf-8')
if not isinstance(value, bytes): def to_bytes(data):
value = value.encode('utf-8') if not isinstance(data, bytes):
params[key] = value return data.encode('utf-8')
else:
return data
if six.PY3:
url = to_unicode(url)
params = {to_unicode(key): to_unicode(value) for (key, value) in params.items()}
else:
url = to_bytes(url)
params = {to_bytes(key): to_bytes(value) for (key, value) in params.items()}
url_parts = list(urlparse(url)) url_parts = list(urlparse(url))
query = dict(parse_qsl(url_parts[4], keep_blank_values=True)) query = dict(parse_qsl(url_parts[4], keep_blank_values=True))
query.update(params) query.update(params)
@ -265,10 +275,12 @@ def update_url(url, params):
query = list(query.items()) query = list(query.items())
query.sort() query.sort()
url_query = urlencode(query) url_query = urlencode(query)
if not isinstance(url_query, bytes): # pragma: no cover in python3 urlencode return an unicode
url_query = url_query.encode("utf-8")
url_parts[4] = url_query url_parts[4] = url_query
return urlunparse(url_parts).decode('utf-8') url = urlunparse(url_parts)
if isinstance(url, bytes):
url = url.decode('utf-8')
return url
def unpack_nested_exception(error): def unpack_nested_exception(error):

View file

@ -153,6 +153,16 @@ class LogoutView(View, LogoutMixin):
self.url = request.GET.get('url') self.url = request.GET.get('url')
self.ajax = settings.CAS_ENABLE_AJAX_AUTH and 'HTTP_X_AJAX' in request.META self.ajax = settings.CAS_ENABLE_AJAX_AUTH and 'HTTP_X_AJAX' in request.META
@staticmethod
def delete_cookies(response):
if settings.CAS_REMOVE_DJANGO_SESSION_COOKIE_ON_LOGOUT:
response.delete_cookie(settings.SESSION_COOKIE_NAME)
if settings.CAS_REMOVE_DJANGO_CSRF_COOKIE_ON_LOGOUT:
response.delete_cookie(settings.CSRF_COOKIE_NAME)
if settings.CAS_REMOVE_DJANGO_LANGUAGE_COOKIE_ON_LOGOUT:
response.delete_cookie(settings.LANGUAGE_COOKIE_NAME)
return response
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
""" """
method called on GET request on this view method called on GET request on this view
@ -181,15 +191,15 @@ class LogoutView(View, LogoutMixin):
response = HttpResponseRedirect(utils.update_url(url, params)) response = HttpResponseRedirect(utils.update_url(url, params))
if request.GET.get("forget_provider"): if request.GET.get("forget_provider"):
response.delete_cookie("remember_provider") response.delete_cookie("remember_provider")
return response return self.delete_cookies(response)
# if service is set, redirect to service after logout # if service is set, redirect to service after logout
if self.service: if self.service:
list(messages.get_messages(request)) # clean messages before leaving the django app list(messages.get_messages(request)) # clean messages before leaving the django app
return HttpResponseRedirect(self.service) return self.delete_cookies(HttpResponseRedirect(self.service))
# if service is not set but url is set, redirect to url after logout # if service is not set but url is set, redirect to url after logout
elif self.url: elif self.url:
list(messages.get_messages(request)) # clean messages before leaving the django app list(messages.get_messages(request)) # clean messages before leaving the django app
return HttpResponseRedirect(self.url) return self.delete_cookies(HttpResponseRedirect(self.url))
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:
@ -224,19 +234,19 @@ class LogoutView(View, LogoutMixin):
'url': url, 'url': url,
'session_nb': session_nb 'session_nb': session_nb
} }
return json_response(request, data) return self.delete_cookies(json_response(request, data))
else: else:
return redirect("cas_server:login") return self.delete_cookies(redirect("cas_server:login"))
else: else:
if self.ajax: if self.ajax:
data = {'status': 'success', 'detail': 'logout', 'session_nb': session_nb} data = {'status': 'success', 'detail': 'logout', 'session_nb': session_nb}
return json_response(request, data) return self.delete_cookies(json_response(request, data))
else: else:
return render( return self.delete_cookies(render(
request, request,
settings.CAS_LOGOUT_TEMPLATE, settings.CAS_LOGOUT_TEMPLATE,
utils.context({'logout_msg': logout_msg}) utils.context({'logout_msg': logout_msg})
) ))
class FederateAuth(CsrfExemptView): class FederateAuth(CsrfExemptView):

View file

@ -2,4 +2,4 @@
testpaths = cas_server/tests/ testpaths = cas_server/tests/
DJANGO_SETTINGS_MODULE = cas_server.tests.settings DJANGO_SETTINGS_MODULE = cas_server.tests.settings
norecursedirs = .* build dist docs norecursedirs = .* build dist docs
python_paths = . pythonpath = .

View file

@ -4,8 +4,7 @@ requests_futures>=0.9.5
lxml>=3.4 lxml>=3.4
six>=1.8 six>=1.8
tox>=1.8.1 tox>=1.8.1
pytest>=2.6.4 pytest>=7
pytest-django>=2.8.0 pytest-django>=2.8.0
pytest-pythonpath>=0.3
pytest-cov>=2.2.1 pytest-cov>=2.2.1
mock>=1 mock>=1

View file

@ -1,4 +1,4 @@
Django >= 1.11,<3.3 Django >= 1.11,<4.2
setuptools>=5.5 setuptools>=5.5
requests>=2.4 requests>=2.4
requests_futures>=0.9.5 requests_futures>=0.9.5

View file

@ -40,14 +40,13 @@ if __name__ == '__main__':
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
@ -62,7 +61,7 @@ if __name__ == '__main__':
}, },
keywords=['django', 'cas', 'cas3', 'server', 'sso', 'single sign-on', 'authentication', 'auth'], keywords=['django', 'cas', 'cas3', 'server', 'sso', 'single sign-on', 'authentication', 'auth'],
install_requires=[ install_requires=[
'Django >= 1.11,<3.3', 'requests >= 2.4', 'requests_futures >= 0.9.5', 'Django >= 1.11,<4.2', 'requests >= 2.4', 'requests_futures >= 0.9.5',
'lxml >= 3.4', 'six >= 1' 'lxml >= 3.4', 'six >= 1'
], ],
url="https://github.com/nitmir/django-cas-server", url="https://github.com/nitmir/django-cas-server",

44
tox.ini
View file

@ -2,11 +2,12 @@
envlist= envlist=
flake8, flake8,
check_rst, check_rst,
py27-django111,
py3-django111, py3-django111,
py3-django22, py3-django22,
py3-django31, py3-django31,
py3-django32, py3-django32,
py3-django40,
py3-django41,
################## ##################
# generic config # # generic config #
@ -117,6 +118,18 @@ deps =
Django>=3.2,<3.3 Django>=3.2,<3.3
{[base]deps} {[base]deps}
[testenv:py3-django40]
basepython=python3
deps =
Django>=4.0,<4.1
{[base]deps}
[testenv:py3-django41]
basepython=python3
deps =
Django>=4.1,<4.2
{[base]deps}
######################### #########################
# Debian strech support # # Debian strech support #
######################### #########################
@ -167,9 +180,9 @@ deps =
Django>=2.2,<3.0 Django>=2.2,<3.0
{[base]deps} {[base]deps}
############################################## #########################################################
# Debian bullseye and Ubuntu hirsute support # # Debian bullseye and Ubuntu hirsute and impish support #
############################################## #########################################################
[testenv:py39-django22] [testenv:py39-django22]
basepython=python3.9 basepython=python3.9
@ -177,6 +190,17 @@ deps =
Django>=2.2,<3.0 Django>=2.2,<3.0
{[base]deps} {[base]deps}
####################################
# Ubuntu jammy and kinetic support #
####################################
[testenv:py310-django32]
basepython=python3.10
deps =
Django>=3.2,<3.3
{[base]deps}
####################################### #######################################
# Django additional supported version # # Django additional supported version #
####################################### #######################################
@ -193,3 +217,15 @@ basepython=python3.9
deps = deps =
Django>=3.2,<3.3 Django>=3.2,<3.3
{[base]deps} {[base]deps}
[testenv:py310-django40]
basepython=python3.10
deps =
Django>=4.0,<4.1
{[base]deps}
[testenv:py310-django41]
basepython=python3.10
deps =
Django>=4.1,<4.2
{[base]deps}