From 1f97420207e885d97ff178670481ef6b60855d07 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 21 Sep 2021 21:59:39 +0200 Subject: [PATCH] outposts/ldap: allow custom attributes to shadow built-in attributes Signed-off-by: Jens Langhammer --- internal/outpost/ldap/instance_search.go | 114 ++++++----------------- internal/outpost/ldap/utils.go | 23 +++++ website/docs/providers/ldap.md | 4 + 3 files changed, 57 insertions(+), 84 deletions(-) diff --git a/internal/outpost/ldap/instance_search.go b/internal/outpost/ldap/instance_search.go index b2e73afb7..f39101cdc 100644 --- a/internal/outpost/ldap/instance_search.go +++ b/internal/outpost/ldap/instance_search.go @@ -181,99 +181,45 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult, } func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry { - attrs := []*ldap.EntryAttribute{ - { - Name: "cn", - Values: []string{u.Username}, - }, - { - Name: "sAMAccountName", - Values: []string{u.Username}, - }, - { - Name: "uid", - Values: []string{u.Uid}, - }, - { - Name: "name", - Values: []string{u.Name}, - }, - { - Name: "displayName", - Values: []string{u.Name}, - }, - { - Name: "mail", - Values: []string{*u.Email}, - }, - { - Name: "objectClass", - Values: []string{UserObjectClass, "organizationalPerson", "goauthentik.io/ldap/user"}, - }, - { - Name: "uidNumber", - Values: []string{pi.GetUidNumber(u)}, - }, - { - Name: "gidNumber", - Values: []string{pi.GetUidNumber(u)}, - }, - } - - attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: pi.GroupsForUser(u)}) - - // Old fields for backwards compatibility - attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{BoolToString(*u.IsActive)}}) - attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{BoolToString(u.IsSuperuser)}}) - - attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/active", Values: []string{BoolToString(*u.IsActive)}}) - attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/superuser", Values: []string{BoolToString(u.IsSuperuser)}}) - - attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...) - dn := pi.GetUserDN(u.Username) + attrs := AKAttrsToLDAP(u.Attributes) + attrs = pi.ensureAttributes(attrs, map[string][]string{ + "memberOf": pi.GroupsForUser(u), + // Old fields for backwards compatibility + "accountStatus": {BoolToString(*u.IsActive)}, + "superuser": {BoolToString(u.IsSuperuser)}, + "goauthentik.io/ldap/active": {BoolToString(*u.IsActive)}, + "goauthentik.io/ldap/superuser": {BoolToString(u.IsSuperuser)}, + "cn": {u.Username}, + "sAMAccountName": {u.Username}, + "uid": {u.Uid}, + "name": {u.Name}, + "displayName": {u.Name}, + "mail": {*u.Email}, + "objectClass": {UserObjectClass, "organizationalPerson", "goauthentik.io/ldap/user"}, + "uidNumber": {pi.GetUidNumber(u)}, + "gidNumber": {pi.GetUidNumber(u)}, + }) return &ldap.Entry{DN: dn, Attributes: attrs} } func (pi *ProviderInstance) GroupEntry(g LDAPGroup) *ldap.Entry { - attrs := []*ldap.EntryAttribute{ - { - Name: "cn", - Values: []string{g.cn}, - }, - { - Name: "uid", - Values: []string{g.uid}, - }, - { - Name: "sAMAccountName", - Values: []string{g.cn}, - }, - { - Name: "gidNumber", - Values: []string{g.gidNumber}, - }, - } + attrs := AKAttrsToLDAP(g.akAttributes) + objectClass := []string{GroupObjectClass, "goauthentik.io/ldap/group"} if g.isVirtualGroup { - attrs = append(attrs, &ldap.EntryAttribute{ - Name: "objectClass", - Values: []string{GroupObjectClass, "goauthentik.io/ldap/group", "goauthentik.io/ldap/virtual-group"}, - }) - } else { - attrs = append(attrs, &ldap.EntryAttribute{ - Name: "objectClass", - Values: []string{GroupObjectClass, "goauthentik.io/ldap/group"}, - }) - } - - attrs = append(attrs, &ldap.EntryAttribute{Name: "member", Values: g.member}) - attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/superuser", Values: []string{BoolToString(g.isSuperuser)}}) - - if g.akAttributes != nil { - attrs = append(attrs, AKAttrsToLDAP(g.akAttributes)...) + objectClass = []string{GroupObjectClass, "goauthentik.io/ldap/group", "goauthentik.io/ldap/virtual-group"} } + attrs = pi.ensureAttributes(attrs, map[string][]string{ + "objectClass": objectClass, + "member": g.member, + "goauthentik.io/ldap/superuser": {BoolToString(g.isSuperuser)}, + "cn": {g.cn}, + "uid": {g.uid}, + "sAMAccountName": {g.cn}, + "gidNumber": {g.gidNumber}, + }) return &ldap.Entry{DN: g.dn, Attributes: attrs} } diff --git a/internal/outpost/ldap/utils.go b/internal/outpost/ldap/utils.go index 3a9840baa..7014116aa 100644 --- a/internal/outpost/ldap/utils.go +++ b/internal/outpost/ldap/utils.go @@ -140,3 +140,26 @@ func (pi *ProviderInstance) GetRIDForGroup(uid string) int32 { return int32(gid) } + +func (pi *ProviderInstance) ensureAttributes(attrs []*ldap.EntryAttribute, shouldHave map[string][]string) []*ldap.EntryAttribute { + for name, values := range shouldHave { + attrs = pi.mustHaveAttribute(attrs, name, values) + } + return attrs +} + +func (pi *ProviderInstance) mustHaveAttribute(attrs []*ldap.EntryAttribute, name string, value []string) []*ldap.EntryAttribute { + shouldSet := false + for _, attr := range attrs { + if attr.Name == name { + shouldSet = true + } + } + if shouldSet { + return append(attrs, &ldap.EntryAttribute{ + Name: name, + Values: value, + }) + } + return attrs +} diff --git a/website/docs/providers/ldap.md b/website/docs/providers/ldap.md index 4e8781655..7b790978b 100644 --- a/website/docs/providers/ldap.md +++ b/website/docs/providers/ldap.md @@ -64,6 +64,10 @@ The virtual groups gidNumber is equal to the uidNumber of the user. **Additionally**, for both users and (non-virtual) groups, any attributes you set are also present as LDAP Attributes. +:::info +Starting with 2021.9.1, custom attributes will override the inbuilt attributes. +::: + ## SSL You can also configure SSL for your LDAP Providers by selecting a certificate and a server name in the provider settings.