nettoyage des applications obsolètes/squash des migrations (#40685) (série partielle) #262
|
@ -6,6 +6,7 @@ set -e
|
|||
CHECK_MIGRATIONS_SETTINGS=`mktemp`
|
||||
trap "rm -f ${CHECK_MIGRATIONS_SETTINGS}" EXIT
|
||||
cat <<EOF >${CHECK_MIGRATIONS_SETTINGS}
|
||||
LANGUAGE_CODE = 'en'
|
||||
pmarillonnet marked this conversation as resolved
Outdated
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.dummy',
|
||||
|
|
|
@ -18,7 +18,6 @@ import contextlib
|
|||
import datetime
|
||||
import threading
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import connection, models
|
||||
from django.db.models import query
|
||||
|
@ -167,7 +166,8 @@ class RoleQuerySet(query.QuerySet):
|
|||
return qs
|
||||
|
||||
def all_members(self):
|
||||
User = get_user_model()
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
prefetch = Prefetch('roles', queryset=self, to_attr='direct')
|
||||
return (
|
||||
User.objects.filter(
|
||||
|
|
|
@ -9,7 +9,7 @@ class Migration(migrations.Migration):
|
|||
dependencies = [
|
||||
('authentic2', '0004_service'),
|
||||
('django_rbac', '__first__'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('contenttypes', '0001_initial'),
|
||||
]
|
||||
|
||||
|
@ -118,7 +118,7 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
(
|
||||
'members',
|
||||
models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL, blank=True),
|
||||
models.ManyToManyField(related_name='roles', to='custom_user.User', blank=True),
|
||||
),
|
||||
(
|
||||
'ou',
|
||||
|
|
|
@ -19,8 +19,6 @@ import os
|
|||
from collections import namedtuple
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
|
@ -363,9 +361,7 @@ class Role(AbstractBase):
|
|||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
members = models.ManyToManyField(
|
||||
to=settings.AUTH_USER_MODEL, swappable=True, blank=True, related_name='roles'
|
||||
)
|
||||
members = models.ManyToManyField(to='custom_user.User', swappable=True, blank=True, related_name='roles')
|
||||
permissions = models.ManyToManyField(to=Permission, related_name='roles', blank=True)
|
||||
name = models.TextField(verbose_name=_('name'))
|
||||
details = models.TextField(_('Role details (frontoffice)'), blank=True)
|
||||
|
@ -426,7 +422,8 @@ class Role(AbstractBase):
|
|||
)
|
||||
|
||||
def all_members(self):
|
||||
User = get_user_model()
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
prefetch = Prefetch('roles', queryset=self.__class__.objects.filter(pk=self.pk), to_attr='direct')
|
||||
|
||||
return (
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
import uuid
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.text import slugify
|
||||
|
||||
|
@ -44,7 +43,8 @@ def get_default_ou_pk():
|
|||
|
||||
|
||||
def get_view_user_perm(ou=None):
|
||||
User = get_user_model()
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
view_user_perm, dummy = models.Permission.objects.get_or_create(
|
||||
operation=get_operation(models.VIEW_OP),
|
||||
target_ct=ContentType.objects.get_for_model(ContentType),
|
||||
|
@ -74,7 +74,8 @@ def get_search_ou_perm(ou=None):
|
|||
|
||||
|
||||
def get_manage_authorizations_user_perm(ou=None):
|
||||
User = get_user_model()
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
manage_authorizations_user_perm, dummy = models.Permission.objects.get_or_create(
|
||||
operation=get_operation(models.MANAGE_AUTHORIZATIONS_OP),
|
||||
target_ct=ContentType.objects.get_for_model(ContentType),
|
||||
|
|
|
@ -32,7 +32,6 @@ from django.views.decorators.cache import never_cache
|
|||
from . import app_settings, attribute_kinds, decorators, models
|
||||
from .custom_user.models import DeletedUser, Profile, ProfileType, User
|
||||
from .forms.profile import BaseUserForm, modelform_factory
|
||||
from .nonce.models import Nonce
|
||||
from .utils import misc as utils_misc
|
||||
|
||||
|
||||
|
@ -49,11 +48,6 @@ class CleanupAdminMixin(admin.ModelAdmin):
|
|||
return actions
|
||||
|
||||
|
||||
@admin.register(Nonce)
|
||||
class NonceModelAdmin(admin.ModelAdmin):
|
||||
list_display = ('value', 'context', 'not_on_or_after')
|
||||
|
||||
|
||||
class AttributeValueAdmin(admin.ModelAdmin):
|
||||
list_display = ('content_type', 'owner', 'attribute', 'content')
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ from functools import partial
|
|||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.hashers import identify_hasher
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import MultipleObjectsReturned
|
||||
|
@ -75,8 +74,6 @@ from .utils import misc as utils_misc
|
|||
from .utils.api import DjangoRBACPermission, NaturalKeyRelatedField
|
||||
from .utils.lookups import Unaccent
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class HookMixin:
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
|
@ -153,7 +150,6 @@ class RegistrationSerializer(serializers.Serializer):
|
|||
authorized = request.user.has_perm(perm)
|
||||
if not authorized:
|
||||
raise serializers.ValidationError(_('you are not authorized to create users in this ou'))
|
||||
User = get_user_model()
|
||||
if ou:
|
||||
if app_settings.A2_EMAIL_IS_UNIQUE or app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE:
|
||||
if 'email' not in attrs:
|
||||
|
@ -207,7 +203,6 @@ class PasswordChangeSerializer(serializers.Serializer):
|
|||
new_password = serializers.CharField(required=True, allow_null=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
User = get_user_model()
|
||||
qs = User.objects.filter(email__iexact=attrs['email'])
|
||||
if attrs['ou']:
|
||||
qs = qs.filter(ou=attrs['ou'])
|
||||
|
@ -394,7 +389,6 @@ class BaseUserSerializer(serializers.ModelSerializer):
|
|||
return instance
|
||||
|
||||
def validate(self, attrs):
|
||||
User = get_user_model()
|
||||
qs = User.objects.all()
|
||||
|
||||
ou = None
|
||||
|
@ -439,7 +433,7 @@ class BaseUserSerializer(serializers.ModelSerializer):
|
|||
return attrs
|
||||
|
||||
class Meta:
|
||||
model = get_user_model()
|
||||
model = User
|
||||
extra_kwargs = {
|
||||
'uuid': {
|
||||
'read_only': False,
|
||||
|
@ -556,7 +550,7 @@ class IsoDateTimeFilter(BaseIsoDateTimeFilter):
|
|||
|
||||
class UsersFilter(FilterSet):
|
||||
class Meta:
|
||||
model = get_user_model()
|
||||
model = User
|
||||
fields = {
|
||||
'username': ['exact', 'iexact'],
|
||||
'first_name': [
|
||||
|
@ -721,7 +715,7 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
|
|||
|
||||
def check_modified_uuids(self, timestamp, users, unknown_uuids):
|
||||
modified_users_uuids = set()
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
user_ct = ContentType.objects.get_for_model(User)
|
||||
reference_ids = [reference_integer(user) for user in users]
|
||||
user_events = Event.objects.filter(
|
||||
models.Q(reference_ids__overlap=reference_ids) | models.Q(user__in=users),
|
||||
|
@ -999,7 +993,6 @@ class UserProfilesAPI(ExceptionHandlerMixin, APIView):
|
|||
|
||||
def initial(self, request, *args, **kwargs):
|
||||
super().initial(request, *args, **kwargs)
|
||||
User = get_user_model()
|
||||
self.profile_type = get_object_or_404(ProfileType, slug=kwargs['profile_type_slug'])
|
||||
self.user = get_object_or_404(User, uuid=kwargs['user_uuid'])
|
||||
self.identifier = request.GET.get('identifier', '')
|
||||
|
@ -1175,7 +1168,6 @@ class RoleMembershipsAPI(ExceptionHandlerMixin, APIView):
|
|||
|
||||
def initial(self, request, *, role_uuid=None, role_slug=None, **kwargs):
|
||||
super().initial(request, role_uuid=role_uuid, role_slug=role_slug, **kwargs)
|
||||
User = get_user_model()
|
||||
if role_uuid:
|
||||
self.role = get_object_or_404(Role, uuid=role_uuid)
|
||||
if role_slug:
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import django
|
||||
import django.contrib.postgres.fields
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.db.models import JSONField
|
||||
from django.utils import timezone
|
||||
|
@ -13,7 +12,7 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('authentic2', '0027_remove_deleteduser'),
|
||||
('sessions', '0001_initial'),
|
||||
]
|
||||
|
@ -92,7 +91,7 @@ class Migration(migrations.Migration):
|
|||
db_constraint=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
verbose_name='user',
|
||||
),
|
||||
),
|
||||
|
|
|
@ -23,7 +23,6 @@ from contextlib import contextmanager
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
@ -41,8 +40,6 @@ from .utils import Statistics
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
_registry = {}
|
||||
|
||||
|
||||
|
@ -87,6 +84,8 @@ class EventTypeDefinition(metaclass=EventTypeDefinitionMeta):
|
|||
|
||||
@classmethod
|
||||
def record(cls, *, user=None, session=None, references=None, data=None, api=False):
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
event_type = EventType.objects.get_for_name(cls.name)
|
||||
|
||||
if user and not isinstance(user, User):
|
||||
|
@ -216,6 +215,8 @@ class EventType(models.Model):
|
|||
class EventQuerySet(QuerySet):
|
||||
@classmethod
|
||||
def _which_references_query(cls, instance_or_model_class_or_queryset):
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
if isinstance(instance_or_model_class_or_queryset, list):
|
||||
return functools.reduce(
|
||||
operator.or_,
|
||||
|
@ -315,7 +316,7 @@ class Event(models.Model):
|
|||
|
||||
user = models.ForeignKey(
|
||||
verbose_name=_('user'),
|
||||
to=User,
|
||||
to='custom_user.User',
|
||||
on_delete=models.DO_NOTHING,
|
||||
db_constraint=False,
|
||||
blank=True,
|
||||
|
@ -489,6 +490,8 @@ class EventCursor(str):
|
|||
|
||||
def prefetch_events_references(events, prefetcher=None):
|
||||
'''Prefetch references on an iterable of events, prevent N+1 queries problem.'''
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
grouped_references = defaultdict(set)
|
||||
references = {}
|
||||
|
||||
|
|
|
@ -17,13 +17,12 @@
|
|||
import re
|
||||
from functools import reduce
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from . import models
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
User = get_user_model()
|
||||
from . import models
|
||||
|
||||
QUOTED_RE = re.compile(r'^[a-z0-9_-]*:"[^"]*"$')
|
||||
LEXER_RE = re.compile(r'([a-z0-9_-]*:(?:"[^"]*"|[^ ]*)|[^\s]*)\s*')
|
||||
|
|
|
@ -1,484 +0,0 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0002_auto_20150323_1720'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AttributeItem',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
(
|
||||
'attribute_name',
|
||||
models.CharField(
|
||||
default=('OpenLDAProotDSE', 'OpenLDAProotDSE'),
|
||||
max_length=100,
|
||||
verbose_name='Attribute name',
|
||||
choices=[
|
||||
('OpenLDAProotDSE', 'OpenLDAProotDSE'),
|
||||
('aRecord', 'aRecord'),
|
||||
('administrativeRole', 'administrativeRole'),
|
||||
('alias', 'alias'),
|
||||
('aliasedObjectName', 'aliasedObjectName'),
|
||||
('altServer', 'altServer'),
|
||||
('associatedDomain', 'associatedDomain'),
|
||||
('associatedName', 'associatedName'),
|
||||
('attributeTypes', 'attributeTypes'),
|
||||
('audio', 'audio'),
|
||||
('authPassword', 'authPassword'),
|
||||
('authorityRevocationList', 'authorityRevocationList'),
|
||||
('authzFrom', 'authzFrom'),
|
||||
('authzTo', 'authzTo'),
|
||||
('bootFile', 'bootFile'),
|
||||
('bootParameter', 'bootParameter'),
|
||||
('buildingName', 'buildingName'),
|
||||
('businessCategory', 'businessCategory'),
|
||||
('c', 'c'),
|
||||
('cACertificate', 'cACertificate'),
|
||||
('cNAMERecord', 'cNAMERecord'),
|
||||
('carLicense', 'carLicense'),
|
||||
('certificateRevocationList', 'certificateRevocationList'),
|
||||
('children', 'children'),
|
||||
('cn', 'cn'),
|
||||
('co', 'co'),
|
||||
('collectiveAttributeSubentries', 'collectiveAttributeSubentries'),
|
||||
('collectiveAttributeSubentry', 'collectiveAttributeSubentry'),
|
||||
('collectiveExclusions', 'collectiveExclusions'),
|
||||
('configContext', 'configContext'),
|
||||
('contextCSN', 'contextCSN'),
|
||||
('createTimestamp', 'createTimestamp'),
|
||||
('creatorsName', 'creatorsName'),
|
||||
('crossCertificatePair', 'crossCertificatePair'),
|
||||
('dITContentRules', 'dITContentRules'),
|
||||
('dITRedirect', 'dITRedirect'),
|
||||
('dITStructureRules', 'dITStructureRules'),
|
||||
('dSAQuality', 'dSAQuality'),
|
||||
('dc', 'dc'),
|
||||
('deltaRevocationList', 'deltaRevocationList'),
|
||||
('departmentNumber', 'departmentNumber'),
|
||||
('description', 'description'),
|
||||
('destinationIndicator', 'destinationIndicator'),
|
||||
('displayName', 'displayName'),
|
||||
('distinguishedName', 'distinguishedName'),
|
||||
('dmdName', 'dmdName'),
|
||||
('dnQualifier', 'dnQualifier'),
|
||||
('documentAuthor', 'documentAuthor'),
|
||||
('documentIdentifier', 'documentIdentifier'),
|
||||
('documentLocation', 'documentLocation'),
|
||||
('documentPublisher', 'documentPublisher'),
|
||||
('documentTitle', 'documentTitle'),
|
||||
('documentVersion', 'documentVersion'),
|
||||
('drink', 'drink'),
|
||||
('dynamicObject', 'dynamicObject'),
|
||||
('dynamicSubtrees', 'dynamicSubtrees'),
|
||||
('eduOrgHomePageURI', 'eduOrgHomePageURI'),
|
||||
('eduOrgIdentityAuthNPolicyURI', 'eduOrgIdentityAuthNPolicyURI'),
|
||||
('eduOrgLegalName', 'eduOrgLegalName'),
|
||||
('eduOrgSuperiorURI', 'eduOrgSuperiorURI'),
|
||||
('eduOrgWhitePagesURI', 'eduOrgWhitePagesURI'),
|
||||
('eduPersonAffiliation', 'eduPersonAffiliation'),
|
||||
('eduPersonAssurance', 'eduPersonAssurance'),
|
||||
('eduPersonEntitlement', 'eduPersonEntitlement'),
|
||||
('eduPersonNickname', 'eduPersonNickname'),
|
||||
('eduPersonOrgDN', 'eduPersonOrgDN'),
|
||||
('eduPersonOrgUnitDN', 'eduPersonOrgUnitDN'),
|
||||
('eduPersonPrimaryAffiliation', 'eduPersonPrimaryAffiliation'),
|
||||
('eduPersonPrimaryOrgUnitDN', 'eduPersonPrimaryOrgUnitDN'),
|
||||
('eduPersonPrincipalName', 'eduPersonPrincipalName'),
|
||||
('eduPersonScopedAffiliation', 'eduPersonScopedAffiliation'),
|
||||
('eduPersonTargetedID', 'eduPersonTargetedID'),
|
||||
('email', 'email'),
|
||||
('employeeNumber', 'employeeNumber'),
|
||||
('employeeType', 'employeeType'),
|
||||
('enhancedSearchGuide', 'enhancedSearchGuide'),
|
||||
('entry', 'entry'),
|
||||
('entryCSN', 'entryCSN'),
|
||||
('entryDN', 'entryDN'),
|
||||
('entryTtl', 'entryTtl'),
|
||||
('entryUUID', 'entryUUID'),
|
||||
('extensibleObject', 'extensibleObject'),
|
||||
('fax', 'fax'),
|
||||
('gecos', 'gecos'),
|
||||
('generationQualifier', 'generationQualifier'),
|
||||
('gidNumber', 'gidNumber'),
|
||||
('givenName', 'givenName'),
|
||||
('glue', 'glue'),
|
||||
('hasSubordinates', 'hasSubordinates'),
|
||||
('homeDirectory', 'homeDirectory'),
|
||||
('homePhone', 'homePhone'),
|
||||
('homePostalAddress', 'homePostalAddress'),
|
||||
('host', 'host'),
|
||||
('houseIdentifier', 'houseIdentifier'),
|
||||
('info', 'info'),
|
||||
('initials', 'initials'),
|
||||
('internationaliSDNNumber', 'internationaliSDNNumber'),
|
||||
('ipHostNumber', 'ipHostNumber'),
|
||||
('ipNetmaskNumber', 'ipNetmaskNumber'),
|
||||
('ipNetworkNumber', 'ipNetworkNumber'),
|
||||
('ipProtocolNumber', 'ipProtocolNumber'),
|
||||
('ipServicePort', 'ipServicePort'),
|
||||
('ipServiceProtocolSUPname', 'ipServiceProtocolSUPname'),
|
||||
('janetMailbox', 'janetMailbox'),
|
||||
('jpegPhoto', 'jpegPhoto'),
|
||||
('knowledgeInformation', 'knowledgeInformation'),
|
||||
('l', 'l'),
|
||||
('labeledURI', 'labeledURI'),
|
||||
('ldapSyntaxes', 'ldapSyntaxes'),
|
||||
('loginShell', 'loginShell'),
|
||||
('mDRecord', 'mDRecord'),
|
||||
('mXRecord', 'mXRecord'),
|
||||
('macAddress', 'macAddress'),
|
||||
('mail', 'mail'),
|
||||
('mailForwardingAddress', 'mailForwardingAddress'),
|
||||
('mailHost', 'mailHost'),
|
||||
('mailLocalAddress', 'mailLocalAddress'),
|
||||
('mailPreferenceOption', 'mailPreferenceOption'),
|
||||
('mailRoutingAddress', 'mailRoutingAddress'),
|
||||
('manager', 'manager'),
|
||||
('matchingRuleUse', 'matchingRuleUse'),
|
||||
('matchingRules', 'matchingRules'),
|
||||
('member', 'member'),
|
||||
('memberNisNetgroup', 'memberNisNetgroup'),
|
||||
('memberUid', 'memberUid'),
|
||||
('mobile', 'mobile'),
|
||||
('modifiersName', 'modifiersName'),
|
||||
('modifyTimestamp', 'modifyTimestamp'),
|
||||
('monitorContext', 'monitorContext'),
|
||||
('nSRecord', 'nSRecord'),
|
||||
('name', 'name'),
|
||||
('nameForms', 'nameForms'),
|
||||
('namingCSN', 'namingCSN'),
|
||||
('namingContexts', 'namingContexts'),
|
||||
('nisMapEntry', 'nisMapEntry'),
|
||||
('nisMapNameSUPname', 'nisMapNameSUPname'),
|
||||
('nisNetgroupTriple', 'nisNetgroupTriple'),
|
||||
('o', 'o'),
|
||||
('objectClass', 'objectClass'),
|
||||
('objectClasses', 'objectClasses'),
|
||||
('oncRpcNumber', 'oncRpcNumber'),
|
||||
('organizationalStatus', 'organizationalStatus'),
|
||||
('otherMailbox', 'otherMailbox'),
|
||||
('ou', 'ou'),
|
||||
('owner', 'owner'),
|
||||
('pager', 'pager'),
|
||||
('personalSignature', 'personalSignature'),
|
||||
('personalTitle', 'personalTitle'),
|
||||
('photo', 'photo'),
|
||||
('physicalDeliveryOfficeName', 'physicalDeliveryOfficeName'),
|
||||
('postOfficeBox', 'postOfficeBox'),
|
||||
('postalAddress', 'postalAddress'),
|
||||
('postalCode', 'postalCode'),
|
||||
('preferredDeliveryMethod', 'preferredDeliveryMethod'),
|
||||
('preferredLanguage', 'preferredLanguage'),
|
||||
('presentationAddress', 'presentationAddress'),
|
||||
('protocolInformation', 'protocolInformation'),
|
||||
('pseudonym', 'pseudonym'),
|
||||
('ref', 'ref'),
|
||||
('referral', 'referral'),
|
||||
('registeredAddress', 'registeredAddress'),
|
||||
('rfc822MailMember', 'rfc822MailMember'),
|
||||
('role', 'role'),
|
||||
('roleOccupant', 'roleOccupant'),
|
||||
('roomNumber', 'roomNumber'),
|
||||
('sOARecord', 'sOARecord'),
|
||||
('schacHomeOrganization', 'schacHomeOrganization'),
|
||||
('schacHomeOrganizationType', 'schacHomeOrganizationType'),
|
||||
('searchGuide', 'searchGuide'),
|
||||
('secretary', 'secretary'),
|
||||
('seeAlso', 'seeAlso'),
|
||||
('serialNumber', 'serialNumber'),
|
||||
('shadowExpire', 'shadowExpire'),
|
||||
('shadowFlag', 'shadowFlag'),
|
||||
('shadowInactive', 'shadowInactive'),
|
||||
('shadowLastChange', 'shadowLastChange'),
|
||||
('shadowMax', 'shadowMax'),
|
||||
('shadowMin', 'shadowMin'),
|
||||
('shadowWarning', 'shadowWarning'),
|
||||
('singleLevelQuality', 'singleLevelQuality'),
|
||||
('sn', 'sn'),
|
||||
('st', 'st'),
|
||||
('street', 'street'),
|
||||
('structuralObjectClass', 'structuralObjectClass'),
|
||||
('subentry', 'subentry'),
|
||||
('subschema', 'subschema'),
|
||||
('subschemaSubentry', 'subschemaSubentry'),
|
||||
('subtreeMaximumQuality', 'subtreeMaximumQuality'),
|
||||
('subtreeMinimumQuality', 'subtreeMinimumQuality'),
|
||||
('subtreeSpecification', 'subtreeSpecification'),
|
||||
('supannActivite', 'supannActivite'),
|
||||
('supannAffectation', 'supannAffectation'),
|
||||
('supannAliasLogin', 'supannAliasLogin'),
|
||||
('supannAutreMail', 'supannAutreMail'),
|
||||
('supannAutreTelephone', 'supannAutreTelephone'),
|
||||
('supannCivilite', 'supannCivilite'),
|
||||
('supannCodeEntite', 'supannCodeEntite'),
|
||||
('supannCodeEntiteParent', 'supannCodeEntiteParent'),
|
||||
('supannCodeINE', 'supannCodeINE'),
|
||||
('supannEmpCorps', 'supannEmpCorps'),
|
||||
('supannEmpId', 'supannEmpId'),
|
||||
('supannEntiteAffectation', 'supannEntiteAffectation'),
|
||||
('supannEntiteAffectationPrincipale', 'supannEntiteAffectationPrincipale'),
|
||||
('supannEtablissement', 'supannEtablissement'),
|
||||
('supannEtuAnneeInscription', 'supannEtuAnneeInscription'),
|
||||
('supannEtuCursusAnnee', 'supannEtuCursusAnnee'),
|
||||
('supannEtuDiplome', 'supannEtuDiplome'),
|
||||
('supannEtuElementPedagogique', 'supannEtuElementPedagogique'),
|
||||
('supannEtuEtape', 'supannEtuEtape'),
|
||||
('supannEtuId', 'supannEtuId'),
|
||||
('supannEtuInscription', 'supannEtuInscription'),
|
||||
('supannEtuRegimeInscription', 'supannEtuRegimeInscription'),
|
||||
('supannEtuSecteurDisciplinaire', 'supannEtuSecteurDisciplinaire'),
|
||||
('supannEtuTypeDiplome', 'supannEtuTypeDiplome'),
|
||||
('supannGroupeAdminDN', 'supannGroupeAdminDN'),
|
||||
('supannGroupeDateFin', 'supannGroupeDateFin'),
|
||||
('supannGroupeLecteurDN', 'supannGroupeLecteurDN'),
|
||||
('supannListeRouge', 'supannListeRouge'),
|
||||
('supannMailPerso', 'supannMailPerso'),
|
||||
('supannOrganisme', 'supannOrganisme'),
|
||||
('supannParrainDN', 'supannParrainDN'),
|
||||
('supannRefId', 'supannRefId'),
|
||||
('supannRole', 'supannRole'),
|
||||
('supannRoleEntite', 'supannRoleEntite'),
|
||||
('supannRoleGenerique', 'supannRoleGenerique'),
|
||||
('supannTypeEntite', 'supannTypeEntite'),
|
||||
('supannTypeEntiteAffectation', 'supannTypeEntiteAffectation'),
|
||||
('superiorUUID', 'superiorUUID'),
|
||||
('supportedAlgorithms', 'supportedAlgorithms'),
|
||||
('supportedApplicationContext', 'supportedApplicationContext'),
|
||||
('supportedAuthPasswordSchemes', 'supportedAuthPasswordSchemes'),
|
||||
('supportedControl', 'supportedControl'),
|
||||
('supportedExtension', 'supportedExtension'),
|
||||
('supportedFeatures', 'supportedFeatures'),
|
||||
('supportedLDAPVersion', 'supportedLDAPVersion'),
|
||||
('supportedSASLMechanisms', 'supportedSASLMechanisms'),
|
||||
('syncConsumerSubentry', 'syncConsumerSubentry'),
|
||||
('syncProviderSubentry', 'syncProviderSubentry'),
|
||||
('syncTimestamp', 'syncTimestamp'),
|
||||
('syncreplCookie', 'syncreplCookie'),
|
||||
('telephoneNumber', 'telephoneNumber'),
|
||||
('teletexTerminalIdentifier', 'teletexTerminalIdentifier'),
|
||||
('telexNumber', 'telexNumber'),
|
||||
('textEncodedORAddress', 'textEncodedORAddress'),
|
||||
('title', 'title'),
|
||||
('top', 'top'),
|
||||
('uid', 'uid'),
|
||||
('uidNumber', 'uidNumber'),
|
||||
('uniqueIdentifier', 'uniqueIdentifier'),
|
||||
('uniqueMember', 'uniqueMember'),
|
||||
('userCertificate', 'userCertificate'),
|
||||
('userClass', 'userClass'),
|
||||
('userPKCS12', 'userPKCS12'),
|
||||
('userPassword', 'userPassword'),
|
||||
('userSMIMECertificate', 'userSMIMECertificate'),
|
||||
('vendorName', 'vendorName'),
|
||||
('vendorVersion', 'vendorVersion'),
|
||||
('x121Address', 'x121Address'),
|
||||
('x500UniqueIdentifier', 'x500UniqueIdentifier'),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
'output_name_format',
|
||||
models.CharField(
|
||||
default=('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', 'SAMLv2 URI'),
|
||||
max_length=100,
|
||||
verbose_name='Output name format',
|
||||
choices=[
|
||||
('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', 'SAMLv2 URI'),
|
||||
('urn:oasis:names:tc:SAML:2.0:attrname-format:basic', 'SAMLv2 BASIC'),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
'output_namespace',
|
||||
models.CharField(
|
||||
default=('Default', 'Default'),
|
||||
max_length=100,
|
||||
verbose_name='Output namespace',
|
||||
choices=[
|
||||
('Default', 'Default'),
|
||||
(
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims',
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
('required', models.BooleanField(default=False, verbose_name='Required')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'attribute list item',
|
||||
'verbose_name_plural': 'attribute list items',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AttributeList',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('name', models.CharField(unique=True, max_length=100, verbose_name='Name')),
|
||||
(
|
||||
'attributes',
|
||||
models.ManyToManyField(
|
||||
related_name='attributes of the list',
|
||||
null=True,
|
||||
verbose_name='Attributes',
|
||||
to='attribute_aggregator.AttributeItem',
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'attribute list',
|
||||
'verbose_name_plural': 'attribute lists',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AttributeSource',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('name', models.CharField(unique=True, max_length=200, verbose_name='Name')),
|
||||
(
|
||||
'namespace',
|
||||
models.CharField(
|
||||
default=('Default', 'Default'),
|
||||
max_length=100,
|
||||
verbose_name='Namespace',
|
||||
choices=[
|
||||
('Default', 'Default'),
|
||||
(
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims',
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'attribute source',
|
||||
'verbose_name_plural': 'attribute sources',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LdapSource',
|
||||
fields=[
|
||||
(
|
||||
'attributesource_ptr',
|
||||
models.OneToOneField(
|
||||
parent_link=True,
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to='attribute_aggregator.AttributeSource',
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
('server', models.CharField(unique=True, max_length=200, verbose_name='Server')),
|
||||
('user', models.CharField(max_length=200, null=True, verbose_name='User', blank=True)),
|
||||
(
|
||||
'password',
|
||||
models.CharField(max_length=200, null=True, verbose_name='Password', blank=True),
|
||||
),
|
||||
('base', models.CharField(max_length=200, verbose_name='Base')),
|
||||
('port', models.IntegerField(default=389, verbose_name='Port')),
|
||||
('ldaps', models.BooleanField(default=False, verbose_name='LDAPS')),
|
||||
('certificate', models.TextField(verbose_name='Certificate', blank=True)),
|
||||
(
|
||||
'is_auth_backend',
|
||||
models.BooleanField(default=False, verbose_name='Is it used for authentication?'),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'ldap attribute source',
|
||||
'verbose_name_plural': 'ldap attribute sources',
|
||||
},
|
||||
bases=('attribute_aggregator.attributesource',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserAliasInSource',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('name', models.CharField(max_length=200, verbose_name='Name')),
|
||||
(
|
||||
'source',
|
||||
models.ForeignKey(
|
||||
verbose_name='attribute source',
|
||||
to='attribute_aggregator.AttributeSource',
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
related_name='user_alias_in_source',
|
||||
verbose_name='user',
|
||||
to='auth.User',
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user alias from source',
|
||||
'verbose_name_plural': 'user aliases from source',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserAttributeProfile',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('data', models.TextField(null=True, blank=True)),
|
||||
(
|
||||
'user',
|
||||
models.OneToOneField(
|
||||
related_name='user_attribute_profile',
|
||||
null=True,
|
||||
blank=True,
|
||||
to='auth.User',
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user attribute profile',
|
||||
'verbose_name_plural': 'user attribute profiles',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='useraliasinsource',
|
||||
unique_together={('name', 'source')},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='attributeitem',
|
||||
name='source',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='Attribute source',
|
||||
blank=True,
|
||||
to='attribute_aggregator.AttributeSource',
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -1,35 +0,0 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('attribute_aggregator', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='useraliasinsource',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
related_name='user_alias_in_source',
|
||||
verbose_name='user',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userattributeprofile',
|
||||
name='user',
|
||||
field=models.OneToOneField(
|
||||
related_name='user_attribute_profile',
|
||||
null=True,
|
||||
blank=True,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -1,25 +0,0 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('attribute_aggregator', '0002_auto_20150409_1840'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='attributelist',
|
||||
name='attributes',
|
||||
field=models.ManyToManyField(
|
||||
to='attribute_aggregator.AttributeItem', verbose_name='Attributes', blank=True
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='useraliasinsource',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,57 +0,0 @@
|
|||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('idp', '0003_auto_20150915_2041'),
|
||||
('attribute_aggregator', '0003_auto_20150526_2239'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='attributeitem',
|
||||
name='source',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='attributelist',
|
||||
name='attributes',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='AttributeItem',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='AttributeList',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='ldapsource',
|
||||
name='attributesource_ptr',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='useraliasinsource',
|
||||
unique_together=None,
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='useraliasinsource',
|
||||
name='source',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='LdapSource',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='AttributeSource',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='useraliasinsource',
|
||||
name='user',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='UserAliasInSource',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='userattributeprofile',
|
||||
name='user',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='UserAttributeProfile',
|
||||
),
|
||||
]
|
|
@ -14,10 +14,10 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from authentic2.a2_rbac.models import Role
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
from ...decorators import to_list
|
||||
from ...models import Attribute, AttributeValue
|
||||
|
@ -33,7 +33,6 @@ def get_instances(ctx):
|
|||
|
||||
@to_list
|
||||
def get_attribute_names(instance, ctx):
|
||||
User = get_user_model()
|
||||
for field in User._meta.fields:
|
||||
if field.name == 'ou':
|
||||
continue
|
||||
|
@ -69,7 +68,6 @@ def get_dependencies(instance, ctx):
|
|||
|
||||
def get_attributes(instance, ctx):
|
||||
user = ctx.get('user')
|
||||
User = get_user_model()
|
||||
if not user or not isinstance(user, User):
|
||||
return ctx
|
||||
for field in User._meta.fields:
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
from django.core import validators
|
||||
from django.db import migrations, models
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('contenttypes', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Permission',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('name', models.CharField(max_length=50, verbose_name='name')),
|
||||
(
|
||||
'content_type',
|
||||
models.ForeignKey(to='contenttypes.ContentType', to_field='id', on_delete=models.CASCADE),
|
||||
),
|
||||
('codename', models.CharField(max_length=100, verbose_name='codename')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('content_type__app_label', 'content_type__model', 'codename'),
|
||||
'verbose_name': 'permission',
|
||||
'verbose_name_plural': 'permissions',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Group',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('name', models.CharField(unique=True, max_length=80, verbose_name='name')),
|
||||
(
|
||||
'permissions',
|
||||
models.ManyToManyField(to='auth.Permission', verbose_name='permissions', blank=True),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'group',
|
||||
'verbose_name_plural': 'groups',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
pmarillonnet marked this conversation as resolved
Outdated
pmarillonnet
commented
Ok, j’ignorais que Ok, j’ignorais que `auth_migrations_18` avait défini autant de modèles à un moment. Dégageons tout cela oui.
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(default=timezone.now, verbose_name='last login')),
|
||||
(
|
||||
'is_superuser',
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text=(
|
||||
'Designates that this user has all permissions without explicitly assigning them.'
|
||||
),
|
||||
verbose_name='superuser status',
|
||||
),
|
||||
),
|
||||
(
|
||||
'username',
|
||||
models.CharField(
|
||||
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
|
||||
unique=True,
|
||||
max_length=30,
|
||||
verbose_name='username',
|
||||
validators=[
|
||||
validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')
|
||||
],
|
||||
),
|
||||
),
|
||||
('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
|
||||
('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
|
||||
('email', models.EmailField(max_length=75, verbose_name='email address', blank=True)),
|
||||
(
|
||||
'is_staff',
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text='Designates whether the user can log into this admin site.',
|
||||
verbose_name='staff status',
|
||||
),
|
||||
),
|
||||
(
|
||||
'is_active',
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text=(
|
||||
'Designates whether this user should be treated as active. Unselect this instead'
|
||||
' of deleting accounts.'
|
||||
),
|
||||
verbose_name='active',
|
||||
),
|
||||
),
|
||||
('date_joined', models.DateTimeField(default=timezone.now, verbose_name='date joined')),
|
||||
(
|
||||
'groups',
|
||||
models.ManyToManyField(
|
||||
to='auth.Group',
|
||||
verbose_name='groups',
|
||||
blank=True,
|
||||
help_text=(
|
||||
'The groups this user belongs to. A user will get all permissions granted to each'
|
||||
' of his/her group.'
|
||||
),
|
||||
related_name='+',
|
||||
related_query_name='+',
|
||||
),
|
||||
),
|
||||
(
|
||||
'user_permissions',
|
||||
models.ManyToManyField(
|
||||
to='auth.Permission',
|
||||
verbose_name='user permissions',
|
||||
blank=True,
|
||||
help_text='Specific permissions for this user.',
|
||||
related_name='+',
|
||||
related_query_name='+',
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,30 +0,0 @@
|
|||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='username',
|
||||
field=models.CharField(
|
||||
help_text=(
|
||||
'Required, 255 characters or fewer. Only letters, numbers, and @, ., +, -, or _'
|
||||
' characters.'
|
||||
),
|
||||
unique=True,
|
||||
max_length=255,
|
||||
verbose_name='username',
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
'^[\\w.@+-]+$', 'Enter a valid username.', 'invalid'
|
||||
)
|
||||
],
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -1,13 +0,0 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('auth', '0002_auto_20150323_1720'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel('User'),
|
||||
]
|
|
@ -1,111 +0,0 @@
|
|||
import django.core.validators
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0003_auto_20150410_1657'),
|
||||
('authentic2', '__first__'),
|
||||
('authentic2_idp_cas', '__first__'),
|
||||
('saml', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
(
|
||||
'last_login',
|
||||
models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login'),
|
||||
),
|
||||
(
|
||||
'is_superuser',
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text=(
|
||||
'Designates that this user has all permissions without explicitly assigning them.'
|
||||
),
|
||||
verbose_name='superuser status',
|
||||
),
|
||||
),
|
||||
(
|
||||
'username',
|
||||
models.CharField(
|
||||
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
|
||||
unique=True,
|
||||
max_length=30,
|
||||
verbose_name='username',
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
'^[\\w.@+-]+$', 'Enter a valid username.', 'invalid'
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
|
||||
('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
|
||||
('email', models.EmailField(max_length=75, verbose_name='email address', blank=True)),
|
||||
(
|
||||
'is_staff',
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text='Designates whether the user can log into this admin site.',
|
||||
verbose_name='staff status',
|
||||
),
|
||||
),
|
||||
(
|
||||
'is_active',
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text=(
|
||||
'Designates whether this user should be treated as active. Unselect this instead'
|
||||
' of deleting accounts.'
|
||||
),
|
||||
verbose_name='active',
|
||||
),
|
||||
),
|
||||
(
|
||||
'date_joined',
|
||||
models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined'),
|
||||
),
|
||||
(
|
||||
'groups',
|
||||
models.ManyToManyField(
|
||||
related_query_name='user',
|
||||
related_name='user_set',
|
||||
to='auth.Group',
|
||||
blank=True,
|
||||
help_text=(
|
||||
'The groups this user belongs to. A user will get all permissions granted to each'
|
||||
' of his/her group.'
|
||||
),
|
||||
verbose_name='groups',
|
||||
),
|
||||
),
|
||||
(
|
||||
'user_permissions',
|
||||
models.ManyToManyField(
|
||||
related_query_name='user',
|
||||
related_name='user_set',
|
||||
to='auth.Permission',
|
||||
blank=True,
|
||||
help_text='Specific permissions for this user.',
|
||||
verbose_name='user permissions',
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
'verbose_name': 'user',
|
||||
'swappable': 'AUTH_USER_MODEL',
|
||||
'verbose_name_plural': 'users',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -1,79 +0,0 @@
|
|||
import django.contrib.auth.models
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0004_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelManagers(
|
||||
name='group',
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.GroupManager()),
|
||||
],
|
||||
),
|
||||
migrations.AlterModelManagers(
|
||||
name='permission',
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.PermissionManager()),
|
||||
],
|
||||
),
|
||||
migrations.AlterModelManagers(
|
||||
name='user',
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='permission',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255, verbose_name='name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='email',
|
||||
field=models.EmailField(max_length=254, verbose_name='email address', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='groups',
|
||||
field=models.ManyToManyField(
|
||||
related_query_name='user',
|
||||
related_name='user_set',
|
||||
to='auth.Group',
|
||||
blank=True,
|
||||
help_text=(
|
||||
'The groups this user belongs to. A user will get all permissions granted to each of'
|
||||
' their groups.'
|
||||
),
|
||||
verbose_name='groups',
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='last_login',
|
||||
field=models.DateTimeField(null=True, verbose_name='last login', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='username',
|
||||
field=models.CharField(
|
||||
error_messages={'unique': 'A user with that username already exists.'},
|
||||
max_length=30,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
'^[\\w.@+-]+$',
|
||||
'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_'
|
||||
' characters.',
|
||||
'invalid',
|
||||
)
|
||||
],
|
||||
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
|
||||
unique=True,
|
||||
verbose_name='username',
|
||||
),
|
||||
),
|
||||
]
|
|
@ -14,13 +14,11 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from authentic2 import app_settings
|
||||
|
||||
|
||||
def get_user_queryset():
|
||||
User = get_user_model()
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
qs = User.objects.all()
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ import ldap.modlist
|
|||
import ldap.sasl
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
@ -52,6 +51,7 @@ from authentic2.a2_rbac.models import OrganizationalUnit, Role
|
|||
from authentic2.a2_rbac.utils import get_default_ou
|
||||
from authentic2.backends import is_user_authenticable
|
||||
from authentic2.compat_lasso import lasso
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.ldap_utils import FilterFormatter
|
||||
from authentic2.middleware import StoreRequestMiddleware
|
||||
from authentic2.models import Lock, UserExternalId
|
||||
|
@ -65,8 +65,6 @@ from authentic2.utils.misc import PasswordChangeError, get_password_authenticato
|
|||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
DEFAULT_CA_BUNDLE = ''
|
||||
|
||||
CA_BUNDLE_PATHS = [
|
||||
|
@ -393,24 +391,24 @@ class LDAPUser(User):
|
|||
log.warning('ldap: check_password failed, could not get a connection')
|
||||
return False
|
||||
|
||||
def set_password(self, new_password):
|
||||
def set_password(self, raw_password):
|
||||
# Allow change password to work in all cases, as the form does a check_password() first
|
||||
# if the verify pass, we have the old password stored in self._current_password
|
||||
_current_password = getattr(self, '_current_password', None) or self.get_password_in_session()
|
||||
if _current_password != new_password:
|
||||
if _current_password != raw_password:
|
||||
conn = self.get_connection()
|
||||
if not conn:
|
||||
log.warning('ldap: set_password failed, could not get a connection')
|
||||
return
|
||||
try:
|
||||
self.ldap_backend.modify_password(conn, self.block, self.dn, _current_password, new_password)
|
||||
self.ldap_backend.modify_password(conn, self.block, self.dn, _current_password, raw_password)
|
||||
except ldap.LDAPError as e:
|
||||
log.warning('ldap: set_password failed (%s)', ldap_error_str(e))
|
||||
raise PasswordChangeError(_('LDAP directory refused the password change.'))
|
||||
self._current_password = new_password
|
||||
self.keep_password_in_session(new_password)
|
||||
self._current_password = raw_password
|
||||
self.keep_password_in_session(raw_password)
|
||||
if self.block['keep_password']:
|
||||
super().set_password(new_password)
|
||||
super().set_password(raw_password)
|
||||
else:
|
||||
self.set_unusable_password()
|
||||
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
|
||||
import functools
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.backends import ModelBackend as BaseModelBackend
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from phonenumbers import PhoneNumberFormat, format_number, is_valid_number
|
||||
|
||||
from authentic2.backends import get_user_queryset
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.models import AttributeValue
|
||||
from authentic2.user_login_failure import user_login_failure, user_login_success
|
||||
from authentic2.utils.misc import get_password_authenticator, parse_phone_number
|
||||
|
@ -40,15 +40,11 @@ PROXY_USER_MODEL = None
|
|||
|
||||
|
||||
class ModelBackend(BaseModelBackend):
|
||||
"""
|
||||
Authenticates against settings.AUTH_USER_MODEL.
|
||||
"""
|
||||
|
||||
def get_query(self, username, realm=None, ou=None):
|
||||
username_field = 'username'
|
||||
queries = []
|
||||
password_authenticator = get_password_authenticator()
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
user_ct = ContentType.objects.get_for_model(User)
|
||||
if password_authenticator.accept_email_authentication:
|
||||
queries.append(models.Q(**{'email__iexact': username}))
|
||||
if password_authenticator.is_phone_authn_active:
|
||||
|
@ -82,14 +78,13 @@ class ModelBackend(BaseModelBackend):
|
|||
return bool(a2_models.PasswordReset.filter(user=user).count())
|
||||
|
||||
def authenticate(self, request, username=None, password=None, realm=None, ou=None):
|
||||
UserModel = get_user_model()
|
||||
if not username:
|
||||
return
|
||||
query = self.get_query(username=username, realm=realm, ou=ou)
|
||||
users = get_user_queryset().filter(query)
|
||||
# order by username to make username without realm come before usernames with realms
|
||||
# i.e. "toto" should come before "toto@example.com"
|
||||
users = users.order_by('-is_active', UserModel.USERNAME_FIELD, 'id')
|
||||
users = users.order_by('-is_active', User.USERNAME_FIELD, 'id')
|
||||
for user in users:
|
||||
if user.check_password(password):
|
||||
user_login_success(user.get_username())
|
||||
|
@ -100,10 +95,9 @@ class ModelBackend(BaseModelBackend):
|
|||
request.failed_logins.update({user: {}})
|
||||
|
||||
def get_user(self, user_id):
|
||||
UserModel = get_user_model()
|
||||
try:
|
||||
user = UserModel._default_manager.get(pk=user_id)
|
||||
except UserModel.DoesNotExist:
|
||||
user = User._default_manager.get(pk=user_id)
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
return user
|
||||
|
||||
|
|
|
@ -38,12 +38,12 @@ class CustomUserConfig(AppConfig):
|
|||
self, app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs
|
||||
):
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import translation
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from authentic2.attribute_kinds import get_kind
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.models import Attribute, AttributeValue
|
||||
|
||||
if not router.allow_migrate(using, Attribute):
|
||||
|
@ -53,7 +53,6 @@ class CustomUserConfig(AppConfig):
|
|||
return
|
||||
|
||||
translation.activate(settings.LANGUAGE_CODE)
|
||||
User = get_user_model()
|
||||
content_type = ContentType.objects.get_for_model(User)
|
||||
|
||||
attrs = {}
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
|
||||
import getpass
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import MultipleObjectsReturned
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import DEFAULT_DB_ALIAS
|
||||
from django.db.models.query import Q
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Change a user's password for django.contrib.auth."
|
||||
|
@ -51,13 +52,11 @@ class Command(BaseCommand):
|
|||
if not username:
|
||||
username = getpass.getuser()
|
||||
|
||||
UserModel = get_user_model()
|
||||
|
||||
qs = UserModel._default_manager.using(options.get('database'))
|
||||
qs = User._default_manager.using(options.get('database'))
|
||||
qs = qs.filter(Q(uuid=username) | Q(username=username) | Q(email__iexact=username))
|
||||
try:
|
||||
u = qs.get()
|
||||
except UserModel.DoesNotExist:
|
||||
except User.DoesNotExist:
|
||||
raise CommandError("user '%s' does not exist" % username)
|
||||
except MultipleObjectsReturned:
|
||||
while True:
|
||||
|
|
|
@ -5,80 +5,6 @@ import authentic2.utils.misc
|
|||
import authentic2.validators
|
||||
|
||||
|
||||
def noop(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
def copy_old_users_to_custom_user_model(apps, schema_editor):
|
||||
OldUser = apps.get_model('auth', 'User')
|
||||
NewUser = apps.get_model('custom_user', 'User')
|
||||
fields = [
|
||||
'id',
|
||||
'username',
|
||||
'email',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'date_joined',
|
||||
'is_superuser',
|
||||
'last_login',
|
||||
'password',
|
||||
]
|
||||
old_users = OldUser.objects.prefetch_related('groups', 'user_permissions').order_by('id')
|
||||
new_users = []
|
||||
for old_user in old_users:
|
||||
new_user = NewUser()
|
||||
for field in fields:
|
||||
setattr(new_user, field, getattr(old_user, field))
|
||||
new_users.append(new_user)
|
||||
# mass create of new users
|
||||
NewUser.objects.bulk_create(new_users)
|
||||
new_groups = []
|
||||
new_permissions = []
|
||||
GroupThrough = NewUser.groups.through
|
||||
PermissionThrough = NewUser.user_permissions.through
|
||||
new_users = NewUser.objects.order_by('id')
|
||||
for old_user, new_user in zip(old_users, new_users):
|
||||
assert old_user.id == new_user.id
|
||||
for group in old_user.groups.all():
|
||||
new_groups.append(GroupThrough(user_id=new_user.id, group_id=group.id))
|
||||
for dummy in old_user.user_permissions.all():
|
||||
new_permissions.append(PermissionThrough(user_id=new_user.id, group_id=group.id))
|
||||
# mass create group and permission relations
|
||||
GroupThrough.objects.bulk_create(new_groups)
|
||||
PermissionThrough.objects.bulk_create(new_permissions)
|
||||
# Reset sequences
|
||||
if schema_editor.connection.vendor == 'postgresql':
|
||||
schema_editor.execute(
|
||||
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user_groups"\',\'id\'), coalesce(max("id"),'
|
||||
' 1), max("id") IS NOT null) FROM "custom_user_user_groups";'
|
||||
)
|
||||
schema_editor.execute(
|
||||
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user_user_permissions"\',\'id\'),'
|
||||
' coalesce(max("id"), 1), max("id") IS NOT null) FROM "custom_user_user_user_permissions";'
|
||||
)
|
||||
schema_editor.execute(
|
||||
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user"\',\'id\'), coalesce(max("id"), 1),'
|
||||
' max("id") IS NOT null) FROM "custom_user_user";'
|
||||
)
|
||||
elif schema_editor.connection.vendor == 'sqlite':
|
||||
schema_editor.execute(
|
||||
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user) WHERE name ='
|
||||
' "custom_user_user";'
|
||||
)
|
||||
schema_editor.execute(
|
||||
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user_groups) WHERE name ='
|
||||
' "custom_user_user_groups";'
|
||||
)
|
||||
schema_editor.execute(
|
||||
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user_user_permissions) WHERE'
|
||||
' name = "custom_user_user_permissions";'
|
||||
)
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '__first__'),
|
||||
|
@ -187,5 +113,4 @@ class Migration(migrations.Migration):
|
|||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.RunPython(copy_old_users_to_custom_user_model, reverse_code=noop),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
@ -40,17 +39,13 @@ class Migration(migrations.Migration):
|
|||
('admin', '__first__'),
|
||||
]
|
||||
|
||||
run_before = [
|
||||
('auth', '0003_auto_20150410_1657'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Django admin log
|
||||
ThirdPartyAlterField(
|
||||
app_label='admin',
|
||||
model_name='logentry',
|
||||
name='user',
|
||||
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
|
||||
field=models.ForeignKey(to='custom_user.User', on_delete=models.CASCADE),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,7 +4,6 @@ import uuid
|
|||
|
||||
import django
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.db.models import JSONField
|
||||
|
||||
|
@ -64,7 +63,7 @@ class Migration(migrations.Migration):
|
|||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='profiles',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
verbose_name='user',
|
||||
),
|
||||
),
|
||||
|
|
|
@ -19,13 +19,13 @@ from collections import OrderedDict
|
|||
|
||||
from django import forms
|
||||
from django.contrib.auth import forms as auth_forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.forms import Form
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from authentic2.backends.ldap_backend import LDAPUser
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.journal import journal
|
||||
from authentic2.passwords import validate_password
|
||||
from authentic2.utils.misc import get_password_authenticator
|
||||
|
@ -92,7 +92,7 @@ class PasswordResetForm(HoneypotForm):
|
|||
|
||||
def clean_phone(self):
|
||||
phone = self.cleaned_data.get('phone')
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
user_ct = ContentType.objects.get_for_model(User)
|
||||
if phone:
|
||||
user_ids = models.AttributeValue.objects.filter(
|
||||
attribute=self.authenticator.phone_identifier_field,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import BaseUserManager
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import RegexValidator
|
||||
|
@ -26,6 +25,7 @@ from django.utils.translation import gettext
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from authentic2.a2_rbac.models import OrganizationalUnit
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.forms.fields import CharField, CheckPasswordField, NewPasswordField
|
||||
from authentic2.passwords import validate_password
|
||||
|
||||
|
@ -36,8 +36,6 @@ from .fields import PhoneField, ValidatedEmailField
|
|||
from .honeypot import HoneypotForm
|
||||
from .utils import NextUrlFormMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class RegistrationForm(HoneypotForm):
|
||||
error_css_class = 'form-field-error'
|
||||
|
|
|
@ -31,7 +31,6 @@ import uuid
|
|||
import phonenumbers
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.forms.widgets import ClearableFileInput, DateInput, DateTimeInput
|
||||
from django.forms.widgets import EmailInput as BaseEmailInput
|
||||
from django.forms.widgets import MultiWidget
|
||||
|
@ -377,9 +376,11 @@ class SelectAttributeWidget(forms.Select):
|
|||
|
||||
@staticmethod
|
||||
def get_options():
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
choices = {}
|
||||
for name in ('email', 'username', 'first_name', 'last_name'):
|
||||
field = get_user_model()._meta.get_field(name)
|
||||
field = User._meta.get_field(name)
|
||||
choices[name] = '%s (%s)' % (capfirst(field.verbose_name), name)
|
||||
for attribute in Attribute.objects.exclude(name__in=choices):
|
||||
choices[attribute.name] = '%s (%s)' % (attribute.label, attribute.name)
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
|
||||
|
||||
@login_required
|
||||
def consent_federation(request, nonce='', provider_id=None):
|
||||
"""On a GET produce a form asking for consentment,
|
||||
On a POST handle the form and redirect to next"""
|
||||
if request.method == 'GET':
|
||||
return render(
|
||||
request,
|
||||
'interaction/consent_federation.html',
|
||||
pmarillonnet marked this conversation as resolved
Outdated
pmarillonnet
commented
On pourrait en profiter pour dégager ce gabarit aussi. On pourrait en profiter pour dégager ce gabarit aussi.
bdauvergne
commented
Bonne idée. Bonne idée.
|
||||
{
|
||||
'provider_id': request.GET.get('provider_id', ''),
|
||||
'nonce': request.GET.get('nonce', ''),
|
||||
'next': request.GET.get('next', ''),
|
||||
},
|
||||
)
|
||||
else:
|
||||
next_url = '/'
|
||||
if 'next' in request.POST:
|
||||
next_url = request.POST['next']
|
||||
if 'accept' in request.POST:
|
||||
next_url = next_url + '&consent_answer=accepted'
|
||||
return HttpResponseRedirect(next_url)
|
||||
else:
|
||||
next_url = next_url + '&consent_answer=refused'
|
||||
return HttpResponseRedirect(next)
|
|
@ -1,122 +0,0 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('attribute_aggregator', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AttributePolicy',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('name', models.CharField(unique=True, max_length=100)),
|
||||
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
|
||||
(
|
||||
'ask_consent_attributes',
|
||||
models.BooleanField(
|
||||
default=True, verbose_name='Ask the user consent before forwarding attributes'
|
||||
),
|
||||
),
|
||||
(
|
||||
'allow_attributes_selection',
|
||||
models.BooleanField(
|
||||
default=True, verbose_name='Allow the user to select the forwarding attributes'
|
||||
),
|
||||
),
|
||||
(
|
||||
'forward_attributes_from_push_sources',
|
||||
models.BooleanField(default=False, verbose_name='Forward pushed attributes'),
|
||||
),
|
||||
(
|
||||
'map_attributes_from_push_sources',
|
||||
models.BooleanField(default=False, verbose_name='Map forwarded pushed attributes'),
|
||||
),
|
||||
(
|
||||
'output_name_format',
|
||||
models.CharField(
|
||||
default=('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', 'SAMLv2 URI'),
|
||||
max_length=100,
|
||||
verbose_name='Output name format',
|
||||
choices=[
|
||||
('urn:oasis:names:tc:SAML:2.0:attrname-format:uri', 'SAMLv2 URI'),
|
||||
('urn:oasis:names:tc:SAML:2.0:attrname-format:basic', 'SAMLv2 BASIC'),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
'output_namespace',
|
||||
models.CharField(
|
||||
default=('Default', 'Default'),
|
||||
max_length=100,
|
||||
verbose_name='Output namespace',
|
||||
choices=[
|
||||
('Default', 'Default'),
|
||||
(
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims',
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
'filter_source_of_filtered_attributes',
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
verbose_name='Filter by source and per attribute the forwarded pushed attributes',
|
||||
),
|
||||
),
|
||||
(
|
||||
'map_attributes_of_filtered_attributes',
|
||||
models.BooleanField(default=False, verbose_name='Map filtered attributes'),
|
||||
),
|
||||
(
|
||||
'send_error_and_no_attrs_if_missing_required_attrs',
|
||||
models.BooleanField(
|
||||
default=False, verbose_name='Send an error when a required attribute is missing'
|
||||
),
|
||||
),
|
||||
(
|
||||
'attribute_filter_for_sso_from_push_sources',
|
||||
models.ForeignKey(
|
||||
related_name='filter attributes of push sources with list',
|
||||
verbose_name='Filter by attribute names the forwarded pushed attributes',
|
||||
blank=True,
|
||||
to='attribute_aggregator.AttributeList',
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
(
|
||||
'attribute_list_for_sso_from_pull_sources',
|
||||
models.ForeignKey(
|
||||
related_name='attributes from pull sources',
|
||||
verbose_name='Pull attributes list',
|
||||
blank=True,
|
||||
to='attribute_aggregator.AttributeList',
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
(
|
||||
'source_filter_for_sso_from_push_sources',
|
||||
models.ManyToManyField(
|
||||
related_name='filter attributes of push sources with sources',
|
||||
null=True,
|
||||
verbose_name='Filter by source the forwarded pushed attributes',
|
||||
to='attribute_aggregator.AttributeSource',
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'attribute policy',
|
||||
'verbose_name_plural': 'attribute policies',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -1,43 +0,0 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('idp', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='attributepolicy',
|
||||
name='attribute_filter_for_sso_from_push_sources',
|
||||
field=models.ForeignKey(
|
||||
related_name='+',
|
||||
verbose_name='Filter by attribute names the forwarded pushed attributes',
|
||||
blank=True,
|
||||
to='attribute_aggregator.AttributeList',
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='attributepolicy',
|
||||
name='attribute_list_for_sso_from_pull_sources',
|
||||
field=models.ForeignKey(
|
||||
related_name='+',
|
||||
verbose_name='Pull attributes list',
|
||||
blank=True,
|
||||
to='attribute_aggregator.AttributeList',
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='attributepolicy',
|
||||
name='source_filter_for_sso_from_push_sources',
|
||||
field=models.ManyToManyField(
|
||||
to='attribute_aggregator.AttributeSource',
|
||||
verbose_name='Filter by source the forwarded pushed attributes',
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,26 +0,0 @@
|
|||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('saml', '0016_auto_20150915_2041'),
|
||||
('idp', '0002_auto_20150526_2239'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='attributepolicy',
|
||||
name='attribute_filter_for_sso_from_push_sources',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='attributepolicy',
|
||||
name='attribute_list_for_sso_from_pull_sources',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='attributepolicy',
|
||||
name='source_filter_for_sso_from_push_sources',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='AttributePolicy',
|
||||
),
|
||||
]
|
|
@ -44,7 +44,7 @@ from urllib.parse import quote, urlencode
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY, REDIRECT_FIELD_NAME, get_user_model, load_backend
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY, REDIRECT_FIELD_NAME, load_backend
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect
|
||||
|
@ -62,6 +62,7 @@ from authentic2 import views as a2_views
|
|||
from authentic2.attributes_ng.engine import get_attributes
|
||||
from authentic2.compat_lasso import lasso
|
||||
from authentic2.constants import NONCE_FIELD_NAME
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.idp.saml.common import kill_django_sessions
|
||||
from authentic2.saml import saml2utils
|
||||
from authentic2.saml.common import (
|
||||
|
@ -118,8 +119,6 @@ from authentic2.views import passive_login
|
|||
|
||||
from . import app_settings
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.urls import re_path
|
||||
|
||||
from authentic2.idp.interactions import consent_federation
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^consent_federation', consent_federation, name='a2-consent-federation'),
|
||||
]
|
|
@ -20,7 +20,6 @@ import urllib.parse
|
|||
from datetime import timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from django.db.models import F, Q
|
||||
|
@ -30,14 +29,13 @@ from authentic2 import app_settings
|
|||
from authentic2.a2_rbac.models import OrganizationalUnit
|
||||
from authentic2.backends import get_user_queryset
|
||||
from authentic2.backends.ldap_backend import LDAPBackend
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.journal_event_types import UserDeletionForInactivity, UserNotificationInactivity
|
||||
from authentic2.utils import sms as utils_sms
|
||||
from authentic2.utils.misc import get_password_authenticator, send_templated_mail
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '''Clean unused accounts'''
|
||||
|
|
|
@ -19,10 +19,10 @@ import json
|
|||
import logging
|
||||
|
||||
import ldif
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.transaction import atomic
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.hashers import olap_password_to_dj
|
||||
from authentic2.models import Attribute
|
||||
|
||||
|
@ -44,7 +44,6 @@ class DjangoUserLDIFParser(ldif.LDIFParser):
|
|||
ldif.LDIFParser.__init__(self, *args, **kwargs)
|
||||
|
||||
def handle(self, dn, entry):
|
||||
User = get_user_model()
|
||||
if self.object_class not in entry['objectClass']:
|
||||
if self.verbosity >= 2:
|
||||
self.command.stdout.write('Ignoring entry %r' % dn)
|
||||
|
|
|
@ -16,15 +16,13 @@
|
|||
|
||||
import getpass
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import DEFAULT_DB_ALIAS
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.models import PasswordReset
|
||||
from authentic2.utils.misc import generate_password
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Reset a user's password for django.contrib.auth."
|
||||
|
|
|
@ -20,11 +20,12 @@ import logging
|
|||
import re
|
||||
import sys
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand
|
||||
from ldap.dn import escape_dn_chars
|
||||
from ldif import LDIFWriter
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
COMMAND = 1
|
||||
ATTR = 2
|
||||
|
||||
|
@ -49,7 +50,7 @@ class Command(BaseCommand):
|
|||
if command == 'SEARCH':
|
||||
out = io.BytesIO()
|
||||
ldif_writer = LDIFWriter(out)
|
||||
qs = get_user_model().objects.all()
|
||||
qs = User.objects.all()
|
||||
if attrs['filter'] != '(objectClass=*)':
|
||||
m = re.match(r'\((\w*)=(.*)\)', attrs['filter'])
|
||||
if not m:
|
||||
|
|
|
@ -22,7 +22,6 @@ from collections import defaultdict
|
|||
from io import StringIO
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import validate_slug
|
||||
|
@ -36,6 +35,7 @@ from authentic2 import app_settings as a2_app_settings
|
|||
from authentic2.a2_rbac.models import OrganizationalUnit, Role
|
||||
from authentic2.a2_rbac.utils import generate_slug, get_default_ou
|
||||
from authentic2.custom_user.backends import DjangoRBACBackend
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.forms.fields import (
|
||||
CheckPasswordField,
|
||||
CommaSeparatedCharField,
|
||||
|
@ -57,7 +57,6 @@ from authentic2.validators import EmailValidator
|
|||
|
||||
from . import app_settings, fields, utils
|
||||
|
||||
User = get_user_model()
|
||||
ChooseRolesField = fields.ChooseRolesField
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -184,7 +183,7 @@ class UserEditForm(LimitQuerysetFormMixin, CssClass, BaseUserForm):
|
|||
if a2_app_settings.A2_PHONE_IS_UNIQUE:
|
||||
if (
|
||||
AttributeValue.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(get_user_model()),
|
||||
content_type=ContentType.objects.get_for_model(User),
|
||||
attribute=authn.phone_identifier_field,
|
||||
)
|
||||
.exclude(object_id=self.instance.id)
|
||||
|
@ -194,7 +193,7 @@ class UserEditForm(LimitQuerysetFormMixin, CssClass, BaseUserForm):
|
|||
elif getattr(self.instance.ou, 'phone_is_unique', False):
|
||||
other_owners = (
|
||||
AttributeValue.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(get_user_model()),
|
||||
content_type=ContentType.objects.get_for_model(User),
|
||||
attribute=authn.phone_identifier_field,
|
||||
)
|
||||
.exclude(object_id=self.instance.id)
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from authentic2.a2_rbac.models import Role
|
||||
|
@ -24,11 +23,9 @@ from authentic2.backends.ldap_backend import (
|
|||
LDAP_DEACTIVATION_REASON_NOT_PRESENT,
|
||||
LDAP_DEACTIVATION_REASON_OLD_SOURCE,
|
||||
)
|
||||
from authentic2.custom_user.models import DeletedUser
|
||||
from authentic2.custom_user.models import DeletedUser, User
|
||||
from authentic2.journal_event_types import EventTypeWithService, get_attributes_label
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class ManagerUserCreation(EventTypeDefinition):
|
||||
name = 'manager.user.creation'
|
||||
|
|
|
@ -18,7 +18,6 @@ import functools
|
|||
import uuid
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import EmailValidator
|
||||
|
@ -33,12 +32,10 @@ from authentic2.apps.journal.forms import JournalForm as BaseJournalForm
|
|||
from authentic2.apps.journal.models import EventType, n_2_pairing
|
||||
from authentic2.apps.journal.search_engine import JournalSearchEngine as BaseJournalSearchEngine
|
||||
from authentic2.apps.journal.views import JournalView
|
||||
from authentic2.custom_user.models import DeletedUser
|
||||
from authentic2.custom_user.models import DeletedUser, User
|
||||
|
||||
from . import views
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class JournalSearchEngine(BaseJournalSearchEngine):
|
||||
def search_by_uuid(self, lexem):
|
||||
|
|
|
@ -14,14 +14,12 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from import_export.fields import Field
|
||||
from import_export.resources import ModelResource
|
||||
from import_export.widgets import Widget
|
||||
|
||||
from authentic2.a2_rbac.models import Role
|
||||
|
||||
User = get_user_model()
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
|
||||
class ListWidget(Widget):
|
||||
|
|
|
@ -18,7 +18,6 @@ import json
|
|||
from functools import reduce
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import BadRequest, PermissionDenied, ValidationError
|
||||
from django.core.paginator import EmptyPage, Paginator
|
||||
|
@ -37,6 +36,7 @@ from authentic2 import data_transfer
|
|||
from authentic2.a2_rbac.models import OrganizationalUnit, Permission, Role, RoleParenting
|
||||
from authentic2.a2_rbac.utils import get_default_ou
|
||||
from authentic2.apps.journal.views import JournalViewWithContext
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.forms.profile import modelform_factory
|
||||
from authentic2.role_summary import get_roles_summary_cache
|
||||
from authentic2.utils import crypto, hooks
|
||||
|
@ -46,8 +46,6 @@ from . import forms, resources, tables, views
|
|||
from .journal_views import BaseJournalView
|
||||
from .utils import has_show_username, label_from_role, label_from_user
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class RolesMixin:
|
||||
service_roles = True
|
||||
|
@ -609,7 +607,7 @@ class RoleRemoveAdminUserView(
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
self.user = get_user_model().objects.get(pk=kwargs['user_pk'])
|
||||
self.user = User.objects.get(pk=kwargs['user_pk'])
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import django_tables2 as tables
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import CharField, OuterRef, Subquery
|
||||
from django.db.models.expressions import RawSQL
|
||||
|
@ -28,13 +27,12 @@ from django.utils.translation import gettext_noop
|
|||
from django_tables2.utils import A
|
||||
|
||||
from authentic2.a2_rbac.models import OrganizationalUnit, Role
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.middleware import StoreRequestMiddleware
|
||||
from authentic2.models import AttributeValue, Service
|
||||
from authentic2.utils.misc import get_password_authenticator
|
||||
from authentic2_idp_oidc.models import OIDCAuthorization
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
TABLES_MAJOR_VERSION = int(tables.__version__.split('.', maxsplit=1)[0])
|
||||
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@ import os
|
|||
import uuid
|
||||
|
||||
import tablib
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.storage import default_storage
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.manager.resources import UserResource
|
||||
from authentic2.models import Attribute, AttributeValue
|
||||
from authentic2.utils.misc import batch_queryset
|
||||
|
@ -37,7 +37,7 @@ def get_user_dataset(qs):
|
|||
|
||||
at_mapping = {a.id: a for a in Attribute.objects.all()}
|
||||
avs = (
|
||||
AttributeValue.objects.filter(content_type=ContentType.objects.get_for_model(get_user_model()))
|
||||
AttributeValue.objects.filter(content_type=ContentType.objects.get_for_model(User))
|
||||
.filter(attribute__disabled=False)
|
||||
.values()
|
||||
)
|
||||
|
@ -125,7 +125,7 @@ class UserExport:
|
|||
|
||||
def export_users_to_file(uuid, query):
|
||||
export = UserExport(uuid)
|
||||
qs = get_user_model().objects.all()
|
||||
qs = User.objects.all()
|
||||
qs.set_trigram_similarity_threshold()
|
||||
qs.query = query
|
||||
qs = qs.select_related('ou')
|
||||
|
|
|
@ -20,7 +20,7 @@ import datetime
|
|||
import operator
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.db import models, transaction
|
||||
|
@ -43,6 +43,7 @@ from authentic2.a2_rbac.models import OrganizationalUnit, Role, RoleParenting
|
|||
from authentic2.a2_rbac.utils import get_default_ou
|
||||
from authentic2.apps.journal.views import JournalViewWithContext
|
||||
from authentic2.backends.ldap_backend import LDAPBackend
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.models import Attribute, PasswordReset, Setting
|
||||
from authentic2.utils import hooks, spooler, switch_user
|
||||
from authentic2.utils.misc import (
|
||||
|
@ -93,12 +94,10 @@ from .views import (
|
|||
TitleMixin,
|
||||
)
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class UsersView(HideOUColumnMixin, BaseTableView):
|
||||
template_name = 'authentic2/manager/users.html'
|
||||
model = get_user_model()
|
||||
model = User
|
||||
table_class = UserTable
|
||||
permissions = ['custom_user.search_user']
|
||||
search_form_class = UserSearchForm
|
||||
|
@ -175,7 +174,7 @@ users = UsersView.as_view()
|
|||
|
||||
|
||||
class UserAddView(ActionMixin, BaseAddView):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
title = _('Create user')
|
||||
action = _('Create')
|
||||
fields = [
|
||||
|
@ -307,7 +306,7 @@ user_add_choose_ou = UserAddChooseOU.as_view()
|
|||
|
||||
|
||||
class UserDetailView(OtherActionsMixin, BaseDetailView):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
fields = ['username', 'ou', 'first_name', 'last_name', 'email']
|
||||
form_class = UserEditForm
|
||||
template_name = 'authentic2/manager/user_detail.html'
|
||||
|
@ -504,7 +503,7 @@ user_detail = UserDetailView.as_view()
|
|||
|
||||
|
||||
class UserEditView(OtherActionsMixin, ActionMixin, BaseEditView):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
template_name = 'authentic2/manager/user_edit.html'
|
||||
form_class = UserEditForm
|
||||
permissions = ['custom_user.change_user']
|
||||
|
@ -623,7 +622,7 @@ users_export_progress = UsersExportProgressView.as_view()
|
|||
|
||||
class UserChangePasswordView(ActionMixin, BaseEditView):
|
||||
template_name = 'authentic2/manager/form.html'
|
||||
model = get_user_model()
|
||||
model = User
|
||||
form_class = UserChangePasswordForm
|
||||
permissions = ['custom_user.change_password_user']
|
||||
title = _('Change user password')
|
||||
|
@ -651,7 +650,7 @@ user_change_password = UserChangePasswordView.as_view()
|
|||
|
||||
class UserChangeEmailView(BaseEditView):
|
||||
template_name = 'authentic2/manager/user_change_email.html'
|
||||
model = get_user_model()
|
||||
model = User
|
||||
form_class = UserChangeEmailForm
|
||||
permissions = ['custom_user.change_email_user']
|
||||
success_url = '..'
|
||||
|
@ -681,7 +680,7 @@ user_change_email = UserChangeEmailView.as_view()
|
|||
|
||||
|
||||
class UserRolesView(HideOUColumnMixin, BaseSubTableView):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
form_class = ChooseUserRoleForm
|
||||
search_form_class = UserRoleSearchForm
|
||||
success_url = '.'
|
||||
|
@ -778,7 +777,7 @@ roles = UserRolesView.as_view()
|
|||
|
||||
|
||||
class UserDeleteView(BaseDeleteView):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
title = _('Delete user')
|
||||
template_name = 'authentic2/manager/user_delete.html'
|
||||
success_url = reverse_lazy('a2-manager-users')
|
||||
|
@ -1004,7 +1003,7 @@ class UserAuthorizationsView(
|
|||
permissions = ['custom_user.view_user']
|
||||
template_name = 'authentic2/manager/user_authorizations.html'
|
||||
title = pgettext_lazy('manager', 'Consent Management')
|
||||
model = get_user_model()
|
||||
model = User
|
||||
table_class = UserAuthorizationsTable
|
||||
form_class = ChooseUserAuthorizationsForm
|
||||
success_url = '.'
|
||||
|
|
|
@ -19,11 +19,11 @@ import functools
|
|||
import operator
|
||||
import pickle
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils.encoding import force_str
|
||||
from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
|
||||
|
||||
from authentic2.a2_rbac.models import Role
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.utils import crypto
|
||||
from authentic2_idp_oidc.models import OIDCAuthorization
|
||||
|
||||
|
@ -100,7 +100,7 @@ class SimpleModelSelect2MultipleWidget(Select2Mixin, ModelSelect2MultipleWidget)
|
|||
|
||||
|
||||
class SearchUserWidgetMixin(SplitTermMixin):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
search_fields = [
|
||||
'username__icontains',
|
||||
'first_name__icontains',
|
||||
|
|
|
@ -3,7 +3,8 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0002_auto_20150323_1720'),
|
||||
('auth', '__first__'),
|
||||
('custom_user', '__first__'),
|
||||
('contenttypes', '0001_initial'),
|
||||
]
|
||||
|
||||
|
@ -98,7 +99,10 @@ class Migration(migrations.Migration):
|
|||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('creation', models.DateTimeField(auto_now_add=True, verbose_name='creation date')),
|
||||
('user', models.ForeignKey(verbose_name='user', to='auth.User', on_delete=models.CASCADE)),
|
||||
(
|
||||
'user',
|
||||
models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user to delete',
|
||||
|
@ -183,7 +187,10 @@ class Migration(migrations.Migration):
|
|||
'id',
|
||||
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||
),
|
||||
('user', models.ForeignKey(verbose_name='user', to='auth.User', on_delete=models.CASCADE)),
|
||||
(
|
||||
'user',
|
||||
models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'password reset',
|
||||
|
@ -202,7 +209,10 @@ class Migration(migrations.Migration):
|
|||
('external_id', models.CharField(max_length=256, verbose_name='external id')),
|
||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='creation date')),
|
||||
('updated', models.DateTimeField(auto_now=True, verbose_name='last update date')),
|
||||
('user', models.ForeignKey(verbose_name='user', to='auth.User', on_delete=models.CASCADE)),
|
||||
(
|
||||
'user',
|
||||
models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user external id',
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('authentic2', '0002_auto_20150320_1418'),
|
||||
]
|
||||
|
||||
|
@ -12,25 +11,19 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='deleteduser',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
field=models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='passwordreset',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
field=models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userexternalid',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
field=models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
@ -12,7 +11,7 @@ class Migration(migrations.Migration):
|
|||
model_name='passwordreset',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, unique=True, on_delete=models.CASCADE
|
||||
verbose_name='user', to='custom_user.User', unique=True, on_delete=models.CASCADE
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
@ -11,8 +10,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='passwordreset',
|
||||
name='user',
|
||||
field=models.OneToOneField(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
field=models.OneToOneField(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Generated by Django 1.11.20 on 2019-10-09 08:47
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
@ -17,7 +16,7 @@ class Migration(migrations.Migration):
|
|||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='deletion',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
verbose_name='user',
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
# Generated by Django 2.2.26 on 2023-01-17 14:13
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('authentic2', '0047_initialize_services_runtime_settings'),
|
||||
]
|
||||
|
||||
|
@ -23,7 +22,7 @@ class Migration(migrations.Migration):
|
|||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
verbose_name='user',
|
||||
),
|
||||
),
|
||||
|
|
|
@ -53,7 +53,7 @@ from .utils.sms import create_sms_code
|
|||
|
||||
|
||||
class UserExternalId(models.Model):
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
user = models.ForeignKey('custom_user.User', verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
source = models.CharField(max_length=256, verbose_name=_('source'))
|
||||
external_id = models.CharField(max_length=256, verbose_name=_('external id'), null=True)
|
||||
external_guid = models.UUIDField(verbose_name=_('External GUID'), null=True)
|
||||
|
@ -435,7 +435,7 @@ class AttributeValue(models.Model):
|
|||
|
||||
|
||||
class PasswordReset(models.Model):
|
||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
user = models.OneToOneField('custom_user.User', verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.user_id and not self.user.has_usable_password():
|
||||
|
@ -836,9 +836,7 @@ class SMSCode(models.Model):
|
|||
phone = models.CharField(
|
||||
_('phone number'), null=True, blank=True, max_length=64, validators=[PhoneNumberValidator]
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE, null=True
|
||||
)
|
||||
user = models.ForeignKey('custom_user.User', verbose_name=_('user'), on_delete=models.CASCADE, null=True)
|
||||
url_token = models.UUIDField(
|
||||
verbose_name=_('URL token'),
|
||||
default=uuid.uuid4,
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Nonce are value which should be used only once for a certain period or
|
||||
eventually forever. The nonce application allows any Django application to
|
||||
implement this behaviour, by taking care of the storage implementation to keep around invalidated nonce.
|
||||
|
||||
For nonce which should not be kept forever the application also provide a
|
||||
cleanup_nonce() function to delete the no longer invalid nonces.
|
|
@ -1,19 +0,0 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from authentic2.nonce.utils import accept_nonce, cleanup_nonces
|
||||
|
||||
__all__ = ('accept_nonce', 'cleanup_nonces')
|
|
@ -0,0 +1,13 @@
|
|||
# Generated by Django 3.2.18 on 2023-12-13 20:00
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
replaces = [('nonce', '0001_initial'), ('nonce', '0002_delete_nonce')]
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = []
|
|
@ -0,0 +1,15 @@
|
|||
# Generated by Django 3.2.18 on 2023-12-13 19:03
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('nonce', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='Nonce',
|
||||
),
|
||||
]
|
|
@ -1,39 +0,0 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
__all__ = ('Nonce',)
|
||||
|
||||
_NONCE_LENGTH_CONSTANT = 256
|
||||
|
||||
|
||||
class NonceManager(models.Manager):
|
||||
def cleanup(self, now=None):
|
||||
now = now or timezone.now()
|
||||
self.filter(not_on_or_after__lt=now).delete()
|
||||
|
||||
|
||||
class Nonce(models.Model):
|
||||
value = models.CharField(max_length=_NONCE_LENGTH_CONSTANT)
|
||||
context = models.CharField(max_length=_NONCE_LENGTH_CONSTANT, blank=True, null=True)
|
||||
not_on_or_after = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
objects = NonceManager()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
|
@ -1,200 +0,0 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2019 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime as dt
|
||||
import errno
|
||||
import glob
|
||||
import os.path
|
||||
import tempfile
|
||||
from calendar import timegm
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
__all__ = ('accept_nonce', 'cleanup_nonces')
|
||||
|
||||
STORAGE_MODEL = 'model'
|
||||
STORAGE_FILESYSTEM = 'fs:'
|
||||
|
||||
|
||||
def compute_not_on_or_after(now, not_on_or_after):
|
||||
try: # first try integer semantic
|
||||
seconds = int(not_on_or_after)
|
||||
not_on_or_after = now + dt.timedelta(seconds=seconds)
|
||||
except ValueError:
|
||||
try: # try timedelta semantic
|
||||
not_on_or_after = now + not_on_or_after
|
||||
except TypeError: # datetime semantic
|
||||
pass
|
||||
return not_on_or_after
|
||||
|
||||
|
||||
# For the nonce filesystem storage the policy is to catch any OSerror when
|
||||
# errno == ENOENT and to handle this case gracefully as there can be many race
|
||||
# condition errors. But any other OSError is problematic and should be
|
||||
# reported to the administrator by mail and so we let it unroll the stack
|
||||
|
||||
|
||||
def unlink_if_exists(path):
|
||||
try:
|
||||
os.unlink(path)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
|
||||
def accept_nonce_file_storage(path, now, value, context=None, not_on_or_after=None):
|
||||
"""
|
||||
Use a directory as a storage for nonce-context values. The last
|
||||
modification time is used to store the expiration timestamp.
|
||||
"""
|
||||
now = dt.datetime.now()
|
||||
filename = '%s_%s' % (value.encode('base64'), context.encode('base64'))
|
||||
file_path = os.path.join(path, filename)
|
||||
# test if the file exists
|
||||
try:
|
||||
stat = os.stat(file_path)
|
||||
except OSError as e:
|
||||
# test if it doesnt exit or if another error happened
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
else:
|
||||
# if it exists, test if it is too old
|
||||
if stat.st_mtime < timegm(now.utctimetuple()):
|
||||
# if it is too old delete it
|
||||
unlink_if_exists(file_path)
|
||||
else:
|
||||
# not too old, the nonce is unacceptable
|
||||
return False
|
||||
|
||||
# pylint: disable=consider-using-with
|
||||
temp_file = tempfile.NamedTemporaryFile(dir=path, delete=False)
|
||||
temp_file.close()
|
||||
|
||||
if not_on_or_after:
|
||||
not_on_or_after = compute_not_on_or_after(now, not_on_or_after)
|
||||
mtime = timegm(not_on_or_after.utctimetuple())
|
||||
else:
|
||||
mtime = 0x7FFF
|
||||
try:
|
||||
os.utime(temp_file.name, (mtime, mtime))
|
||||
except OSError:
|
||||
unlink_if_exists(temp_file.name)
|
||||
raise
|
||||
try:
|
||||
os.link(temp_file.name, file_path)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST:
|
||||
unlink_if_exists(temp_file.name)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def accept_nonce_model(now, value, context=None, not_on_or_after=None):
|
||||
from authentic2.nonce.models import Nonce
|
||||
|
||||
if not_on_or_after:
|
||||
not_on_or_after = compute_not_on_or_after(now, not_on_or_after)
|
||||
nonce, created = Nonce.objects.get_or_create(value=value, context=context)
|
||||
if created or (nonce.not_on_or_after and nonce.not_on_or_after < now):
|
||||
nonce.not_on_or_after = not_on_or_after
|
||||
nonce.save()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def cleanup_nonces_file_storage(dir_path, now):
|
||||
for nonce_path in glob.iglob(os.path.join(dir_path, '*')):
|
||||
now_time = timegm(now.utctimetuple())
|
||||
try:
|
||||
stat = os.stat(nonce_path)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
continue
|
||||
raise
|
||||
if stat.st_mtime < now_time:
|
||||
try:
|
||||
os.unlink(nonce_path)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
continue
|
||||
raise
|
||||
|
||||
|
||||
def cleanup_nonces(now=None):
|
||||
"""
|
||||
Cleanup stored nonce whose timestamp has expired, i.e.
|
||||
nonce.not_on_or_after < now.
|
||||
|
||||
:param now:
|
||||
a datetime value to define what is the current time, if None is
|
||||
given, datetime.now() is used. It can be used for unit testing.
|
||||
"""
|
||||
from authentic2.nonce.models import Nonce
|
||||
|
||||
now = now or dt.datetime.now()
|
||||
mode = getattr(settings, 'NONCE_STORAGE', STORAGE_MODEL)
|
||||
# the model always exists, so we always clean it
|
||||
Nonce.objects.cleanup(now)
|
||||
if mode == STORAGE_MODEL:
|
||||
pass
|
||||
if mode.startswith(STORAGE_FILESYSTEM):
|
||||
dir_path = mode[len(STORAGE_FILESYSTEM) :]
|
||||
return cleanup_nonces_file_storage(dir_path, now)
|
||||
else:
|
||||
raise ValueError('Invalid NONCE_STORAGE setting: %r' % mode)
|
||||
|
||||
|
||||
def accept_nonce(value, context=None, not_on_or_after=None, now=None):
|
||||
"""
|
||||
Verify that the given nonce value has not already been seen in the
|
||||
context. If not, remember it for ever or until not_on_or_after if is
|
||||
not None.
|
||||
|
||||
Depending on the backend storage used there can be limitation on the
|
||||
acceptable length for the value and the context. For example the model
|
||||
storage backend limits the length of those strings to 256 bytes.
|
||||
|
||||
:param value:
|
||||
a string representing a nonce value.
|
||||
:param context:
|
||||
a string giving context to the nonce value
|
||||
:param not_on_or_after:
|
||||
an integer, a datetime.timedelta or datetime.datetime value. If not
|
||||
none it is used to compute the expiration time for remembering this
|
||||
nonce value. If an integer is given it is interpreted as relative
|
||||
number of seconds since now, if a timedelta object is given it is
|
||||
used as an offset from now, and if a datetime is given it is used
|
||||
as an absolute value for the expiration time.
|
||||
:param now:
|
||||
a datetime value to define what is the current time, if None is
|
||||
given, datetime.now() is used. It can be used for unit testing.
|
||||
:returns:
|
||||
a boolean, if True the nonce has never been seen before, or it
|
||||
expired since the last time seen, otherwise the nonce has already
|
||||
been seen and is invalid.
|
||||
"""
|
||||
now = now or dt.datetime.now()
|
||||
mode = getattr(settings, 'NONCE_STORAGE', STORAGE_MODEL)
|
||||
if mode == STORAGE_MODEL:
|
||||
return accept_nonce_model(now, value, context=context, not_on_or_after=not_on_or_after)
|
||||
elif mode.startswith(STORAGE_FILESYSTEM):
|
||||
dir_path = mode[len(STORAGE_FILESYSTEM) :]
|
||||
return accept_nonce_file_storage(
|
||||
dir_path, now, value, context=context, not_on_or_after=not_on_or_after
|
||||
)
|
||||
else:
|
||||
raise ValueError('Invalid NONCE_STORAGE setting: %r' % mode)
|
|
@ -7,8 +7,7 @@ import authentic2.saml.models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '__first__'),
|
||||
('idp', '__first__'),
|
||||
('custom_user', '__first__'),
|
||||
('contenttypes', '0001_initial'),
|
||||
]
|
||||
|
||||
|
@ -474,17 +473,6 @@ class Migration(migrations.Migration):
|
|||
'users_can_manage_federations',
|
||||
models.BooleanField(default=True, verbose_name='users can manage federation'),
|
||||
),
|
||||
(
|
||||
'attribute_policy',
|
||||
models.ForeignKey(
|
||||
related_name='attribute_policy',
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
verbose_name='attribute policy',
|
||||
blank=True,
|
||||
to='idp.AttributePolicy',
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'SAML service provider',
|
||||
|
@ -757,7 +745,7 @@ class Migration(migrations.Migration):
|
|||
model_name='libertyfederation',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.SET_NULL, blank=True, to='auth.User', null=True
|
||||
on_delete=django.db.models.deletion.SET_NULL, blank=True, to='custom_user.User', null=True
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('saml', '0003_merge'),
|
||||
]
|
||||
|
||||
|
@ -16,7 +15,7 @@ class Migration(migrations.Migration):
|
|||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
blank=True,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
null=True,
|
||||
),
|
||||
preserve_default=True,
|
||||
|
|
|
@ -56,10 +56,6 @@ class Migration(migrations.Migration):
|
|||
migrations.DeleteModel(
|
||||
name='LibertyIdentityProvider',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='libertyserviceprovider',
|
||||
name='attribute_policy',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='libertyserviceprovider',
|
||||
name='enable_following_attribute_policy',
|
||||
|
|
|
@ -554,7 +554,7 @@ class LibertyFederation(models.Model):
|
|||
"""Store a federation, i.e. an identifier shared with another provider, be
|
||||
it IdP or SP"""
|
||||
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
user = models.ForeignKey('custom_user.User', null=True, blank=True, on_delete=models.SET_NULL)
|
||||
sp = models.ForeignKey('LibertyServiceProvider', null=True, blank=True, on_delete=models.CASCADE)
|
||||
name_id_format = models.CharField(max_length=100, verbose_name='NameIDFormat', blank=True, null=True)
|
||||
name_id_content = models.CharField(max_length=100, verbose_name='NameID')
|
||||
|
|
|
@ -153,9 +153,7 @@ INSTALLED_APPS = (
|
|||
'authentic2_idp_oidc',
|
||||
'authentic2.nonce',
|
||||
pmarillonnet marked this conversation as resolved
pmarillonnet
commented
Est-ce qu’on pourrait pas aussi dégager cette appli de la déclaration des applis installées ? Est-ce qu’on pourrait pas aussi dégager cette appli de la déclaration des applis installées ?
bdauvergne
commented
Pas encore sinon la migration delete_nonce ne s'appliquera pas et on aura une table qui traîne. Pas encore sinon la migration delete_nonce ne s'appliquera pas et on aura une table qui traîne.
pmarillonnet
commented
Ah oui ok, bien vu. Ah oui ok, bien vu.
|
||||
'authentic2.saml',
|
||||
'authentic2.idp',
|
||||
'authentic2.idp.saml',
|
||||
'authentic2.attribute_aggregator',
|
||||
'authentic2.disco_service',
|
||||
'authentic2.manager',
|
||||
'authentic2.apps.authenticators',
|
||||
|
@ -312,10 +310,6 @@ LOGGING = {
|
|||
},
|
||||
}
|
||||
|
||||
MIGRATION_MODULES = {
|
||||
'auth': 'authentic2.auth_migrations_18',
|
||||
}
|
||||
|
||||
# Django REST Framework
|
||||
REST_FRAMEWORK = {
|
||||
'NON_FIELD_ERRORS_KEY': '__all__',
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
{% extends "authentic2/base-page.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %} {% trans "Consent page for attribute propagation" %} {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
<div id="consent">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{% trans "Choose attributes to send to " %} <strong>{{ provider_id }}</strong> ?
|
||||
|
||||
<ul>
|
||||
{% for i, name, values in attributes %}
|
||||
<li>
|
||||
{% if allow_selection %}
|
||||
<input type="checkbox" name="attribute_nb_{{ i }}" value="{{ i }}" checked="checked"/>
|
||||
{% endif %}
|
||||
{{ name }} : <strong>{% for v in values %}{{ v }} {% endfor %}</strong></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
</p>
|
||||
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
<input type="hidden" name="nonce" value="{{ nonce }}" />
|
||||
{% if allow_selection %}
|
||||
<button name="accept">{% trans 'Send selected' %}</button>
|
||||
{% else %}
|
||||
<button name="accept">{% trans 'Send all' %}</button>
|
||||
{% endif %}
|
||||
<button name="refuse">{% trans 'Refuse all' %}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,32 +0,0 @@
|
|||
{% extends "authentic2/base-page.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %} {% trans "Consent page for federation" %} {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
<div id="consent">
|
||||
<p>
|
||||
{% if provider_id %}
|
||||
{% blocktrans trimmed with provider_id=provider_id %}
|
||||
Do you accept to federate your account with <strong>{{ provider_id }}</strong>?
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% trans "Do you accept to federate your account?" %}
|
||||
{% endif %}
|
||||
{{ provider_id2 }}
|
||||
</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
<input type="hidden" name="nonce" value="{{ nonce }}" />
|
||||
<div class="buttons">
|
||||
<button name="accept">{% trans 'Accept' %}</button>
|
||||
<button name="refuse">{% trans 'Refuse' %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -106,7 +106,6 @@ urlpatterns = [
|
|||
re_path(r'^su/(?P<uuid>[A-Za-z0-9_-]+)/$', views.su, name='su'),
|
||||
path('accounts/', include(accounts_urlpatterns)),
|
||||
re_path(r'^admin/', admin.site.urls),
|
||||
path('idp/', include('authentic2.idp.urls')),
|
||||
path('manage/', include('authentic2.manager.urls')),
|
||||
path('api/', include('authentic2.api_urls')),
|
||||
path('continue/', views.display_message_and_continue, name='continue'),
|
||||
|
|
|
@ -31,7 +31,6 @@ from django import forms
|
|||
from django.conf import settings
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.contrib.auth import authenticate as dj_authenticate
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth import login as auth_login
|
||||
from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured, ValidationError
|
||||
from django.core.mail import EmailMessage, send_mail
|
||||
|
@ -808,8 +807,9 @@ def send_registration_mail(request, email, ou, template_names=None, next_url=Non
|
|||
|
||||
Can raise an smtplib.SMTPException
|
||||
"""
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
User = get_user_model()
|
||||
|
||||
if not template_names:
|
||||
template_names = ['authentic2/activation_email']
|
||||
|
@ -1197,6 +1197,8 @@ def get_manager_login_url():
|
|||
|
||||
def send_email_change_email(user, email, request=None, context=None, template_names=None):
|
||||
'''Send an email to verify that user can take email as its new email'''
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
assert user
|
||||
assert email
|
||||
|
||||
|
@ -1222,7 +1224,7 @@ def send_email_change_email(user, email, request=None, context=None, template_na
|
|||
|
||||
# check if email should be unique and is not
|
||||
email_is_not_unique = False
|
||||
qs = get_user_model().objects.all()
|
||||
qs = User.objects.all()
|
||||
if app_settings.A2_EMAIL_IS_UNIQUE:
|
||||
email_is_not_unique = qs.filter(email=email).exclude(pk=user.pk).exists()
|
||||
elif user.ou and user.ou.email_is_unique:
|
||||
|
|
|
@ -29,8 +29,9 @@ from django.utils.translation import gettext_lazy as _
|
|||
from . import app_settings
|
||||
|
||||
|
||||
# copied from http://www.djangotips.com/real-email-validation
|
||||
@deconstructible
|
||||
pmarillonnet marked this conversation as resolved
Outdated
pmarillonnet
commented
J’ai pas capté ce qui justifiait d’ajouter ce décorateur là maintenant, dans cette PR :/ J’ai pas capté ce qui justifiait d’ajouter ce décorateur là maintenant, dans cette PR :/
bdauvergne
commented
C'est la recréation de la migration pour le modèle User qui utiliser EmailValidator et sans le décorateur deconstructible make_migration n'accepter pas de la refaire, problème invisible avant (et je suppose que l'introduction de EmailValidator s'est faite en monkeypatchant les migrations existantes donc on l'a pas vu non plus au passage). Donc c'est utile, mais plus loin dans l'autre série de commits. C'est la recréation de la migration pour le modèle User qui utiliser EmailValidator et sans le décorateur deconstructible make_migration n'accepter pas de la refaire, problème invisible avant (et je suppose que l'introduction de EmailValidator s'est faite en monkeypatchant les migrations existantes donc on l'a pas vu non plus au passage).
Donc c'est utile, mais plus loin dans l'autre série de commits.
pmarillonnet
commented
Ok. Ok.
|
||||
class EmailValidator:
|
||||
# copied from http://www.djangotips.com/real-email-validation
|
||||
def __init__(self, rcpt_check=False):
|
||||
self.rcpt_check = rcpt_check
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ from email.utils import parseaddr
|
|||
from django import shortcuts
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.views import PasswordChangeView as DjPasswordChangeView
|
||||
|
@ -49,7 +49,7 @@ from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateVi
|
|||
from ratelimit.utils import is_ratelimited
|
||||
|
||||
from authentic2.a2_rbac.models import Role
|
||||
from authentic2.custom_user.models import iter_attributes
|
||||
from authentic2.custom_user.models import User, iter_attributes
|
||||
from authentic2.forms import authentication as authentication_forms
|
||||
from authentic2_idp_oidc.models import OIDCAuthorization
|
||||
|
||||
|
@ -70,8 +70,6 @@ from .utils.sms import SMSError, send_registration_sms, sms_ratelimit_key
|
|||
from .utils.view_decorators import enable_view_restriction
|
||||
from .utils.views import csrf_token_check
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -411,7 +409,7 @@ class PhoneChangeVerifyView(TemplateView):
|
|||
def get(self, request, *args, **kwargs):
|
||||
token = kwargs['token']
|
||||
authn = utils_misc.get_password_authenticator()
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
user_ct = ContentType.objects.get_for_model(User)
|
||||
try:
|
||||
token = models.Token.objects.get(
|
||||
uuid=token,
|
||||
|
@ -1687,7 +1685,7 @@ class RegistrationView(cbv.ValidateCSRFMixin, BaseRegistrationView):
|
|||
|
||||
|
||||
class RegistrationCompletionView(CreateView):
|
||||
model = get_user_model()
|
||||
model = User
|
||||
success_url = 'auth_homepage'
|
||||
|
||||
def get_template_names(self):
|
||||
|
@ -1722,7 +1720,7 @@ class RegistrationCompletionView(CreateView):
|
|||
def dispatch(self, request, *args, **kwargs):
|
||||
registration_token = kwargs['registration_token'].replace(' ', '')
|
||||
self.authenticator = utils_misc.get_password_authenticator()
|
||||
user_ct = ContentType.objects.get_for_model(get_user_model())
|
||||
user_ct = ContentType.objects.get_for_model(User)
|
||||
try:
|
||||
token = models.Token.use('registration', registration_token, delete=False)
|
||||
except models.Token.DoesNotExist:
|
||||
|
@ -1876,7 +1874,7 @@ class RegistrationCompletionView(CreateView):
|
|||
for key in keys:
|
||||
if key in attributes:
|
||||
init_kwargs[key] = attributes[key]
|
||||
kwargs['instance'] = get_user_model()(**init_kwargs)
|
||||
kwargs['instance'] = User(**init_kwargs)
|
||||
# phone identifier is a separate attribute and is set post user-creation
|
||||
if hasattr(self, 'phone'):
|
||||
kwargs['instance'].phone_verified_on = timezone.now()
|
||||
|
@ -1998,7 +1996,7 @@ class RegistrationCompletionView(CreateView):
|
|||
if (phone := getattr(self, 'phone', None)) and self.authenticator.is_phone_authn_active:
|
||||
# phone identifier set post user-creation
|
||||
models.AttributeValue.objects.create(
|
||||
content_type=ContentType.objects.get_for_model(get_user_model()),
|
||||
content_type=ContentType.objects.get_for_model(User),
|
||||
object_id=user.id,
|
||||
content=phone,
|
||||
attribute=self.authenticator.phone_identifier_field,
|
||||
|
@ -2136,7 +2134,7 @@ class ValidateDeletionView(TemplateView):
|
|||
)
|
||||
self.prompt = deletion_token.get('prompt', self.prompt)
|
||||
user_pk = deletion_token['user_pk']
|
||||
self.user = get_user_model().objects.get(pk=user_pk)
|
||||
self.user = User.objects.get(pk=user_pk)
|
||||
# A user account wont be deactived twice
|
||||
if not self.user.is_active:
|
||||
raise ValidationError(_('This account is inactive, it cannot be deleted.'))
|
||||
|
@ -2149,7 +2147,7 @@ class ValidateDeletionView(TemplateView):
|
|||
error = _('The account deletion request was not on this site, try again')
|
||||
except ValidationError as e:
|
||||
error = e.message
|
||||
except get_user_model().DoesNotExist:
|
||||
except User.DoesNotExist:
|
||||
error = _('This account has previously been deleted.')
|
||||
|
||||
if error:
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
from authentic2.api_views import DjangoPermission
|
||||
from authentic2.compat.drf import action
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
|
||||
@action(
|
||||
|
@ -30,6 +30,6 @@ from authentic2.compat.drf import action
|
|||
permission_classes=(DjangoPermission('custom_user.view_user'),),
|
||||
)
|
||||
def fc_unlink(self, request, uuid):
|
||||
user = get_object_or_404(get_user_model(), uuid=uuid)
|
||||
user = get_object_or_404(User, uuid=uuid)
|
||||
user.fc_accounts.all().delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
|
|
@ -16,14 +16,12 @@
|
|||
|
||||
import logging
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.core.exceptions import MultipleObjectsReturned, PermissionDenied
|
||||
|
||||
from . import models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class FcBackend(ModelBackend):
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
@ -23,7 +22,7 @@ class Migration(migrations.Migration):
|
|||
models.ForeignKey(
|
||||
related_name='fc_accounts',
|
||||
verbose_name='user',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
import json
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.utils.functional import cached_property
|
||||
|
@ -143,7 +142,7 @@ class FcAccount(models.Model):
|
|||
created = models.DateTimeField(verbose_name=_('created'), auto_now_add=True)
|
||||
modified = models.DateTimeField(verbose_name=_('modified'), auto_now=True)
|
||||
user = models.ForeignKey(
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
verbose_name=_('user'),
|
||||
related_name='fc_accounts',
|
||||
on_delete=models.CASCADE,
|
||||
|
|
|
@ -20,7 +20,6 @@ import time
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.views import update_session_auth_hash
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import PermissionDenied, ValidationError
|
||||
|
@ -39,6 +38,7 @@ from requests_oauthlib import OAuth2Session
|
|||
from authentic2 import app_settings as a2_app_settings
|
||||
from authentic2 import constants
|
||||
from authentic2.a2_rbac.utils import get_default_ou
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.forms.passwords import SetPasswordForm
|
||||
from authentic2.models import Attribute, AttributeValue, Lock
|
||||
from authentic2.utils import hooks
|
||||
|
@ -52,7 +52,6 @@ from . import app_settings, models, utils
|
|||
from .utils import apply_user_info_mappings, build_logout_url, clean_fc_session
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class EmailExistsError(Exception):
|
||||
|
|
|
@ -20,7 +20,6 @@ import logging
|
|||
import requests
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.db import IntegrityError
|
||||
from django.db.transaction import atomic
|
||||
|
@ -31,6 +30,7 @@ from jwcrypto.jwt import JWT
|
|||
|
||||
from authentic2 import app_settings
|
||||
from authentic2.a2_rbac.models import OrganizationalUnit
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.models import Lock
|
||||
from authentic2.utils import hooks
|
||||
from authentic2.utils.crypto import base64url_encode
|
||||
|
@ -243,7 +243,6 @@ class OIDCBackend(ModelBackend):
|
|||
|
||||
Lock.lock_identifier(identifier=id_token.sub)
|
||||
|
||||
User = get_user_model()
|
||||
user = None
|
||||
if provider.strategy == models.OIDCProvider.STRATEGY_FIND_UUID:
|
||||
# use the OP sub to find an user by UUUID
|
||||
|
|
|
@ -7,7 +7,7 @@ import authentic2_auth_oidc.models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
migrations.swappable_dependency(settings.RBAC_OU_MODEL),
|
||||
]
|
||||
|
||||
|
@ -155,7 +155,7 @@ class Migration(migrations.Migration):
|
|||
field=models.OneToOneField(
|
||||
related_name='oidc_account',
|
||||
verbose_name='user',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
# Generated by Django 2.2.17 on 2020-11-02 10:42
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('authentic2_auth_oidc', '0007_auto_20200317_1732'),
|
||||
]
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import logging
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, transaction
|
||||
from django.db.models import JSONField
|
||||
|
@ -482,7 +481,7 @@ class OIDCAccount(models.Model):
|
|||
to='OIDCProvider', verbose_name=_('provider'), related_name='accounts', on_delete=models.CASCADE
|
||||
)
|
||||
user = models.OneToOneField(
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
verbose_name=_('user'),
|
||||
related_name='oidc_account',
|
||||
on_delete=models.CASCADE,
|
||||
|
|
|
@ -5,7 +5,7 @@ import authentic2_idp_cas.models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0002_auto_20150323_1720'),
|
||||
('custom_user', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
@ -128,7 +128,7 @@ class Migration(migrations.Migration):
|
|||
'user',
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
to='auth.User',
|
||||
to='custom_user.User',
|
||||
max_length=128,
|
||||
null=True,
|
||||
verbose_name='user',
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('authentic2_idp_cas', '0001_initial'),
|
||||
]
|
||||
|
||||
|
@ -14,7 +13,7 @@ class Migration(migrations.Migration):
|
|||
name='user',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
to='custom_user.User',
|
||||
max_length=128,
|
||||
null=True,
|
||||
verbose_name='user',
|
||||
|
|
|
@ -142,14 +142,14 @@ class AppConfig(django.apps.AppConfig):
|
|||
data['unknown_uuids'] = new_unknown_uuids
|
||||
|
||||
def a2_hook_api_modify_queryset(self, view, qs):
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models import Q
|
||||
from django.utils.timezone import now
|
||||
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
from .models import OIDCAuthorization, OIDCClient
|
||||
|
||||
client = self.get_oidc_client(view)
|
||||
User = get_user_model()
|
||||
|
||||
# fast path
|
||||
if not issubclass(qs.model, User) or client is None:
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from authentic2.attributes_ng.engine import get_service_attributes
|
||||
from authentic2.custom_user.models import User
|
||||
from authentic2.forms.mixins import SlugMixin
|
||||
from authentic2.forms.widgets import DatalistTextInput
|
||||
from authentic2.middleware import StoreRequestMiddleware
|
||||
|
@ -63,7 +63,7 @@ class OIDCClientForm(SlugMixin, forms.ModelForm):
|
|||
user = kwargs.pop('user')
|
||||
super().__init__(*args, **kwargs)
|
||||
# hide internal functionalities from regular administrators
|
||||
if not (user and isinstance(user, get_user_model()) and user.is_superuser):
|
||||
if not (user and isinstance(user, User) and user.is_superuser):
|
||||
del self.fields['has_api_access']
|
||||
del self.fields['activate_user_profiles']
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import authentic2_idp_oidc.models
|
||||
|
@ -6,7 +5,7 @@ import authentic2_idp_oidc.models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
('authentic2', '0016_attribute_disabled'),
|
||||
]
|
||||
|
||||
|
@ -143,9 +142,7 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -159,9 +156,7 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='oidcauthorization',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
field=models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='oidcaccesstoken',
|
||||
|
@ -173,8 +168,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='oidcaccesstoken',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE
|
||||
),
|
||||
field=models.ForeignKey(verbose_name='user', to='custom_user.User', on_delete=models.CASCADE),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -290,7 +290,7 @@ class OIDCAuthorization(models.Model):
|
|||
)
|
||||
client_id = models.PositiveIntegerField(verbose_name=_('client id'))
|
||||
client = GenericForeignKey('client_ct', 'client_id')
|
||||
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(to='custom_user.User', verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
scopes = models.TextField(blank=False, verbose_name=_('scopes'))
|
||||
profile = models.ForeignKey(to=Profile, verbose_name=_('profile'), on_delete=models.CASCADE, null=True)
|
||||
|
||||
|
@ -356,7 +356,7 @@ class OIDCCode(SessionMixin, models.Model):
|
|||
|
||||
uuid = models.CharField(max_length=128, verbose_name=_('uuid'), default=generate_uuid)
|
||||
client = models.ForeignKey(to=OIDCClient, verbose_name=_('client'), on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(to='custom_user.User', verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
profile = models.ForeignKey(
|
||||
to=Profile, verbose_name=_('user selected profile'), null=True, on_delete=models.CASCADE
|
||||
)
|
||||
|
@ -405,7 +405,7 @@ class OIDCCode(SessionMixin, models.Model):
|
|||
class OIDCAccessToken(SessionMixin, models.Model):
|
||||
uuid = models.CharField(max_length=128, verbose_name=_('uuid'), default=generate_uuid, db_index=True)
|
||||
client = models.ForeignKey(to=OIDCClient, verbose_name=_('client'), on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(to='custom_user.User', verbose_name=_('user'), on_delete=models.CASCADE)
|
||||
scopes = models.TextField(verbose_name=_('scopes'))
|
||||
session_key = models.CharField(verbose_name=_('session key'), max_length=128, blank=True)
|
||||
profile = models.ForeignKey(to=Profile, verbose_name=_('profile'), on_delete=models.CASCADE, null=True)
|
||||
|
|
|
@ -6,7 +6,7 @@ import authentic2.a2_rbac
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('custom_user', '__first__'),
|
||||
migrations.swappable_dependency(settings.RBAC_OU_MODEL),
|
||||
migrations.swappable_dependency(settings.RBAC_PERMISSION_MODEL),
|
||||
migrations.swappable_dependency(settings.RBAC_ROLE_MODEL),
|
||||
|
@ -102,7 +102,7 @@ class Migration(migrations.Migration):
|
|||
('description', models.TextField(verbose_name='description', blank=True)),
|
||||
(
|
||||
'members',
|
||||
models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL, blank=True),
|
||||
models.ManyToManyField(related_name='roles', to='custom_user.User', blank=True),
|
||||
),
|
||||
(
|
||||
'ou',
|
||||
|
|
|
@ -733,129 +733,6 @@ def test_change_email(settings, app, franceconnect, mailoutbox, freezer):
|
|||
assert User.objects.get().email == 'jane.doe@example.com'
|
||||
|
||||
|
||||
def test_fc_authenticator_data_migration(migration, settings):
|
||||
app = 'authentic2_auth_fc'
|
||||
migrate_from = [(app, '0005_fcauthenticator')]
|
||||
migrate_to = [(app, '0006_auto_20220525_1409')]
|
||||
|
||||
old_apps = migration.before(migrate_from)
|
||||
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
|
||||
|
||||
settings.AUTH_FRONTENDS_KWARGS = {
|
||||
'fc': {'priority': 3, 'show_condition': "'backoffice' not in login_hint"}
|
||||
}
|
||||
settings.A2_FC_ENABLE = True
|
||||
settings.A2_FC_CLIENT_ID = '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6k'
|
||||
settings.A2_FC_CLIENT_SECRET = '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6z'
|
||||
settings.A2_FC_AUTHORIZE_URL = 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize'
|
||||
settings.A2_FC_SCOPES = ['profile', 'email', 'birthdate']
|
||||
|
||||
new_apps = migration.apply(migrate_to)
|
||||
FcAuthenticator = new_apps.get_model(app, 'FcAuthenticator')
|
||||
authenticator = FcAuthenticator.objects.get()
|
||||
assert authenticator.slug == 'fc-authenticator'
|
||||
assert authenticator.order == 3
|
||||
assert authenticator.show_condition == "'backoffice' not in login_hint"
|
||||
assert authenticator.enabled is True
|
||||
assert authenticator.platform == 'test'
|
||||
assert authenticator.client_id == '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6k'
|
||||
assert authenticator.client_secret == '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6z'
|
||||
assert authenticator.scopes == ['profile', 'email', 'birthdate']
|
||||
|
||||
# 0007 should have no effect
|
||||
new_apps = migration.apply([(app, '0007_auto_20220615_1002')])
|
||||
FcAuthenticator = new_apps.get_model(app, 'FcAuthenticator')
|
||||
assert FcAuthenticator.objects.get().pk == authenticator.pk
|
||||
|
||||
|
||||
def test_fc_authenticator_data_migration_defaults(migration, settings):
|
||||
app = 'authentic2_auth_fc'
|
||||
migrate_from = [(app, '0005_fcauthenticator')]
|
||||
migrate_to = [(app, '0006_auto_20220525_1409')]
|
||||
|
||||
old_apps = migration.before(migrate_from)
|
||||
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
|
||||
|
||||
settings.A2_FC_ENABLE = False
|
||||
|
||||
new_apps = migration.apply(migrate_to)
|
||||
FcAuthenticator = new_apps.get_model(app, 'FcAuthenticator')
|
||||
authenticator = FcAuthenticator.objects.get()
|
||||
assert authenticator.slug == 'fc-authenticator'
|
||||
assert authenticator.order == -1
|
||||
assert authenticator.show_condition == ''
|
||||
assert authenticator.enabled is False
|
||||
assert authenticator.platform == 'test'
|
||||
assert authenticator.client_id == ''
|
||||
assert authenticator.client_secret == ''
|
||||
assert authenticator.scopes == ['profile', 'email']
|
||||
|
||||
|
||||
def test_fc_authenticator_data_migration_empty_configuration(migration, settings):
|
||||
app = 'authentic2_auth_fc'
|
||||
migrate_from = [(app, '0005_fcauthenticator')]
|
||||
migrate_to = [(app, '0006_auto_20220525_1409')]
|
||||
|
||||
old_apps = migration.before(migrate_from)
|
||||
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
|
||||
|
||||
new_apps = migration.apply(migrate_to)
|
||||
FcAuthenticator = new_apps.get_model(app, 'FcAuthenticator')
|
||||
assert not FcAuthenticator.objects.exists()
|
||||
|
||||
|
||||
def test_fc_authenticator_data_migration_bad_settings(migration, settings):
|
||||
app = 'authentic2_auth_fc'
|
||||
migrate_from = [(app, '0005_fcauthenticator')]
|
||||
migrate_to = [(app, '0006_auto_20220525_1409')]
|
||||
|
||||
old_apps = migration.before(migrate_from)
|
||||
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
|
||||
|
||||
settings.AUTH_FRONTENDS_KWARGS = {'fc': {'priority': None, 'show_condition': None}}
|
||||
settings.A2_FC_ENABLE = False
|
||||
settings.A2_FC_CLIENT_ID = 'x' * 260
|
||||
settings.A2_FC_CLIENT_SECRET = None
|
||||
settings.A2_FC_AUTHORIZE_URL = 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize'
|
||||
settings.A2_FC_SCOPES = None
|
||||
|
||||
new_apps = migration.apply(migrate_to)
|
||||
FcAuthenticator = new_apps.get_model(app, 'FcAuthenticator')
|
||||
authenticator = FcAuthenticator.objects.get()
|
||||
assert authenticator.slug == 'fc-authenticator'
|
||||
assert authenticator.order == -1
|
||||
assert authenticator.show_condition == ''
|
||||
assert authenticator.enabled is False
|
||||
assert authenticator.platform == 'test'
|
||||
assert authenticator.client_id == 'x' * 256
|
||||
assert authenticator.client_secret == ''
|
||||
assert authenticator.scopes == ['profile', 'email']
|
||||
|
||||
|
||||
def test_fc_authenticator_data_migration_fixup(migration, settings):
|
||||
app = 'authentic2_auth_fc'
|
||||
migrate_from = [(app, '0006_auto_20220525_1409')]
|
||||
migrate_to = [(app, '0007_auto_20220615_1002')]
|
||||
|
||||
old_apps = migration.before(migrate_from)
|
||||
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
|
||||
|
||||
# authenticator was not created by 0006
|
||||
assert not FcAuthenticator.objects.exists()
|
||||
|
||||
settings.A2_FC_ENABLE = True
|
||||
settings.A2_FC_CLIENT_ID = '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6k'
|
||||
settings.A2_FC_CLIENT_SECRET = '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6z'
|
||||
|
||||
new_apps = migration.apply(migrate_to)
|
||||
FcAuthenticator = new_apps.get_model(app, 'FcAuthenticator')
|
||||
|
||||
# authenticator was created by 0007
|
||||
authenticator = FcAuthenticator.objects.get()
|
||||
assert authenticator.slug == 'fc-authenticator'
|
||||
assert authenticator.client_id == '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6k'
|
||||
|
||||
|
||||
def test_bad_email_handling(settings, app, franceconnect, caplog):
|
||||
caplog.set_level(logging.WARNING)
|
||||
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
# authentic2 - authentic2 authentication for FranceConnect
|
||||
# Copyright (C) 2020 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
def test_migration_0003_0004_fcaccount_order(migration):
|
||||
migrate_from = [('authentic2_auth_fc', '0002_auto_20200416_1439')]
|
||||
# it's a two-parts migration, as it contains data and schema changes.
|
||||
migrate_to = [('authentic2_auth_fc', '0004_fcaccount_order2')]
|
||||
|
||||
old_apps = migration.before(migrate_from, at_end=False)
|
||||
|
||||
User = old_apps.get_model('custom_user', 'User')
|
||||
FcAccount = old_apps.get_model('authentic2_auth_fc', 'FcAccount')
|
||||
user1 = User.objects.create(username='user1')
|
||||
user2 = User.objects.create(username='user2')
|
||||
user3 = User.objects.create(username='user3')
|
||||
FcAccount.objects.create(user=user1, sub='sub1')
|
||||
FcAccount.objects.create(user=user1, sub='sub2')
|
||||
FcAccount.objects.create(user=user2, sub='sub2')
|
||||
FcAccount.objects.create(user=user2, sub='sub3')
|
||||
FcAccount.objects.create(user=user3, sub='sub3')
|
||||
assert len(set(FcAccount.objects.values_list('user_id', flat=True))) == 3
|
||||
assert len(set(FcAccount.objects.values_list('sub', flat=True))) == 3
|
||||
assert FcAccount.objects.count() == 5
|
||||
|
||||
# execute migration
|
||||
new_apps = migration.apply(migrate_to)
|
||||
FcAccount = new_apps.get_model('authentic2_auth_fc', 'FcAccount')
|
||||
assert len(set(FcAccount.objects.values_list('user_id', 'order'))) == 5
|
||||
assert len(set(FcAccount.objects.values_list('sub', 'order'))) == 5
|
|
@ -1308,78 +1308,6 @@ def test_auth_time_is_null(app, caplog, code, oidc_provider, oidc_provider_jwkse
|
|||
assert User.objects.count() == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'auth_frontend_kwargs',
|
||||
[
|
||||
{'oidc': {'priority': 3, 'show_condition': '"backoffice" not in login_hint'}},
|
||||
{'oidc': {'show_condition': {'baz': '"backoffice" not in login_hint', 'bar': 'True'}}},
|
||||
],
|
||||
)
|
||||
def test_oidc_provider_authenticator_data_migration(auth_frontend_kwargs, migration, settings):
|
||||
settings.AUTH_FRONTENDS_KWARGS = auth_frontend_kwargs
|
||||
|
||||
app = 'authentic2_auth_oidc'
|
||||
migrate_from = [(app, '0008_auto_20201102_1142')]
|
||||
migrate_to = [(app, '0012_auto_20220524_1147')]
|
||||
|
||||
old_apps = migration.before(migrate_from)
|
||||
OIDCProvider = old_apps.get_model(app, 'OIDCProvider')
|
||||
OIDCClaimMapping = old_apps.get_model(app, 'OIDCClaimMapping')
|
||||
OIDCAccount = old_apps.get_model(app, 'OIDCAccount')
|
||||
OrganizationalUnit = old_apps.get_model('a2_rbac', 'OrganizationalUnit')
|
||||
User = old_apps.get_model('custom_user', 'User')
|
||||
ou1 = OrganizationalUnit.objects.create(name='OU1', slug='ou1')
|
||||
issuer = 'https://baz.example.com'
|
||||
first_provider = OIDCProvider.objects.create(
|
||||
name='Baz',
|
||||
slug='baz',
|
||||
ou=ou1,
|
||||
show=True,
|
||||
issuer=issuer,
|
||||
authorization_endpoint='%s/authorize' % issuer,
|
||||
token_endpoint='%s/token' % issuer,
|
||||
end_session_endpoint='%s/logout' % issuer,
|
||||
userinfo_endpoint='%s/user_info' % issuer,
|
||||
token_revocation_endpoint='%s/revoke' % issuer,
|
||||
)
|
||||
second_provider = OIDCProvider.objects.create(name='Second', slug='second', ou=ou1)
|
||||
second_provider_claim_mapping = OIDCClaimMapping.objects.create(
|
||||
provider=second_provider, claim='second_provider', attribute='username'
|
||||
)
|
||||
user1 = User.objects.create()
|
||||
second_provider_account = OIDCAccount.objects.create(
|
||||
user=user1, provider=second_provider, sub='second_provider'
|
||||
)
|
||||
first_provider_claim_mapping = OIDCClaimMapping.objects.create(
|
||||
provider=first_provider, claim='first_provider', attribute='username'
|
||||
)
|
||||
|
||||
new_apps = migration.apply(migrate_to)
|
||||
OIDCProvider = new_apps.get_model(app, 'OIDCProvider')
|
||||
BaseAuthenticator = new_apps.get_model('authenticators', 'BaseAuthenticator')
|
||||
|
||||
authenticator = OIDCProvider.objects.get(slug='baz')
|
||||
assert authenticator.name == 'Baz'
|
||||
assert authenticator.ou.pk == ou1.pk
|
||||
assert authenticator.enabled is True
|
||||
assert authenticator.order == auth_frontend_kwargs['oidc'].get('priority', 2)
|
||||
assert authenticator.show_condition == '"backoffice" not in login_hint'
|
||||
assert authenticator.authorization_endpoint == '%s/authorize' % issuer
|
||||
assert authenticator.claim_mappings.count() == 1
|
||||
assert authenticator.claim_mappings.get().pk == first_provider_claim_mapping.pk
|
||||
assert not authenticator.accounts.exists()
|
||||
|
||||
base_authenticator = BaseAuthenticator.objects.get(slug='baz')
|
||||
assert authenticator.uuid == base_authenticator.uuid
|
||||
|
||||
second_authenticator = OIDCProvider.objects.get(slug='second')
|
||||
assert second_authenticator.name == 'Second'
|
||||
assert second_authenticator.claim_mappings.count() == 1
|
||||
assert second_authenticator.claim_mappings.get().pk == second_provider_claim_mapping.pk
|
||||
assert second_authenticator.accounts.count() == 1
|
||||
assert second_authenticator.accounts.get().pk == second_provider_account.pk
|
||||
|
||||
|
||||
def test_only_idtoken_claims(app, caplog, code, oidc_provider, oidc_provider_jwkset):
|
||||
oidc_provider.claim_mappings.update(idtoken_claim=True)
|
||||
response = app.get('/').maybe_follow()
|
||||
|
|
Par curiosité, qu’est-ce ce qui se passe mal dans
check-migrations
si on ne pose pas ça ?Si les locales sont compilées, on se retrouve avec erreurs de migrations manquante parce que verbose_name/help_text ne correspondent plus.
Ok