diff --git a/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go.tmpl b/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go.tmpl index d4e481b94..2994b491e 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -131,6 +131,11 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes ActiveDirectoryIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an ActiveDirectory identity provider. diff --git a/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go.tmpl b/apis/supervisor/idp/v1alpha1/types_ldapidentityprovider.go.tmpl index 74570a92d..efbb14ae6 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -119,6 +119,11 @@ type LDAPIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes LDAPIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an LDAP identity provider. diff --git a/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml b/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml index 9929b2fc7..3cc4ead01 100644 --- a/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/deploy/supervisor/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -119,6 +119,14 @@ spec: search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the AD server. + type: boolean + required: + - skipGroupRefresh type: object host: description: 'Host is the hostname of this Active Directory identity diff --git a/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml b/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml index ed9780b5b..617b23bf3 100644 --- a/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/deploy/supervisor/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -111,6 +111,14 @@ spec: an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the LDAP server. + type: boolean + required: + - skipGroupRefresh 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 d18e76108..cd97eb527 100644 --- a/generated/1.17/README.adoc +++ b/generated/1.17/README.adoc @@ -801,6 +801,7 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro | *`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={})" | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD server. |=== @@ -988,6 +989,7 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire | *`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={}". | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP server. |=== 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 d4e481b94..2994b491e 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -131,6 +131,11 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes ActiveDirectoryIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an ActiveDirectory identity provider. 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 74570a92d..efbb14ae6 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -119,6 +119,11 @@ type LDAPIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes LDAPIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an LDAP identity provider. 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 9929b2fc7..3cc4ead01 100644 --- a/generated/1.17/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.17/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -119,6 +119,14 @@ spec: search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the AD server. + type: boolean + required: + - skipGroupRefresh type: object host: description: 'Host is the hostname of this Active Directory identity 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 ed9780b5b..617b23bf3 100644 --- a/generated/1.17/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.17/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -111,6 +111,14 @@ spec: an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the LDAP server. + type: boolean + required: + - skipGroupRefresh 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 417b57acc..cb9a4738e 100644 --- a/generated/1.18/README.adoc +++ b/generated/1.18/README.adoc @@ -801,6 +801,7 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro | *`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={})" | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD server. |=== @@ -988,6 +989,7 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire | *`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={}". | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP server. |=== 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 d4e481b94..2994b491e 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -131,6 +131,11 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes ActiveDirectoryIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an ActiveDirectory identity provider. 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 74570a92d..efbb14ae6 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -119,6 +119,11 @@ type LDAPIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes LDAPIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an LDAP identity provider. 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 9929b2fc7..3cc4ead01 100644 --- a/generated/1.18/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.18/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -119,6 +119,14 @@ spec: search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the AD server. + type: boolean + required: + - skipGroupRefresh type: object host: description: 'Host is the hostname of this Active Directory identity 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 ed9780b5b..617b23bf3 100644 --- a/generated/1.18/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.18/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -111,6 +111,14 @@ spec: an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the LDAP server. + type: boolean + required: + - skipGroupRefresh 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 0317faedd..3a4a0b36b 100644 --- a/generated/1.19/README.adoc +++ b/generated/1.19/README.adoc @@ -801,6 +801,7 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro | *`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={})" | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD server. |=== @@ -988,6 +989,7 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire | *`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={}". | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP server. |=== 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 d4e481b94..2994b491e 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -131,6 +131,11 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes ActiveDirectoryIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an ActiveDirectory identity provider. 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 74570a92d..efbb14ae6 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -119,6 +119,11 @@ type LDAPIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes LDAPIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an LDAP identity provider. 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 9929b2fc7..3cc4ead01 100644 --- a/generated/1.19/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.19/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -119,6 +119,14 @@ spec: search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the AD server. + type: boolean + required: + - skipGroupRefresh type: object host: description: 'Host is the hostname of this Active Directory identity 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 ed9780b5b..617b23bf3 100644 --- a/generated/1.19/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.19/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -111,6 +111,14 @@ spec: an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the LDAP server. + type: boolean + required: + - skipGroupRefresh 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 faf7ad542..4b7ce7e18 100644 --- a/generated/1.20/README.adoc +++ b/generated/1.20/README.adoc @@ -801,6 +801,7 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro | *`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={})" | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD server. |=== @@ -988,6 +989,7 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire | *`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={}". | *`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__ | SkipGroupRefresh skips the group refresh operation that occurs with each refresh (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP server. |=== 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 d4e481b94..2994b491e 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -131,6 +131,11 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes ActiveDirectoryIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an ActiveDirectory identity provider. 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 74570a92d..efbb14ae6 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -119,6 +119,11 @@ type LDAPIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes LDAPIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an LDAP identity provider. 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 9929b2fc7..3cc4ead01 100644 --- a/generated/1.20/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml +++ b/generated/1.20/crds/idp.supervisor.pinniped.dev_activedirectoryidentityproviders.yaml @@ -119,6 +119,14 @@ spec: search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})" type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the AD server. + type: boolean + required: + - skipGroupRefresh type: object host: description: 'Host is the hostname of this Active Directory identity 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 ed9780b5b..617b23bf3 100644 --- a/generated/1.20/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml +++ b/generated/1.20/crds/idp.supervisor.pinniped.dev_ldapidentityproviders.yaml @@ -111,6 +111,14 @@ spec: an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}". type: string + skipGroupRefresh: + description: SkipGroupRefresh skips the group refresh operation + that occurs with each refresh (every 5 minutes). This can be + done if group search is very slow or resource intensive for + the LDAP server. + type: boolean + required: + - skipGroupRefresh type: object host: description: 'Host is the hostname of this LDAP identity provider, diff --git a/generated/latest/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go b/generated/latest/apis/supervisor/idp/v1alpha1/types_activedirectoryidentityprovider.go index d4e481b94..2994b491e 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -131,6 +131,11 @@ type ActiveDirectoryIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes ActiveDirectoryIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the AD + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an ActiveDirectory 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 74570a92d..efbb14ae6 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 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package v1alpha1 @@ -119,6 +119,11 @@ type LDAPIdentityProviderGroupSearch struct { // the result of the group search. // +optional Attributes LDAPIdentityProviderGroupSearchAttributes `json:"attributes,omitempty"` + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool `json:"skipGroupRefresh"` } // Spec for configuring an LDAP identity provider. diff --git a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go index 33d1557ac..4fb699b77 100644 --- a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go +++ b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher.go @@ -333,6 +333,7 @@ func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context, Base: spec.GroupSearch.Base, Filter: adUpstreamImpl.Spec().GroupSearch().Filter(), 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 7777bfec8..ce69b4af3 100644 --- a/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/activedirectoryupstreamwatcher/active_directory_upstream_watcher_test.go @@ -192,6 +192,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { Attributes: v1alpha1.ActiveDirectoryIdentityProviderGroupSearchAttributes{ GroupName: testGroupNameAttrName, }, + SkipGroupRefresh: false, }, }, } @@ -1907,6 +1908,75 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) { SearchBaseFoundCondition: condPtr(withoutTime(searchBaseFoundInRootDSECondition(0))), }}, }, + { + name: "skipping group refresh is valid", + inputUpstreams: []runtime.Object{editedValidUpstream(func(upstream *v1alpha1.ActiveDirectoryIdentityProvider) { + upstream.Spec.GroupSearch.SkipGroupRefresh = true + })}, + inputSecrets: []runtime.Object{validBindUserSecret("4242")}, + setupMocks: func(conn *mockldapconn.MockConn) { + // Should perform a test dial and bind. + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantResultingCache: []*upstreamldap.ProviderConfig{ + { + Name: testName, + ResourceUID: testResourceUID, + Host: testHost, + ConnectionProtocol: upstreamldap.TLS, + CABundle: testCABundle, + BindUsername: testBindUsername, + BindPassword: testBindPassword, + UserSearch: upstreamldap.UserSearchConfig{ + Base: testUserSearchBase, + Filter: testUserSearchFilter, + UsernameAttribute: testUsernameAttrName, + UIDAttribute: testUIDAttrName, + }, + GroupSearch: upstreamldap.GroupSearchConfig{ + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + GroupNameAttribute: testGroupNameAttrName, + SkipGroupRefresh: true, + }, + UIDAttributeParsingOverrides: map[string]func(*ldap.Entry) (string, error){"objectGUID": microsoftUUIDFromBinaryAttr("objectGUID")}, + RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{ + "pwdLastSet": upstreamldap.AttributeUnchangedSinceLogin("pwdLastSet"), + "userAccountControl": validUserAccountControl, + "msDS-User-Account-Control-Computed": validComputedUserAccountControl, + }, + }, + }, + wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{ + ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID}, + Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{ + Phase: "Ready", + Conditions: []v1alpha1.Condition{ + bindSecretValidTrueCondition(1234), + activeDirectoryConnectionValidTrueCondition(1234, "4242"), + searchBaseFoundInConfigCondition(1234), + { + Type: "TLSConfigurationValid", + Status: "True", + LastTransitionTime: now, + Reason: "Success", + Message: "loaded TLS configuration", + ObservedGeneration: 1234, + }, + }, + }, + }}, + wantValidatedSettings: map[string]upstreamwatchers.ValidatedSettings{testName: { + BindSecretResourceVersion: "4242", + LDAPConnectionProtocol: upstreamldap.TLS, + UserSearchBase: testUserSearchBase, + GroupSearchBase: testGroupSearchBase, + IDPSpecGeneration: 1234, + ConnectionValidCondition: condPtr(activeDirectoryConnectionValidTrueConditionWithoutTimeOrGeneration("4242")), + SearchBaseFoundCondition: condPtr(withoutTime(searchBaseFoundInConfigCondition(0))), + }}, + }, } for _, tt := range tests { diff --git a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go index 82a9fdece..fd57cc28d 100644 --- a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go +++ b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go @@ -239,6 +239,7 @@ func (c *ldapWatcherController) validateUpstream(ctx context.Context, upstream * Base: spec.GroupSearch.Base, Filter: spec.GroupSearch.Filter, 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 d7f82edf5..0f57bc2fa 100644 --- a/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go @@ -196,6 +196,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { Attributes: v1alpha1.LDAPIdentityProviderGroupSearchAttributes{ GroupName: testGroupNameAttrName, }, + SkipGroupRefresh: false, }, }, } @@ -1053,6 +1054,67 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) { IDPSpecGeneration: 1234, ConnectionValidCondition: condPtr(ldapConnectionValidTrueConditionWithoutTimeOrGeneration("4242")), }}}, + { + name: "skipping group refresh is valid", + inputUpstreams: []runtime.Object{editedValidUpstream(func(upstream *v1alpha1.LDAPIdentityProvider) { + upstream.Spec.GroupSearch.SkipGroupRefresh = true + })}, + inputSecrets: []runtime.Object{validBindUserSecret("4242")}, + setupMocks: func(conn *mockldapconn.MockConn) { + // Should perform a test dial and bind. + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Close().Times(1) + }, + wantResultingCache: []*upstreamldap.ProviderConfig{ + { + Name: testName, + ResourceUID: testResourceUID, + Host: testHost, + ConnectionProtocol: upstreamldap.TLS, + CABundle: testCABundle, + BindUsername: testBindUsername, + BindPassword: testBindPassword, + UserSearch: upstreamldap.UserSearchConfig{ + Base: testUserSearchBase, + Filter: testUserSearchFilter, + UsernameAttribute: testUsernameAttrName, + UIDAttribute: testUIDAttrName, + }, + GroupSearch: upstreamldap.GroupSearchConfig{ + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + GroupNameAttribute: testGroupNameAttrName, + SkipGroupRefresh: true, + }, + }, + }, + wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{ + ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID}, + Status: v1alpha1.LDAPIdentityProviderStatus{ + Phase: "Ready", + Conditions: []v1alpha1.Condition{ + bindSecretValidTrueCondition(1234), + ldapConnectionValidTrueCondition(1234, "4242"), + { + Type: "TLSConfigurationValid", + Status: "True", + LastTransitionTime: now, + Reason: "Success", + Message: "loaded TLS configuration", + ObservedGeneration: 1234, + }, + }, + }, + }}, + wantValidatedSettings: map[string]upstreamwatchers.ValidatedSettings{testName: { + BindSecretResourceVersion: "4242", + LDAPConnectionProtocol: upstreamldap.TLS, + UserSearchBase: testUserSearchBase, + GroupSearchBase: testGroupSearchBase, + IDPSpecGeneration: 1234, + ConnectionValidCondition: condPtr(ldapConnectionValidTrueConditionWithoutTimeOrGeneration("4242")), + }}, + }, } for _, tt := range tests { diff --git a/internal/oidc/provider/dynamic_upstream_idp_provider.go b/internal/oidc/provider/dynamic_upstream_idp_provider.go index 6f0ced3d1..797719436 100644 --- a/internal/oidc/provider/dynamic_upstream_idp_provider.go +++ b/internal/oidc/provider/dynamic_upstream_idp_provider.go @@ -115,6 +115,7 @@ type StoredRefreshAttributes struct { Username string Subject string DN string + Groups []string AdditionalAttributes map[string]string } diff --git a/internal/oidc/token/token_handler.go b/internal/oidc/token/token_handler.go index eab5ed115..55e73352d 100644 --- a/internal/oidc/token/token_handler.go +++ b/internal/oidc/token/token_handler.go @@ -275,6 +275,10 @@ func upstreamLDAPRefresh(ctx context.Context, providerCache oidc.UpstreamIdentit return err } subject := session.Fosite.Claims.Subject + oldGroups, err := getDownstreamGroupsFromPinnipedSession(session) + if err != nil { + return err + } s := session.Custom @@ -305,6 +309,7 @@ func upstreamLDAPRefresh(ctx context.Context, providerCache oidc.UpstreamIdentit Username: username, Subject: subject, DN: dn, + Groups: oldGroups, AdditionalAttributes: additionalAttributes, }) if err != nil { @@ -353,7 +358,7 @@ func getDownstreamUsernameFromPinnipedSession(session *psession.PinnipedSession) if extra == nil { return "", errorsx.WithStack(errMissingUpstreamSessionInternalError) } - downstreamUsernameInterface := extra["username"] + downstreamUsernameInterface := extra[oidc.DownstreamUsernameClaim] if downstreamUsernameInterface == nil { return "", errorsx.WithStack(errMissingUpstreamSessionInternalError) } @@ -363,3 +368,28 @@ func getDownstreamUsernameFromPinnipedSession(session *psession.PinnipedSession) } return downstreamUsername, nil } + +func getDownstreamGroupsFromPinnipedSession(session *psession.PinnipedSession) ([]string, error) { + extra := session.Fosite.Claims.Extra + if extra == nil { + return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError) + } + downstreamGroupsInterface := extra[oidc.DownstreamGroupsClaim] + if downstreamGroupsInterface == nil { + return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError) + } + downstreamGroupsInterfaceList, ok := downstreamGroupsInterface.([]interface{}) + if !ok { + return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError) + } + + downstreamGroups := make([]string, 0, len(downstreamGroupsInterfaceList)) + for _, downstreamGroupInterface := range downstreamGroupsInterfaceList { + downstreamGroup, ok := downstreamGroupInterface.(string) + if !ok || len(downstreamGroup) == 0 { + return nil, errorsx.WithStack(errMissingUpstreamSessionInternalError) + } + downstreamGroups = append(downstreamGroups, downstreamGroup) + } + return downstreamGroups, nil +} diff --git a/internal/upstreamldap/upstreamldap.go b/internal/upstreamldap/upstreamldap.go index 6ea38b6b1..136fc023f 100644 --- a/internal/upstreamldap/upstreamldap.go +++ b/internal/upstreamldap/upstreamldap.go @@ -150,6 +150,11 @@ type GroupSearchConfig struct { // GroupNameAttribute is the attribute in the LDAP group entry from which the group name should be // retrieved. Empty means to use 'cn'. GroupNameAttribute string + + // SkipGroupRefresh skips the group refresh operation that occurs with each refresh + // (every 5 minutes). This can be done if group search is very slow or resource intensive for the LDAP + // server. + SkipGroupRefresh bool } type Provider struct { @@ -230,6 +235,10 @@ func (p *Provider) PerformRefresh(ctx context.Context, storedRefreshAttributes p } } + if p.c.GroupSearch.SkipGroupRefresh { + return storedRefreshAttributes.Groups, nil + } + mappedGroupNames, err := p.searchGroupsForUserDN(conn, userDN) if err != nil { return nil, err diff --git a/internal/upstreamldap/upstreamldap_test.go b/internal/upstreamldap/upstreamldap_test.go index 8b8995686..bb8373399 100644 --- a/internal/upstreamldap/upstreamldap_test.go +++ b/internal/upstreamldap/upstreamldap_test.go @@ -1298,6 +1298,37 @@ func TestUpstreamRefresh(t *testing.T) { }, wantGroups: []string{}, }, + { + name: "happy path where group search is configured but skipGroupRefresh is set", + providerConfig: &ProviderConfig{ + Name: "some-provider-name", + Host: testHost, + CABundle: nil, // this field is only used by the production dialer, which is replaced by a mock for this test + ConnectionProtocol: TLS, + BindUsername: testBindUsername, + BindPassword: testBindPassword, + UserSearch: UserSearchConfig{ + Base: testUserSearchBase, + UIDAttribute: testUserSearchUIDAttribute, + UsernameAttribute: testUserSearchUsernameAttribute, + }, + GroupSearch: GroupSearchConfig{ + Base: testGroupSearchBase, + Filter: testGroupSearchFilter, + GroupNameAttribute: testGroupSearchGroupNameAttribute, + SkipGroupRefresh: true, + }, + RefreshAttributeChecks: map[string]func(*ldap.Entry, provider.StoredRefreshAttributes) error{ + pwdLastSetAttribute: AttributeUnchangedSinceLogin(pwdLastSetAttribute), + }, + }, + setupMocks: func(conn *mockldapconn.MockConn) { + conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1) + conn.EXPECT().Search(expectedUserSearch).Return(happyPathUserSearchResult, nil).Times(1) // note that group search is not expected + conn.EXPECT().Close().Times(1) + }, + wantGroups: nil, // do not update groups + }, { name: "error where dial fails", providerConfig: providerConfig,