From 71b416fab1acf2f1089ccbd1f534b1526f014938 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 29 May 2015 00:38:20 +0200 Subject: [PATCH] Update project - Make authentic2_pratic.User and authentic2_pratic.Collectivity derive from custom_user.User and a2_rbac.OrganizationalUnit - Merge with RBAC changes from authentic2, refactor forms and views to use those from authentic2.manager - Remove OAuth2 mentions - Implement restriction of authentication to X509 for some services --- README | 13 +- src/authentic2_pratic/forms.py | 38 +- .../locale/fr/LC_MESSAGES/django.po | 465 ++++++++++-------- .../management/commands/load-pratic-ldif.py | 2 +- .../migrations/0001_initial.py | 15 +- .../0002_serviceinstance_certificate.py | 20 + src/authentic2_pratic/models.py | 45 +- src/authentic2_pratic/tables.py | 3 - .../authentic2_pratic/collectivities.html | 4 + .../authentic2_pratic/collectivity_edit.html | 15 +- .../collectivity_sidebar.html | 8 - .../templates/authentic2_pratic/form.html | 70 +-- .../authentic2_pratic/service_instances.html | 7 + .../authentic2_pratic/user_edit.html | 33 ++ .../templates/authentic2_pratic/users.html | 13 +- src/authentic2_pratic/urls.py | 4 + src/authentic2_pratic/utils.py | 8 +- src/authentic2_pratic/views.py | 76 ++- 18 files changed, 479 insertions(+), 360 deletions(-) create mode 100644 src/authentic2_pratic/migrations/0002_serviceinstance_certificate.py create mode 100644 src/authentic2_pratic/templates/authentic2_pratic/user_edit.html diff --git a/README b/README index 0402833..96f9c03 100644 --- a/README +++ b/README @@ -32,22 +32,19 @@ authentic2_pratic.models.Service -------------------------------- Il décrit un service proposé par le CDG59. Ce service peut -éventuellement utiliser l'authentification d'authentic soit via le protocole -SAML 2.0 soit via le protocole OAuth 2.0. +éventuellement utiliser l'authentification d'authentic via le protocole +SAML 2.0. Les champs `name`, `slug` et `service_url` sont obgligatoires. Le champs `service_url` indique l'URL de base pour accéder au service, c'est l'URL qui sera affichée aux utilisateurs. Dans le cas SAML 2.0 le champ `metadata_url` contiendra l'URL des métadonnées -du service. Dans le cas OAuth 2.0 les champs oauth2_url et oauth2_key -contiendront respecitive l'URL de retour et la clé secrète pour les échanges -OAuth 2.0. +du service. Le champ booléen `is_global` indique si un service est global, dans ce cas les -champs `service_url`, 'metadata_url`, `oauth2_url` et `oauth2_key` des -instances de ce service seront ignorés et ceux de la définition du service -seront utilisés. +champs `service_url` et 'metadata_url` des instances de ce service seront +ignorés et ceux de la définition du service seront utilisés. authentic2_pratic.models.ServiceInstance ---------------------------------------- diff --git a/src/authentic2_pratic/forms.py b/src/authentic2_pratic/forms.py index ac1e1b9..7246d32 100644 --- a/src/authentic2_pratic/forms.py +++ b/src/authentic2_pratic/forms.py @@ -1,4 +1,5 @@ import re +import uuid import tempfile import subprocess @@ -7,6 +8,8 @@ from django.utils.translation import ugettext_lazy as _, ugettext from django.contrib.auth import authenticate +from authentic2.manager.forms import UserEditForm, UserAddForm + from . import models, fields class BaseForm(forms.ModelForm): @@ -23,7 +26,8 @@ class CertificateMixin(forms.ModelForm): 'the issuer and subject DNs by uploading the certificate'), required=False) def clean(self): - cleaned_data = super(CertificateMixin, self).clean() + super(CertificateMixin, self).clean() + cleaned_data = self.cleaned_data certificate = cleaned_data.get('certificate') if certificate is not None: with tempfile.NamedTemporaryFile() as certificate_file: @@ -43,7 +47,7 @@ class CertificateMixin(forms.ModelForm): class CollectivityForm(CertificateMixin, BaseForm): class Meta: model = models.Collectivity - fields = '__all__' + exclude = ('uuid',) class ServiceInstanceForm(BaseForm): class Meta: @@ -61,7 +65,35 @@ class AccessForm(BaseForm): model = models.Access fields = '__all__' -class UserForm(CertificateMixin, BaseForm): + +class UserMixin(object): + def clean(self): + cleaned_data = self.cleaned_data + cleaned_data['username'] = str(uuid.uuid1()) + return super(UserMixin, self).clean() + + +class UserEditForm(UserMixin, CertificateMixin, UserEditForm): + class Meta: + model = models.User + fields = ( + 'uid', + 'first_name', + 'last_name', + 'email', + 'is_admin', + 'direction', + 'employee_type', + 'postal_address', + 'fax', + 'mobile', + 'phone', + 'certificate_issuer_dn', + 'certificate_subject_dn', + 'certificate', + ) + +class UserAddForm(UserMixin, CertificateMixin, UserAddForm): class Meta: model = models.User fields = ( diff --git a/src/authentic2_pratic/locale/fr/LC_MESSAGES/django.po b/src/authentic2_pratic/locale/fr/LC_MESSAGES/django.po index 6b88866..2545ffe 100644 --- a/src/authentic2_pratic/locale/fr/LC_MESSAGES/django.po +++ b/src/authentic2_pratic/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: authentic2-pratic 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-11-24 11:26+0100\n" +"POT-Creation-Date: 2015-05-29 10:31+0200\n" "PO-Revision-Date: 2014-11-24 11:28+0100\n" "Last-Translator: Benjamin Dauvergne \n" "Language-Team: France \n" @@ -17,33 +17,33 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: auth_frontends.py:20 dashboard.py:8 +#: authentic2_pratic/auth_frontends.py:17 authentic2_pratic/dashboard.py:8 msgid "Pr@tic" msgstr "" -#: forms.py:21 +#: authentic2_pratic/forms.py:25 msgid "X509 Certificate" msgstr "Certificat X509 au format PEM" -#: forms.py:21 +#: authentic2_pratic/forms.py:25 msgid "You can set the issuer and subject DNs by uploading the certificate" msgstr "" "Vous pouvez aussi définir les noms distingués du certificat en le " "téléchargeant." -#: forms.py:85 +#: authentic2_pratic/forms.py:121 msgid "Collectivity" msgstr "Collectivité" -#: forms.py:86 +#: authentic2_pratic/forms.py:122 msgid "Username" msgstr "Identifiant" -#: forms.py:87 +#: authentic2_pratic/forms.py:123 msgid "Password" msgstr "Mot de passe" -#: forms.py:90 +#: authentic2_pratic/forms.py:126 msgid "" "Please enter a correct username and password. Note that both fields may be " "case-sensitive." @@ -52,188 +52,192 @@ msgstr "" "chacun de ces champs est sensible à la casse (différenciation des majuscules/" "minuscules)." -#: forms.py:92 +#: authentic2_pratic/forms.py:128 msgid "This account is inactive." msgstr "Ce compte est inactif" -#: forms.py:130 +#: authentic2_pratic/forms.py:166 msgid "username" msgstr "identifiant" -#: models.py:22 models.py:109 tables.py:37 tables.py:50 +#: authentic2_pratic/models.py:29 authentic2_pratic/tables.py:47 msgid "identifier" msgstr "identifiant" -#: models.py:26 models.py:245 models.py:316 +#: authentic2_pratic/models.py:34 authentic2_pratic/models.py:248 +#: authentic2_pratic/models.py:312 msgid "collectivity" msgstr "collectivité" -#: models.py:29 +#: authentic2_pratic/models.py:38 msgid "is admin" msgstr "Administrateur?" -#: models.py:34 models.py:123 models.py:128 +#: authentic2_pratic/models.py:43 authentic2_pratic/models.py:126 +#: authentic2_pratic/models.py:131 msgid "SIRH Code" msgstr "" -#: models.py:39 +#: authentic2_pratic/models.py:48 msgid "direction" msgstr "" -#: models.py:44 +#: authentic2_pratic/models.py:53 msgid "last connection duration" msgstr "durée de la dernière connexion" -#: models.py:50 +#: authentic2_pratic/models.py:59 msgid "employee type" msgstr "type de poste" -#: models.py:55 models.py:146 +#: authentic2_pratic/models.py:64 authentic2_pratic/models.py:149 msgid "postal address" msgstr "Adresse postale" -#: models.py:59 models.py:206 +#: authentic2_pratic/models.py:68 authentic2_pratic/models.py:209 msgid "fax" msgstr "" -#: models.py:64 +#: authentic2_pratic/models.py:73 msgid "mobile" msgstr "" -#: models.py:69 models.py:201 +#: authentic2_pratic/models.py:78 authentic2_pratic/models.py:204 msgid "phone" msgstr "téléphone" -#: models.py:73 models.py:220 +#: authentic2_pratic/models.py:82 authentic2_pratic/models.py:223 msgid "certificate issuer DN" msgstr "nom distingué de l'émetteur du certificat" -#: models.py:78 models.py:225 +#: authentic2_pratic/models.py:87 authentic2_pratic/models.py:228 msgid "certificate subject DN" msgstr "nom distingué du sujet du certificat" -#: models.py:87 +#: authentic2_pratic/models.py:96 msgid "agent" msgstr "" -#: models.py:88 +#: authentic2_pratic/models.py:97 msgid "agents" msgstr "" -#: models.py:105 models.py:256 tables.py:11 tables.py:24 -msgid "collectivity name" -msgstr "nom" +#: authentic2_pratic/models.py:105 +msgid "This username is already used" +msgstr "" -#: models.py:113 +#: authentic2_pratic/models.py:116 msgid "is superuser" msgstr "Tous les utilisateurs sont des super-administrateurs?" -#: models.py:118 +#: authentic2_pratic/models.py:121 msgid "collectivity id" msgstr "identifiant de la collectivité" -#: models.py:133 +#: authentic2_pratic/models.py:136 msgid "INSEE Code" msgstr "code INSEE" -#: models.py:138 +#: authentic2_pratic/models.py:141 msgid "SIRET Code" msgstr "code SIRET" -#: models.py:150 +#: authentic2_pratic/models.py:153 msgid "street number" msgstr "numéro dans la rue" -#: models.py:155 +#: authentic2_pratic/models.py:158 msgid "street" msgstr "rue" -#: models.py:160 +#: authentic2_pratic/models.py:163 msgid "postal code" msgstr "code postal" -#: models.py:165 +#: authentic2_pratic/models.py:168 msgid "complementary address" msgstr "adresse complémentaire" -#: models.py:170 +#: authentic2_pratic/models.py:173 msgid "address mention" msgstr "adresse (mention complémentaire)" -#: models.py:175 +#: authentic2_pratic/models.py:178 msgid "arrondissement code" msgstr "code d'arrondissement" -#: models.py:180 +#: authentic2_pratic/models.py:183 msgid "canton code" msgstr "numéro de canton" -#: models.py:185 +#: authentic2_pratic/models.py:188 msgid "departement code" msgstr "numéro de département" -#: models.py:190 models.py:195 +#: authentic2_pratic/models.py:193 authentic2_pratic/models.py:198 msgid "distribution office" msgstr "centre de distribution du courrier" -#: models.py:211 +#: authentic2_pratic/models.py:214 msgid "email" msgstr "courriel" -#: models.py:216 models.py:269 models.py:318 +#: authentic2_pratic/models.py:219 authentic2_pratic/models.py:272 +#: authentic2_pratic/models.py:314 msgid "URL" msgstr "" -#: models.py:246 +#: authentic2_pratic/models.py:249 msgid "collectivities" msgstr "collectivités" -#: models.py:265 +#: authentic2_pratic/models.py:259 authentic2_pratic/tables.py:11 +#: authentic2_pratic/tables.py:24 +msgid "name" +msgstr "nom" + +#: authentic2_pratic/models.py:268 msgid "is global" msgstr "service global?" -#: models.py:271 models.py:321 +#: authentic2_pratic/models.py:274 authentic2_pratic/models.py:317 msgid "SAML Metadata URL" msgstr "URL des métadonnées SAML" -#: models.py:274 models.py:324 -msgid "OAuth2 URL" -msgstr "URL du point d'accès OAuth2" - -#: models.py:277 models.py:327 -msgid "OAuth2 Key" -msgstr "Clé OAuth2" - -#: models.py:290 models.py:313 +#: authentic2_pratic/models.py:286 authentic2_pratic/models.py:309 msgid "service" msgstr "" -#: models.py:291 +#: authentic2_pratic/models.py:287 msgid "services" msgstr "" -#: models.py:345 +#: authentic2_pratic/models.py:320 +msgid "Authentication by certificate only" +msgstr "Authentificiation seulement par certificat" + +#: authentic2_pratic/models.py:338 msgid "There can be only one instance of a global service by collectivity" msgstr "" "Il ne peut y avoir qu'une seule instance d'un service global par collectivité" -#: models.py:352 +#: authentic2_pratic/models.py:343 msgid "Service URL field is required" msgstr "L'URL de service est requise pour un service non global" -#: models.py:355 models.py:376 +#: authentic2_pratic/models.py:346 authentic2_pratic/models.py:367 msgid "service instance" msgstr "instance de service" -#: models.py:356 +#: authentic2_pratic/models.py:347 msgid "service instances" msgstr "instances de service" -#: models.py:374 +#: authentic2_pratic/models.py:365 msgid "user" msgstr "agent" -#: models.py:383 +#: authentic2_pratic/models.py:374 msgid "" "Access can only be created between users and service instances of the same " "collectivity" @@ -241,233 +245,169 @@ msgstr "" "Les accréditations ne peuvent être créé qu'entre une instance de service et " "un utilisateur de la même collectivité" -#: models.py:390 +#: authentic2_pratic/models.py:381 msgid "access" msgstr "accréditation" -#: models.py:391 +#: authentic2_pratic/models.py:382 msgid "accesses" msgstr "accréditations" -#: models.py:423 +#: authentic2_pratic/models.py:414 +msgid "This service requires certificate authentication." +msgstr "" + +#: authentic2_pratic/models.py:423 msgid "" "You are not authorized to access this service. Please contact your " "administrator" msgstr "" -"Vous n'êtes pas autorisé à accéder à ce service. Veuillez prendre " -"contact avec votre administrateur." +"Vous n'êtes pas autorisé à accéder à ce service. Veuillez prendre contact " +"avec votre administrateur." -#: pratic_attribute_source.py:28 -msgid "User domain" -msgstr "Domaine de l'utilisateur" - -#: pratic_attribute_source.py:29 -msgid "User identifier" -msgstr "Identifiant utilisateur" - -#: tables.py:62 +#: authentic2_pratic/tables.py:59 msgid "Last name" msgstr "Nom" -#: tables.py:64 +#: authentic2_pratic/tables.py:61 msgid "First name" msgstr "Prénom" -#: views.py:37 -msgid "You are not a super-administrator or a collectivity administrator" -msgstr "" -"Vous n'êtes pas un super-administrateur ou un administrateur de collectivité." - -#: views.py:48 -msgid "You are not a super-administrator" -msgstr "Vous n'êtes pas un super-administrateur." - -#: views.py:65 templates/authentic2_pratic/services.html:10 -msgid "Add service" -msgstr "Ajouter un service" - -#: views.py:67 views.py:93 views.py:152 views.py:186 views.py:225 -msgid "Add" -msgstr "Ajouter" - -#: views.py:72 -msgid "Edit service" -msgstr "Éditer un service" - -#: views.py:79 -msgid "Delete service" -msgstr "Supprimer un service" - -#: views.py:91 templates/authentic2_pratic/collectivities.html:10 -msgid "Add collectivity" -msgstr "Ajouter une collectivité" - -#: views.py:98 -msgid "Edit collectivity" -msgstr "Éditer une collectivité" - -#: views.py:106 -msgid "Delete collectivity" -msgstr "Supprimer une collectivité" - -#: views.py:121 -#, python-format -msgid "You are not a super-administrator or an administrator of %s" -msgstr "Vous n'êtes pas un super-administrateur ou un administrateur de %s" - -#: views.py:150 templates/authentic2_pratic/users.html:10 -msgid "Add agent" -msgstr "Ajouter un agent" - -#: views.py:157 -msgid "Edit agent" -msgstr "Éditer un agent" - -#: views.py:162 -msgid "Reset password" -msgstr "Ré-initialiser le mot de passe" - -#: views.py:164 -msgid "Deactivate" -msgstr "Désactiver" - -#: views.py:166 -msgid "Activate" -msgstr "Activer" - -#: views.py:172 -msgid "Delete agent" -msgstr "Supprimer un agent" - -#: views.py:184 views.py:223 -msgid "Add service instance" -msgstr "Ajouter une instance de service" - -#: views.py:192 views.py:231 -msgid "Edit service instance" -msgstr "Éditer une instance de service" - -#: views.py:200 views.py:239 -msgid "Delete service instance" -msgstr "Supprimer une instance de service" - -#: templates/authentic2_pratic/accesses.html:4 -#: templates/authentic2_pratic/accesses.html:6 -#: templates/authentic2_pratic/collectivity_edit.html:14 -#: templates/authentic2_pratic/homepage.html:29 +#: authentic2_pratic/templates/authentic2_pratic/accesses.html:4 +#: authentic2_pratic/templates/authentic2_pratic/accesses.html:6 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:10 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:29 msgid "Accesses management" -msgstr "Gestion des accréditations" +msgstr "Accréditations" -#: templates/authentic2_pratic/accesses.html:10 +#: authentic2_pratic/templates/authentic2_pratic/accesses.html:10 msgid "Add access" msgstr "Ajouter une accréditation" -#: templates/authentic2_pratic/accesses.html:14 +#: authentic2_pratic/templates/authentic2_pratic/accesses.html:14 #, python-format msgid "%(count)s accesses" msgid_plural "%(count)s access" msgstr[0] "%(count)s accréditation" msgstr[1] "%(count)s accréditations" -#: templates/authentic2_pratic/base.html:4 -#: templates/authentic2_pratic/base.html:26 +#: authentic2_pratic/templates/authentic2_pratic/base.html:4 +#: authentic2_pratic/templates/authentic2_pratic/base.html:26 msgid "Management" msgstr "Gestion" -#: templates/authentic2_pratic/collectivities.html:4 -#: templates/authentic2_pratic/collectivities.html:6 -#: templates/authentic2_pratic/collectivity_edit.html:8 +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:4 +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:6 +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:9 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:15 +#: authentic2_pratic/templates/authentic2_pratic/service_instances.html:10 +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:10 +#: authentic2_pratic/templates/authentic2_pratic/users.html:10 msgid "Collectivities management" -msgstr "Gestion des collectivités" +msgstr "Collectivités" -#: templates/authentic2_pratic/collectivities.html:15 -#: templates/authentic2_pratic/collectivities.html:18 +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:14 +#: authentic2_pratic/views.py:95 +msgid "Add collectivity" +msgstr "Ajouter une collectivité" + +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:19 +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:22 msgid "Search" msgstr "Recherche" -#: templates/authentic2_pratic/collectivities.html:21 +#: authentic2_pratic/templates/authentic2_pratic/collectivities.html:25 #, python-format msgid "%(count)s collectivities" msgid_plural "%(count)s collectivity" msgstr[0] "%(count)s collectivité" msgstr[1] "%(count)s collectivités" -#: templates/authentic2_pratic/collectivity_edit.html:12 -#: templates/authentic2_pratic/homepage.html:27 -#: templates/authentic2_pratic/users.html:4 -#: templates/authentic2_pratic/users.html:6 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:8 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:27 +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:12 +#: authentic2_pratic/templates/authentic2_pratic/users.html:4 +#: authentic2_pratic/templates/authentic2_pratic/users.html:6 +#: authentic2_pratic/templates/authentic2_pratic/users.html:12 msgid "Agents management" -msgstr "Gestion des agents" +msgstr "Agents" -#: templates/authentic2_pratic/collectivity_edit.html:13 -#: templates/authentic2_pratic/homepage.html:28 -#: templates/authentic2_pratic/service_instances.html:4 -#: templates/authentic2_pratic/service_instances.html:6 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:9 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:28 +#: authentic2_pratic/templates/authentic2_pratic/service_instances.html:4 +#: authentic2_pratic/templates/authentic2_pratic/service_instances.html:6 +#: authentic2_pratic/templates/authentic2_pratic/service_instances.html:12 msgid "Service instances management" -msgstr "Gestion des instances de service" +msgstr "Instances de service" -#: templates/authentic2_pratic/collectivity_edit.html:24 -#: templates/authentic2_pratic/form.html:31 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:22 msgid "Actions" msgstr "" -#: templates/authentic2_pratic/collectivity_edit.html:48 -#: templates/authentic2_pratic/form.html:26 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:48 +#: authentic2_pratic/templates/authentic2_pratic/form.html:6 +msgid "Certificate" +msgstr "Certificat" + +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:67 msgid "Save" msgstr "Sauvegarder" -#: templates/authentic2_pratic/collectivity_edit.html:49 -#: templates/authentic2_pratic/delete.html:28 -#: templates/authentic2_pratic/form.html:27 -#: templates/authentic2_pratic/login.html:50 +#: authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html:68 +#: authentic2_pratic/templates/authentic2_pratic/delete.html:28 +#: authentic2_pratic/templates/authentic2_pratic/login.html:50 msgid "Cancel" msgstr "Annuler" -#: templates/authentic2_pratic/delete.html:23 +#: authentic2_pratic/templates/authentic2_pratic/delete.html:23 #, python-format msgid "Do you really want to delete « %(object)s » ?" msgstr "Êtez-vous sûr de vouloir supprimer « %(object)s » ?" -#: templates/authentic2_pratic/delete.html:27 +#: authentic2_pratic/templates/authentic2_pratic/delete.html:27 msgid "Delete" msgstr "Supprimer" -#: templates/authentic2_pratic/homepage.html:8 +#: authentic2_pratic/templates/authentic2_pratic/form.html:9 +msgid "Passwords" +msgstr "Mot de passe" + +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:8 msgid "Welcome" msgstr "Bievenue" -#: templates/authentic2_pratic/homepage.html:15 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:15 msgid "Password change" msgstr "Changer de mot de passe" -#: templates/authentic2_pratic/homepage.html:21 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:21 msgid "Collectivities" msgstr "Collectivités" -#: templates/authentic2_pratic/homepage.html:22 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:22 msgid "Services" msgstr "" -#: templates/authentic2_pratic/homepage.html:25 +#: authentic2_pratic/templates/authentic2_pratic/homepage.html:25 #, python-format msgid "Management of %(collectivity)s" -msgstr "Gestion de %(collectivity)s" +msgstr "%(collectivity)s" -#: templates/authentic2_pratic/login.html:20 +#: authentic2_pratic/templates/authentic2_pratic/login.html:20 msgid "You are authenticated with certificate of users :" msgstr "Vous êtez authentifié avec le certificat des utilisateurs :" -#: templates/authentic2_pratic/login.html:26 +#: authentic2_pratic/templates/authentic2_pratic/login.html:26 #, python-format msgid "%(user)s from %(collectivity)s" msgstr "%(user)s de %(collectivity)s" -#: templates/authentic2_pratic/login.html:29 -#: templates/authentic2_pratic/login.html:49 +#: authentic2_pratic/templates/authentic2_pratic/login.html:29 +#: authentic2_pratic/templates/authentic2_pratic/login.html:49 msgid "Log in" msgstr "Connexion" -#: templates/authentic2_pratic/login.html:40 +#: authentic2_pratic/templates/authentic2_pratic/login.html:40 #, python-format msgid "" "You are\n" @@ -478,32 +418,139 @@ msgstr "" "Vous êtez authentifié avec le certificat de la collectivité " "%(collectivity)s. Cette collectivité a été pré-selectionné pour vous." -#: templates/authentic2_pratic/service_instances.html:10 +#: authentic2_pratic/templates/authentic2_pratic/service_instances.html:17 msgid "Add service-instance" msgstr "Ajouter une instance de service" -#: templates/authentic2_pratic/service_instances.html:14 +#: authentic2_pratic/templates/authentic2_pratic/service_instances.html:21 #, python-format msgid "%(count)s services instances" msgid_plural "%(count)s service instance" msgstr[0] "%(count)s instance de service" msgstr[1] "%(count)s instances de service" -#: templates/authentic2_pratic/services.html:4 -#: templates/authentic2_pratic/services.html:6 +#: authentic2_pratic/templates/authentic2_pratic/services.html:4 +#: authentic2_pratic/templates/authentic2_pratic/services.html:6 msgid "Services management" -msgstr "Gestion des services" +msgstr "Services" -#: templates/authentic2_pratic/services.html:14 +#: authentic2_pratic/templates/authentic2_pratic/services.html:10 +#: authentic2_pratic/views.py:68 +msgid "Add service" +msgstr "Ajouter un service" + +#: authentic2_pratic/templates/authentic2_pratic/services.html:14 #, python-format msgid "%(count)s services" msgid_plural "%(count)s service" msgstr[0] "%(count)s service" msgstr[1] "%(count)s services" -#: templates/authentic2_pratic/users.html:14 +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:4 +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:6 +msgid "Edit user" +msgstr "Éditer un utilisateur" + +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:22 +msgid "UUID" +msgstr "Identifiant unique" + +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:29 +msgid "User must change its password on next access to authentic" +msgstr "L'utilisateur devra change de mot de passe à sa prochain connexion." + +#: authentic2_pratic/templates/authentic2_pratic/user_edit.html:30 +msgid "Cancel this constraint" +msgstr "Supprimer cette contrainte" + +#: authentic2_pratic/templates/authentic2_pratic/users.html:17 +#: authentic2_pratic/views.py:155 +msgid "Add agent" +msgstr "Ajouter un agent" + +#: authentic2_pratic/templates/authentic2_pratic/users.html:21 #, python-format msgid "%(count)s agent" msgid_plural "%(count)s agents" msgstr[0] "%(count)s agent" msgstr[1] "%(count)s agents" + +#: authentic2_pratic/views.py:40 +msgid "You are not a super-administrator or a collectivity administrator" +msgstr "" +"Vous n'êtes pas un super-administrateur ou un administrateur de collectivité." + +#: authentic2_pratic/views.py:51 +msgid "You are not a super-administrator" +msgstr "Vous n'êtes pas un super-administrateur." + +#: authentic2_pratic/views.py:70 authentic2_pratic/views.py:97 +#: authentic2_pratic/views.py:156 authentic2_pratic/views.py:232 +#: authentic2_pratic/views.py:273 +msgid "Add" +msgstr "Ajouter" + +#: authentic2_pratic/views.py:76 +msgid "Edit service" +msgstr "Éditer un service" + +#: authentic2_pratic/views.py:83 +msgid "Delete service" +msgstr "Supprimer un service" + +#: authentic2_pratic/views.py:104 +msgid "Edit collectivity" +msgstr "Éditer une collectivité" + +#: authentic2_pratic/views.py:112 +msgid "Delete collectivity" +msgstr "Supprimer une collectivité" + +#: authentic2_pratic/views.py:127 +#, python-format +msgid "You are not a super-administrator or an administrator of %s" +msgstr "Vous n'êtes pas un super-administrateur ou un administrateur de %s" + +#: authentic2_pratic/views.py:182 +msgid "Edit agent" +msgstr "Éditer un agent" + +#: authentic2_pratic/views.py:218 +msgid "Delete agent" +msgstr "Supprimer un agent" + +#: authentic2_pratic/views.py:230 authentic2_pratic/views.py:271 +msgid "Add service instance" +msgstr "Ajouter une instance de service" + +#: authentic2_pratic/views.py:240 authentic2_pratic/views.py:280 +msgid "Edit service instance" +msgstr "Éditer une instance de service" + +#: authentic2_pratic/views.py:248 authentic2_pratic/views.py:288 +msgid "Delete service instance" +msgstr "Supprimer une instance de service" + +#~ msgid "collectivity name" +#~ msgstr "nom" + +#~ msgid "OAuth2 URL" +#~ msgstr "URL du point d'accès OAuth2" + +#~ msgid "OAuth2 Key" +#~ msgstr "Clé OAuth2" + +#~ msgid "User domain" +#~ msgstr "Domaine de l'utilisateur" + +#~ msgid "User identifier" +#~ msgstr "Identifiant utilisateur" + +#~ msgid "Reset password" +#~ msgstr "Ré-initialiser le mot de passe" + +#~ msgid "Deactivate" +#~ msgstr "Désactiver" + +#~ msgid "Activate" +#~ msgstr "Activer" diff --git a/src/authentic2_pratic/management/commands/load-pratic-ldif.py b/src/authentic2_pratic/management/commands/load-pratic-ldif.py index 2a7bb71..30952bd 100644 --- a/src/authentic2_pratic/management/commands/load-pratic-ldif.py +++ b/src/authentic2_pratic/management/commands/load-pratic-ldif.py @@ -160,7 +160,7 @@ class PraticLDIFParser(ldif.LDIFParser): last_login_duration = int(entry.get('cdg59lastConnectionDuration', [0])[0]) is_admin = entry.get('cdg59isAdmin', ['FALSE'])[0] == 'TRUE' user = User( - collectivity=collectivity, + ou=collectivity, is_active=is_active, last_login_duration=last_login_duration, is_admin=is_admin, diff --git a/src/authentic2_pratic/migrations/0001_initial.py b/src/authentic2_pratic/migrations/0001_initial.py index c76eaa5..17d81a5 100644 --- a/src/authentic2_pratic/migrations/0001_initial.py +++ b/src/authentic2_pratic/migrations/0001_initial.py @@ -8,7 +8,8 @@ from django.conf import settings class Migration(migrations.Migration): dependencies = [ - ('custom_user', '0005_auto_20150522_1527'), + ('a2_rbac', '0005_auto_20150526_1406'), + ('custom_user', '0006_auto_20150527_1212'), ] operations = [ @@ -26,9 +27,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Collectivity', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(unique=True, max_length=128, verbose_name='collectivity name')), - ('slug', models.SlugField(unique=True, max_length=128, verbose_name='identifier')), + ('organizationalunit_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to=settings.RBAC_OU_MODEL)), ('is_superuser', models.BooleanField(default=False, verbose_name='is superuser')), ('collectivity_id', models.CharField(max_length=8, verbose_name='collectivity id', blank=True)), ('sirh_code', models.CharField(max_length=8, verbose_name='SIRH Code', blank=True)), @@ -58,7 +57,7 @@ class Migration(migrations.Migration): 'verbose_name': 'collectivity', 'verbose_name_plural': 'collectivities', }, - bases=(models.Model,), + bases=('a2_rbac.organizationalunit',), ), migrations.CreateModel( name='Service', @@ -69,8 +68,6 @@ class Migration(migrations.Migration): ('is_global', models.BooleanField(default=False, verbose_name='is global')), ('service_url', models.URLField(verbose_name='URL')), ('metadata_url', models.URLField(verbose_name='SAML Metadata URL', blank=True)), - ('oauth2_url', models.URLField(verbose_name='OAuth2 URL', blank=True)), - ('oauth2_key', models.CharField(max_length=64, verbose_name='OAuth2 Key', blank=True)), ], options={ 'ordering': ('name',), @@ -86,8 +83,6 @@ class Migration(migrations.Migration): ('slug', models.SlugField(max_length=128, verbose_name=b'identifier')), ('service_url', models.URLField(verbose_name='URL', blank=True)), ('metadata_url', models.URLField(verbose_name='SAML Metadata URL', blank=True)), - ('oauth2_url', models.URLField(verbose_name='OAuth2 URL', blank=True)), - ('oauth2_key', models.CharField(max_length=64, verbose_name='OAuth2 Key', blank=True)), ('collectivity', models.ForeignKey(verbose_name='collectivity', to='authentic2_pratic.Collectivity')), ('service', models.ForeignKey(verbose_name='service', to='authentic2_pratic.Service')), ], @@ -113,7 +108,7 @@ class Migration(migrations.Migration): ('phone', models.CharField(max_length=32, verbose_name='phone', blank=True)), ('certificate_issuer_dn', models.CharField(max_length=256, null=True, verbose_name='certificate issuer DN', blank=True)), ('certificate_subject_dn', models.CharField(max_length=256, null=True, verbose_name='certificate subject DN', blank=True)), - ('collectivity', models.ForeignKey(verbose_name='collectivity', to='authentic2_pratic.Collectivity')), + ('collectivity', models.ForeignKey(related_name='collectivities', verbose_name='collectivity', to='authentic2_pratic.Collectivity')), ], options={ 'verbose_name': 'agent', diff --git a/src/authentic2_pratic/migrations/0002_serviceinstance_certificate.py b/src/authentic2_pratic/migrations/0002_serviceinstance_certificate.py new file mode 100644 index 0000000..9bc8bdb --- /dev/null +++ b/src/authentic2_pratic/migrations/0002_serviceinstance_certificate.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentic2_pratic', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='serviceinstance', + name='certificate', + field=models.BooleanField(default=False, verbose_name='Authentication by certificate only'), + preserve_default=True, + ), + ] diff --git a/src/authentic2_pratic/models.py b/src/authentic2_pratic/models.py index a7e2c07..2e75a48 100644 --- a/src/authentic2_pratic/models.py +++ b/src/authentic2_pratic/models.py @@ -2,7 +2,6 @@ import logging from django.db.models import (Model, TextField, CharField, EmailField, URLField, BooleanField, IntegerField, ForeignKey, SlugField, Manager) -from django.contrib.auth.models import User as AuthUser from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ValidationError from django.dispatch import receiver @@ -12,6 +11,9 @@ from django.contrib.auth.models import Group from authentic2 import managers from authentic2.idp.signals import authorize_service from authentic2.custom_user.models import User as BaseUser +from authentic2.a2_rbac.models import OrganizationalUnit +from authentic2.constants import AUTHENTICATION_EVENTS_SESSION_KEY + class User(BaseUser): # givenName -> first_name @@ -28,7 +30,9 @@ class User(BaseUser): max_length=128) collectivity = ForeignKey( 'Collectivity', + related_name='collectivities', verbose_name=_('collectivity')) + # cdg59isAdmin is_admin = BooleanField( verbose_name=_('is admin'), @@ -96,24 +100,18 @@ class User(BaseUser): def clean(self): # prevent collisions between users from multiple collectivities + qs = self.__class__.objects.exclude(pk=self.pk) + if qs.filter(uid=self.uid, collectivity=self.collectivity).exists(): + raise ValidationError(_('This username is already used')) if self.uid and not self.username and self.collectivity: self.username = u'%s@%s' % (self.uid, self.collectivity.slug) if self.collectivity: self.is_superuser = self.collectivity.is_superuser - super(User, self).clean() # Fields to support -class Collectivity(Model): +class Collectivity(OrganizationalUnit): # Identifiers # cn = ou - name = CharField( - verbose_name=_('collectivity name'), - max_length=128, - unique=True) - slug = SlugField( - verbose_name=_('identifier'), - max_length=128, - unique=True) is_superuser = BooleanField( verbose_name=_('is superuser'), default=False, @@ -275,13 +273,6 @@ class Service(Model): metadata_url = URLField( verbose_name=_('SAML Metadata URL'), blank=True) - oauth2_url = URLField( - verbose_name=_('OAuth2 URL'), - blank=True) - oauth2_key = CharField( - verbose_name=_('OAuth2 Key'), - max_length=64, - blank=True) def __unicode__(self): return self.name @@ -325,13 +316,10 @@ class ServiceInstance(Model): metadata_url = URLField( verbose_name=_('SAML Metadata URL'), blank=True) - oauth2_url = URLField( - verbose_name=_('OAuth2 URL'), - blank=True) - oauth2_key = CharField( - verbose_name=_('OAuth2 Key'), - max_length=64, - blank=True) + certificate = BooleanField( + verbose_name=_('Authentication by certificate only'), + default=False, + blank=True) def __unicode__(self): return unicode(self.service) @@ -351,8 +339,6 @@ class ServiceInstance(Model): if self.service and self.service.is_global: self.service_url = self.service.service_url self.metadata_url = self.service.metadata_url - self.oauth2_url = self.service.oauth2_url - self.oauth2_key = self.oauth2_key if not self.service.is_global and not self.service_url: raise ValidationError(_('Service URL field is required')) @@ -422,6 +408,11 @@ def authorize_service_cb(request, user, audience, attributes, **kwargs): logger.warn('unable to find service for audience %r and user %r in collectivity %r', audience, unicode(user), unicode(collectivity)) return authz(False, 'service not found') + if si.certificate: + events = request.session.get(AUTHENTICATION_EVENTS_SESSION_KEY, []) + if not any(event['how'] in ('ssl', 'ssl-collectivity') for event in events): + return authz(False, _('This service requires certificate authentication.')) + if Access.objects.filter(service_instance=si, user=user).exists(): logger.info('%r of collectivity %r is authorized to connect on %r', unicode(user), unicode(collectivity), audience) diff --git a/src/authentic2_pratic/tables.py b/src/authentic2_pratic/tables.py index 04733ec..9213a85 100644 --- a/src/authentic2_pratic/tables.py +++ b/src/authentic2_pratic/tables.py @@ -32,9 +32,6 @@ class CollectivityTable(tables.Table): fields = ('name', 'insee_code', 'postal_code', 'delete') class UserTable(tables.Table): - uid = tables.TemplateColumn( - '{{ record.uid }}', - verbose_name=_('identifier')) delete = tables.TemplateColumn( '{% load i18n %}{% trans "Delete" %}', verbose_name=mark_safe(' ')) diff --git a/src/authentic2_pratic/templates/authentic2_pratic/collectivities.html b/src/authentic2_pratic/templates/authentic2_pratic/collectivities.html index 4c63975..78d1ab6 100644 --- a/src/authentic2_pratic/templates/authentic2_pratic/collectivities.html +++ b/src/authentic2_pratic/templates/authentic2_pratic/collectivities.html @@ -4,6 +4,10 @@ {% block page-title %}{{ block.super }} - {% trans "Collectivities management" %}{% endblock %} {% block page_title %}{% trans "Collectivities management" %}{% endblock %} +{% block more-user-links %} + {{ block.super }} + {% trans "Collectivities management" %} +{% endblock %} {% block appbar %} {{ block.super }} diff --git a/src/authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html b/src/authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html index 63cd913..144a5a1 100644 --- a/src/authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html +++ b/src/authentic2_pratic/templates/authentic2_pratic/collectivity_edit.html @@ -4,21 +4,19 @@ {% block messages %} {% endblock %} -{% block page_title %} -{% trans "Collectivities management" %} -{% endblock %} - {% block sidebar %}

{% trans "Agents management" %}

{% trans "Service instances management" %}

{% trans "Accesses management" %}

{% endblock %} +{% block more-user-links %} + {{ block.super }} + {% trans "Collectivities management" %} + {{ collectivity }} +{% endblock %} + {% block main %} -
- {% if title %} -

{{ title }}

- {% endif %} {% if other_actions %}
{% trans "Actions" %} @@ -71,5 +69,4 @@
- {% endblock %} diff --git a/src/authentic2_pratic/templates/authentic2_pratic/collectivity_sidebar.html b/src/authentic2_pratic/templates/authentic2_pratic/collectivity_sidebar.html index aae3d67..0f9b522 100644 --- a/src/authentic2_pratic/templates/authentic2_pratic/collectivity_sidebar.html +++ b/src/authentic2_pratic/templates/authentic2_pratic/collectivity_sidebar.html @@ -2,12 +2,4 @@ {% load i18n staticfiles django_tables2 %} {% block page_title %} - {% comment %} - Only show link for super-admins, collectivity's admins just go back to the homepag - {% endcomment %} - {% if user.is_superuser %} - - {{ collectivity }} - - {% endif %} {% endblock %} diff --git a/src/authentic2_pratic/templates/authentic2_pratic/form.html b/src/authentic2_pratic/templates/authentic2_pratic/form.html index 30279de..3140b68 100644 --- a/src/authentic2_pratic/templates/authentic2_pratic/form.html +++ b/src/authentic2_pratic/templates/authentic2_pratic/form.html @@ -1,65 +1,11 @@ -{% extends "authentic2_pratic/sidebar.html" %} +{% extends "authentic2/manager/form.html" %} {% load i18n %} -{% block messages %} -{% endblock %} - -{% block main %} -
- {% if title %} -

{{ title }}

- {% endif %} -
-
- {% if messages %} -
    - {% for message in messages %} - - {{ message }} - - {% endfor %} -
- {% endif %} - {% csrf_token %} - {{ form.non_field_errors}} - {% for field in form %} - {% block form.before-field %} - {% if field.name == 'certificate_issuer_dn' %} -

{% trans "Certificate" %}

- {% endif %} - {% endblock %} -

- {{ field.label_tag }} - {{ field }} - {% if field.errors %} - - {% for error in field.errors %} - {{ error }} - {% endfor %} - - {% endif %} -

- {% endfor %} -
- - {% trans "Cancel" %} -
- {% if other_actions %} -
- {% trans "Actions" %} - - {% for action in other_actions %} - - {% endfor %} - -
- {% endif %} -
- -
+{% block beforefield %} + {% if field.name == 'certificate_issuer_dn' %} +

{% trans "Certificate" %}

+ {% endif %} + {% if field.name == 'generate_password' %} +

{% trans "Passwords" %}

+ {% endif %} {% endblock %} diff --git a/src/authentic2_pratic/templates/authentic2_pratic/service_instances.html b/src/authentic2_pratic/templates/authentic2_pratic/service_instances.html index 5d597da..624715e 100644 --- a/src/authentic2_pratic/templates/authentic2_pratic/service_instances.html +++ b/src/authentic2_pratic/templates/authentic2_pratic/service_instances.html @@ -5,6 +5,13 @@ {% block page_title %}{{ block.super }}{% trans "Service instances management" %}{% endblock %} +{% block more-user-links %} + {{ block.super }} + {% trans "Collectivities management" %} + {{ collectivity }} + {% trans "Service instances management" %} +{% endblock %} + {% block appbar %} {{ block.super }} {% trans "Add service-instance" %} diff --git a/src/authentic2_pratic/templates/authentic2_pratic/user_edit.html b/src/authentic2_pratic/templates/authentic2_pratic/user_edit.html new file mode 100644 index 0000000..88d4f88 --- /dev/null +++ b/src/authentic2_pratic/templates/authentic2_pratic/user_edit.html @@ -0,0 +1,33 @@ +{% extends "authentic2_pratic/form.html" %} +{% load i18n %} + +{% block page-title %}{{ block.super }} - {% trans "Edit user" %} {{ object }}{% endblock %} + +{% block page_title %}{% trans "Edit user" %} {{ object }}{% endblock %} + +{% block more-user-links %} + {{ block.super }} + {% trans "Collectivities management" %} + {{ collectivity }} + {% trans "Agents management" %} + {{ object.get_full_name }} +{% endblock %} + +{% block appbar %} +

{{ object.get_full_name }}

+{% endblock %} + +{% block beforeform %} +

+ + +

+{% endblock %} + +{% block afterform %} + {% if object.passwordreset_set.exists %} +
{% trans "User must change its password on next access to authentic" %} + +
+ {% endif %} +{% endblock %} diff --git a/src/authentic2_pratic/templates/authentic2_pratic/users.html b/src/authentic2_pratic/templates/authentic2_pratic/users.html index 55d5633..5bca84a 100644 --- a/src/authentic2_pratic/templates/authentic2_pratic/users.html +++ b/src/authentic2_pratic/templates/authentic2_pratic/users.html @@ -1,10 +1,17 @@ -{% extends "authentic2_pratic/collectivity_sidebar.html" %} +{% extends "authentic2/manager/sidebar.html" %} {% load i18n staticfiles django_tables2 %} {% block page-title %}{{ block.super }} - {% trans "Agents management" %}{% endblock %} {% block page_title %}{{ block.super }}{% trans "Agents management" %}{% endblock %} +{% block more-user-links %} + {{ block.super }} + {% trans "Collectivities management" %} + {{ collectivity }} + {% trans "Agents management" %} +{% endblock %} + {% block appbar %} {{ block.super }} {% trans "Add agent" %} @@ -15,5 +22,7 @@ {% endblock %} {% block main %} - {% render_table table "authentic2_pratic/table.html" %} + {% with row_link=1 %} + {% render_table table "authentic2/manager/table.html" %} + {% endwith %} {% endblock %} diff --git a/src/authentic2_pratic/urls.py b/src/authentic2_pratic/urls.py index b789b46..c2e26ed 100644 --- a/src/authentic2_pratic/urls.py +++ b/src/authentic2_pratic/urls.py @@ -1,5 +1,6 @@ from django.conf.urls import patterns, url, include +from authentic2.manager import user_views as user_views from . import views access_urlpatterns = patterns('', @@ -20,6 +21,9 @@ service_instance_urlpatterns = patterns('', user_urlpatterns = patterns('', url('^$', views.user_edit, name='a2-pratic-user-edit'), + url(r'change-password/$', + user_views.user_change_password, + name='a2-manager-user-change-password'), url('^delete/$', views.user_delete, name='a2-pratic-user-delete')) collectivity_urlpatterns = patterns('', diff --git a/src/authentic2_pratic/utils.py b/src/authentic2_pratic/utils.py index ee385b9..3e50e94 100644 --- a/src/authentic2_pratic/utils.py +++ b/src/authentic2_pratic/utils.py @@ -106,12 +106,14 @@ def sync_saml_provider(service_or_service_instance): saml_slug = u'siid-%s-%s' % (service_or_service_instance.collectivity.slug, service_or_service_instance.slug) name = service_or_service_instance.service.name + ou = service_or_service_instance.collectivity else: # if service is not global, do not create it if not service_or_service_instance.is_global: return saml_slug = u'sid-%s' % service_or_service_instance.slug name = service_or_service_instance.name + ou = None # enforce limits of LibertyProvider model name = name[:140] saml_slug = saml_slug[:128] @@ -137,15 +139,17 @@ def sync_saml_provider(service_or_service_instance): logger.warning('updating of metadata of provider %r failed: %s', saml_slug, e) return False - liberty_provider.metadata = response.content + print response.headers['Content-Type'] + liberty_provider.metadata = unicode(response.content, 'utf-8') try: - liberty_provider.clean() + liberty_provider.full_clean(exclude=('ou', 'entity_id', 'protocol_conformance')) except ValidationError, e: logger.warning('updating of metadata of provider %r failed: %s', saml_slug, e) return False liberty_provider.save() liberty_service_provider, created = LibertyServiceProvider.objects.get_or_create( + ou=ou, liberty_provider=liberty_provider, defaults={'enabled': True}) return True diff --git a/src/authentic2_pratic/views.py b/src/authentic2_pratic/views.py index d2af44a..1fa309a 100644 --- a/src/authentic2_pratic/views.py +++ b/src/authentic2_pratic/views.py @@ -3,15 +3,16 @@ from django.shortcuts import get_object_or_404, redirect from django.contrib import messages from django.contrib.auth.views import redirect_to_login from django.db.models.query import Q +from django.core.urlresolvers import reverse from django.views.generic import (TemplateView, UpdateView, - CreateView, DeleteView) + CreateView, DeleteView) from django_tables2 import SingleTableView from authentic2.manager.views import AjaxFormViewMixin, \ ActionMixin, OtherActionsMixin, TitleMixin, Action -from authentic2.manager.user_views import UserEditView +from authentic2.manager.user_views import UserEditView, UserAddView from . import models, tables, forms @@ -121,8 +122,8 @@ class CollectivityMixin(object): return redirect_to_login(request.get_full_path()) if not user.is_superuser and \ - (not hasattr(user, 'is_admin') or - not (user.is_admin and user.collectivity == self.collectivity)): + (not hasattr(user, 'is_admin') or + not (user.is_admin and user.ou == self.collectivity)): messages.warning(request, _('You are not a super-administrator or an administrator of %s') % self.collectivity) return redirect('auth_homepage') return super(CollectivityMixin, self).dispatch(request, *args, **kwargs) @@ -149,27 +150,66 @@ class UsersView(CollectivityChildMixin, SingleTableView): model = models.User table_class = tables.UserTable -class UserAddView(CollectivityChildMixin, TitleMixin, ActionMixin, - AjaxFormViewMixin, CreateView): +class UserAddView(CollectivityChildMixin, UserAddView): model = models.User title = _('Add agent') - template_name = 'authentic2_pratic/form.html' action = _('Add') - form_class = forms.UserForm + form_class = forms.UserAddForm + template_name = 'authentic2_pratic/form.html' success_url = '..' + fields = ( + 'uid', + 'first_name', + 'last_name', + 'email', + 'is_admin', + 'direction', + 'employee_type', + 'postal_address', + 'fax', + 'mobile', + 'phone', + 'certificate_issuer_dn', + 'certificate_subject_dn', + 'certificate', + ) + + def get_success_url(self): + return reverse('a2-pratic-user-edit', kwargs={'collectivity_pk': self.object.collectivity.pk, 'pk': self.object.pk}) class UserView(CollectivityChildMixin, UserEditView): model = models.User title = _('Edit agent') - template_name = 'authentic2_pratic/form.html' - form_class = forms.UserForm + form_class = forms.UserEditForm + template_name = 'authentic2_pratic/user_edit.html' + fields = ( + 'uid', + 'first_name', + 'last_name', + 'email', + 'is_admin', + 'direction', + 'employee_type', + 'postal_address', + 'fax', + 'mobile', + 'phone', + 'certificate_issuer_dn', + 'certificate_subject_dn', + 'certificate', + ) def get_other_actions(self): - yield Action('password_reset', _('Reset password')) - if self.object.is_active: - yield Action('deactivate', _('Deactivate')) - else: - yield Action('activate', _('Activate')) + actions = list(super(UserView, self).get_other_actions()) + for action in actions: + if action.url_name == 'a2-manager-user-change-password': + action.url_name = None + action.url = reverse('a2-manager-user-change-password', + kwargs={'collectivity_pk': + self.object.collectivity.pk, + 'pk': self.object.pk}) + return actions + class UserDeleteView(CollectivityChildMixin, TitleMixin, AjaxFormViewMixin, DeleteView): @@ -191,6 +231,8 @@ class ServiceInstanceAddView(CollectivityChildMixin, TitleMixin, ActionMixin, template_name = 'authentic2_pratic/form.html' action = _('Add') form_class = forms.ServiceInstanceForm + success_url = '..' + class ServiceInstanceView(CollectivityChildMixin, TitleMixin, OtherActionsMixin, AjaxFormViewMixin, UpdateView): @@ -204,7 +246,7 @@ class ServiceInstanceDeleteView(CollectivityChildMixin, TitleMixin, model = models.ServiceInstance template_name = 'authentic2_pratic/delete.html' title = _('Delete service instance') - success_url = 'a2-pratic-users' + success_url = '../..' # accesses class AccessMixin(object): @@ -230,6 +272,7 @@ class AccessAddView(AccessMixin, CollectivityMixin, TitleMixin, ActionMixin, template_name = 'authentic2_pratic/form.html' action = _('Add') form_class = forms.AccessForm + success_url = '..' class AccessView(AccessMixin, CollectivityMixin, TitleMixin, OtherActionsMixin, AjaxFormViewMixin, UpdateView): @@ -244,6 +287,7 @@ class AccessDeleteView(AccessMixin, CollectivityMixin, TitleMixin, template_name = 'authentic2_pratic/delete.html' title = _('Delete service instance') success_url = 'a2-pratic-users' + success_url = '../..' # general views homepage = HomepageView.as_view()