From e4dc810bfffea0679552de05ce1d027af7917633 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Tue, 23 May 2023 16:47:39 -0700 Subject: [PATCH 1/9] Add some posixGroups to the openldap server for use in integration tests --- test/deploy/tools/ldap.yaml | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/test/deploy/tools/ldap.yaml b/test/deploy/tools/ldap.yaml index 94638ecfd..d8a82525d 100644 --- a/test/deploy/tools/ldap.yaml +++ b/test/deploy/tools/ldap.yaml @@ -1,4 +1,4 @@ -#! Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +#! Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. #! SPDX-License-Identifier: Apache-2.0 #@ load("@ytt:data", "data") @@ -116,6 +116,31 @@ ldap.ldif: | objectClass: groupOfNames member: cn=pinnipeds,ou=groups,dc=pinniped,dc=dev member: cn=olive,ou=users,dc=pinniped,dc=dev + + # ball-game-players group again, but this time defined as a posixGroup + dn: cn=ball-game-players-posix,ou=groups,dc=pinniped,dc=dev + objectClass: posixGroup + objectClass: top + cn: ball-game-players-posix + gidNumber: 1001 + memberUid: pinny + memberUid: olive + + # seals group again, but this time defined as a posixGroup + dn: cn=seals-posix,ou=groups,dc=pinniped,dc=dev + objectClass: posixGroup + objectClass: top + cn: seals-posix + gidNumber: 1002 + memberUid: pinny + + # walruses group again, but this time defined as a posixGroup + dn: cn=walruses-posix,ou=groups,dc=pinniped,dc=dev + objectClass: posixGroup + objectClass: top + cn: walruses-posix + gidNumber: 1002 + memberUid: wally #@ end --- From bad5e60a8ef5ae44d6583c2e15a1965c25aac3a2 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Tue, 23 May 2023 16:51:36 -0700 Subject: [PATCH 2/9] Add LDAPIdentityProvider.spec.groupSearch.userAttributeForFilter Add the field to the tmpl file and run codegen. Also update the count of the fields of our APIs in an integration test. --- .../types_ldapidentityprovider.go.tmpl | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.17/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.18/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.19/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.20/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.21/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.22/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.23/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.24/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.25/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.26/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- generated/1.27/README.adoc | 5 ++-- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- ...or.pinniped.dev_ldapidentityproviders.yaml | 23 +++++++++++++++---- .../v1alpha1/types_ldapidentityprovider.go | 21 +++++++++++++---- test/integration/kube_api_discovery_test.go | 2 +- 37 files changed, 470 insertions(+), 136 deletions(-) diff --git a/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go.tmpl b/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go.tmpl index 09cb843d4..5c76d6af4 100644 --- a/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go.tmpl +++ b/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go.tmpl @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.17/README.adoc b/generated/1.17/README.adoc index e7e343c17..bf90b3bcf 100644 --- a/generated/1.17/README.adoc +++ b/generated/1.17/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.17/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.17/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.17/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.17/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.17/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.17/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.17/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.17/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.18/README.adoc b/generated/1.18/README.adoc index f0cf42d33..ba453a286 100644 --- a/generated/1.18/README.adoc +++ b/generated/1.18/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.18/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.18/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.18/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.18/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.18/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.18/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.18/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.18/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.19/README.adoc b/generated/1.19/README.adoc index 1f3fd6005..979c79b83 100644 --- a/generated/1.19/README.adoc +++ b/generated/1.19/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.19/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.19/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.19/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.19/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.19/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.19/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.19/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.19/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.20/README.adoc b/generated/1.20/README.adoc index c428a84d6..9da145050 100644 --- a/generated/1.20/README.adoc +++ b/generated/1.20/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.20/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.20/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.20/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.20/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.20/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.20/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.20/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.20/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.21/README.adoc b/generated/1.21/README.adoc index f2af6b18c..b14a89b1d 100644 --- a/generated/1.21/README.adoc +++ b/generated/1.21/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.21/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.21/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.21/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.21/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.21/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.21/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.21/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.21/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.22/README.adoc b/generated/1.22/README.adoc index 2a8e4c85f..b3de67b2e 100644 --- a/generated/1.22/README.adoc +++ b/generated/1.22/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.22/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.22/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.22/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.22/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.22/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.22/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.22/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.22/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.23/README.adoc b/generated/1.23/README.adoc index d1961bda5..3f1604633 100644 --- a/generated/1.23/README.adoc +++ b/generated/1.23/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.23/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.23/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.23/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.23/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.23/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.23/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.23/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.23/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.24/README.adoc b/generated/1.24/README.adoc index 84a9c29e7..b4bb2b68b 100644 --- a/generated/1.24/README.adoc +++ b/generated/1.24/README.adoc @@ -1252,8 +1252,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.24/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.24/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.24/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.24/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.24/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.24/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.24/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.24/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.25/README.adoc b/generated/1.25/README.adoc index 18d18f0fc..1e81b7ca0 100644 --- a/generated/1.25/README.adoc +++ b/generated/1.25/README.adoc @@ -1248,8 +1248,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.25/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.25/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.25/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.25/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.25/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.25/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.25/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.25/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.26/README.adoc b/generated/1.26/README.adoc index 52e6d6376..a89085ac2 100644 --- a/generated/1.26/README.adoc +++ b/generated/1.26/README.adoc @@ -1248,8 +1248,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.26/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.26/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.26/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.26/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.26/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.26/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.26/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.26/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/1.27/README.adoc b/generated/1.27/README.adoc index 84e479fd7..487570a7b 100644 --- a/generated/1.27/README.adoc +++ b/generated/1.27/README.adoc @@ -1248,8 +1248,9 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire [cols="25a,75a", options="header"] |=== | Field | Description -| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter and Attributes are ignored. -| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. +| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.27/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/1.27/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/1.27/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/1.27/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/generated/1.27/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/generated/1.27/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index 211a70a1a..5799cb5c1 100644 --- a/generated/1.27/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.27/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -96,15 +96,16 @@ spec: used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and authenticated users will not belong to any groups from the LDAP provider. - Also, when not specified, the values of Filter and Attributes - are ignored. + Also, when not specified, the values of Filter, UserAttributeForFilter, + Attributes, and SkipGroupRefresh are ignored. type: string filter: description: Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically - replaced by the dn (distinguished name) of the user entry found - as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + replaced by the value of an attribute of the user entry found + as a result of the user search. Which attribute's value is used + to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, @@ -134,6 +135,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/latest/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go b/generated/latest/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go index 09cb843d4..5c76d6af4 100644 --- a/generated/latest/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go +++ b/generated/latest/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -101,20 +101,31 @@ type LDAPIdentityProviderGroupSearch struct { // Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. // "ou=groups,dc=example,dc=com". When not specified, no group search will be performed and // authenticated users will not belong to any groups from the LDAP provider. Also, when not specified, - // the values of Filter and Attributes are ignored. + // the values of Filter, UserAttributeForFilter, Attributes, and SkipGroupRefresh are ignored. // +optional Base string `json:"base,omitempty"` // Filter is the LDAP search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about LDAP filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // For more information about LDAP filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the Filter were specified as "member={}". // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each LDAP entry which was found as // the result of the group search. // +optional diff --git a/test/integration/kube_api_discovery_test.go b/test/integration/kube_api_discovery_test.go index 5a2862109..53c810811 100644 --- a/test/integration/kube_api_discovery_test.go +++ b/test/integration/kube_api_discovery_test.go @@ -441,7 +441,7 @@ func TestGetAPIResourceList(t *testing.T) { //nolint:gocyclo // each t.Run is pr // over time, make a rudimentary assertion that this test exercised the whole tree of all fields of all // Pinniped API resources. Without this, the test could accidentally skip parts of the tree if the // format has changed. - require.Equal(t, 225, foundFieldNames, + require.Equal(t, 226, foundFieldNames, "Expected to find all known fields of all Pinniped API resources. "+ "You may will need to update this expectation if you added new fields to the API types.", ) From c187474499a6cb628eb3ae4b2f5a00c140a07752 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Thu, 25 May 2023 14:25:17 -0700 Subject: [PATCH 3/9] Use groupSearch.userAttributeForFilter during LDAP group searches Load the setting in the controller. Use the setting during authentication and during refreshes. --- .../active_directory_upstream_watcher.go | 6 +- .../ldap_upstream_watcher.go | 15 +- .../ldap_upstream_watcher_test.go | 134 ++--- .../upstreamwatchers/upstream_watchers.go | 3 +- internal/upstreamldap/upstreamldap.go | 69 ++- internal/upstreamldap/upstreamldap_test.go | 466 +++++++++++++++++- 6 files changed, 605 insertions(+), 88 deletions(-) diff --git a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go index 105f1ed75..38a677f03 100644 --- a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go +++ b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Package activedirectoryupstreamwatcher implements a controller which watches ActiveDirectoryIdentityProviders. @@ -203,6 +203,10 @@ func (g *activeDirectoryUpstreamGenericLDAPGroupSearch) Filter() string { return g.groupSearch.Filter } +func (g *activeDirectoryUpstreamGenericLDAPGroupSearch) UserAttributeForFilter() string { + return "" +} + func (g *activeDirectoryUpstreamGenericLDAPGroupSearch) GroupNameAttribute() string { if len(g.groupSearch.Attributes.GroupName) == 0 { return defaultActiveDirectoryGroupNameAttributeName diff --git a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go index 6d370e26e..424a90289 100644 --- a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go +++ b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Package ldapupstreamwatcher implements a controller which watches LDAPIdentityProviders. @@ -115,6 +115,10 @@ func (g *ldapUpstreamGenericLDAPGroupSearch) Filter() string { return g.groupSearch.Filter } +func (g *ldapUpstreamGenericLDAPGroupSearch) UserAttributeForFilter() string { + return g.groupSearch.UserAttributeForFilter +} + func (g *ldapUpstreamGenericLDAPGroupSearch) GroupNameAttribute() string { return g.groupSearch.Attributes.GroupName } @@ -236,10 +240,11 @@ func (c *ldapWatcherController) validateUpstream(ctx context.Context, upstream * UIDAttribute: spec.UserSearch.Attributes.UID, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: spec.GroupSearch.Base, - Filter: spec.GroupSearch.Filter, - GroupNameAttribute: spec.GroupSearch.Attributes.GroupName, - SkipGroupRefresh: spec.GroupSearch.SkipGroupRefresh, + Base: spec.GroupSearch.Base, + Filter: spec.GroupSearch.Filter, + UserAttributeForFilter: spec.GroupSearch.UserAttributeForFilter, + GroupNameAttribute: spec.GroupSearch.Attributes.GroupName, + SkipGroupRefresh: spec.GroupSearch.SkipGroupRefresh, }, Dialer: c.ldapDialer, } diff --git a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go index 0f57bc2fa..3eff7621c 100644 --- a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package ldapupstreamwatcher @@ -148,20 +148,25 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { now := metav1.NewTime(time.Now().UTC()) const ( - testNamespace = "test-namespace" - testName = "test-name" - testResourceUID = "test-resource-uid" - testSecretName = "test-bind-secret" - testBindUsername = "test-bind-username" - testBindPassword = "test-bind-password" - testHost = "ldap.example.com:123" - testUserSearchBase = "test-user-search-base" - testUserSearchFilter = "test-user-search-filter" - testGroupSearchBase = "test-group-search-base" - testGroupSearchFilter = "test-group-search-filter" - testUsernameAttrName = "test-username-attr" - testGroupNameAttrName = "test-group-name-attr" - testUIDAttrName = "test-uid-attr" + testNamespace = "test-namespace" + testName = "test-name" + testResourceUID = "test-resource-uid" + + testHost = "ldap.example.com:123" + + testBindSecretName = "test-bind-secret" + testBindUsername = "test-bind-username" + testBindPassword = "test-bind-password" + + testUserSearchBase = "test-user-search-base" + testUserSearchFilter = "test-user-search-filter" + testUserSearchUsernameAttrName = "test-username-attr" + testUserSearchUIDAttrName = "test-uid-attr" + + testGroupSearchBase = "test-group-search-base" + testGroupSearchFilter = "test-group-search-filter" + testGroupSearchUserAttributeForFilter = "test-group-search-filter-user-attr-for-filter" + testGroupSearchNameAttrName = "test-group-name-attr" ) testValidSecretData := map[string][]byte{"username": []byte(testBindUsername), "password": []byte(testBindPassword)} @@ -181,20 +186,21 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Spec: v1alpha1.LDAPIdentityProviderSpec{ Host: testHost, TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded}, - Bind: v1alpha1.LDAPIdentityProviderBind{SecretName: testSecretName}, + Bind: v1alpha1.LDAPIdentityProviderBind{SecretName: testBindSecretName}, UserSearch: v1alpha1.LDAPIdentityProviderUserSearch{ Base: testUserSearchBase, Filter: testUserSearchFilter, Attributes: v1alpha1.LDAPIdentityProviderUserSearchAttributes{ - Username: testUsernameAttrName, - UID: testUIDAttrName, + Username: testUserSearchUsernameAttrName, + UID: testUserSearchUIDAttrName, }, }, GroupSearch: v1alpha1.LDAPIdentityProviderGroupSearch{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, Attributes: v1alpha1.LDAPIdentityProviderGroupSearchAttributes{ - GroupName: testGroupNameAttrName, + GroupName: testGroupSearchNameAttrName, }, SkipGroupRefresh: false, }, @@ -217,13 +223,14 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, } @@ -250,7 +257,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Reason: "Success", Message: fmt.Sprintf( `successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, - testHost, testBindUsername, testSecretName, secretVersion), + testHost, testBindUsername, testBindSecretName, secretVersion), ObservedGeneration: gen, } } @@ -282,7 +289,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { validBindUserSecret := func(secretVersion string) *corev1.Secret { return &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: testSecretName, Namespace: testNamespace, ResourceVersion: secretVersion}, + ObjectMeta: metav1.ObjectMeta{Name: testBindSecretName, Namespace: testNamespace, ResourceVersion: secretVersion}, Type: corev1.SecretTypeBasicAuth, Data: testValidSecretData, } @@ -346,7 +353,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Status: "False", LastTransitionTime: now, Reason: "SecretNotFound", - Message: fmt.Sprintf(`secret "%s" not found`, testSecretName), + Message: fmt.Sprintf(`secret "%s" not found`, testBindSecretName), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -358,7 +365,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { name: "secret has wrong type", inputUpstreams: []runtime.Object{validUpstream}, inputSecrets: []runtime.Object{&corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: testSecretName, Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: testBindSecretName, Namespace: testNamespace}, Type: "some-other-type", Data: testValidSecretData, }}, @@ -374,7 +381,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Status: "False", LastTransitionTime: now, Reason: "SecretWrongType", - Message: fmt.Sprintf(`referenced Secret "%s" has wrong type "some-other-type" (should be "kubernetes.io/basic-auth")`, testSecretName), + Message: fmt.Sprintf(`referenced Secret "%s" has wrong type "some-other-type" (should be "kubernetes.io/basic-auth")`, testBindSecretName), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -386,7 +393,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { name: "secret is missing key", inputUpstreams: []runtime.Object{validUpstream}, inputSecrets: []runtime.Object{&corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: testSecretName, Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: testBindSecretName, Namespace: testNamespace}, Type: corev1.SecretTypeBasicAuth, }}, wantErr: controllerlib.ErrSyntheticRequeue.Error(), @@ -401,7 +408,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Status: "False", LastTransitionTime: now, Reason: "SecretMissingKeys", - Message: fmt.Sprintf(`referenced Secret "%s" is missing required keys ["username" "password"]`, testSecretName), + Message: fmt.Sprintf(`referenced Secret "%s" is missing required keys ["username" "password"]`, testBindSecretName), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -484,13 +491,14 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, }, }, @@ -548,13 +556,14 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, }, }, @@ -571,7 +580,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Reason: "Success", Message: fmt.Sprintf( `successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, - "ldap.example.com", testBindUsername, testSecretName, "4242"), + "ldap.example.com", testBindUsername, testBindSecretName, "4242"), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -590,7 +599,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Reason: "Success", Message: fmt.Sprintf( `successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, - "ldap.example.com", testBindUsername, testSecretName, "4242"), + "ldap.example.com", testBindUsername, testBindSecretName, "4242"), }, }}, }, @@ -619,13 +628,14 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, }, }, @@ -675,13 +685,14 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, }, }, @@ -1077,14 +1088,15 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, - SkipGroupRefresh: true, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, + SkipGroupRefresh: true, }, }, }, diff --git a/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go b/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go index 5c33ea2d7..33107dd8b 100644 --- a/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go +++ b/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package upstreamwatchers @@ -126,6 +126,7 @@ type UpstreamGenericLDAPUserSearch interface { type UpstreamGenericLDAPGroupSearch interface { Base() string Filter() string + UserAttributeForFilter() string GroupNameAttribute() string } diff --git a/internal/upstreamldap/upstreamldap.go b/internal/upstreamldap/upstreamldap.go index 9c8dd1d67..80d02b000 100644 --- a/internal/upstreamldap/upstreamldap.go +++ b/internal/upstreamldap/upstreamldap.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Package upstreamldap implements an abstraction of upstream LDAP IDP interactions. @@ -149,6 +149,10 @@ type GroupSearchConfig struct { // Filter is the filter to use for the group search in the upstream LDAP IDP. Empty means to use `member={}`. Filter string + // UserAttributeForFilter is the name of the user attribute whose value should be used to replace the placeholder + // in the Filter. Empty means to use 'dn'. + UserAttributeForFilter string + // GroupNameAttribute is the attribute in the LDAP group entry from which the group name should be // retrieved. Empty means to use 'cn'. GroupNameAttribute string @@ -166,13 +170,13 @@ type Provider struct { var _ provider.UpstreamLDAPIdentityProviderI = &Provider{} var _ authenticators.UserAuthenticator = &Provider{} -// Create a Provider. The config is not a pointer to ensure that a copy of the config is created, +// New creates a Provider. The config is not a pointer to ensure that a copy of the config is created, // making the resulting Provider use an effectively read-only configuration. func New(config ProviderConfig) *Provider { return &Provider{c: config} } -// A reader for the config. Returns a copy of the config to keep the underlying config read-only. +// GetConfig is a reader for the config. Returns a copy of the config to keep the underlying config read-only. func (p *Provider) GetConfig() ProviderConfig { return p.c } @@ -245,7 +249,15 @@ func (p *Provider) PerformRefresh(ctx context.Context, storedRefreshAttributes p return nil, nil } - mappedGroupNames, err := p.searchGroupsForUserDN(conn, userDN) + var groupSearchUserAttributeForFilterValue string + if p.useGroupSearchUserAttributeForFilter() { + groupSearchUserAttributeForFilterValue, err = p.getSearchResultAttributeValue(p.c.GroupSearch.UserAttributeForFilter, userEntry, newUsername) + if err != nil { + return nil, err + } + } + + mappedGroupNames, err := p.searchGroupsForUserMembership(conn, userDN, groupSearchUserAttributeForFilterValue) if err != nil { return nil, err } @@ -358,7 +370,7 @@ func (p *Provider) tlsConfig() (*tls.Config, error) { return ptls.DefaultLDAP(rootCAs), nil } -// A name for this upstream provider. +// GetName returns a name for this upstream provider. func (p *Provider) GetName() string { return p.c.Name } @@ -367,7 +379,7 @@ func (p *Provider) GetResourceUID() types.UID { return p.c.ResourceUID } -// Return a URL which uniquely identifies this LDAP provider, e.g. "ldaps://host.example.com:1234?base=user-search-base". +// GetURL returns a URL which uniquely identifies this LDAP provider, e.g. "ldaps://host.example.com:1234?base=user-search-base". // This URL is not used for connecting to the provider, but rather is used for creating a globally unique user // identifier by being combined with the user's UID, since user UIDs are only unique within one provider. func (p *Provider) GetURL() *url.URL { @@ -412,7 +424,7 @@ func (p *Provider) DryRunAuthenticateUser(ctx context.Context, username string, return p.authenticateUserImpl(ctx, username, grantedScopes, endUserBindFunc) } -// Authenticate an end user and return their mapped username, groups, and UID. Implements authenticators.UserAuthenticator. +// AuthenticateUser authenticates an end user and returns their mapped username, groups, and UID. Implements authenticators.UserAuthenticator. func (p *Provider) AuthenticateUser(ctx context.Context, username, password string, grantedScopes []string) (*authenticators.Response, bool, error) { endUserBindFunc := func(conn Conn, foundUserDN string) error { return conn.Bind(foundUserDN, password) @@ -463,13 +475,13 @@ func (p *Provider) authenticateUserImpl(ctx context.Context, username string, gr return response, true, nil } -func (p *Provider) searchGroupsForUserDN(conn Conn, userDN string) ([]string, error) { +func (p *Provider) searchGroupsForUserMembership(conn Conn, userDN string, groupSearchUserAttributeForFilterValue string) ([]string, error) { // If we do not have group search configured, skip this search. if len(p.c.GroupSearch.Base) == 0 { return []string{}, nil } - searchResult, err := conn.SearchWithPaging(p.groupSearchRequest(userDN), groupSearchPageSize) + searchResult, err := conn.SearchWithPaging(p.groupSearchRequest(userDN, groupSearchUserAttributeForFilterValue), groupSearchPageSize) if err != nil { return nil, fmt.Errorf(`error searching for group memberships for user with DN %q: %w`, userDN, err) } @@ -594,7 +606,15 @@ func (p *Provider) searchAndBindUser(conn Conn, username string, grantedScopes [ var mappedGroupNames []string if slices.Contains(grantedScopes, oidcapi.ScopeGroups) { - mappedGroupNames, err = p.searchGroupsForUserDN(conn, userEntry.DN) + var groupSearchUserAttributeForFilterValue string + if p.useGroupSearchUserAttributeForFilter() { + groupSearchUserAttributeForFilterValue, err = p.getSearchResultAttributeValue(p.c.GroupSearch.UserAttributeForFilter, userEntry, username) + if err != nil { + return nil, err + } + } + + mappedGroupNames, err = p.searchGroupsForUserMembership(conn, userEntry.DN, groupSearchUserAttributeForFilterValue) if err != nil { return nil, err } @@ -668,7 +688,7 @@ func (p *Provider) userSearchRequest(username string) *ldap.SearchRequest { } } -func (p *Provider) groupSearchRequest(userDN string) *ldap.SearchRequest { +func (p *Provider) groupSearchRequest(userDN string, groupSearchUserAttributeForFilterValue string) *ldap.SearchRequest { // See https://ldap.com/the-ldap-search-operation for general documentation of LDAP search options. return &ldap.SearchRequest{ BaseDN: p.c.GroupSearch.Base, @@ -677,7 +697,7 @@ func (p *Provider) groupSearchRequest(userDN string) *ldap.SearchRequest { SizeLimit: 0, // unlimited size because we will search with paging TimeLimit: 90, TypesOnly: false, - Filter: p.groupSearchFilter(userDN), + Filter: p.groupSearchFilter(userDN, groupSearchUserAttributeForFilterValue), Attributes: p.groupSearchRequestedAttributes(), Controls: nil, // nil because ldap.SearchWithPaging() will set the appropriate controls for us } @@ -698,6 +718,11 @@ func (p *Provider) refreshUserSearchRequest(dn string) *ldap.SearchRequest { } } +func (p *Provider) useGroupSearchUserAttributeForFilter() bool { + return len(p.c.GroupSearch.UserAttributeForFilter) > 0 && + p.c.GroupSearch.UserAttributeForFilter != distinguishedNameAttributeName +} + func (p *Provider) userSearchRequestedAttributes() []string { attributes := make([]string, 0, len(p.c.RefreshAttributeChecks)+2) if p.c.UserSearch.UsernameAttribute != distinguishedNameAttributeName { @@ -706,6 +731,9 @@ func (p *Provider) userSearchRequestedAttributes() []string { if p.c.UserSearch.UIDAttribute != distinguishedNameAttributeName { attributes = append(attributes, p.c.UserSearch.UIDAttribute) } + if p.useGroupSearchUserAttributeForFilter() { + attributes = append(attributes, p.c.GroupSearch.UserAttributeForFilter) + } for k := range p.c.RefreshAttributeChecks { attributes = append(attributes, k) } @@ -733,15 +761,20 @@ func (p *Provider) userSearchFilter(username string) string { return interpolateSearchFilter(p.c.UserSearch.Filter, safeUsername) } -func (p *Provider) groupSearchFilter(userDN string) string { - // The DN can contain characters that are considered special characters by LDAP searches, so it should be - // escaped before being included in the search filter to prevent bad search syntax. +func (p *Provider) groupSearchFilter(userDN string, groupSearchUserAttributeForFilterValue string) string { + valueToInterpolate := userDN + if p.useGroupSearchUserAttributeForFilter() { + // Instead of using the DN in placeholder substitution, use the value of the specified attribute. + valueToInterpolate = groupSearchUserAttributeForFilterValue + } + // The value to interpolate can contain characters that are considered special characters by LDAP searches, + // so it should be escaped before being included in the search filter to prevent bad search syntax. // E.g. for the DN `CN=My User (Admin),OU=Users,OU=my,DC=my,DC=domain` we must escape the parens. - safeUserDN := p.escapeForSearchFilter(userDN) + escapedValueToInterpolate := p.escapeForSearchFilter(valueToInterpolate) if len(p.c.GroupSearch.Filter) == 0 { - return fmt.Sprintf("(member=%s)", safeUserDN) + return fmt.Sprintf("(member=%s)", escapedValueToInterpolate) } - return interpolateSearchFilter(p.c.GroupSearch.Filter, safeUserDN) + return interpolateSearchFilter(p.c.GroupSearch.Filter, escapedValueToInterpolate) } func interpolateSearchFilter(filterFormat, valueToInterpolateIntoFilter string) string { diff --git a/internal/upstreamldap/upstreamldap_test.go b/internal/upstreamldap/upstreamldap_test.go index 469b5bffc..c6d1d1269 100644 --- a/internal/upstreamldap/upstreamldap_test.go +++ b/internal/upstreamldap/upstreamldap_test.go @@ -56,11 +56,13 @@ const ( testUserDNWithSpecialCharsEscaped = `user DN with \2a \5c special characters \28\29` expectedGroupSearchPageSize = uint32(250) + + testGroupSearchFilterInterpolationSpec = "(some-group-filter=%s-and-more-filter=%s)" ) var ( testUserSearchFilterInterpolated = fmt.Sprintf("(some-user-filter=%s-and-more-filter=%s)", testUpstreamUsername, testUpstreamUsername) - testGroupSearchFilterInterpolated = fmt.Sprintf("(some-group-filter=%s-and-more-filter=%s)", testUserSearchResultDNValue, testUserSearchResultDNValue) + testGroupSearchFilterInterpolated = fmt.Sprintf(testGroupSearchFilterInterpolationSpec, testUserSearchResultDNValue, testUserSearchResultDNValue) ) func TestEndUserAuthentication(t *testing.T) { @@ -714,6 +716,236 @@ func TestEndUserAuthentication(t *testing.T) { }, wantError: testutil.WantExactErrorString("found 0 values for attribute \"some-attribute-to-check-during-refresh\" while searching for user \"some-upstream-username\", but expected 1 result"), }, + { + name: "when the UserAttributeForFilter is set to something other than dn", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + ldap.NewEntryAttribute(testUserSearchUIDAttribute, []string{testUserSearchResultUIDAttributeValue}), + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue"}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(func(r *ldap.SearchRequest) { + // need to interpolate the attr's value into the filter instead of interpolating the default (user's dn) + r.Filter = fmt.Sprintf(testGroupSearchFilterInterpolationSpec, "someUserAttrValue", "someUserAttrValue") + }), expectedGroupSearchPageSize). + Return(exampleGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + bindEndUserMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testUserSearchResultDNValue, testUpstreamPassword).Times(1) + }, + wantAuthResponse: expectedAuthResponse(nil), + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but groups scope is not granted so skips validating UserAttributeForFilter attribute value", + username: testUpstreamUsername, + password: testUpstreamPassword, + grantedScopes: []string{}, // no groups scope + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(exampleUserSearchResult, nil).Times(1) // result does not contain someUserAttrName, but does not matter since group search is skipped + conn.EXPECT().Close().Times(1) + }, + bindEndUserMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testUserSearchResultDNValue, testUpstreamPassword).Times(1) + }, + wantAuthResponse: expectedAuthResponse(func(r *authenticators.Response) { + info := r.User.(*user.DefaultInfo) + info.Groups = nil + }), + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but that attribute is not returned by the user search", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(exampleUserSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantError: testutil.WantExactErrorString("found 0 values for attribute \"someUserAttrName\" while searching for user \"some-upstream-username\", but expected 1 result"), + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but that attribute is returned by the user search with an empty value", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + ldap.NewEntryAttribute(testUserSearchUIDAttribute, []string{testUserSearchResultUIDAttributeValue}), + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{""}), // empty value! + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantError: testutil.WantExactErrorString("found empty value for attribute \"someUserAttrName\" while searching for user \"some-upstream-username\", but expected value to be non-empty"), + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but that attribute is returned by the user search with multiple values", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + ldap.NewEntryAttribute(testUserSearchUIDAttribute, []string{testUserSearchResultUIDAttributeValue}), + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue1", "someUserAttrValue2"}), // oops, multiple values! + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantError: testutil.WantExactErrorString("found 2 values for attribute \"someUserAttrName\" while searching for user \"some-upstream-username\", but expected 1 result"), + }, + { + name: "when the UserAttributeForFilter is set to dn, it should act the same as when it is not set", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "dn" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(nil)).Return(exampleUserSearchResult, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(nil), expectedGroupSearchPageSize). + Return(exampleGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + bindEndUserMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testUserSearchResultDNValue, testUpstreamPassword).Times(1) + }, + wantAuthResponse: expectedAuthResponse(nil), + }, + { + name: "when the UserAttributeForFilter is set to something other than dn and the value of that attr contains special characters which need to be escaped for an LDAP filter", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + ldap.NewEntryAttribute(testUserSearchUIDAttribute, []string{testUserSearchResultUIDAttributeValue}), + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue&(abc)"}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(func(r *ldap.SearchRequest) { + // need to interpolate the attr's value into the filter instead of interpolating the default (user's dn) + r.Filter = fmt.Sprintf(testGroupSearchFilterInterpolationSpec, `someUserAttrValue&\28abc\29`, `someUserAttrValue&\28abc\29`) + }), expectedGroupSearchPageSize). + Return(exampleGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + bindEndUserMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testUserSearchResultDNValue, testUpstreamPassword).Times(1) + }, + wantAuthResponse: expectedAuthResponse(nil), + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but the group search filter is not set", + username: testUpstreamUsername, + password: testUpstreamPassword, + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.Filter = "" + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + searchMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName"} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + ldap.NewEntryAttribute(testUserSearchUIDAttribute, []string{testUserSearchResultUIDAttributeValue}), + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue&(abc)"}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(func(r *ldap.SearchRequest) { + // need to interpolate the attr's value into the filter instead of interpolating the default (user's dn) + r.Filter = `(member=someUserAttrValue&\28abc\29)` // note that "member={}" is the default group search filter + }), expectedGroupSearchPageSize). + Return(exampleGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + bindEndUserMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testUserSearchResultDNValue, testUpstreamPassword).Times(1) + }, + wantAuthResponse: expectedAuthResponse(nil), + }, { name: "when dial fails", username: testUpstreamUsername, @@ -1486,7 +1718,8 @@ func TestUpstreamRefresh(t *testing.T) { }), setupMocks: func(conn *mockldapconn.MockConn) { conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) - conn.EXPECT().Search(expectedUserSearch(nil)).Return(happyPathUserSearchResult, nil).Times(1) // note that group search is not expected + conn.EXPECT().Search(expectedUserSearch(nil)).Return(happyPathUserSearchResult, nil).Times(1) + // note that group search is not expected conn.EXPECT().Close().Times(1) }, wantGroups: nil, // do not update groups @@ -1497,11 +1730,240 @@ func TestUpstreamRefresh(t *testing.T) { setupMocks: func(conn *mockldapconn.MockConn) { conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) conn.EXPECT().Search(expectedUserSearch(nil)).Return(happyPathUserSearchResult, nil).Times(1) + // note that group search is not expected + conn.EXPECT().Close().Times(1) + }, + grantedScopes: []string{}, + wantGroups: nil, + }, + { + name: "happy path where group search is configured but skipGroupRefresh is set, when the UserAttributeForFilter is set to something other than dn, still skips group refresh, and skips validating UserAttributeForFilter attribute value", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.SkipGroupRefresh = true + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(happyPathUserSearchResult, nil).Times(1) + // note that group search is not expected + conn.EXPECT().Close().Times(1) + }, + wantGroups: nil, // do not update groups + }, + { + name: "happy path where group search is configured but groups scope isn't included, when the UserAttributeForFilter is set to something other than dn, still skips group refresh, and skips validating UserAttributeForFilter attribute value", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(happyPathUserSearchResult, nil).Times(1) + // note that group search is not expected conn.EXPECT().Close().Times(1) }, grantedScopes: []string{}, wantGroups: nil, }, + { + name: "happy path when the UserAttributeForFilter is set to something other than dn", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + { + Name: testUserSearchUIDAttribute, + ByteValues: [][]byte{[]byte(testUserSearchResultUIDAttributeValue)}, + }, + { + Name: pwdLastSetAttribute, + Values: []string{"132801740800000000"}, + ByteValues: [][]byte{[]byte("132801740800000000")}, + }, + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue"}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(func(r *ldap.SearchRequest) { + // need to interpolate the attr's value into the filter instead of interpolating the default (user's dn) + r.Filter = fmt.Sprintf(testGroupSearchFilterInterpolationSpec, "someUserAttrValue", "someUserAttrValue") + }), expectedGroupSearchPageSize).Return(happyPathGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantGroups: []string{testGroupSearchResultGroupNameAttributeValue1, testGroupSearchResultGroupNameAttributeValue2}, + }, + { + name: "happy path when the UserAttributeForFilter is set to something other than dn but the group search filter is not set", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.Filter = "" + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + { + Name: testUserSearchUIDAttribute, + ByteValues: [][]byte{[]byte(testUserSearchResultUIDAttributeValue)}, + }, + { + Name: pwdLastSetAttribute, + Values: []string{"132801740800000000"}, + ByteValues: [][]byte{[]byte("132801740800000000")}, + }, + // additionally get back the attr from the user search + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue&(abc)"}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(func(r *ldap.SearchRequest) { + // need to interpolate the attr's value into the filter instead of interpolating the default (user's dn) + r.Filter = `(member=someUserAttrValue&\28abc\29)` // member={} is the default, and special chars are escaped + }), expectedGroupSearchPageSize).Return(happyPathGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantGroups: []string{testGroupSearchResultGroupNameAttributeValue1, testGroupSearchResultGroupNameAttributeValue2}, + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but that attribute is not returned by the user search", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + { + Name: testUserSearchUIDAttribute, + ByteValues: [][]byte{[]byte(testUserSearchResultUIDAttributeValue)}, + }, + { + Name: pwdLastSetAttribute, + Values: []string{"132801740800000000"}, + ByteValues: [][]byte{[]byte("132801740800000000")}, + }, + // did not return "someUserAttrName" attribute + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantErr: "found 0 values for attribute \"someUserAttrName\" while searching for user \"some-upstream-username-value\", but expected 1 result", + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but that attribute is returned by the user search with an empty value", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + { + Name: testUserSearchUIDAttribute, + ByteValues: [][]byte{[]byte(testUserSearchResultUIDAttributeValue)}, + }, + { + Name: pwdLastSetAttribute, + Values: []string{"132801740800000000"}, + ByteValues: [][]byte{[]byte("132801740800000000")}, + }, + ldap.NewEntryAttribute("someUserAttrName", []string{""}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantErr: "found empty value for attribute \"someUserAttrName\" while searching for user \"some-upstream-username-value\", but expected value to be non-empty", + }, + { + name: "when the UserAttributeForFilter is set to something other than dn but that attribute is returned by the user search with a multiple values", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "someUserAttrName" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(func(r *ldap.SearchRequest) { + // need to additionally ask for the attribute when performing user search + r.Attributes = []string{testUserSearchUsernameAttribute, testUserSearchUIDAttribute, "someUserAttrName", pwdLastSetAttribute} + })).Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: testUserSearchResultDNValue, + Attributes: []*ldap.EntryAttribute{ + ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testUserSearchResultUsernameAttributeValue}), + { + Name: testUserSearchUIDAttribute, + ByteValues: [][]byte{[]byte(testUserSearchResultUIDAttributeValue)}, + }, + { + Name: pwdLastSetAttribute, + Values: []string{"132801740800000000"}, + ByteValues: [][]byte{[]byte("132801740800000000")}, + }, + ldap.NewEntryAttribute("someUserAttrName", []string{"someUserAttrValue1", "someUserAttrValue2"}), + }, + }, + }, + }, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantErr: "found 2 values for attribute \"someUserAttrName\" while searching for user \"some-upstream-username-value\", but expected 1 result", + }, + { + name: "happy path when the UserAttributeForFilter is set to dn, it should act the same as when it is not set", + providerConfig: providerConfig(func(p *ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "dn" + }), + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch(nil)).Return(happyPathUserSearchResult, nil).Times(1) + conn.EXPECT().SearchWithPaging(expectedGroupSearch(nil), expectedGroupSearchPageSize).Return(happyPathGroupSearchResult, nil).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantGroups: []string{testGroupSearchResultGroupNameAttributeValue1, testGroupSearchResultGroupNameAttributeValue2}, + }, { name: "error where dial fails", providerConfig: providerConfig(nil), From e3b7ba3677f96a1a907f17a0345f160b0ceab6f9 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Fri, 26 May 2023 08:38:00 -0700 Subject: [PATCH 4/9] Add group search tests for UserAttributeForFilter in ldap_client_test.go --- test/deploy/tools/ldap.yaml | 6 +- test/integration/ldap_client_test.go | 92 ++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/test/deploy/tools/ldap.yaml b/test/deploy/tools/ldap.yaml index d8a82525d..895765070 100644 --- a/test/deploy/tools/ldap.yaml +++ b/test/deploy/tools/ldap.yaml @@ -122,7 +122,7 @@ ldap.ldif: | objectClass: posixGroup objectClass: top cn: ball-game-players-posix - gidNumber: 1001 + gidNumber: 1002 memberUid: pinny memberUid: olive @@ -131,7 +131,7 @@ ldap.ldif: | objectClass: posixGroup objectClass: top cn: seals-posix - gidNumber: 1002 + gidNumber: 1001 memberUid: pinny # walruses group again, but this time defined as a posixGroup @@ -139,7 +139,7 @@ ldap.ldif: | objectClass: posixGroup objectClass: top cn: walruses-posix - gidNumber: 1002 + gidNumber: 1000 memberUid: wally #@ end diff --git a/test/integration/ldap_client_test.go b/test/integration/ldap_client_test.go index 2312516f6..04eead885 100644 --- a/test/integration/ldap_client_test.go +++ b/test/integration/ldap_client_test.go @@ -347,6 +347,98 @@ func TestLDAPSearch_Parallel(t *testing.T) { ExtraRefreshAttributes: map[string]string{}, }, }, + { + name: "using a group search with UserAttributeForFilter set to uid", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.Filter = "&(objectClass=posixGroup)(memberUid={})" + p.GroupSearch.UserAttributeForFilter = "uid" + })), + wantAuthResponse: &authenticators.Response{ + User: &user.DefaultInfo{Name: "pinny", UID: b64("1000"), Groups: []string{"ball-game-players-posix", "seals-posix"}}, + DN: "cn=pinny,ou=users,dc=pinniped,dc=dev", + ExtraRefreshAttributes: map[string]string{}, + }, + }, + { + name: "using a group search with UserAttributeForFilter set to cn", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.Filter = "&(objectClass=posixGroup)(memberUid={})" + p.GroupSearch.UserAttributeForFilter = "cn" // this only works because pinny's uid and cn are both "pinny" + })), + wantAuthResponse: &authenticators.Response{ + User: &user.DefaultInfo{Name: "pinny", UID: b64("1000"), Groups: []string{"ball-game-players-posix", "seals-posix"}}, + DN: "cn=pinny,ou=users,dc=pinniped,dc=dev", + ExtraRefreshAttributes: map[string]string{}, + }, + }, + { + name: "using a group search with UserAttributeForFilter and a creative filter", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.Filter = "&(objectClass=groupOfNames)(member=cn={},ou=users,dc=pinniped,dc=dev)" // not the typical usage, but possible + p.GroupSearch.UserAttributeForFilter = "cn" + })), + wantAuthResponse: &authenticators.Response{ + User: &user.DefaultInfo{Name: "pinny", UID: b64("1000"), Groups: []string{"ball-game-players", "seals"}}, + DN: "cn=pinny,ou=users,dc=pinniped,dc=dev", + ExtraRefreshAttributes: map[string]string{}, + }, + }, + { + name: "using a group search with UserAttributeForFilter set to givenName", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.Filter = "&(objectClass=posixGroup)(memberUid={})" + p.GroupSearch.UserAttributeForFilter = "givenName" // pinny's givenName is not "pinny" so it should not find any groups, and also should not error on the emoji in the givenName + })), + wantAuthResponse: &authenticators.Response{ + User: &user.DefaultInfo{Name: "pinny", UID: b64("1000"), Groups: []string{}}, + DN: "cn=pinny,ou=users,dc=pinniped,dc=dev", + ExtraRefreshAttributes: map[string]string{}, + }, + }, + { + name: "using a group search with UserAttributeForFilter set to gidNumber", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.Filter = "&(objectClass=posixGroup)(gidNumber={})" + p.GroupSearch.UserAttributeForFilter = "gidNumber" + })), + wantAuthResponse: &authenticators.Response{ + User: &user.DefaultInfo{Name: "pinny", UID: b64("1000"), Groups: []string{"walruses-posix"}}, + DN: "cn=pinny,ou=users,dc=pinniped,dc=dev", + ExtraRefreshAttributes: map[string]string{}, + }, + }, + { + name: "using a group search with UserAttributeForFilter set to dn", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "dn" // this should act the same as when it is not set + })), + wantAuthResponse: &authenticators.Response{ + User: &user.DefaultInfo{Name: "pinny", UID: b64("1000"), Groups: []string{"ball-game-players", "seals"}}, + DN: "cn=pinny,ou=users,dc=pinniped,dc=dev", + ExtraRefreshAttributes: map[string]string{}, + }, + }, + { + name: "using a group search with UserAttributeForFilter set to an attribute that does not exist on the user", + username: "pinny", + password: pinnyPassword, + provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { + p.GroupSearch.UserAttributeForFilter = "foobar" + })), + wantError: testutil.WantExactErrorString(`found 0 values for attribute "foobar" while searching for user "pinny", but expected 1 result`), + }, { name: "when the bind user username is not a valid DN", username: "pinny", From 552eceabdbf52678edb1e84bcdf136d8237fce27 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Fri, 26 May 2023 11:47:54 -0700 Subject: [PATCH 5/9] Add integration test for UserAttributeForFilter group search setting Also adds new integration test env var to support the new test: PINNIPED_TEST_LDAP_EXPECTED_DIRECT_POSIX_GROUPS_CN --- hack/prepare-for-integration-tests.sh | 3 +- test/integration/supervisor_login_test.go | 38 +++++++++++++++++++++-- test/testlib/env.go | 4 ++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/hack/prepare-for-integration-tests.sh b/hack/prepare-for-integration-tests.sh index 76c5edf0a..bb0fa104a 100755 --- a/hack/prepare-for-integration-tests.sh +++ b/hack/prepare-for-integration-tests.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +# Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 # @@ -420,6 +420,7 @@ export PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_VALUE="pinny.ldap@example.com" export PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_DN="cn=ball-game-players,ou=beach-groups,ou=groups,dc=pinniped,dc=dev;cn=seals,ou=groups,dc=pinniped,dc=dev" export PINNIPED_TEST_LDAP_EXPECTED_INDIRECT_GROUPS_DN="cn=pinnipeds,ou=groups,dc=pinniped,dc=dev;cn=mammals,ou=groups,dc=pinniped,dc=dev" export PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_CN="ball-game-players;seals" +export PINNIPED_TEST_LDAP_EXPECTED_DIRECT_POSIX_GROUPS_CN="ball-game-players-posix;seals-posix" export PINNIPED_TEST_LDAP_EXPECTED_INDIRECT_GROUPS_CN="pinnipeds;mammals" export PINNIPED_TEST_CLI_OIDC_ISSUER=https://dex.tools.svc.cluster.local/dex export PINNIPED_TEST_CLI_OIDC_ISSUER_CA_BUNDLE="${test_ca_bundle_pem}" diff --git a/test/integration/supervisor_login_test.go b/test/integration/supervisor_login_test.go index fb8efd09a..511377b57 100644 --- a/test/integration/supervisor_login_test.go +++ b/test/integration/supervisor_login_test.go @@ -134,11 +134,13 @@ func TestSupervisorLogin_Browser(t *testing.T) { }, }, GroupSearch: idpv1alpha1.LDAPIdentityProviderGroupSearch{ - Base: env.SupervisorUpstreamLDAP.GroupSearchBase, - Filter: "", + Base: env.SupervisorUpstreamLDAP.GroupSearchBase, + Filter: "", + UserAttributeForFilter: "", Attributes: idpv1alpha1.LDAPIdentityProviderGroupSearchAttributes{ GroupName: "dn", }, + SkipGroupRefresh: false, }, } @@ -471,6 +473,38 @@ func TestSupervisorLogin_Browser(t *testing.T) { }, wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs, }, + { + name: "ldap using posix groups by using the UserAttributeForFilter option to adjust the group search filter behavior", + maybeSkip: skipLDAPTests, + createIDP: func(t *testing.T) string { + idp, _ := createLDAPIdentityProvider(t, func(spec *idpv1alpha1.LDAPIdentityProviderSpec) { + spec.GroupSearch.Filter = "&(objectClass=posixGroup)(memberUid={})" + spec.GroupSearch.UserAttributeForFilter = "uid" + spec.GroupSearch.Attributes.GroupName = "cn" + }) + return idp.Name + }, + requestAuthorization: func(t *testing.T, _, downstreamAuthorizeURL, _, _, _ string, httpClient *http.Client) { + requestAuthorizationUsingCLIPasswordFlow(t, + downstreamAuthorizeURL, + env.SupervisorUpstreamLDAP.TestUserMailAttributeValue, // username to present to server during login + env.SupervisorUpstreamLDAP.TestUserPassword, // password to present to server during login + httpClient, + false, + ) + }, + // the ID token Subject should be the Host URL plus the value pulled from the requested UserSearch.Attributes.UID attribute + wantDownstreamIDTokenSubjectToMatch: "^" + regexp.QuoteMeta( + "ldaps://"+env.SupervisorUpstreamLDAP.Host+ + "?base="+url.QueryEscape(env.SupervisorUpstreamLDAP.UserSearchBase)+ + "&sub="+base64.RawURLEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeValue)), + ) + "$", + // the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute + wantDownstreamIDTokenUsernameToMatch: func(_ string) string { + return "^" + regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUserMailAttributeValue) + "$" + }, + wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectPosixGroupsCNs, + }, { name: "ldap without requesting username and groups scope gets them anyway for pinniped-cli for backwards compatibility with old CLIs", maybeSkip: skipLDAPTests, diff --git a/test/testlib/env.go b/test/testlib/env.go index fd79fd858..387d8a08c 100644 --- a/test/testlib/env.go +++ b/test/testlib/env.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package testlib @@ -98,6 +98,7 @@ type TestLDAPUpstream struct { TestUserUniqueIDAttributeName string `json:"testUserUniqueIDAttributeName"` TestUserUniqueIDAttributeValue string `json:"testUserUniqueIDAttributeValue"` TestUserDirectGroupsCNs []string `json:"testUserDirectGroupsCNs"` + TestUserDirectPosixGroupsCNs []string `json:"testUserDirectPosixGroupsCNs"` TestUserDirectGroupsDNs []string `json:"testUserDirectGroupsDNs"` //nolint:revive // this is "distinguished names", not "DNS" TestUserSAMAccountNameValue string `json:"testUserSAMAccountNameValue"` TestUserPrincipalNameValue string `json:"testUserPrincipalNameValue"` @@ -267,6 +268,7 @@ func loadEnvVars(t *testing.T, result *TestEnv) { TestUserMailAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_NAME"), TestUserMailAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_VALUE"), TestUserDirectGroupsCNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_CN"), ";")), + TestUserDirectPosixGroupsCNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_POSIX_GROUPS_CN"), ";")), TestUserDirectGroupsDNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_DN"), ";")), TestUserPassword: needEnv(t, "PINNIPED_TEST_LDAP_USER_PASSWORD"), } From 0a1f96688676c3fc110357730de31d1cc7e35792 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Wed, 31 May 2023 11:09:08 -0700 Subject: [PATCH 6/9] Add ActiveDirectoryIdentityProvider.spec.groupSearch.userAttributeForFilter Add the field to the tmpl file and run codegen. Also update the count of the fields of our APIs in an integration test. --- ...es_activedirectoryidentityprovider.go.tmpl | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.17/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.18/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.19/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.20/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.21/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.22/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.23/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.24/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.25/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.26/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- generated/1.27/README.adoc | 3 ++- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- ....dev_activedirectoryidentityproviders.yaml | 23 +++++++++++++++---- .../types_activedirectoryidentityprovider.go | 20 ++++++++++++---- test/integration/kube_api_discovery_test.go | 2 +- 37 files changed, 459 insertions(+), 112 deletions(-) diff --git a/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go.tmpl b/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go.tmpl index 18626629e..a8a83e644 100644 --- a/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go.tmpl +++ b/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go.tmpl @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.17/README.adoc b/generated/1.17/README.adoc index bf90b3bcf..78ee0c31b 100644 --- a/generated/1.17/README.adoc +++ b/generated/1.17/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.17/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.17/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.17/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.17/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.17/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.17/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.17/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.17/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.18/README.adoc b/generated/1.18/README.adoc index ba453a286..06536d63c 100644 --- a/generated/1.18/README.adoc +++ b/generated/1.18/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.18/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.18/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.18/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.18/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.18/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.18/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.18/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.18/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.19/README.adoc b/generated/1.19/README.adoc index 979c79b83..abafdbf0a 100644 --- a/generated/1.19/README.adoc +++ b/generated/1.19/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.19/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.19/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.19/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.19/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.19/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.19/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.19/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.19/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.20/README.adoc b/generated/1.20/README.adoc index 9da145050..56e3bb2be 100644 --- a/generated/1.20/README.adoc +++ b/generated/1.20/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.20/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.20/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.20/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.20/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.20/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.20/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.20/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.20/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.21/README.adoc b/generated/1.21/README.adoc index b14a89b1d..3a8e90363 100644 --- a/generated/1.21/README.adoc +++ b/generated/1.21/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.21/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.21/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.21/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.21/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.21/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.21/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.21/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.21/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.22/README.adoc b/generated/1.22/README.adoc index b3de67b2e..d73354676 100644 --- a/generated/1.22/README.adoc +++ b/generated/1.22/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.22/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.22/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.22/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.22/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.22/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.22/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.22/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.22/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.23/README.adoc b/generated/1.23/README.adoc index 3f1604633..c08364bcc 100644 --- a/generated/1.23/README.adoc +++ b/generated/1.23/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.23/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.23/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.23/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.23/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.23/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.23/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.23/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.23/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.24/README.adoc b/generated/1.24/README.adoc index b4bb2b68b..128e88a6e 100644 --- a/generated/1.24/README.adoc +++ b/generated/1.24/README.adoc @@ -1062,7 +1062,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.24/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.24/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.24/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.24/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.24/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.24/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.24/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.24/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.25/README.adoc b/generated/1.25/README.adoc index 1e81b7ca0..314d1c119 100644 --- a/generated/1.25/README.adoc +++ b/generated/1.25/README.adoc @@ -1058,7 +1058,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.25/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.25/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.25/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.25/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.25/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.25/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.25/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.25/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.26/README.adoc b/generated/1.26/README.adoc index a89085ac2..6e3a4d4fe 100644 --- a/generated/1.26/README.adoc +++ b/generated/1.26/README.adoc @@ -1058,7 +1058,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.26/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.26/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.26/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.26/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.26/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.26/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.26/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.26/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/1.27/README.adoc b/generated/1.27/README.adoc index 487570a7b..c099d5572 100644 --- a/generated/1.27/README.adoc +++ b/generated/1.27/README.adoc @@ -1058,7 +1058,8 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro |=== | Field | Description | *`base`* __string__ | Base is the dn (distinguished name) that should be used as the search base when searching for groups. E.g. "ou=groups,dc=example,dc=com". Optional, when not specified it will be based on the result of a query for the defaultNamingContext (see https://docs.microsoft.com/en-us/windows/win32/adschema/rootdse). The default behavior searches your entire domain for groups. It may make sense to specify a subtree as a search base if you wish to exclude some groups for security reasons or to make searches faster. -| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" +| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. | *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search. | *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. diff --git a/generated/1.27/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/1.27/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/1.27/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/1.27/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/generated/1.27/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/generated/1.27/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 15d2a7919..5fab109d8 100644 --- a/generated/1.27/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.27/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -107,10 +107,11 @@ spec: description: Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will - be dynamically replaced by the dn (distinguished name) of the - user entry found as a result of the user search. E.g. "member={}" - or "&(objectClass=groupOfNames)(member={})". For more information - about ActiveDirectory filters, see https://ldap.com/ldap-filters. + be dynamically replaced by the value of an attribute of the + user entry found as a result of the user search. Which attribute's + value is used to replace the placeholder(s) depends on the value + of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -142,6 +143,20 @@ spec: carefully read all release notes before upgrading to ensure that the meaning of this field has not changed." type: boolean + userAttributeForFilter: + description: UserAttributeForFilter specifies which attribute's + value from the user entry found as a result of the user search + will be used to replace the "{}" placeholder(s) in the group + search Filter. For example, specifying "uid" as the UserAttributeForFilter + while specifying "&(objectClass=posixGroup)(memberUid={})" as + the Filter would search for groups by replacing the "{}" placeholder + in the Filter with the value of the user's "uid" attribute. + Optional. When not specified, the default will act as if "dn" + were specified. For example, leaving UserAttributeForFilter + unspecified while specifying "&(objectClass=groupOfNames)(member={})" + as the Filter would search for groups by replacing the "{}" + placeholder(s) with the dn (distinguished name) of the user. + type: string type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/generated/latest/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/latest/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index 18626629e..a8a83e644 100644 --- a/generated/latest/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go +++ b/generated/latest/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -114,9 +114,10 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. // The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the - // dn (distinguished name) of the user entry found as a result of the user search. E.g. "member={}" or - // "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see - // https://ldap.com/ldap-filters. + // value of an attribute of the user entry found as a result of the user search. Which attribute's + // value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. + // E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". + // For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. // Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. // Optional. When not specified, the default will act as if the filter were specified as // "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". @@ -127,6 +128,17 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // +optional Filter string `json:"filter,omitempty"` + // UserAttributeForFilter specifies which attribute's value from the user entry found as a result of + // the user search will be used to replace the "{}" placeholder(s) in the group search Filter. + // For example, specifying "uid" as the UserAttributeForFilter while specifying + // "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing + // the "{}" placeholder in the Filter with the value of the user's "uid" attribute. + // Optional. When not specified, the default will act as if "dn" were specified. For example, leaving + // UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter + // would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user. + // +optional + UserAttributeForFilter string `json:"userAttributeForFilter,omitempty"` + // Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as // the result of the group search. // +optional diff --git a/test/integration/kube_api_discovery_test.go b/test/integration/kube_api_discovery_test.go index 53c810811..524f9116d 100644 --- a/test/integration/kube_api_discovery_test.go +++ b/test/integration/kube_api_discovery_test.go @@ -441,7 +441,7 @@ func TestGetAPIResourceList(t *testing.T) { //nolint:gocyclo // each t.Run is pr // over time, make a rudimentary assertion that this test exercised the whole tree of all fields of all // Pinniped API resources. Without this, the test could accidentally skip parts of the tree if the // format has changed. - require.Equal(t, 226, foundFieldNames, + require.Equal(t, 227, foundFieldNames, "Expected to find all known fields of all Pinniped API resources. "+ "You may will need to update this expectation if you added new fields to the API types.", ) From 600d002a35f454b1cbd31460d0bf40d3555ac287 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Wed, 31 May 2023 11:17:40 -0700 Subject: [PATCH 7/9] Use groupSearch.userAttributeForFilter during ActiveDirectory group searches - Load the setting in the controller. - The LDAP auth code is shared between AD and LDAP, so no new changes there in this commit. --- .../active_directory_upstream_watcher.go | 11 +- .../active_directory_upstream_watcher_test.go | 213 ++++++++++-------- 2 files changed, 123 insertions(+), 101 deletions(-) diff --git a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go index 38a677f03..9cb773b51 100644 --- a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go +++ b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go @@ -204,7 +204,7 @@ func (g *activeDirectoryUpstreamGenericLDAPGroupSearch) Filter() string { } func (g *activeDirectoryUpstreamGenericLDAPGroupSearch) UserAttributeForFilter() string { - return "" + return g.groupSearch.UserAttributeForFilter } func (g *activeDirectoryUpstreamGenericLDAPGroupSearch) GroupNameAttribute() string { @@ -333,10 +333,11 @@ func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context, UIDAttribute: adUpstreamImpl.Spec().UserSearch().UIDAttribute(), }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: spec.GroupSearch.Base, - Filter: adUpstreamImpl.Spec().GroupSearch().Filter(), - GroupNameAttribute: adUpstreamImpl.Spec().GroupSearch().GroupNameAttribute(), - SkipGroupRefresh: spec.GroupSearch.SkipGroupRefresh, + Base: spec.GroupSearch.Base, + Filter: adUpstreamImpl.Spec().GroupSearch().Filter(), + UserAttributeForFilter: adUpstreamImpl.Spec().GroupSearch().UserAttributeForFilter(), + GroupNameAttribute: adUpstreamImpl.Spec().GroupSearch().GroupNameAttribute(), + SkipGroupRefresh: spec.GroupSearch.SkipGroupRefresh, }, Dialer: c.ldapDialer, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){ diff --git a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher_test.go b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher_test.go index dc5fa6939..9d8d88404 100644 --- a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package activedirectoryupstreamwatcher @@ -149,20 +149,25 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { now := metav1.NewTime(time.Now().UTC()) const ( - testNamespace = "test-namespace" - testName = "test-name" - testResourceUID = "test-uid" - testSecretName = "test-bind-secret" - testBindUsername = "test-bind-username" - testBindPassword = "test-bind-password" - testHost = "ldap.example.com:123" - testUserSearchBase = "test-user-search-base" - testUserSearchFilter = "test-user-search-filter" - testGroupSearchBase = "test-group-search-base" - testGroupSearchFilter = "test-group-search-filter" - testUsernameAttrName = "test-username-attr" - testGroupNameAttrName = "test-group-name-attr" - testUIDAttrName = "test-uid-attr" + testNamespace = "test-namespace" + testName = "test-name" + testResourceUID = "test-uid" + + testHost = "ldap.example.com:123" + + testBindSecretName = "test-bind-secret" + testBindUsername = "test-bind-username" + testBindPassword = "test-bind-password" + + testUserSearchBase = "test-user-search-base" + testUserSearchFilter = "test-user-search-filter" + testUserSearchUsernameAttrName = "test-username-attr" + testUserSearchUIDAttrName = "test-uid-attr" + + testGroupSearchBase = "test-group-search-base" + testGroupSearchFilter = "test-group-search-filter" + testGroupSearchUserAttributeForFilter = "test-group-search-filter-user-attr-for-filter" + testGroupSearchNameAttrName = "test-group-name-attr" ) testValidSecretData := map[string][]byte{"username": []byte(testBindUsername), "password": []byte(testBindPassword)} @@ -177,20 +182,21 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Spec: v1alpha1.ActiveDirectoryIdentityProviderSpec{ Host: testHost, TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded}, - Bind: v1alpha1.ActiveDirectoryIdentityProviderBind{SecretName: testSecretName}, + Bind: v1alpha1.ActiveDirectoryIdentityProviderBind{SecretName: testBindSecretName}, UserSearch: v1alpha1.ActiveDirectoryIdentityProviderUserSearch{ Base: testUserSearchBase, Filter: testUserSearchFilter, Attributes: v1alpha1.ActiveDirectoryIdentityProviderUserSearchAttributes{ - Username: testUsernameAttrName, - UID: testUIDAttrName, + Username: testUserSearchUsernameAttrName, + UID: testUserSearchUIDAttrName, }, }, GroupSearch: v1alpha1.ActiveDirectoryIdentityProviderGroupSearch{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, Attributes: v1alpha1.ActiveDirectoryIdentityProviderGroupSearchAttributes{ - GroupName: testGroupNameAttrName, + GroupName: testGroupSearchNameAttrName, }, SkipGroupRefresh: false, }, @@ -213,13 +219,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -252,7 +259,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Reason: "Success", Message: fmt.Sprintf( `successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, - testHost, testBindUsername, testSecretName, secretVersion), + testHost, testBindUsername, testBindSecretName, secretVersion), ObservedGeneration: gen, } } @@ -324,7 +331,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { validBindUserSecret := func(secretVersion string) *corev1.Secret { return &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: testSecretName, Namespace: testNamespace, ResourceVersion: secretVersion}, + ObjectMeta: metav1.ObjectMeta{Name: testBindSecretName, Namespace: testNamespace, ResourceVersion: secretVersion}, Type: corev1.SecretTypeBasicAuth, Data: testValidSecretData, } @@ -417,7 +424,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Status: "False", LastTransitionTime: now, Reason: "SecretNotFound", - Message: fmt.Sprintf(`secret "%s" not found`, testSecretName), + Message: fmt.Sprintf(`secret "%s" not found`, testBindSecretName), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -429,7 +436,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { name: "secret has wrong type", inputUpstreams: []runtime.Object{validUpstream}, inputSecrets: []runtime.Object{&corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: testSecretName, Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: testBindSecretName, Namespace: testNamespace}, Type: "some-other-type", Data: testValidSecretData, }}, @@ -445,7 +452,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Status: "False", LastTransitionTime: now, Reason: "SecretWrongType", - Message: fmt.Sprintf(`referenced Secret "%s" has wrong type "some-other-type" (should be "kubernetes.io/basic-auth")`, testSecretName), + Message: fmt.Sprintf(`referenced Secret "%s" has wrong type "some-other-type" (should be "kubernetes.io/basic-auth")`, testBindSecretName), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -457,7 +464,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { name: "secret is missing key", inputUpstreams: []runtime.Object{validUpstream}, inputSecrets: []runtime.Object{&corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: testSecretName, Namespace: testNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: testBindSecretName, Namespace: testNamespace}, Type: corev1.SecretTypeBasicAuth, }}, wantErr: controllerlib.ErrSyntheticRequeue.Error(), @@ -472,7 +479,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Status: "False", LastTransitionTime: now, Reason: "SecretMissingKeys", - Message: fmt.Sprintf(`referenced Secret "%s" is missing required keys ["username" "password"]`, testSecretName), + Message: fmt.Sprintf(`referenced Secret "%s" is missing required keys ["username" "password"]`, testBindSecretName), ObservedGeneration: 1234, }, tlsConfigurationValidLoadedTrueCondition(1234), @@ -555,13 +562,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -624,13 +632,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: "sAMAccountName", + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: "sAMAccountName", }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -696,13 +705,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -725,7 +735,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Reason: "Success", Message: fmt.Sprintf( `successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, - "ldap.example.com", testBindUsername, testSecretName, "4242"), + "ldap.example.com", testBindUsername, testBindSecretName, "4242"), ObservedGeneration: 1234, }, searchBaseFoundInConfigCondition(1234), @@ -745,7 +755,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Reason: "Success", Message: fmt.Sprintf( `successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, - "ldap.example.com", testBindUsername, testSecretName, "4242"), + "ldap.example.com", testBindUsername, testBindSecretName, "4242"), }, SearchBaseFoundCondition: condPtr(withoutTime(searchBaseFoundInConfigCondition(0))), }}, @@ -775,13 +785,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -838,13 +849,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -988,13 +1000,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: exampleDefaultNamingContext, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1137,13 +1150,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: exampleDefaultNamingContext, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1208,13 +1222,14 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: exampleDefaultNamingContext, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1477,9 +1492,10 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UIDAttribute: "objectGUID", }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={}))", - GroupNameAttribute: "sAMAccountName", + Base: testGroupSearchBase, + Filter: "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={}))", + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: "sAMAccountName", }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, GroupAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"sAMAccountName": groupSAMAccountNameWithDomainSuffix}, @@ -1537,9 +1553,10 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UIDAttribute: "objectGUID", }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: exampleDefaultNamingContext, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: exampleDefaultNamingContext, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1600,9 +1617,10 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UIDAttribute: "objectGUID", }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1663,9 +1681,10 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UIDAttribute: "objectGUID", }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: exampleDefaultNamingContext, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: exampleDefaultNamingContext, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1874,9 +1893,10 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UIDAttribute: "objectGUID", }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: exampleDefaultNamingContext, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, + Base: exampleDefaultNamingContext, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ @@ -1931,14 +1951,15 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { UserSearch: upstreamldap.UserSearchConfig{ Base: testUserSearchBase, Filter: testUserSearchFilter, - UsernameAttribute: testUsernameAttrName, - UIDAttribute: testUIDAttrName, + UsernameAttribute: testUserSearchUsernameAttrName, + UIDAttribute: testUserSearchUIDAttrName, }, GroupSearch: upstreamldap.GroupSearchConfig{ - Base: testGroupSearchBase, - Filter: testGroupSearchFilter, - GroupNameAttribute: testGroupNameAttrName, - SkipGroupRefresh: true, + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + UserAttributeForFilter: testGroupSearchUserAttributeForFilter, + GroupNameAttribute: testGroupSearchNameAttrName, + SkipGroupRefresh: true, }, UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.RefreshAttributes) error{ From d4710cb16ec9098b478923639052edefa7ffdaa8 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Wed, 31 May 2023 11:36:49 -0700 Subject: [PATCH 8/9] Add integration test for AD UserAttributeForFilter group search setting --- test/integration/supervisor_login_test.go | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/integration/supervisor_login_test.go b/test/integration/supervisor_login_test.go index 511377b57..1eac3027a 100644 --- a/test/integration/supervisor_login_test.go +++ b/test/integration/supervisor_login_test.go @@ -1000,6 +1000,54 @@ func TestSupervisorLogin_Browser(t *testing.T) { }, wantDownstreamIDTokenGroups: env.SupervisorUpstreamActiveDirectory.TestUserDirectGroupsDNs, }, + { + name: "active directory with custom options including UserAttributeForFilter", + maybeSkip: skipActiveDirectoryTests, + createIDP: func(t *testing.T) string { + idp, _ := createActiveDirectoryIdentityProvider(t, func(spec *idpv1alpha1.ActiveDirectoryIdentityProviderSpec) { + spec.UserSearch = idpv1alpha1.ActiveDirectoryIdentityProviderUserSearch{ + Base: env.SupervisorUpstreamActiveDirectory.UserSearchBase, + Filter: env.SupervisorUpstreamActiveDirectory.TestUserMailAttributeName + "={}", + Attributes: idpv1alpha1.ActiveDirectoryIdentityProviderUserSearchAttributes{ + Username: env.SupervisorUpstreamActiveDirectory.TestUserMailAttributeName, + }, + } + spec.GroupSearch = idpv1alpha1.ActiveDirectoryIdentityProviderGroupSearch{ + // This is not a common way to configure Filter but is rather a silly hack to be able to test + // that UserAttributeForFilter is also working for AD. It assumes that the user appears directly + // under the user search base, which is the case for our test AD server. Also note that by using + // "member=" we are excluding nested groups from the search. + Filter: fmt.Sprintf("member=CN={},%s", env.SupervisorUpstreamActiveDirectory.UserSearchBase), + Base: env.SupervisorUpstreamActiveDirectory.GroupSearchBase, + UserAttributeForFilter: "cn", // substitute the user's CN into the "{}" placeholder in the Filter + Attributes: idpv1alpha1.ActiveDirectoryIdentityProviderGroupSearchAttributes{ + GroupName: "dn", + }, + } + }) + return idp.Name + }, + requestAuthorization: func(t *testing.T, _, downstreamAuthorizeURL, _, _, _ string, httpClient *http.Client) { + requestAuthorizationUsingCLIPasswordFlow(t, + downstreamAuthorizeURL, + env.SupervisorUpstreamActiveDirectory.TestUserMailAttributeValue, // username to present to server during login + env.SupervisorUpstreamActiveDirectory.TestUserPassword, // password to present to server during login + httpClient, + false, + ) + }, + // the ID token Subject should be the Host URL plus the value pulled from the requested UserSearch.Attributes.UID attribute + wantDownstreamIDTokenSubjectToMatch: "^" + regexp.QuoteMeta( + "ldaps://"+env.SupervisorUpstreamActiveDirectory.Host+ + "?base="+url.QueryEscape(env.SupervisorUpstreamActiveDirectory.UserSearchBase)+ + "&sub="+env.SupervisorUpstreamActiveDirectory.TestUserUniqueIDAttributeValue, + ) + "$", + // the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute + wantDownstreamIDTokenUsernameToMatch: func(_ string) string { + return "^" + regexp.QuoteMeta(env.SupervisorUpstreamActiveDirectory.TestUserMailAttributeValue) + "$" + }, + wantDownstreamIDTokenGroups: env.SupervisorUpstreamActiveDirectory.TestUserDirectGroupsDNs, + }, { name: "active directory login still works after updating bind secret", maybeSkip: skipActiveDirectoryTests, From d0048595dac8bc545d010d411b631f2f628eef14 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Wed, 31 May 2023 13:01:17 -0700 Subject: [PATCH 9/9] Add docs for UserAttributeForFilter group search setting --- .../configure-supervisor-with-activedirectory.md | 11 ++++++++++- .../howto/configure-supervisor-with-jumpcloudldap.md | 11 ++++++++++- .../docs/howto/configure-supervisor-with-openldap.md | 11 ++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/site/content/docs/howto/configure-supervisor-with-activedirectory.md b/site/content/docs/howto/configure-supervisor-with-activedirectory.md index 68adcc028..e314d5867 100644 --- a/site/content/docs/howto/configure-supervisor-with-activedirectory.md +++ b/site/content/docs/howto/configure-supervisor-with-activedirectory.md @@ -131,9 +131,18 @@ spec: # Specify the search filter which should be applied when searching for # groups for a user. "{}" will be replaced by the dn (distinguished - # name) of the user entry found as a result of the user search. + # name) of the user entry found as a result of the user search, or by + # the attribute specified by userAttributeForFilter below. filter: "&(objectClass=group)(member={})" + # Specify what user attribute should be used to replace the "{}" + # placeholder in the group search filter. This defaults to "dn". + # For example, if you wanted to instead use posixGroups, you + # would set the group search filter to + # "&(objectClass=posixGroup)(memberUid={})" and set the + # userAttributeForFilter to "uid". + userAttributeForFilter: "dn" + # Specify which fields from each group entry should be used upon # successful login. attributes: diff --git a/site/content/docs/howto/configure-supervisor-with-jumpcloudldap.md b/site/content/docs/howto/configure-supervisor-with-jumpcloudldap.md index afd22e6d4..53becbb14 100644 --- a/site/content/docs/howto/configure-supervisor-with-jumpcloudldap.md +++ b/site/content/docs/howto/configure-supervisor-with-jumpcloudldap.md @@ -101,9 +101,18 @@ spec: # Specify the search filter which should be applied when searching for # groups for a user. "{}" will be replaced by the dn (distinguished - # name) of the user entry found as a result of the user search. + # name) of the user entry found as a result of the user search, or by + # the attribute specified by userAttributeForFilter below. filter: "&(objectClass=groupOfNames)(member={})" + # Specify what user attribute should be used to replace the "{}" + # placeholder in the group search filter. This defaults to "dn". + # For example, if you wanted to instead use posixGroups, you + # would set the group search filter to + # "&(objectClass=posixGroup)(memberUid={})" and set the + # userAttributeForFilter to "uid". + userAttributeForFilter: "dn" + # Specify which fields from each group entry should be used upon # successful login. attributes: diff --git a/site/content/docs/howto/configure-supervisor-with-openldap.md b/site/content/docs/howto/configure-supervisor-with-openldap.md index 286c0ebee..399a9fcec 100644 --- a/site/content/docs/howto/configure-supervisor-with-openldap.md +++ b/site/content/docs/howto/configure-supervisor-with-openldap.md @@ -247,9 +247,18 @@ spec: # Specify the search filter which should be applied when searching for # groups for a user. "{}" will be replaced by the dn (distinguished - # name) of the user entry found as a result of the user search. + # name) of the user entry found as a result of the user search, or by + # the attribute specified by userAttributeForFilter below. filter: "&(objectClass=groupOfNames)(member={})" + # Specify what user attribute should be used to replace the "{}" + # placeholder in the group search filter. This defaults to "dn". + # For example, if you wanted to instead use posixGroups, you + # would set the group search filter to + # "&(objectClass=posixGroup)(memberUid={})" and set the + # userAttributeForFilter to "uid". + userAttributeForFilter: "dn" + # Specify which fields from each group entry should be used upon # successful login. attributes: