diff --git a/TODO b/TODO new file mode 100644 index 0000000..9407e18 --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ +- Authentication is handled by authsaml2 +- First user created must be superadmin +- User admin must be read-only diff --git a/portail_citoyen/admin.py b/portail_citoyen/admin.py index 8769041..857c185 100644 --- a/portail_citoyen/admin.py +++ b/portail_citoyen/admin.py @@ -1,69 +1,17 @@ -import urlparse -import urllib2 -import time import logging -from django.contrib import messages -from django.conf import settings -from django.utils.translation import ugettext_lazy as _ -from django.utils.html import format_html -from django.core.exceptions import ValidationError from django.contrib import admin from django.contrib.auth.models import Group -from authentic2.saml.models import LibertyProvider, LibertyServiceProvider - -from . import app_settings from . import models logger = logging.getLogger(__name__) -if settings.AUTH_USER_MODEL == 'portail_citoyen.Citoyen': - import forms - - from django.contrib.auth.admin import UserAdmin - class CitoyenAdmin(UserAdmin): - list_display = UserAdmin.list_display + ('is_active',) - non_superuser_fieldsets = ( - (None, {'fields': ('username', 'password')}), - (_('Personal info'), {'fields': ('first_name', 'last_name', - 'email', 'address', 'city', 'postal_code', 'phone', - 'mobile')}), - (_('Permissions'), {'fields': ('is_active', - 'groups')}), - (_('Important dates'), {'fields': ('last_login', 'date_joined')}), - ) - fieldsets = ( - (None, {'fields': ('username', 'password')}), - (_('Personal info'), {'fields': ('first_name', 'last_name', - 'email', 'address', 'city', 'postal_code', 'phone', - 'mobile')}), - (_('Permissions'), {'fields': ('is_active', - 'is_superuser', 'groups')}), - (_('Important dates'), {'fields': ('last_login', 'date_joined')}), - ) - form = forms.UserChangeForm - add_form = forms.UserCreationForm - add_fieldsets = ( - (None, { - 'classes': ('wide',), - 'fields': ('username', 'password1', 'password2', 'first_name', 'last_name', 'email')} - ), - ) - - def get_fieldsets(self, request, obj=None): - if not obj: - return self.add_fieldsets - if not request.user.is_superuser: - return self.non_superuser_fieldsets - return self.fieldsets - - - admin.site.register(models.Citoyen, CitoyenAdmin) - from django.contrib.auth.admin import GroupAdmin +# XXX: the UserAdmin must be read-only + class GroupPortailCitoyenAdmin(GroupAdmin): fieldsets = ((None, {'fields': ('name', 'permissions')}),) default_fieldsets = ((None, {'fields': ('name', )}),) @@ -108,104 +56,3 @@ if hasattr(get_user_model(), 'groups'): .filter(permissions__isnull=False) \ .exists() or user.is_superuser user.save(update_fields=['is_staff']) - - -if 'wcsinst.wcsinst' in settings.INSTALLED_APPS: - - from wcsinst.wcsinst.admin import WcsInstanceAdmin - from wcsinst.wcsinst.models import WcsInstance - - admin.site.unregister(WcsInstance) - - class WcsInstancePortailCitoyenAdmin(WcsInstanceAdmin): - list_display = [ '__unicode__', 'link' ] - fieldsets = ( - (None, {'fields': ('title', 'domain', 'link'),}), - ('site-options.cfg', - {'fields': ('postgresql', 'backoffice_feed_url' )} - ), - ('site-options.cfg au-quotidien', - {'fields': ('drupal', 'ezldap', 'strongbox', 'clicrdv', 'domino' )} - ), - ) - readonly_fields = WcsInstanceAdmin.readonly_fields + ('link',) - - def link(self, obj): - url = str(settings.WCSINST_URL_TEMPLATE % { 'domain': obj.domain }) - return format_html('{0}', - url, url) - link.allow_tags = True - link.short_description = _('URL') - - def delete_model(self, request, obj): - title = obj.title - super(WcsInstancePortailCitoyenAdmin, self).delete_model(request, obj) - Group.objects.filter(name__startswith=title+' - ').delete() - - def save_related(self, request, form, formsets, change): - instance = form.instance - admin.ModelAdmin.save_related(self, request, form, formsets, change) - for key, value in app_settings.WCSINST_DEFAULT_VARIABLES.iteritems(): - if instance.variables.filter(key=key).count() == 0: - instance.variables.create(key=key, value=value) - instance.notify() - # Get and configure metadata - sleep_length = 4 - c = 0 - done = False - if LibertyProvider.objects.filter(slug=instance.domain).exists(): - provider = LibertyProvider.objects.get(slug=instance.domain) - provider.name = instance.title - else: - provider = LibertyProvider(name=instance.title, slug=instance.domain) - while not done: - time.sleep(sleep_length) - url = str(settings.WCSINST_URL_TEMPLATE % { 'domain': instance.domain }) - url = urlparse.urljoin(url, 'saml/metadata') - try: - provider.metadata = urllib2.urlopen(url).read().decode('utf-8') - except: - logger.warning("Unable to retrieve SAML 2.0 metadata for %r", instance.title, exc_info=True) - if c >= 3: - messages.error(request, _('Unable to retrieve SAML 2.0 metadatas, please report it to an administrator')) - break - else: - try: - provider.clean() - except ValidationError, v: - provider.delete() - logger.error('Unable to create the SAML 2.0 provider: %r', v) - messages.error(request, _('Unable to create the SAML 2.0 provider: %s') % v) - break - provider.save() - LibertyServiceProvider.objects.get_or_create(liberty_provider=provider, enabled=True) - done = True - c += 1 - sleep_length *= 2 - - def save_model(self, request, obj, form, change): - if change: - old_obj = WcsInstance.objects.get(pk=obj.pk) - super(WcsInstancePortailCitoyenAdmin, self).save_model(request, obj, form, change) - new_prefix = obj.title - new_prefix += ' - ' - if change: - # rename old admin group if needed - old_prefix = old_obj.title + ' - ' - if old_prefix != new_prefix: - for group in Group.objects.select_for_update() \ - .filter(name__startswith=old_prefix): - group.name = new_prefix + group.name[len(old_prefix):] - group.save() - else: - # create first group - admin_group, created = Group.objects.get_or_create(name=new_prefix+'Administrateur') - # make current user admin of the new site - request.user.groups.add(admin_group) - - - admin.site.register(WcsInstance, - WcsInstancePortailCitoyenAdmin) - - - diff --git a/portail_citoyen/dashboard.py b/portail_citoyen/dashboard.py index 4279bd2..9a3386e 100644 --- a/portail_citoyen/dashboard.py +++ b/portail_citoyen/dashboard.py @@ -10,7 +10,7 @@ class CustomIndexDashboard(Dashboard): # append an app list module for "Applications" self.children.append(modules.ModelList( _('Users and roles'), - models=('portail_citoyen.models.Citoyen', + models=('django.contrib.auth.models.User', 'portail_citoyen.models.Role'), )) self.children.append(modules.ModelList( diff --git a/portail_citoyen/models.py b/portail_citoyen/models.py index 56ca9a9..f5af0e3 100644 --- a/portail_citoyen/models.py +++ b/portail_citoyen/models.py @@ -1,58 +1,6 @@ -from django.db import models -from django.core.validators import RegexValidator, MinLengthValidator, \ - MaxLengthValidator -from django.utils.translation import ugettext_lazy as _, pgettext_lazy from django.contrib.auth.models import Group -from authentic2.models import AbstractUser - - -class Citoyen(AbstractUser): - title = models.CharField(pgettext_lazy('person title', 'title'), max_length=16, blank=True, - choices=tuple((x, x) for x in (_('Mrs'), - _('Mr')))) - - first_name = models.CharField(_('first name'), max_length=30, blank=True) - last_name = models.CharField(_('last name'), max_length=30, blank=True) - email = models.EmailField(_('e-mail address'), max_length=128, blank=True) - city = models.CharField(_('city'), max_length=64, blank=True) - address = models.CharField(_('address'), max_length=128, blank=True) - postal_code = models.CharField(_('postal code'), max_length=5, blank=True, - validators=[ - RegexValidator(r'^[0-9]*$', - _('Postal code must be five numbers'), - _('Invalid postal code')), - MinLengthValidator(5), - MaxLengthValidator(5)]) - phone = models.CharField(verbose_name=_("phone"), - max_length=16, blank=True, - help_text=_('Phone number must start with 01, 02, 03, 04, 05, 08 or 07 and be ten digits long without spaces'), - validators=[ - RegexValidator(r'^0[1234589][0-9]{8}$', - _('Phone number must start with 01, 02, 03, 04, 05, 08 or 07 and be ten digits long without spaces'), - _('Invalid mobile phone number')),]) - mobile = models.CharField(verbose_name=_("mobile"), - max_length=16, blank=True, - help_text=_('Mobile phone number must start with 06 or 07 and be ten digits long without spaces'), - validators=[ - RegexValidator(r'^0[67][0-9]{8}$', - _('Mobile phone number must start with 06 or 07 and be ten digits long without spaces'), - _('Invalid mobile phone number')),]) - - REQUIRED_FIELDS = ['first_name', 'last_name', 'email'] - USERNAME = 'username' - USER_PROFILE = ( 'title', 'username', 'first_name', 'last_name', 'email', - 'phone', 'mobile', 'address', 'postal_code', 'city', 'roles') - -from authentic2.attribute_aggregator.core import ATTRIBUTE_MAPPING - -ATTRIBUTE_MAPPING['l']['profile_field_name'] = 'city' -ATTRIBUTE_MAPPING['personalTitle']['profile_field_name'] = 'title' -ATTRIBUTE_MAPPING['street']['profile_field_name'] = 'address' -ATTRIBUTE_MAPPING['postalCode']['profile_field_name'] = 'postal_code' -ATTRIBUTE_MAPPING['mobile']['profile_field_name'] = 'mobile' - class Role(Group): class Meta: proxy = True