Compare commits

...

17 commits

Author SHA1 Message Date
Tom Hubrecht fc36d0cf34 feat(authens): Release 0.2.0 2024-07-04 23:15:21 +02:00
thubrecht 9eacf8c19b Merge pull request 'Rename get_next_page to get_success_url' (#59) from update into master
Reviewed-on: #59
2024-07-04 23:14:29 +02:00
sinavir 2fdb73e485 Rename get_next_page to get_success_url and update pyproject
From django 4.1, this function has been renamed
(https://docs.djangoproject.com/en/4.2/releases/4.1/)
2024-07-04 23:12:50 +02:00
Tom Hubrecht 3d0b9e578d feat: Move code under src, add nix tooling and switch to pyproject.toml 2024-07-04 22:46:55 +02:00
Martin Pepin 58747e57b3 Merge branch 'dorian/improve-pwd-reset' into 'master'
Dorian/improve pwd reset

See merge request klub-dev-ens/authens!36
2022-12-01 16:31:20 +01:00
Dorian Lesbre 83d63845ae
Fix typo 2022-11-02 10:26:52 +01:00
Dorian Lesbre 018fd5249f
Clearer password reset error message 2022-11-02 10:26:26 +01:00
Tom Hubrecht ba1fa8c82c We need to use a string 2022-08-27 17:53:32 +02:00
Tom Hubrecht 0b0926ba76 Specify default auto field to avoid creating migrations by other apps using authens 2022-08-27 17:44:12 +02:00
Tom Hubrecht e1eb6cc577 Version 0.1b5 2021-10-10 19:19:56 +02:00
Tom Hubrecht a5682f0674 Merge branch 'kerl/bump-ci-versions' into 'master'
Bump python and Django versions in CI

See merge request klub-dev-ens/authens!35
2021-10-10 19:16:11 +02:00
Martin Pépin 6ea557e76a
Drop python3.5 support 2021-10-10 17:37:23 +02:00
Martin Pépin cec9edba12
Fix Django version in the django22 tox env 2021-10-08 00:03:24 +02:00
Tom Hubrecht 22b4d440c3 Merge branch 'kerl/issue20' into 'master'
Handle LOGOUT_URL=None in the logout view

Closes #20

See merge request klub-dev-ens/authens!34
2021-10-03 17:50:10 +02:00
Martin Pépin 7809a3c639
Apply Tomate's suggestion: not x → x is not None 2021-10-03 17:34:25 +02:00
Martin Pépin 7b7a51ec5f
Bump python and Django versions in CI 2021-10-02 17:27:50 +02:00
Martin Pépin acea5a6f4e
Handle LOGOUT_URL=None in the logout view
The view used to crash when `LOGOUT_URL` was not set and the user was
connect via CAS.

Cause: we assumed the result of `LogoutView.get_next_page()` to be a
  string and tried to prepend the domain name of the site to it.

Fix: redirect to the CAS' logout view without any `next_page` parameter.
2021-10-02 17:02:30 +02:00
45 changed files with 263 additions and 78 deletions

View file

@ -35,32 +35,37 @@ before_script:
- apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq python3-dev libldap2-dev libsasl2-dev
- pip install tox
python35:
image: python:3.5
stage: tests
script:
- tox -e py35-django22
python36:
image: python:3.6
stage: tests
script:
- tox -e py36-django22
- tox -e py36-django30
- tox -e py36-django31
- tox -e py36-django32
python37:
image: python:3.7
stage: tests
script:
- tox -e py37-django22
- tox -e py37-django30
- tox -e py37-django31
- tox -e py37-django32
python38:
image: python:3.8
stage: tests
script:
- tox -e py38-django22
- tox -e py38-django30
- tox -e py38-django31
- tox -e py38-django32
python39:
image: python:3.9
stage: tests
script:
- tox -e py39-django22
- tox -e py39-django31
- tox -e py39-django32
# ---
# Release artifacts

View file

@ -1,3 +0,0 @@
include LICENSE
recursive-include authens/static *
recursive-include authens/templates *

View file

@ -96,7 +96,7 @@ AUTHENS_ALLOW_STAFF = True
### Création d'utilisateurices
AuthENS maintient une tables des comptes clipper connus.
AuthENS maintient une table des comptes clipper connus.
Cette table est automatiquement mise à jour lors qu'une personne se connecte via
le CAS pour la première fois.
En revanche lorsqu'un nouveau compte est créé manuellement et que ce compte

53
default.nix Normal file
View file

@ -0,0 +1,53 @@
{
sources ? import ./npins,
pkgs ? import sources.nixpkgs { },
}:
let
nix-pkgs = import sources.nix-pkgs { inherit pkgs; };
python3 = pkgs.python3.override { packageOverrides = _: _: { inherit (nix-pkgs) python-cas; }; };
deploy-pypi = pkgs.writeShellApplication {
name = "deploy-pypi";
runtimeInputs = [
(pkgs.python3.withPackages (ps: [
ps.setuptools
ps.build
ps.twine
]))
];
text = ''
# Clean the repository
rm -rf dist
python -m build
twine upload dist/*
'';
};
in
{
devShell = pkgs.mkShell {
name = "cas-eleves.dev";
packages = [
(python3.withPackages (ps: [
ps.django
ps.python-ldap
ps.python-cas
]))
pkgs.gettext
pkgs.gtranslator
];
};
publishShell = pkgs.mkShell {
name = "loadcredential.publish";
packages = [ deploy-pypi ];
};
}

80
npins/default.nix Normal file
View file

@ -0,0 +1,80 @@
# Generated by npins. Do not modify; will be overwritten regularly
let
data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version;
mkSource =
spec:
assert spec ? type;
let
path =
if spec.type == "Git" then
mkGitSource spec
else if spec.type == "GitRelease" then
mkGitSource spec
else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in
spec // { outPath = path; };
mkGitSource =
{
repository,
revision,
url ? null,
hash,
branch ? null,
...
}:
assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball
if url != null then
(builtins.fetchTarball {
inherit url;
sha256 = hash;
})
else
assert repository.type == "Git";
let
urlToName =
url: rev:
let
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
short = builtins.substring 0 7 rev;
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
in
"${if matched == null then "source" else builtins.head matched}${appendShort}";
name = urlToName repository.url revision;
in
builtins.fetchGit {
url = repository.url;
rev = revision;
inherit name;
narHash = hash;
};
mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl {
inherit url;
sha256 = hash;
};
mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball {
inherit url;
sha256 = hash;
};
in
if version == 4 then
builtins.mapAttrs (_: mkSource) data.pins
else
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"

22
npins/sources.json Normal file
View file

@ -0,0 +1,22 @@
{
"pins": {
"nix-pkgs": {
"type": "Git",
"repository": {
"type": "Git",
"url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs.git"
},
"branch": "main",
"revision": "46879d052e4a694ceb3027dbcff641c44e0ae1bd",
"url": null,
"hash": "sha256-/Yn3NDYA76bv8x06jahLAJ2z54L0vFeAtQKzyW3MfGA="
},
"nixpkgs": {
"type": "Channel",
"name": "nixpkgs-unstable",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.11pre647329.6842b061970b/nixexprs.tar.xz",
"hash": "04inyzaffqclmymaphc4cwhywnyk51hi44508kfbsj9h57875hb6"
}
},
"version": 4
}

49
pyproject.toml Normal file
View file

@ -0,0 +1,49 @@
[build-system]
requires = ["setuptools", "setuptools_scm"]
build-backend = "setuptools.build_meta"
[project]
name = "authens"
dynamic = ["version"]
authors = [
{name = "Klub Dev ENS", email = "klub-dev@ens.fr"},
{name = "Tom Hubrecht", email = "pypi@mail.hubrecht.ovh"},
]
description = "CAS Authentication Client at the ENS."
license = {file = "LICENSE"}
readme = "README.md"
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 4.1",
"Framework :: Django :: 4.2",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"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",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
]
dependencies = [
"django >= 4.1",
"python-ldap >= 3, < 4",
"python-cas >= 1.5, < 2",
]
[project.urls]
Homepage = "https://git.dgnum.eu/DGNum/authens"
Repository = "https://git.dgnum.eu/DGNum/authens"
Issues = "https://git.dgnum.eu/DGNum/authens/issues"
[tool.setuptools.dynamic]
version = {attr = "authens.__VERSION__"}
[tool.setuptools.packages.find]
where = ["src"]

View file

@ -1,37 +0,0 @@
import setuptools
with open("README.md", "r") as file:
long_description = file.read()
setuptools.setup(
name="authens",
version="0.1b4",
author="Klub Dev ENS",
author_email="klub-dev@ens.fr",
description="CAS Authentication at the ENS",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://git.eleves.ens.fr/klub-dev-ens/authens",
packages=setuptools.find_packages(),
include_package_data=True,
classifiers=[
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 2.2",
"Framework :: Django :: 3.0",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
],
python_requires=">=3.5",
install_requires=["Django>=2.2", "python-ldap>=3,<4", "python-cas>=1.5,<2"],
)

1
shell.nix Normal file
View file

@ -0,0 +1 @@
(import ./. { }).devShell

5
src/authens/__init__.py Normal file
View file

@ -0,0 +1,5 @@
__VERSION__ = "0.2.0"
__all__ = [
"__VERSION__",
]

View file

@ -3,3 +3,4 @@ from django.apps import AppConfig
class AuthEnsConfig(AppConfig):
name = "authens"
default_auto_field = "django.db.models.AutoField"

Binary file not shown.

View file

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-28 20:40+0100\n"
"POT-Creation-Date: 2022-11-02 10:22+0100\n"
"PO-Revision-Date: 2021-01-30 20:48+0100\n"
"Last-Translator: Tom Hubrecht <tom.hubrecht@ens.fr>\n"
"Language-Team: \n"
@ -22,7 +22,7 @@ msgstr ""
msgid "Ancien login clipper"
msgstr "Old clipper username"
#: forms.py:18 templates/authens/login_switch.html:14
#: forms.py:18 templates/authens/login_switch.html:15
msgid "Mot de passe"
msgstr "Password"
@ -39,7 +39,7 @@ msgstr ""
"No user exists with this username, this entrance year and/or this password. "
"Please check your entry. Attention, all fields are case sensitive!"
#: models.py:19 models.py:57
#: models.py:19 models.py:60
msgid "utilisateurice"
msgstr "user"
@ -47,36 +47,36 @@ msgstr "user"
msgid "login CAS"
msgstr "CAS username"
#: models.py:30 models.py:67
#: models.py:30 models.py:70
msgid "année de création du compte CAS"
msgstr "year of CAS account creation"
#: models.py:34
#: models.py:37
msgid "Compte CAS"
msgstr "CAS account"
#: models.py:35
#: models.py:38
msgid "Comptes CAS"
msgstr "CAS accounts"
#: models.py:39
#: models.py:42
#, python-format
msgid "compte CAS %(cas_login)s (promo %(entrance_year)s) lié à %(user)s"
msgstr "CAS account %(cas_login)s (year %(entrance_year)s) linked to %(user)s"
#: models.py:63
#: models.py:66
msgid "ancien login CAS"
msgstr "old CAS username"
#: models.py:78
#: models.py:81
msgid "Ancien compte CAS"
msgstr "Old CAS account"
#: models.py:79
#: models.py:82
msgid "Anciens comptes CAS"
msgstr "Old CAS accounts"
#: models.py:83
#: models.py:86
#, python-format
msgid ""
"Ancien compte CAS %(cas_login)s (promo %(entrance_year)s) lié à %(user)s"
@ -91,11 +91,11 @@ msgstr "Connection method"
msgid "Clipper"
msgstr "Clipper"
#: templates/authens/login_switch.html:18
#: templates/authens/login_switch.html:20
msgid "Vieilleux"
msgstr "Alumni"
#: templates/authens/login_switch.html:25
#: templates/authens/login_switch.html:27
#, python-format
msgid ""
"Si votre fin de scolarité approche, créez un mot de passe pour votre compte "
@ -153,16 +153,25 @@ msgstr "For your information, your username is the following: %(username)s"
msgid "L'équipe %(site_name)s"
msgstr "The %(site_name)s team"
#: views.py:86
msgid "Connexion échouée !"
#: views.py:89
#, fuzzy
#| msgid "Connexion échouée !"
msgid "Connection échouée !"
msgstr "Connection failed!"
#: views.py:102
#: views.py:105
msgid ""
"Un email de réinitialisation du mot de passe vient d'être envoyé à l'adresse "
"indiquée !"
msgstr "A password reset email has just been sent to the indicated address!"
"Si un compte avec cet email existe, un email de réinitialisation vient de "
"lui être envoyé !"
msgstr ""
"A password reset email has just been send to the inidcated address, "
"provided an account with this email exists)"
#: views.py:112
#: views.py:115
msgid "Mot de passe modifié avec succès !"
msgstr "Password changed successfully!"
#~ msgid ""
#~ "Un email de réinitialisation du mot de passe vient d'être envoyé à "
#~ "l'adresse indiquée !"
#~ msgstr "A password reset email has just been sent to the indicated address!"

View file

@ -102,7 +102,7 @@ class PasswordResetView(SuccessMessageMixin, auth_views.PasswordResetView):
success_url = reverse_lazy("authens:login")
success_message = _(
"Un email de réinitialisation vient d'être envoyé à l'adresse indiquée !"
"Si un compte avec cet email existe, un email de réinitialisation vient de lui être envoyé !"
)
@ -138,14 +138,14 @@ class LogoutView(auth_views.LogoutView):
else:
self.cas_connected = False
def get_next_page(self):
next_page = super().get_next_page()
def get_success_url(self):
next_page = super().get_success_url()
if self.cas_connected:
cas_client = get_cas_client(self.request)
# If the next_url is local (no hostname), make it absolute so that the user
# is correctly redirected from CAS.
if not urlparse(next_page).netloc:
if next_page is not None and not urlparse(next_page).netloc:
request = self.request
next_page = urlunparse(
(request.scheme, request.get_host(), next_page, "", "", "")

View file

@ -1,12 +1,12 @@
[tox]
envlist =
py{35,36,37,38}-django22,
py{36,37,38}-django30
py{36,37,38,39}-django{22,31,32}
[testenv]
deps =
django22: Django==2.2.*
django30: Django==3.0.*
django22: Django>=2.2.17,<3
django31: Django==3.1.*
django32: Django==3.2.*
python-cas
python-ldap
commands =