Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-django-rest-knox for
openSUSE:Factory checked in at 2024-09-01 19:22:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-rest-knox (Old)
and /work/SRC/openSUSE:Factory/.python-django-rest-knox.new.2698 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-rest-knox"
Sun Sep 1 19:22:36 2024 rev:9 rq:1198089 version:5.0.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-django-rest-knox/python-django-rest-knox.changes
2024-03-21 17:01:39.911128509 +0100
+++
/work/SRC/openSUSE:Factory/.python-django-rest-knox.new.2698/python-django-rest-knox.changes
2024-09-01 19:23:04.148049632 +0200
@@ -1,0 +2,28 @@
+Sat Aug 31 14:50:57 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 5.0.1:
+ * Fix migration: retrieve `TOKEN_MODEL` from `knox_settings`
+ instead of Django settings.
+ * Tokens created prior to this release will no longer work
+ * Fix migration reverse flow, enable migrate 0
+ * Various documentation fixes and improvements
+ * Drop `cryptography` in favor of hashlib
+ * Make custom AuthModel work
+ * Token prefix can be set in the setttings
+ * Drop support for Django 4.0
+ * Add support for Dango 4.2, 5.0 and Python 3.11 and 3.12
+ * Cleanup legacy Python 2.0 code
+ * Fix isort, flake8 usage for Python 3.10 in the test suite
+ * Update Github actions version
+ * Upgrade markdown dependency
+ * Get rid of the `six` library
+ * Add custom login / logout response support
+ * Join the jazzband organization
+ * Add pre-commit hooks
+ * Add tracking of tests code coverage
+ * Fix migrations when used in condition with a custom DB
+ * Improve typing
+ * Use `self.authenticate_header()` in `authenticate()` method
+ to get auth header prefix
+
+-------------------------------------------------------------------
Old:
----
django-rest-knox-4.2.0.tar.gz
New:
----
django-rest-knox-5.0.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-django-rest-knox.spec ++++++
--- /var/tmp/diff_new_pack.OrEUQg/_old 2024-09-01 19:23:04.612068630 +0200
+++ /var/tmp/diff_new_pack.OrEUQg/_new 2024-09-01 19:23:04.616068794 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-django-rest-knox
#
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
%define skip_python2 1
%{?sle15_python_module_pythons}
Name: python-django-rest-knox
-Version: 4.2.0
+Version: 5.0.1
Release: 0
Summary: Authentication for Django REST framework
License: MIT
++++++ django-rest-knox-4.2.0.tar.gz -> django-rest-knox-5.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.codecov.yml
new/django-rest-knox-5.0.1/.codecov.yml
--- old/django-rest-knox-4.2.0/.codecov.yml 1970-01-01 01:00:00.000000000
+0100
+++ new/django-rest-knox-5.0.1/.codecov.yml 2024-07-19 18:36:00.000000000
+0200
@@ -0,0 +1,11 @@
+coverage:
+ status:
+ project:
+ default: false
+ tests:
+ paths: tests
+ informational: true
+ knox:
+ paths: knox
+ informational: true
+ patch: off
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.coveragerc
new/django-rest-knox-5.0.1/.coveragerc
--- old/django-rest-knox-4.2.0/.coveragerc 1970-01-01 01:00:00.000000000
+0100
+++ new/django-rest-knox-5.0.1/.coveragerc 2024-07-19 18:36:00.000000000
+0200
@@ -0,0 +1,5 @@
+[run]
+branch = True
+source = knox
+omit =
+ */migrations/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-rest-knox-4.2.0/.github/workflows/gh-pages.yml
new/django-rest-knox-5.0.1/.github/workflows/gh-pages.yml
--- old/django-rest-knox-4.2.0/.github/workflows/gh-pages.yml 1970-01-01
01:00:00.000000000 +0100
+++ new/django-rest-knox-5.0.1/.github/workflows/gh-pages.yml 2024-07-19
18:36:00.000000000 +0200
@@ -0,0 +1,34 @@
+name: Publish Docs to GitHub Pages
+
+permissions:
+ contents: write
+
+on:
+ push:
+ branches:
+ - develop
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.x
+
+ - name: Install dependencies
+ run: pip install mkdocs-material
+
+ - name: Build docs
+ run: mkdocs build
+
+ - name: Deploy to GitHub Pages
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ personal_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./site
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.github/workflows/test.yml
new/django-rest-knox-5.0.1/.github/workflows/test.yml
--- old/django-rest-knox-4.2.0/.github/workflows/test.yml 2022-01-31
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/.github/workflows/test.yml 2024-07-19
18:36:00.000000000 +0200
@@ -9,23 +9,23 @@
fail-fast: false
max-parallel: 5
matrix:
- python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
+ python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Get pip cache dir
id: pip-cache
run: |
- echo "::set-output name=dir::$(pip cache dir)"
+ echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
- name: Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
@@ -36,8 +36,14 @@
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- python -m pip install --upgrade tox tox-gh-actions
+ python -m pip install --upgrade tox tox-gh-actions coverage
- name: Tox tests
run: |
tox -v
+
+ - name: Generate coverage XML report
+ run: coverage xml
+
+ - name: Codecov
+ uses: codecov/codecov-action@v3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.gitignore
new/django-rest-knox-5.0.1/.gitignore
--- old/django-rest-knox-4.2.0/.gitignore 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/.gitignore 2024-07-19 18:36:00.000000000
+0200
@@ -57,3 +57,6 @@
target/
db.sqlite3
site/
+
+# PyCharm Project
+.idea
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.pre-commit-config.yaml
new/django-rest-knox-5.0.1/.pre-commit-config.yaml
--- old/django-rest-knox-4.2.0/.pre-commit-config.yaml 1970-01-01
01:00:00.000000000 +0100
+++ new/django-rest-knox-5.0.1/.pre-commit-config.yaml 2024-07-19
18:36:00.000000000 +0200
@@ -0,0 +1,9 @@
+repos:
+ - repo: https://github.com/PyCQA/isort
+ rev: 5.13.2
+ hooks:
+ - id: isort
+ - repo: https://github.com/PyCQA/flake8
+ rev: 7.1.0
+ hooks:
+ - id: flake8
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/CHANGELOG.md
new/django-rest-knox-5.0.1/CHANGELOG.md
--- old/django-rest-knox-4.2.0/CHANGELOG.md 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/CHANGELOG.md 2024-07-19 18:36:00.000000000
+0200
@@ -1,7 +1,32 @@
+## 5.0.1
+- Fix migration: retrieve `TOKEN_MODEL` from `knox_settings` instead of Django
settings.
+
+## 5.0.0
+- Tokens created prior to this release will no longer work
+- Fix migration reverse flow, enable migrate 0
+- Various documentation fixes and improvements
+- Drop `cryptography` in favor of hashlib
+- Make custom AuthModel work
+- Token prefix can be set in the setttings
+- Drop support for Django 4.0
+- Add support for Dango 4.2, 5.0 and Python 3.11 and 3.12
+- Cleanup legacy Python 2.0 code
+- Fix isort, flake8 usage for Python 3.10 in the test suite
+- Update Github actions version
+- Upgrade markdown dependency
+- Get rid of the `six` library
+- Add custom login / logout response support
+- Join the jazzband organization
+- Add pre-commit hooks
+- Add tracking of tests code coverage
+- Fix migrations when used in condition with a custom DB
+- Improve typing
+- Use `self.authenticate_header()` in `authenticate()` method to get auth
header prefix
+
## 4.2.0
-- compatibility with Python up to 3.10 and Django up to 3.2
+- compatibility with Python up to 3.10 and Django up to 4.0
- integration with github CI instead of travis
-- Migration: "salt" field of model "AuthToken" is removed
+- Migration: "salt" field of model "AuthToken" is removed, WARNING:
invalidates old tokens!
## 4.1.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/CONTRIBUTING.md
new/django-rest-knox-5.0.1/CONTRIBUTING.md
--- old/django-rest-knox-4.2.0/CONTRIBUTING.md 1970-01-01 01:00:00.000000000
+0100
+++ new/django-rest-knox-5.0.1/CONTRIBUTING.md 2024-07-19 18:36:00.000000000
+0200
@@ -0,0 +1,3 @@
+[](https://jazzband.co/)
+
+This is a [Jazzband](https://jazzband.co/) project. By contributing you agree
to abide by the [Contributor Code of
Conduct](https://jazzband.co/about/conduct) and follow the
[guidelines](https://jazzband.co/about/guidelines).
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/README.md
new/django-rest-knox-5.0.1/README.md
--- old/django-rest-knox-4.2.0/README.md 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/README.md 2024-07-19 18:36:00.000000000
+0200
@@ -1,17 +1,18 @@
django-rest-knox
================
-[](https://github.com/James1345/django-rest-knox/actions)
+[](https://jazzband.co/)
+[](https://github.com/jazzband/django-rest-knox/actions)
-Authentication Module for django rest auth
+Authentication module for Django rest auth.
-Knox provides easy to use authentication for [Django REST
+Knox provides easy-to-use authentication for [Django REST
Framework](https://www.django-rest-framework.org/) The aim is to allow
-for common patterns in applications that are REST based, with little
+for common patterns in applications that are REST-based, with little
extra effort; and to ensure that connections remain secure.
-Knox authentication is token based, similar to the `TokenAuthentication`
-built in to DRF. However, it overcomes some problems present in the
+Knox authentication is token-based, similar to the `TokenAuthentication`
+built into DRF. However, it overcomes some problems present in the
default implementation:
- DRF tokens are limited to one per user. This does not facilitate
@@ -23,13 +24,14 @@
client to have its own token which is deleted on the server side
when the client logs out.
- Knox also provides an option for a logged in client to remove *all*
+ Knox also provides an option for a logged-in client to remove *all*
tokens that the server has - forcing all clients to re-authenticate.
- DRF tokens are stored unencrypted in the database. This would allow
- an attacker unrestricted access to an account with a token if the
+ an attacker unrestricted access to an account with a token if the
database were compromised.
+
Knox tokens are only stored in a secure hash form (like a password). Even
if the
database were somehow stolen, an attacker would not be able to log
in with the stolen credentials.
@@ -39,12 +41,11 @@
the app settings (default is 10 hours.)
More information can be found in the
-[Documentation](https://james1345.github.io/django-rest-knox/)
+[Documentation](https://jazzband.github.io/django-rest-knox/)
# Run the tests locally
-If you need to debug a test locally and if you have
[docker](https://www.docker.com/) installed:
-
+If you need to debug a test locally and if you have
[docker](https://www.docker.com/) installed,
simply run the ``./docker-run-tests.sh`` script and it will run the test suite
in every Python /
Django versions.
@@ -55,7 +56,7 @@
Our documentation is generated by [Mkdocs](https://www.mkdocs.org).
-You can refer to their documentation on how to install it locally.
+You can refer to their
[documentation](https://www.mkdocs.org/user-guide/installation/) on how to
install it locally.
Another option is to use `mkdocs.sh` in this repository.
It will run mkdocs in a [docker](https://www.docker.com/) container.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/auth.md
new/django-rest-knox-5.0.1/docs/auth.md
--- old/django-rest-knox-4.2.0/docs/auth.md 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/docs/auth.md 2024-07-19 18:36:00.000000000
+0200
@@ -49,18 +49,17 @@
For instance, you can authenticate users using Basic Authentication by simply
overwriting knox's LoginView and setting BasicAuthentication as one of the
acceptable authentication classes, as follows:
+**views.py:**
```python
-
-views.py:
-
from knox.views import LoginView as KnoxLoginView
from rest_framework.authentication import BasicAuthentication
class LoginView(KnoxLoginView):
authentication_classes = [BasicAuthentication]
+```
-urls.py:
-
+**urls.py:**
+```python
from knox import views as knox_views
from yourapp.api.views import LoginView
@@ -75,10 +74,8 @@
If you decide to use Token Authentication as your only authentication class,
you can overwrite knox's login view as such:
+**views.py:**
```python
-
-views.py:
-
from django.contrib.auth import login
from rest_framework import permissions
@@ -94,9 +91,10 @@
user = serializer.validated_data['user']
login(request, user)
return super(LoginView, self).post(request, format=None)
+```
-urls.py:
-
+**urls.py:**
+```python
from knox import views as knox_views
from yourapp.api.views import LoginView
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/index.md
new/django-rest-knox-5.0.1/docs/index.md
--- old/django-rest-knox-4.2.0/docs/index.md 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/docs/index.md 2024-07-19 18:36:00.000000000
+0200
@@ -1,10 +1,10 @@
# Django-Rest-Knox
-Knox provides easy to use authentication for [Django REST
Framework](https://www.django-rest-framework.org/)
+Knox provides easy-to-use authentication for [Django REST
Framework](https://www.django-rest-framework.org/)
The aim is to allow for common patterns in applications that are REST based,
with little extra effort; and to ensure that connections remain secure.
Knox authentication is token based, similar to the `TokenAuthentication` built
-in to DRF. However, it overcomes some problems present in the default
implementation:
+into DRF. However, it overcomes some problems present in the default
implementation:
- DRF tokens are limited to one per user. This does not facilitate securely
signing in from multiple devices, as the token is shared. It also requires
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/installation.md
new/django-rest-knox-5.0.1/docs/installation.md
--- old/django-rest-knox-4.2.0/docs/installation.md 2022-01-31
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/docs/installation.md 2024-07-19
18:36:00.000000000 +0200
@@ -2,27 +2,8 @@
## Requirements
-Knox depends on `cryptography` to provide bindings to `OpenSSL` for token
generation
-This requires the OpenSSL build libraries to be available.
-
-### Windows
-Cryptography is a statically linked build, no extra steps are needed.
-
-### Linux
-`cryptography` should build very easily on Linux provided you have a C
compiler,
-headers for Python (if youâre not using `pypy`), and headers for the OpenSSL
and
-`libffi` libraries available on your system.
-
-Debian and Ubuntu:
-```bash
-sudo apt-get install build-essential libssl-dev libffi-dev python3-dev
python-dev
-```
-
-Fedora and RHEL-derivatives:
-```bash
-sudo yum install gcc libffi-devel python-devel openssl-devel
-```
-For other systems or problems, see the [cryptography installation
docs](https://cryptography.io/en/latest/installation/)
+Knox depends on pythons internal library `hashlib` to provide bindings to
`OpenSSL` or uses
+an internal implementation of hashing algorithms for token generation.
## Installing Knox
Knox should be installed with pip
@@ -59,7 +40,7 @@
- If you set TokenAuthentication as the only default authentication class on
the second step, [override knox's LoginView](auth.md#global-usage-on-all-views)
to accept another authentication method and use it instead of knox's default
login view.
-- Apply the migrations for the models
+- Apply the migrations for the models.
```bash
python manage.py migrate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/settings.md
new/django-rest-knox-5.0.1/docs/settings.md
--- old/django-rest-knox-4.2.0/docs/settings.md 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/docs/settings.md 2024-07-19 18:36:00.000000000
+0200
@@ -10,18 +10,27 @@
# These are the default values if none are set
from datetime import timedelta
from rest_framework.settings import api_settings
+
+KNOX_TOKEN_MODEL = 'knox.AuthToken'
+
REST_KNOX = {
- 'SECURE_HASH_ALGORITHM': 'cryptography.hazmat.primitives.hashes.SHA512',
+ 'SECURE_HASH_ALGORITHM': 'hashlib.sha512',
'AUTH_TOKEN_CHARACTER_LENGTH': 64,
'TOKEN_TTL': timedelta(hours=10),
'USER_SERIALIZER': 'knox.serializers.UserSerializer',
'TOKEN_LIMIT_PER_USER': None,
'AUTO_REFRESH': False,
+ 'MIN_REFRESH_INTERVAL': 60,
+ 'AUTH_HEADER_PREFIX': 'Token',
'EXPIRY_DATETIME_FORMAT': api_settings.DATETIME_FORMAT,
+ 'TOKEN_MODEL': 'knox.AuthToken',
}
#...snip...
```
+## KNOX_TOKEN_MODEL
+This is the variable used in the swappable dependency of the `AuthToken` model
+
## SECURE_HASH_ALGORITHM
This is a reference to the class used to provide the hashing algorithm for
token storage.
@@ -30,14 +39,13 @@
By default, Knox uses SHA-512 to hash tokens in the database.
-`cryptography.hazmat.primitives.hashes.Whirlpool` is an acceptable alternative
setting
-for production use.
+`hashlib.sha3_512` is an acceptable alternative setting for production use.
### Tests
-SHA-512 and Whirlpool are secure, however, they are slow. This should not be a
+SHA-512 and SHA3-512 are secure, however, they are slow. This should not be a
problem for your users, but when testing it may be noticeable (as test cases
tend
to use many more requests much more quickly than real users). In testing
scenarios
-it is acceptable to use `MD5`
hashing.(`cryptography.hazmat.primitives.hashes.MD5`)
+it is acceptable to use `MD5` hashing (`hashlib.md5`).
MD5 is **not secure** and must *never* be used in production sites.
@@ -58,7 +66,8 @@
the system will not prevent you setting this.
## TOKEN_LIMIT_PER_USER
-This allows you to control how many tokens can be issued per user.
+This allows you to control how many valid tokens can be issued per user.
+If the limit for valid tokens is reached, an error is returned at login.
By default this option is disabled and set to `None` -- thus no limit.
## USER_SERIALIZER
@@ -81,9 +90,18 @@
[DATETIME_FORMAT][DATETIME_FORMAT] of Django REST framework. May be any of
`None`, `iso-8601`
or a Python [strftime format][strftime format] string.
+## TOKEN_MODEL
+This is the reference to the model used as `AuthToken`. We can define a custom
`AuthToken`
+model in our project that extends `knox.AbstractAuthToken` and add our
business logic to it.
+The default is `knox.AuthToken`
+
[DATETIME_FORMAT]:
https://www.django-rest-framework.org/api-guide/settings/#date-and-time-formatting
[strftime format]: https://docs.python.org/3/library/time.html#time.strftime
+## TOKEN_PREFIX
+This is the prefix for the generated token that is used in the Authorization
header. The default is just an empty string.
+It can be up to `CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH` long.
+
# Constants `knox.settings`
Knox also provides some constants for information. These must not be changed in
external code; they are used in the model definitions in knox and an error will
@@ -97,3 +115,6 @@
## DIGEST_LENGTH
This is the length of the digest that will be stored in the database for each
token.
+
+## MAXIMUM_TOKEN_PREFIX_LENGTH
+This is the maximum length of the token prefix.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/views.md
new/django-rest-knox-5.0.1/docs/views.md
--- old/django-rest-knox-4.2.0/docs/views.md 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/docs/views.md 2024-07-19 18:36:00.000000000
+0200
@@ -21,6 +21,7 @@
- `get_user_serializer_class(self)`, to change the class used for serializing
the user
- `get_expiry_datetime_format(self)`, to change the datetime format used for
expiry
- `format_expiry_datetime(self, expiry)`, to format the expiry `datetime`
object at your convenience
+- `create_token(self)`, to create the `AuthToken` instance at your convenience
Finally, if none of these helper methods are sufficient, you can also override
`get_post_response_data`
to return a fully customized payload.
@@ -66,12 +67,24 @@
the token used to authenticate is deleted from the
system and can no longer be used to authenticate.
+By default, this endpoint returns a HTTP 204 response on a successful request.
To
+customize this behavior, you can override the `get_post_response` method, for
example
+to include a body in the logout response and/or to modify the status code:
+
+```python
+...snip...
+ def get_post_response(self, request):
+ return Response({"bye-bye": request.user.username}, status=200)
+...snip...
+```
+
## LogoutAllView
This view accepts only a post request with an empty body. It responds to Knox
Token
Authentication.
-On a successful request, the token used to authenticate, and *all other tokens*
-registered to the same `User` account, are deleted from the
-system and can no longer be used to authenticate.
+On a successful request, a HTTP 204 is returned and the token used to
authenticate,
+and *all other tokens* registered to the same `User` account, are deleted from
the
+system and can no longer be used to authenticate. The success response can be
modified
+like the `LogoutView` by overriding the `get_post_response` method.
**Note** It is not recommended to alter the Logout views. They are designed
specifically for token management, and to respond to Knox authentication.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/auth.py
new/django-rest-knox-5.0.1/knox/auth.py
--- old/django-rest-knox-4.2.0/knox/auth.py 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/knox/auth.py 2024-07-19 18:36:00.000000000
+0200
@@ -1,10 +1,5 @@
-try:
- from hmac import compare_digest
-except ImportError:
- def compare_digest(a, b):
- return a == b
-
import binascii
+from hmac import compare_digest
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
@@ -14,7 +9,7 @@
)
from knox.crypto import hash_token
-from knox.models import AuthToken
+from knox.models import get_token_model
from knox.settings import CONSTANTS, knox_settings
from knox.signals import token_expired
@@ -31,11 +26,10 @@
- `request.user` will be a django `User` instance
- `request.auth` will be an `AuthToken` instance
'''
- model = AuthToken
def authenticate(self, request):
auth = get_authorization_header(request).split()
- prefix = knox_settings.AUTH_HEADER_PREFIX.encode()
+ prefix = self.authenticate_header(request).encode()
if not auth:
return None
@@ -62,7 +56,7 @@
'''
msg = _('Invalid token.')
token = token.decode("utf-8")
- for auth_token in AuthToken.objects.filter(
+ for auth_token in get_token_model().objects.filter(
token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]):
if self._cleanup_token(auth_token):
continue
@@ -77,7 +71,7 @@
return self.validate_user(auth_token)
raise exceptions.AuthenticationFailed(msg)
- def renew_token(self, auth_token):
+ def renew_token(self, auth_token) -> None:
current_expiry = auth_token.expiry
new_expiry = timezone.now() + knox_settings.TOKEN_TTL
auth_token.expiry = new_expiry
@@ -95,7 +89,7 @@
def authenticate_header(self, request):
return knox_settings.AUTH_HEADER_PREFIX
- def _cleanup_token(self, auth_token):
+ def _cleanup_token(self, auth_token) -> bool:
for other_token in auth_token.user.auth_token_set.all():
if other_token.digest != auth_token.digest and other_token.expiry:
if other_token.expiry < timezone.now():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/crypto.py
new/django-rest-knox-5.0.1/knox/crypto.py
--- old/django-rest-knox-4.2.0/knox/crypto.py 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/knox/crypto.py 2024-07-19 18:36:00.000000000
+0200
@@ -1,28 +1,31 @@
import binascii
from os import urandom as generate_bytes
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-
from knox.settings import knox_settings
-sha = knox_settings.SECURE_HASH_ALGORITHM
+hash_func = knox_settings.SECURE_HASH_ALGORITHM
-def create_token_string():
+def create_token_string() -> str:
return binascii.hexlify(
generate_bytes(int(knox_settings.AUTH_TOKEN_CHARACTER_LENGTH / 2))
).decode()
-def hash_token(token):
- '''
- Calculates the hash of a token.
- input is unhexlified
+def make_hex_compatible(token: str) -> bytes:
+ """
+ We need to make sure that the token, that is send is hex-compatible.
+ When a token prefix is used, we cannot guarantee that.
+ """
+ return binascii.unhexlify(binascii.hexlify(bytes(token, 'utf-8')))
- token must contain an even number of hex digits or a binascii.Error
- exception will be raised
- '''
- digest = hashes.Hash(sha(), backend=default_backend())
- digest.update(binascii.unhexlify(token))
- return binascii.hexlify(digest.finalize()).decode()
+
+def hash_token(token: str) -> str:
+ """
+ Calculates the hash of a token.
+ Token must contain an even number of hex digits or
+ a binascii.Error exception will be raised.
+ """
+ digest = hash_func()
+ digest.update(make_hex_compatible(token))
+ return digest.hexdigest()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-rest-knox-4.2.0/knox/migrations/0001_initial.py
new/django-rest-knox-5.0.1/knox/migrations/0001_initial.py
--- old/django-rest-knox-4.2.0/knox/migrations/0001_initial.py 2022-01-31
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox/migrations/0001_initial.py 2024-07-19
18:36:00.000000000 +0200
@@ -4,11 +4,14 @@
from django.conf import settings
from django.db import migrations, models
+from knox.settings import knox_settings
+
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ migrations.swappable_dependency(knox_settings.TOKEN_MODEL),
]
operations = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-rest-knox-4.2.0/knox/migrations/0006_auto_20160818_0932.py
new/django-rest-knox-5.0.1/knox/migrations/0006_auto_20160818_0932.py
--- old/django-rest-knox-4.2.0/knox/migrations/0006_auto_20160818_0932.py
2022-01-31 16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox/migrations/0006_auto_20160818_0932.py
2024-07-19 18:36:00.000000000 +0200
@@ -7,7 +7,7 @@
def cleanup_tokens(apps, schema_editor):
AuthToken = apps.get_model('knox', 'AuthToken')
- AuthToken.objects.filter(token_key__isnull=True).delete()
+
AuthToken.objects.using(schema_editor.connection.alias).filter(token_key__isnull=True).delete()
class Migration(migrations.Migration):
@@ -17,7 +17,7 @@
]
operations = [
- migrations.RunPython(cleanup_tokens),
+ migrations.RunPython(cleanup_tokens,
reverse_code=migrations.RunPython.noop),
migrations.AlterField(
model_name='authtoken',
name='token_key',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-rest-knox-4.2.0/knox/migrations/0009_extend_authtoken_field.py
new/django-rest-knox-5.0.1/knox/migrations/0009_extend_authtoken_field.py
--- old/django-rest-knox-4.2.0/knox/migrations/0009_extend_authtoken_field.py
1970-01-01 01:00:00.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox/migrations/0009_extend_authtoken_field.py
2024-07-19 18:36:00.000000000 +0200
@@ -0,0 +1,18 @@
+# Generated by Django 4.1rc1 on 2022-07-20 17:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("knox", "0008_remove_authtoken_salt"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="authtoken",
+ name="token_key",
+ field=models.CharField(db_index=True, max_length=25),
+ ),
+ ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/models.py
new/django-rest-knox-5.0.1/knox/models.py
--- old/django-rest-knox-4.2.0/knox/models.py 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/knox/models.py 2024-07-19 18:36:00.000000000
+0200
@@ -1,39 +1,76 @@
+from django.apps import apps
from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.utils import timezone
from knox import crypto
from knox.settings import CONSTANTS, knox_settings
+sha = knox_settings.SECURE_HASH_ALGORITHM
+
User = settings.AUTH_USER_MODEL
class AuthTokenManager(models.Manager):
- def create(self, user, expiry=knox_settings.TOKEN_TTL):
- token = crypto.create_token_string()
+ def create(
+ self,
+ user,
+ expiry=knox_settings.TOKEN_TTL,
+ prefix=knox_settings.TOKEN_PREFIX,
+ **kwargs
+ ):
+ token = prefix + crypto.create_token_string()
digest = crypto.hash_token(token)
-
if expiry is not None:
expiry = timezone.now() + expiry
-
instance = super(AuthTokenManager, self).create(
token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH], digest=digest,
- user=user, expiry=expiry)
+ user=user, expiry=expiry, **kwargs)
return instance, token
-class AuthToken(models.Model):
+class AbstractAuthToken(models.Model):
objects = AuthTokenManager()
digest = models.CharField(
max_length=CONSTANTS.DIGEST_LENGTH, primary_key=True)
token_key = models.CharField(
- max_length=CONSTANTS.TOKEN_KEY_LENGTH, db_index=True)
+ max_length=CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH +
+ CONSTANTS.TOKEN_KEY_LENGTH,
+ db_index=True
+ )
user = models.ForeignKey(User, null=False, blank=False,
related_name='auth_token_set',
on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
expiry = models.DateTimeField(null=True, blank=True)
- def __str__(self):
- return '%s : %s' % (self.digest, self.user)
+ class Meta:
+ abstract = True
+
+ def __str__(self) -> str:
+ return f'{self.digest} : {self.user}'
+
+
+class AuthToken(AbstractAuthToken):
+ class Meta:
+ swappable = 'KNOX_TOKEN_MODEL'
+
+
+def get_token_model():
+ """
+ Return the AuthToken model that is active in this project.
+ """
+
+ try:
+ return apps.get_model(knox_settings.TOKEN_MODEL, require_ready=False)
+ except ValueError:
+ raise ImproperlyConfigured(
+ "TOKEN_MODEL must be of the form 'app_label.model_name'"
+ )
+ except LookupError:
+ raise ImproperlyConfigured(
+ "TOKEN_MODEL refers to model '%s' that has not been installed"
+ % knox_settings.TOKEN_MODEL
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/settings.py
new/django-rest-knox-5.0.1/knox/settings.py
--- old/django-rest-knox-4.2.0/knox/settings.py 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/knox/settings.py 2024-07-19 18:36:00.000000000
+0200
@@ -1,13 +1,13 @@
from datetime import timedelta
from django.conf import settings
-from django.test.signals import setting_changed
+from django.core.signals import setting_changed
from rest_framework.settings import APISettings, api_settings
USER_SETTINGS = getattr(settings, 'REST_KNOX', None)
DEFAULTS = {
- 'SECURE_HASH_ALGORITHM': 'cryptography.hazmat.primitives.hashes.SHA512',
+ 'SECURE_HASH_ALGORITHM': 'hashlib.sha512',
'AUTH_TOKEN_CHARACTER_LENGTH': 64,
'TOKEN_TTL': timedelta(hours=10),
'USER_SERIALIZER': None,
@@ -16,6 +16,8 @@
'MIN_REFRESH_INTERVAL': 60,
'AUTH_HEADER_PREFIX': 'Token',
'EXPIRY_DATETIME_FORMAT': api_settings.DATETIME_FORMAT,
+ 'TOKEN_MODEL': getattr(settings, 'KNOX_TOKEN_MODEL', 'knox.AuthToken'),
+ 'TOKEN_PREFIX': '',
}
IMPORT_STRINGS = {
@@ -31,6 +33,8 @@
setting, value = kwargs['setting'], kwargs['value']
if setting == 'REST_KNOX':
knox_settings = APISettings(value, DEFAULTS, IMPORT_STRINGS)
+ if len(knox_settings.TOKEN_PREFIX) >
CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH:
+ raise ValueError("Illegal TOKEN_PREFIX length")
setting_changed.connect(reload_api_settings)
@@ -40,8 +44,9 @@
'''
Constants cannot be changed at runtime
'''
- TOKEN_KEY_LENGTH = 8
+ TOKEN_KEY_LENGTH = 15
DIGEST_LENGTH = 128
+ MAXIMUM_TOKEN_PREFIX_LENGTH = 10
def __setattr__(self, *args, **kwargs):
raise Exception('''
@@ -50,4 +55,4 @@
''')
-CONSTANTS = CONSTANTS()
+CONSTANTS = CONSTANTS() # type: ignore
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/views.py
new/django-rest-knox-5.0.1/knox/views.py
--- old/django-rest-knox-4.2.0/knox/views.py 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/knox/views.py 2024-07-19 18:36:00.000000000
+0200
@@ -8,7 +8,7 @@
from rest_framework.views import APIView
from knox.auth import TokenAuthentication
-from knox.models import AuthToken
+from knox.models import get_token_model
from knox.settings import knox_settings
@@ -22,6 +22,9 @@
def get_token_ttl(self):
return knox_settings.TOKEN_TTL
+ def get_token_prefix(self):
+ return knox_settings.TOKEN_PREFIX
+
def get_token_limit_per_user(self):
return knox_settings.TOKEN_LIMIT_PER_USER
@@ -35,6 +38,12 @@
datetime_format = self.get_expiry_datetime_format()
return DateTimeField(format=datetime_format).to_representation(expiry)
+ def create_token(self):
+ token_prefix = self.get_token_prefix()
+ return get_token_model().objects.create(
+ user=self.request.user, expiry=self.get_token_ttl(),
prefix=token_prefix
+ )
+
def get_post_response_data(self, request, token, instance):
UserSerializer = self.get_user_serializer_class()
@@ -49,6 +58,10 @@
).data
return data
+ def get_post_response(self, request, token, instance):
+ data = self.get_post_response_data(request, token, instance)
+ return Response(data)
+
def post(self, request, format=None):
token_limit_per_user = self.get_token_limit_per_user()
if token_limit_per_user is not None:
@@ -59,23 +72,24 @@
{"error": "Maximum amount of tokens allowed per user
exceeded."},
status=status.HTTP_403_FORBIDDEN
)
- token_ttl = self.get_token_ttl()
- instance, token = AuthToken.objects.create(request.user, token_ttl)
+ instance, token = self.create_token()
user_logged_in.send(sender=request.user.__class__,
request=request, user=request.user)
- data = self.get_post_response_data(request, token, instance)
- return Response(data)
+ return self.get_post_response(request, token, instance)
class LogoutView(APIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
+ def get_post_response(self, request):
+ return Response(None, status=status.HTTP_204_NO_CONTENT)
+
def post(self, request, format=None):
request._auth.delete()
user_logged_out.send(sender=request.user.__class__,
request=request, user=request.user)
- return Response(None, status=status.HTTP_204_NO_CONTENT)
+ return self.get_post_response(request)
class LogoutAllView(APIView):
@@ -86,8 +100,11 @@
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
+ def get_post_response(self, request):
+ return Response(None, status=status.HTTP_204_NO_CONTENT)
+
def post(self, request, format=None):
request.user.auth_token_set.all().delete()
user_logged_out.send(sender=request.user.__class__,
request=request, user=request.user)
- return Response(None, status=status.HTTP_204_NO_CONTENT)
+ return self.get_post_response(request)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox_project/settings.py
new/django-rest-knox-5.0.1/knox_project/settings.py
--- old/django-rest-knox-4.2.0/knox_project/settings.py 2022-01-31
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox_project/settings.py 2024-07-19
18:36:00.000000000 +0200
@@ -49,7 +49,9 @@
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
-USE_L10N = True
+USE_L10N = True # Deprecated since django 4.0.
USE_TZ = True
STATIC_URL = '/static/'
+
+KNOX_TOKEN_MODEL = 'knox.AuthToken'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/mkdocs.sh
new/django-rest-knox-5.0.1/mkdocs.sh
--- old/django-rest-knox-4.2.0/mkdocs.sh 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/mkdocs.sh 2024-07-19 18:36:00.000000000
+0200
@@ -9,4 +9,4 @@
-w $MOUNT_FOLDER \
-p $MKDOCS_DEV_PORT:$MKDOCS_DEV_PORT \
-e MKDOCS_DEV_ADDR="$MKDOCS_DEV_ADDR:$MKDOCS_DEV_PORT" \
- squidfunk/mkdocs-material:3.2.0 $*
+ squidfunk/mkdocs-material:latest $*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/mkdocs.yml
new/django-rest-knox-5.0.1/mkdocs.yml
--- old/django-rest-knox-4.2.0/mkdocs.yml 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/mkdocs.yml 2024-07-19 18:36:00.000000000
+0200
@@ -1,5 +1,5 @@
site_name: Django-Rest-Knox
-repo_url: https://github.com/James1345/django-rest-knox
+repo_url: https://github.com/jazzband/django-rest-knox
theme: readthedocs
nav:
- Home: 'index.md'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/setup.py
new/django-rest-knox-5.0.1/setup.py
--- old/django-rest-knox-4.2.0/setup.py 2022-01-31 16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/setup.py 2024-07-19 18:36:00.000000000 +0200
@@ -17,13 +17,13 @@
# Versions should comply with PEP440. For a discussion on single-sourcing
# the version across setup.py and the project code, see
# https://packaging.python.org/en/latest/single_source_version.html
- version='4.2.0',
+ version='5.0.1',
description='Authentication for django rest framework',
long_description=long_description,
long_description_content_type='text/markdown',
# The project's main homepage.
- url='https://github.com/James1345/django-rest-knox',
+ url='https://github.com/jazzband/django-rest-knox',
# Author details
author='James McMahon',
@@ -51,6 +51,8 @@
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
+ 'Programming Language :: Python :: 3.11',
+ 'Programming Language :: Python :: 3.12',
],
# What does your project relate to?
@@ -69,7 +71,6 @@
install_requires=[
'django>=3.2',
'djangorestframework',
- 'cryptography',
],
# List additional groups of dependencies here (e.g. development
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/tests/tests.py
new/django-rest-knox-5.0.1/tests/tests.py
--- old/django-rest-knox-4.2.0/tests/tests.py 2022-01-31 16:24:27.000000000
+0100
+++ new/django-rest-knox-5.0.1/tests/tests.py 2024-07-19 18:36:00.000000000
+0200
@@ -1,5 +1,6 @@
import base64
from datetime import datetime, timedelta
+from importlib import reload
from django.contrib.auth import get_user_model
from django.test import override_settings
@@ -8,9 +9,8 @@
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.serializers import DateTimeField
from rest_framework.test import APIRequestFactory, APITestCase as TestCase
-from six.moves import reload_module
-from knox import auth, views
+from knox import auth, crypto, views
from knox.auth import TokenAuthentication
from knox.models import AuthToken
from knox.serializers import UserSerializer
@@ -23,7 +23,7 @@
def get_basic_auth_header(username, password):
return 'Basic %s' % base64.b64encode(
- ('%s:%s' % (username, password)).encode('ascii')).decode()
+ (f'{username}:{password}').encode('ascii')).decode()
auto_refresh_knox = knox_settings.defaults.copy()
@@ -45,6 +45,14 @@
expiry_datetime_format_knox = knox_settings.defaults.copy()
expiry_datetime_format_knox["EXPIRY_DATETIME_FORMAT"] = EXPIRY_DATETIME_FORMAT
+token_prefix = "TEST_"
+token_prefix_knox = knox_settings.defaults.copy()
+token_prefix_knox["TOKEN_PREFIX"] = token_prefix
+
+token_prefix_too_long = "a" * CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH + "a"
+token_prefix_too_long_knox = knox_settings.defaults.copy()
+token_prefix_too_long_knox["TOKEN_PREFIX"] = token_prefix_too_long
+
class AuthTestCase(TestCase):
@@ -86,7 +94,7 @@
def test_login_returns_serialized_token_and_username_field(self):
with override_settings(REST_KNOX=user_serializer_knox):
- reload_module(views)
+ reload(views)
self.assertEqual(AuthToken.objects.count(), 0)
url = reverse('knox_login')
self.client.credentials(
@@ -94,7 +102,7 @@
)
response = self.client.post(url, {}, format='json')
self.assertEqual(user_serializer_knox["USER_SERIALIZER"],
UserSerializer)
- reload_module(views)
+ (views)
self.assertEqual(response.status_code, 200)
self.assertIn('token', response.data)
username_field = self.user.USERNAME_FIELD
@@ -104,7 +112,7 @@
def test_login_returns_configured_expiry_datetime_format(self):
with override_settings(REST_KNOX=expiry_datetime_format_knox):
- reload_module(views)
+ reload(views)
self.assertEqual(AuthToken.objects.count(), 0)
url = reverse('knox_login')
self.client.credentials(
@@ -115,7 +123,7 @@
expiry_datetime_format_knox["EXPIRY_DATETIME_FORMAT"],
EXPIRY_DATETIME_FORMAT
)
- reload_module(views)
+ reload(views)
self.assertEqual(response.status_code, 200)
self.assertIn('token', response.data)
self.assertNotIn('user', response.data)
@@ -190,7 +198,7 @@
instance, token = AuthToken.objects.create(self.user)
rf = APIRequestFactory()
request = rf.get('/')
- request.META = {'HTTP_AUTHORIZATION': 'Token {}'.format(token)}
+ request.META = {'HTTP_AUTHORIZATION': f'Token {token}'}
(self.user, auth_token) = TokenAuthentication().authenticate(request)
self.assertEqual(
token[:CONSTANTS.TOKEN_KEY_LENGTH],
@@ -250,10 +258,10 @@
self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
five_hours_later = original_time + timedelta(hours=5)
with override_settings(REST_KNOX=auto_refresh_knox):
- reload_module(auth) # necessary to reload settings in core code
+ reload(auth) # necessary to reload settings in core code
with freeze_time(five_hours_later):
response = self.client.get(root_url, {}, format='json')
- reload_module(auth)
+ reload(auth)
self.assertEqual(response.status_code, 200)
# original expiry date was extended:
@@ -302,10 +310,10 @@
self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
in_min_interval = now +
timedelta(seconds=knox_settings.MIN_REFRESH_INTERVAL - 10)
with override_settings(REST_KNOX=auto_refresh_knox):
- reload_module(auth) # necessary to reload settings in core code
+ reload(auth) # necessary to reload settings in core code
with freeze_time(in_min_interval):
response = self.client.get(root_url, {}, format='json')
- reload_module(auth) # necessary to reload settings in core code
+ reload(auth) # necessary to reload settings in core code
self.assertEqual(response.status_code, 200)
self.assertEqual(original_expiry, AuthToken.objects.get().expiry)
@@ -318,7 +326,10 @@
token_expired.connect(handler)
- instance, token = AuthToken.objects.create(user=self.user,
expiry=timedelta(seconds=-1))
+ instance, token = AuthToken.objects.create(
+ user=self.user,
+ expiry=timedelta(seconds=-1),
+ )
self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
self.client.post(root_url, {}, format='json')
@@ -327,7 +338,7 @@
def test_exceed_token_amount_per_user(self):
with override_settings(REST_KNOX=token_user_limit_knox):
- reload_module(views)
+ reload(views)
for _ in range(10):
AuthToken.objects.create(user=self.user)
url = reverse('knox_login')
@@ -335,7 +346,7 @@
HTTP_AUTHORIZATION=get_basic_auth_header(self.username,
self.password)
)
response = self.client.post(url, {}, format='json')
- reload_module(views)
+ reload(views)
self.assertEqual(response.status_code, 403)
self.assertEqual(response.data,
{"error": "Maximum amount of tokens allowed per user
exceeded."})
@@ -343,7 +354,7 @@
def test_does_not_exceed_on_expired_keys(self):
with override_settings(REST_KNOX=token_user_limit_knox):
- reload_module(views)
+ reload(views)
for _ in range(9):
AuthToken.objects.create(user=self.user)
AuthToken.objects.create(user=self.user,
expiry=timedelta(seconds=-1))
@@ -354,7 +365,7 @@
)
response = self.client.post(url, {}, format='json')
failed_response = self.client.post(url, {}, format='json')
- reload_module(views)
+ reload(views)
self.assertEqual(response.status_code, 200)
self.assertIn('token', response.data)
self.assertEqual(failed_response.status_code, 403)
@@ -364,7 +375,7 @@
def test_invalid_prefix_return_401(self):
with override_settings(REST_KNOX=auth_header_prefix_knox):
- reload_module(auth)
+ reload(auth)
instance, token = AuthToken.objects.create(user=self.user)
self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
failed_response = self.client.get(root_url)
@@ -374,13 +385,13 @@
)
)
response = self.client.get(root_url)
- reload_module(auth)
+ reload(auth)
self.assertEqual(failed_response.status_code, 401)
self.assertEqual(response.status_code, 200)
def test_expiry_present_also_when_none(self):
with override_settings(REST_KNOX=token_no_expiration_knox):
- reload_module(views)
+ reload(views)
self.assertEqual(AuthToken.objects.count(), 0)
url = reverse('knox_login')
self.client.credentials(
@@ -399,7 +410,7 @@
response.data['expiry'],
None
)
- reload_module(views)
+ reload(views)
def test_expiry_is_present(self):
self.assertEqual(AuthToken.objects.count(), 0)
@@ -419,3 +430,69 @@
response.data['expiry'],
DateTimeField().to_representation(AuthToken.objects.first().expiry)
)
+
+ def test_login_returns_serialized_token_with_prefix_when_prefix_set(self):
+ with override_settings(REST_KNOX=token_prefix_knox):
+ reload(views)
+ reload(crypto)
+ self.assertEqual(AuthToken.objects.count(), 0)
+ url = reverse('knox_login')
+ self.client.credentials(
+ HTTP_AUTHORIZATION=get_basic_auth_header(self.username,
self.password)
+ )
+ response = self.client.post(
+ url,
+ {},
+ format='json'
+ )
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(response.data['token'].startswith(token_prefix))
+ reload(views)
+ reload(crypto)
+
+ def test_token_with_prefix_returns_200(self):
+ with override_settings(REST_KNOX=token_prefix_knox):
+ reload(views)
+ self.assertEqual(AuthToken.objects.count(), 0)
+ url = reverse('knox_login')
+ self.client.credentials(
+ HTTP_AUTHORIZATION=get_basic_auth_header(self.username,
self.password)
+ )
+ response = self.client.post(
+ url,
+ {},
+ format='json'
+ )
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(response.data['token'].startswith(token_prefix))
+ self.client.credentials(
+ HTTP_AUTHORIZATION=('Token %s' % response.data['token'])
+ )
+ response = self.client.get(root_url, {}, format='json')
+ self.assertEqual(response.status_code, 200)
+ reload(views)
+
+ def test_prefix_set_longer_than_max_length_raises_valueerror(self):
+ with self.assertRaises(ValueError):
+ with override_settings(REST_KNOX=token_prefix_too_long_knox):
+ pass
+
+ def test_tokens_created_before_prefix_still_work(self):
+ self.client.credentials(
+ HTTP_AUTHORIZATION=get_basic_auth_header(self.username,
self.password)
+ )
+ url = reverse('knox_login')
+ response = self.client.post(
+ url,
+ {},
+ format='json'
+ )
+ self.assertFalse(response.data['token'].startswith(token_prefix))
+ with override_settings(REST_KNOX=token_prefix_knox):
+ reload(views)
+ self.client.credentials(
+ HTTP_AUTHORIZATION=('Token %s' % response.data['token'])
+ )
+ response = self.client.get(root_url, {}, format='json')
+ self.assertEqual(response.status_code, 200)
+ reload(views)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-rest-knox-4.2.0/tox.ini
new/django-rest-knox-5.0.1/tox.ini
--- old/django-rest-knox-4.2.0/tox.ini 2022-01-31 16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/tox.ini 2024-07-19 18:36:00.000000000 +0200
@@ -1,49 +1,37 @@
[tox]
envlist =
- isort,
- flake8,
py{36,37,38,39,310}-django32,
- py{38,39,310}-django40,
-
-[testenv:flake8]
-deps = flake8
-changedir = {toxinidir}
-commands = flake8 knox
-
-[testenv:isort]
-deps = isort
-changedir = {toxinidir}
-commands = isort --check-only --diff \
- knox \
- knox_project/views.py \
- setup.py \
- tests
+ py{38,39,310,311,312}-django42,
+ py{310,311,312}-django50,
[testenv]
commands =
python manage.py migrate
- python manage.py test
+ coverage run manage.py test
+ coverage report
setenv =
DJANGO_SETTINGS_MODULE = knox_project.settings
PIP_INDEX_URL = https://pypi.python.org/simple/
deps =
django32: Django>=3.2,<3.3
- django40: Django>=4.0,<4.1
- markdown<3.0
- isort>=5.0
+ django42: Django>=4.2,<4.3
+ django50: Django>=5.0,<5.1
+ markdown>=3.0
djangorestframework
freezegun
mkdocs
- cryptography
pytest-django
setuptools
twine
wheel
+ coverage
[gh-actions]
python =
3.6: py36
3.7: py37
3.8: py38
- 3.9: py39, isort, flake8
+ 3.9: py39
3.10: py310
+ 3.11: py311
+ 3.12: py312