diff --git a/.travis.yml b/.travis.yml index 4c39d04..f41ca1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: focal language: python matrix: include: @@ -8,13 +9,7 @@ matrix: env: TOX_ENV=check_rst - python: "3.9" env: TOX_ENV=coverage - # Debian strech support - - python: "3.5" - env: TOX_ENV=py35-django111 - - python: "3.5" - env: TOX_ENV=py35-django111 - arch: ppc64le - # Ubuntu bionic and EPEL 7 support + # REHL 7 support and Ubuntu bionic - python: "3.6" env: TOX_ENV=py36-django111 - python: "3.6" @@ -38,17 +33,25 @@ matrix: - python: "3.8" env: TOX_ENV=py38-django22 arch: ppc64le - # Debian bullseye and Ubuntu hirsute support + # Debian bullseye and Ubuntu hirsute and impish support - python: "3.9" env: TOX_ENV=py39-django22 - python: "3.9" env: TOX_ENV=py39-django22 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 - - python: "3.9" - env: TOX_ENV=py39-django31 - python: "3.9" env: TOX_ENV=py39-django32 + - python: "3.10" + env: TOX_ENV=py310-django40 + - python: "3.10" + env: TOX_ENV=py310-django41 cache: directories: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f2a8071..a8ea1ce 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,34 @@ All notable changes to this project will be documented in this file. .. contents:: Table of Contents :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 =================== diff --git a/README.rst b/README.rst index 50bc8c7..69d8fc1 100644 --- a/README.rst +++ b/README.rst @@ -21,15 +21,15 @@ Features * Possibility to rename/rewrite attributes per service * Possibility to require some attribute values per service * Federated mode between multiple CAS -* Supports Django 1.11, 2.2, 3.1 and 3.2 -* Supports Python 3.5+ +* Supports Django 1.11, 2.2, 3.2, 4.0 and 4.1 +* Supports Python 3.6+ Dependencies ============ ``django-cas-server`` depends on the following python packages: -* Django >= 1.11 < 3.3 +* Django >= 1.11 < 4.2 * requests >= 2.4 * requests_futures >= 0.9.5 * 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_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 ------------------- diff --git a/cas_server/__init__.py b/cas_server/__init__.py index 2ac3122..72c98ae 100644 --- a/cas_server/__init__.py +++ b/cas_server/__init__.py @@ -9,9 +9,14 @@ # # (c) 2015-2016 Valentin Samir """A django CAS server application""" +try: + import django +except ModuleNotFoundError: + django = None #: version of the application -VERSION = '1.3.1' +VERSION = '2.0.0' -#: path the the application configuration class -default_app_config = 'cas_server.apps.CasAppConfig' +if django is None or django.VERSION < (3, 2): + #: path the the application configuration class + default_app_config = 'cas_server.apps.CasAppConfig' diff --git a/cas_server/default_settings.py b/cas_server/default_settings.py index cbdb7f8..408e146 100644 --- a/cas_server/default_settings.py +++ b/cas_server/default_settings.py @@ -239,6 +239,13 @@ CAS_INFO_MESSAGES = { #: Let the list empty to disable messages display. 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() for name, default_value in GLOBALS.items(): diff --git a/cas_server/locale/zh_Hans/LC_MESSAGES/django.mo b/cas_server/locale/zh_Hans/LC_MESSAGES/django.mo new file mode 100644 index 0000000..7c166c4 Binary files /dev/null and b/cas_server/locale/zh_Hans/LC_MESSAGES/django.mo differ diff --git a/cas_server/locale/zh_Hans/LC_MESSAGES/django.po b/cas_server/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 0000000..1f2c9c4 --- /dev/null +++ b/cas_server/locale/zh_Hans/LC_MESSAGES/django.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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 "" +"

Log In Successful

You have successfully logged into the Central " +"Authentication Service.
For security reasons, please Log Out and Exit " +"your web browser when you are done accessing services that require " +"authentication!" +msgstr "" +"

登入成功

您已经成功登入认证中心." +"
出于安全考虑, 当您用完需要认证的服务时,请您登出并退出您的浏览器!" + +#: 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 "" +"

Logout successful

You have successfully logged out from the Central " +"Authentication Service. For security reasons, close your web browser." +msgstr "" +"

登出成功

您成功从认证中心登出." +"安全起见,请关闭您的浏览器" + + +#: views.py:203 +#, python-format +msgid "" +"

Logout successful

You have successfully logged out from %d sessions " +"of the Central Authentication Service. For security reasons, close your web " +"browser." +msgstr "" +"

登出成功

您已经从认证中心服务的会话 %d 中成功登出" +"为安全起见,请关闭您的浏览器" + +#: views.py:210 +msgid "" +"

Logout successful

You were already logged out from the Central " +"Authentication Service. For security reasons, close your web browser." +msgstr "" +"

登出成功

您已经从认证中心服务登出. " +"为安全起见,请关闭您的浏览器" + +#: 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" diff --git a/cas_server/tests/settings.py b/cas_server/tests/settings.py index 1a06d3c..5fb28e5 100644 --- a/cas_server/tests/settings.py +++ b/cas_server/tests/settings.py @@ -90,7 +90,8 @@ TIME_ZONE = 'UTC' USE_I18N = True -USE_L10N = True +if django.VERSION < (4, 0): + USE_L10N = True USE_TZ = True diff --git a/cas_server/tests/test_utils.py b/cas_server/tests/test_utils.py index 3064abf..d690724 100644 --- a/cas_server/tests/test_utils.py +++ b/cas_server/tests/test_utils.py @@ -10,6 +10,7 @@ # # (c) 2016 Valentin Samir """Tests module for utils""" +import django from django.test import TestCase, RequestFactory from django.db import connection @@ -173,10 +174,11 @@ class UtilsTestCase(TestCase): utils.import_attr('cas_server.utils.toto') with self.assertRaises(ValueError): utils.import_attr('toto') - self.assertEqual( - utils.import_attr('cas_server.default_app_config'), - 'cas_server.apps.CasAppConfig' - ) + if django.VERSION < (3, 2): + self.assertEqual( + utils.import_attr('cas_server.default_app_config'), + 'cas_server.apps.CasAppConfig' + ) self.assertEqual(utils.import_attr(utils), utils) def test_update_url(self): diff --git a/cas_server/tests/test_view.py b/cas_server/tests/test_view.py index a1aba1b..99ef9ce 100644 --- a/cas_server/tests/test_view.py +++ b/cas_server/tests/test_view.py @@ -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 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""" # On ticket emission, we should be redirected to the service url, setting the ticket # GET parameter @@ -270,7 +270,7 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): self.assertTrue(response.has_header('Location')) self.assertTrue( 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 @@ -337,6 +337,19 @@ class LoginTestCase(TestCase, BaseServicePattern, CanLogin): self.assertFalse(b"Service https://www.example.net not allowed" in response.content) def test_view_login_get_auth_allowed_service(self): + """ + Request a ticket for an allowed service by an authenticated client 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""" # get a client that is already authenticated client = get_auth_client() diff --git a/cas_server/utils.py b/cas_server/utils.py index 4ec2333..31d923e 100644 --- a/cas_server/utils.py +++ b/cas_server/utils.py @@ -249,15 +249,25 @@ def update_url(url, params): :return: The URL with an updated querystring :rtype: unicode """ - if not isinstance(url, bytes): - url = url.encode('utf-8') - for key, value in list(params.items()): - if not isinstance(key, bytes): - del params[key] - key = key.encode('utf-8') - if not isinstance(value, bytes): - value = value.encode('utf-8') - params[key] = value + def to_unicode(data): + if isinstance(data, bytes): + return data.decode('utf-8') + else: + return data + + def to_bytes(data): + if not isinstance(data, bytes): + 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)) query = dict(parse_qsl(url_parts[4], keep_blank_values=True)) query.update(params) @@ -265,10 +275,12 @@ def update_url(url, params): query = list(query.items()) query.sort() 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 - 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): diff --git a/cas_server/views.py b/cas_server/views.py index bbf5490..d26309e 100644 --- a/cas_server/views.py +++ b/cas_server/views.py @@ -153,6 +153,16 @@ class LogoutView(View, LogoutMixin): self.url = request.GET.get('url') 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): """ method called on GET request on this view @@ -181,15 +191,15 @@ class LogoutView(View, LogoutMixin): response = HttpResponseRedirect(utils.update_url(url, params)) if request.GET.get("forget_provider"): response.delete_cookie("remember_provider") - return response + return self.delete_cookies(response) # if service is set, redirect to service after logout if self.service: 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 elif self.url: list(messages.get_messages(request)) # clean messages before leaving the django app - return HttpResponseRedirect(self.url) + return self.delete_cookies(HttpResponseRedirect(self.url)) else: # build logout message depending of the number of sessions the user logs out if session_nb == 1: @@ -224,19 +234,19 @@ class LogoutView(View, LogoutMixin): 'url': url, 'session_nb': session_nb } - return json_response(request, data) + return self.delete_cookies(json_response(request, data)) else: - return redirect("cas_server:login") + return self.delete_cookies(redirect("cas_server:login")) else: if self.ajax: data = {'status': 'success', 'detail': 'logout', 'session_nb': session_nb} - return json_response(request, data) + return self.delete_cookies(json_response(request, data)) else: - return render( + return self.delete_cookies(render( request, settings.CAS_LOGOUT_TEMPLATE, utils.context({'logout_msg': logout_msg}) - ) + )) class FederateAuth(CsrfExemptView): diff --git a/pytest.ini b/pytest.ini index 74acafe..809f960 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,4 +2,4 @@ testpaths = cas_server/tests/ DJANGO_SETTINGS_MODULE = cas_server.tests.settings norecursedirs = .* build dist docs -python_paths = . +pythonpath = . diff --git a/requirements-dev.txt b/requirements-dev.txt index b793b42..eb0f952 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,8 +4,7 @@ requests_futures>=0.9.5 lxml>=3.4 six>=1.8 tox>=1.8.1 -pytest>=2.6.4 +pytest>=7 pytest-django>=2.8.0 -pytest-pythonpath>=0.3 pytest-cov>=2.2.1 mock>=1 diff --git a/requirements.txt b/requirements.txt index ced9200..da78ada 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django >= 1.11,<3.3 +Django >= 1.11,<4.2 setuptools>=5.5 requests>=2.4 requests_futures>=0.9.5 diff --git a/setup.py b/setup.py index 6210936..53d2b14 100644 --- a/setup.py +++ b/setup.py @@ -40,14 +40,13 @@ if __name__ == '__main__': 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', @@ -62,7 +61,7 @@ if __name__ == '__main__': }, keywords=['django', 'cas', 'cas3', 'server', 'sso', 'single sign-on', 'authentication', 'auth'], 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' ], url="https://github.com/nitmir/django-cas-server", diff --git a/tox.ini b/tox.ini index 265b4ef..8838364 100644 --- a/tox.ini +++ b/tox.ini @@ -2,11 +2,12 @@ envlist= flake8, check_rst, - py27-django111, py3-django111, py3-django22, py3-django31, py3-django32, + py3-django40, + py3-django41, ################## # generic config # @@ -117,6 +118,18 @@ deps = Django>=3.2,<3.3 {[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 # ######################### @@ -167,9 +180,9 @@ deps = Django>=2.2,<3.0 {[base]deps} -############################################## -# Debian bullseye and Ubuntu hirsute support # -############################################## +######################################################### +# Debian bullseye and Ubuntu hirsute and impish support # +######################################################### [testenv:py39-django22] basepython=python3.9 @@ -177,6 +190,17 @@ deps = Django>=2.2,<3.0 {[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 # ####################################### @@ -193,3 +217,15 @@ basepython=python3.9 deps = Django>=3.2,<3.3 {[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}