*: rewrite managed objects, use nullable text flag instead of boolean as uid (#533)
This commit is contained in:
parent
05d777c373
commit
a6ac82c492
|
@ -42,7 +42,7 @@ class PropertyMappingViewSet(ReadOnlyModelViewSet):
|
|||
search_fields = [
|
||||
"name",
|
||||
]
|
||||
filterset_fields = ["managed"]
|
||||
filterset_fields = {"managed": ["isnull"]}
|
||||
ordering = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -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,
|
||||
self._kwargs.setdefault("managed", self._managed_uid)
|
||||
self._obj.objects.update_or_create(
|
||||
**{
|
||||
"managed": self._managed_uid,
|
||||
"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)
|
||||
)
|
||||
|
||||
|
||||
class ObjectManager:
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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]:
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"),
|
||||
]
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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')",
|
||||
|
|
|
@ -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"),
|
||||
]
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -3597,7 +3597,7 @@ paths:
|
|||
operationId: propertymappings_all_list
|
||||
description: PropertyMapping Viewset
|
||||
parameters:
|
||||
- name: managed
|
||||
- name: managed__isnull
|
||||
in: query
|
||||
description: ''
|
||||
required: false
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue