*: rewrite managed objects, use nullable text flag instead of boolean as uid (#533)

This commit is contained in:
Jens L 2021-02-06 16:56:21 +01:00 committed by GitHub
parent 05d777c373
commit a6ac82c492
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 115 additions and 70 deletions

View File

@ -42,7 +42,7 @@ class PropertyMappingViewSet(ReadOnlyModelViewSet):
search_fields = [
"name",
]
filterset_fields = ["managed"]
filterset_fields = {"managed": ["isnull"]}
ordering = ["name"]
def get_queryset(self):

View File

@ -13,19 +13,23 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="propertymapping",
name="managed",
field=models.BooleanField(
default=False,
field=models.TextField(
default=None,
help_text="Objects which are managed by authentik. These objects are created and updated automatically. This is flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
null=True,
verbose_name="Managed by authentik",
unique=True,
),
),
migrations.AddField(
model_name="token",
name="managed",
field=models.BooleanField(
default=False,
field=models.TextField(
default=None,
help_text="Objects which are managed by authentik. These objects are created and updated automatically. This is flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
null=True,
verbose_name="Managed by authentik",
unique=True,
),
),
]

View File

@ -12,12 +12,12 @@ class EnsureOp:
"""Ensure operation, executed as part of an ObjectManager run"""
_obj: Type[ManagedModel]
_match_fields: tuple[str, ...]
_managed_uid: str
_kwargs: dict
def __init__(self, obj: Type[ManagedModel], *match_fields: str, **kwargs) -> None:
def __init__(self, obj: Type[ManagedModel], managed_uid: str, **kwargs) -> None:
self._obj = obj
self._match_fields = match_fields
self._managed_uid = managed_uid
self._kwargs = kwargs
def run(self):
@ -29,16 +29,13 @@ class EnsureExists(EnsureOp):
"""Ensure object exists, with kwargs as given values"""
def run(self):
update_kwargs = {
"managed": True,
"defaults": self._kwargs,
}
for field in self._match_fields:
value = self._kwargs.get(field, None)
if value:
update_kwargs[field] = value
self._kwargs.setdefault("managed", True)
self._obj.objects.update_or_create(**update_kwargs)
self._kwargs.setdefault("managed", self._managed_uid)
self._obj.objects.update_or_create(
**{
"managed": self._managed_uid,
"defaults": self._kwargs,
}
)
class ObjectManager:

View File

@ -7,8 +7,9 @@ from django.utils.translation import gettext_lazy as _
class ManagedModel(models.Model):
"""Model which can be managed by authentik exclusively"""
managed = models.BooleanField(
default=False,
managed = models.TextField(
default=None,
null=True,
verbose_name=_("Managed by authentik"),
help_text=_(
(
@ -18,11 +19,12 @@ class ManagedModel(models.Model):
"to be overwritten in a later update."
)
),
unique=True,
)
def managed_objects(self) -> QuerySet:
"""Get all objects which are managed"""
return self.objects.filter(managed=True)
return self.objects.exclude(managed__isnull=True)
class Meta:

View File

@ -363,7 +363,7 @@ class Outpost(models.Model):
intent=TokenIntents.INTENT_API,
description=f"Autogenerated by authentik for Outpost {self.name}",
expiring=False,
managed=True,
managed="goauthentik.io/outpost",
)
def get_required_objects(self) -> Iterable[models.Model]:

View File

@ -34,14 +34,14 @@ class ScopeMappingManager(ObjectManager):
return [
EnsureExists(
ScopeMapping,
"scope_name",
"goauthentik.io/providers/oauth2/scope-openid",
name="authentik default OAuth Mapping: OpenID 'openid'",
scope_name="openid",
expression=SCOPE_OPENID_EXPRESSION,
),
EnsureExists(
ScopeMapping,
"scope_name",
"goauthentik.io/providers/oauth2/scope-email",
name="authentik default OAuth Mapping: OpenID 'email'",
scope_name="email",
description="Email address",
@ -49,7 +49,7 @@ class ScopeMappingManager(ObjectManager):
),
EnsureExists(
ScopeMapping,
"scope_name",
"goauthentik.io/providers/oauth2/scope-profile",
name="authentik default OAuth Mapping: OpenID 'profile'",
scope_name="profile",
description="General Profile Information",

View File

@ -3,6 +3,13 @@
from django.apps.registry import Apps
from django.db import migrations
scope_uid_map = {
"openid": "goauthentik.io/providers/oauth2/scope-openid",
"email": "goauthentik.io/providers/oauth2/scope-email",
"profile": "goauthentik.io/providers/oauth2/scope-profile",
"ak_proxy": "goauthentik.io/providers/proxy/scope-proxy",
}
def set_managed_flag(apps: Apps, schema_editor):
ScopeMapping = apps.get_model("authentik_providers_oauth2", "ScopeMapping")
@ -10,13 +17,14 @@ def set_managed_flag(apps: Apps, schema_editor):
for mapping in ScopeMapping.objects.using(db_alias).filter(
name__startswith="Autogenerated "
):
mapping.managed = True
mapping.managed = scope_uid_map[mapping.scope_name]
mapping.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0017_managed"),
("authentik_providers_oauth2", "0010_auto_20201227_1804"),
]

View File

@ -20,7 +20,7 @@ class ProxyScopeMappingManager(ObjectManager):
return [
EnsureExists(
ScopeMapping,
"scope_name",
"goauthentik.io/providers/proxy/scope-proxy",
name="authentik default OAuth Mapping: proxy outpost",
scope_name=SCOPE_AK_PROXY,
expression=SCOPE_AK_PROXY_EXPRESSION,

View File

@ -2,6 +2,11 @@
from authentik.managed.manager import EnsureExists, ObjectManager
from authentik.providers.saml.models import SAMLPropertyMapping
GROUP_EXPRESSION = """
for group in user.ak_groups.all():
yield group.name
"""
class SAMLProviderManager(ObjectManager):
"""SAML Provider managed objects"""
@ -10,53 +15,53 @@ class SAMLProviderManager(ObjectManager):
return [
EnsureExists(
SAMLPropertyMapping,
"saml_name",
"goauthentik.io/providers/saml/upn",
name="authentik default SAML Mapping: UPN",
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
expression="return user.attributes.get('upn', user.email)",
),
EnsureExists(
SAMLPropertyMapping,
"saml_name",
"goauthentik.io/providers/saml/name",
name="authentik default SAML Mapping: Name",
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
expression="return user.name",
),
EnsureExists(
SAMLPropertyMapping,
"saml_name",
"goauthentik.io/providers/saml/email",
name="authentik default SAML Mapping: Email",
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
expression="return user.email",
),
EnsureExists(
SAMLPropertyMapping,
"saml_name",
"goauthentik.io/providers/saml/username",
name="authentik default SAML Mapping: Username",
saml_name="http://schemas.goauthentik.io/2021/02/saml/username",
expression="return user.username",
),
EnsureExists(
SAMLPropertyMapping,
"saml_name",
"goauthentik.io/providers/saml/uid",
name="authentik default SAML Mapping: User ID",
saml_name="http://schemas.goauthentik.io/2021/02/saml/uid",
expression="return user.pk",
),
EnsureExists(
SAMLPropertyMapping,
"saml_name",
"goauthentik.io/providers/saml/groups",
name="authentik default SAML Mapping: Groups",
saml_name="http://schemas.xmlsoap.org/claims/Group",
expression=GROUP_EXPRESSION,
),
EnsureExists(
SAMLPropertyMapping,
"goauthentik.io/providers/saml/ms-windowsaccountname",
name="authentik default SAML Mapping: WindowsAccountname (Username)",
saml_name=(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"
),
expression="return user.username",
),
EnsureExists(
SAMLPropertyMapping,
"saml_name",
name="authentik default SAML Mapping: Groups",
saml_name="http://schemas.xmlsoap.org/claims/Group",
expression="for group in user.ak_groups.all():\n yield group.name",
),
]

View File

@ -6,6 +6,7 @@ saml_name_map = {
"http://schemas.xmlsoap.org/claims/CommonName": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname": "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
"member-of": "http://schemas.xmlsoap.org/claims/Group",
"http://schemas.xmlsoap.org/claims/Group": "http://schemas.xmlsoap.org/claims/Group",
"urn:oid:0.9.2342.19200300.100.1.1": "http://schemas.goauthentik.io/2021/02/saml/uid",
"urn:oid:0.9.2342.19200300.100.1.3": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"urn:oid:1.3.6.1.4.1.5923.1.1.1.6": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
@ -13,6 +14,16 @@ saml_name_map = {
"urn:oid:2.5.4.3": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
}
saml_name_uid_map = {
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn": "goauthentik.io/providers/saml/upn",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "goauthentik.io/providers/saml/name",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "goauthentik.io/providers/saml/email",
"http://schemas.goauthentik.io/2021/02/saml/username": "goauthentik.io/providers/saml/username",
"http://schemas.goauthentik.io/2021/02/saml/uid": "goauthentik.io/providers/saml/uid",
"http://schemas.xmlsoap.org/claims/Group": "goauthentik.io/providers/saml/groups",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname": "goauthentik.io/providers/saml/ms-windowsaccountname",
}
def add_managed_update(apps, schema_editor):
"""Create default SAML Property Mappings"""
@ -23,15 +34,14 @@ def add_managed_update(apps, schema_editor):
for pm in SAMLPropertyMapping.objects.using(db_alias).filter(
name__startswith="Autogenerated "
):
pm.managed = True
if pm.saml_name not in saml_name_map:
pm.save()
continue
new_name = saml_name_map[pm.saml_name]
if not new_name:
pm.delete()
continue
pm.saml_name = new_name
pm.managed = saml_name_uid_map[new_name]
pm.save()

View File

@ -10,15 +10,14 @@ class LDAPProviderManager(ObjectManager):
return [
EnsureExists(
LDAPPropertyMapping,
"object_field",
"expression",
name="authentik default LDAP Mapping: name",
"goauthentik.io/sources/ldap/default-name",
name="authentik default LDAP Mapping: Name",
object_field="name",
expression="return ldap.get('name')",
),
EnsureExists(
LDAPPropertyMapping,
"object_field",
"goauthentik.io/sources/ldap/default-mail",
name="authentik default LDAP Mapping: mail",
object_field="email",
expression="return ldap.get('mail')",
@ -26,32 +25,43 @@ class LDAPProviderManager(ObjectManager):
# Active Directory-specific mappings
EnsureExists(
LDAPPropertyMapping,
"object_field",
"expression",
"goauthentik.io/sources/ldap/ms-samaccountname",
name="authentik default Active Directory Mapping: sAMAccountName",
object_field="username",
expression="return ldap.get('sAMAccountName')",
),
EnsureExists(
LDAPPropertyMapping,
"object_field",
"goauthentik.io/sources/ldap/ms-userprincipalname",
name="authentik default Active Directory Mapping: userPrincipalName",
object_field="attributes.upn",
expression="return ldap.get('userPrincipalName')",
),
EnsureExists(
LDAPPropertyMapping,
"goauthentik.io/sources/ldap/ms-givenName",
name="authentik default Active Directory Mapping: givenName",
object_field="attributes.givenName",
expression="return ldap.get('givenName')",
),
EnsureExists(
LDAPPropertyMapping,
"goauthentik.io/sources/ldap/ms-sn",
name="authentik default Active Directory Mapping: sn",
object_field="attributes.sn",
expression="return ldap.get('sn')",
),
# OpenLDAP specific mappings
EnsureExists(
LDAPPropertyMapping,
"object_field",
"expression",
"goauthentik.io/sources/ldap/openldap-uid",
name="authentik default OpenLDAP Mapping: uid",
object_field="username",
expression="return ldap.get('uid')",
),
EnsureExists(
LDAPPropertyMapping,
"object_field",
"expression",
"goauthentik.io/sources/ldap/openldap-cn",
name="authentik default OpenLDAP Mapping: cn",
object_field="name",
expression="return ldap.get('cn')",

View File

@ -9,16 +9,25 @@ def set_managed_flag(apps: Apps, schema_editor):
"authentik_sources_ldap", "LDAPPropertyMapping"
)
db_alias = schema_editor.connection.alias
field_to_uid = {
"name": "goauthentik.io/sources/ldap/default-name",
"email": "goauthentik.io/sources/ldap/default-mail",
"username": "goauthentik.io/sources/ldap/ms-samaccountname",
"attributes.upn": "goauthentik.io/sources/ldap/ms-userprincipalname",
"first_name": "goauthentik.io/sources/ldap/ms-givenName",
"last_name": "goauthentik.io/sources/ldap/ms-sn",
}
for mapping in LDAPPropertyMapping.objects.using(db_alias).filter(
name__startswith="Autogenerated "
):
mapping.managed = True
mapping.managed = field_to_uid.get(mapping.object_field)
mapping.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0017_managed"),
("authentik_sources_ldap", "0007_ldapsource_sync_users_password"),
]

View File

@ -35,8 +35,8 @@ class LDAPSyncTests(TestCase):
"""Test user sync"""
self.source.property_mappings.set(
LDAPPropertyMapping.objects.filter(
Q(name__startswith="authentik default LDAP Mapping")
| Q(name__startswith="authentik default Active Directory Mapping")
Q(managed__startswith="goauthentik.io/sources/ldap/default")
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
)
)
self.source.save()
@ -52,8 +52,8 @@ class LDAPSyncTests(TestCase):
self.source.object_uniqueness_field = "uid"
self.source.property_mappings.set(
LDAPPropertyMapping.objects.filter(
Q(name__startswith="authentik default LDAP Mapping")
| Q(name__startswith="authentik default OpenLDAP Mapping")
Q(managed__startswith="goauthentik.io/sources/ldap/default")
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
)
)
self.source.save()
@ -68,13 +68,13 @@ class LDAPSyncTests(TestCase):
"""Test group sync"""
self.source.property_mappings.set(
LDAPPropertyMapping.objects.filter(
Q(name__startswith="authentik default LDAP Mapping")
| Q(name__startswith="authentik default Active Directory Mapping")
Q(managed__startswith="goauthentik.io/sources/ldap/default")
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
)
)
self.source.property_mappings_group.set(
LDAPPropertyMapping.objects.filter(
name="authentik default LDAP Mapping: name"
managed="goauthentik.io/sources/ldap/default-name"
)
)
self.source.save()
@ -93,13 +93,13 @@ class LDAPSyncTests(TestCase):
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.property_mappings.set(
LDAPPropertyMapping.objects.filter(
Q(name__startswith="authentik default LDAP Mapping")
| Q(name__startswith="authentik default OpenLDAP Mapping")
Q(managed__startswith="goauthentik.io/sources/ldap/default")
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
)
)
self.source.property_mappings_group.set(
LDAPPropertyMapping.objects.filter(
name="authentik default OpenLDAP Mapping: cn"
managed="goauthentik.io/sources/ldap/openldap-cn"
)
)
self.source.save()
@ -116,8 +116,8 @@ class LDAPSyncTests(TestCase):
"""Test Scheduled tasks"""
self.source.property_mappings.set(
LDAPPropertyMapping.objects.filter(
Q(name__startswith="authentik default LDAP Mapping")
| Q(name__startswith="authentik default Active Directory Mapping")
Q(managed__startswith="goauthentik.io/sources/ldap/default")
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
)
)
self.source.save()
@ -131,8 +131,8 @@ class LDAPSyncTests(TestCase):
self.source.group_object_filter = "(objectClass=groupOfNames)"
self.source.property_mappings.set(
LDAPPropertyMapping.objects.filter(
Q(name__startswith="authentik default LDAP Mapping")
| Q(name__startswith="authentik default OpenLDAP Mapping")
Q(managed__startswith="goauthentik.io/sources/ldap/default")
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
)
)
self.source.save()

View File

@ -3597,7 +3597,7 @@ paths:
operationId: propertymappings_all_list
description: PropertyMapping Viewset
parameters:
- name: managed
- name: managed__isnull
in: query
description: ''
required: false

View File

@ -35,7 +35,7 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
ordering: this.order,
page: page,
search: this.search || "",
managed: this.hideManaged ? false : null,
managed__isnull: this.hideManaged,
});
}