Add integration test for upstreamldap.Provider
- The unit tests for upstreamldap.Provider need to mock the LDAP server, so add an integration test which allows us to get fast feedback for this code against a real LDAP server. - Automatically wrap the user search filter in parenthesis if it is not already wrapped in parens. - More special handling for using "dn" as the username or UID attribute name. - Also added some more comments to types_ldapidentityprovider.go.tmpl
This commit is contained in:
parent
7b8c86b38e
commit
fec3d92f26
@ -54,12 +54,18 @@ type LDAPIdentityProviderBindSpec struct {
|
|||||||
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
||||||
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
||||||
// of the user after a successful authentication. This would typically be the same attribute name used in
|
// of the user after a successful authentication. This would typically be the same attribute name used in
|
||||||
// the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
// the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field
|
||||||
|
// is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default
|
||||||
|
// value of "dn={}" would not work.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
|
||||||
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
||||||
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
UniqueID string `json:"uniqueID,omitempty"`
|
UniqueID string `json:"uniqueID,omitempty"`
|
||||||
}
|
}
|
||||||
@ -72,8 +78,10 @@ type LDAPIdentityProviderUserSearchSpec struct {
|
|||||||
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
||||||
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
||||||
// or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
// or "&(objectClass=person)(uid={})". 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 the value from
|
// Optional. When not specified, the default will act as if the Filter were specified as the value from
|
||||||
// Attributes.Username appended by "={}".
|
// Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be
|
||||||
|
// explicitly specified, since the default value of "dn={}" would not work.
|
||||||
// +optional
|
// +optional
|
||||||
Filter string `json:"filter,omitempty"`
|
Filter string `json:"filter,omitempty"`
|
||||||
|
|
||||||
|
@ -97,15 +97,26 @@ spec:
|
|||||||
description: UniqueID specifies the name of the attribute
|
description: UniqueID specifies the name of the attribute
|
||||||
in the LDAP entry which whose value shall be used to uniquely
|
in the LDAP entry which whose value shall be used to uniquely
|
||||||
identify the user within this LDAP provider after a successful
|
identify the user within this LDAP provider after a successful
|
||||||
authentication. E.g. "uidNumber" or "objectGUID".
|
authentication. E.g. "uidNumber" or "objectGUID". The value
|
||||||
|
of this field is case-sensitive and must match the case
|
||||||
|
of the attribute name returned by the LDAP server in the
|
||||||
|
user's entry. Distinguished names can be used by specifying
|
||||||
|
lower-case "dn".
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
description: Username specifies the name of attribute in the
|
description: Username specifies the name of attribute in the
|
||||||
LDAP entry which whose value shall become the username of
|
LDAP entry which whose value shall become the username of
|
||||||
the user after a successful authentication. This would typically
|
the user after a successful authentication. This would typically
|
||||||
be the same attribute name used in the user search filter.
|
be the same attribute name used in the user search filter,
|
||||||
E.g. "mail" or "uid" or "userPrincipalName".
|
although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
The value of this field is case-sensitive and must match
|
||||||
|
the case of the attribute name returned by the LDAP server
|
||||||
|
in the user's entry. Distinguished names can be used by
|
||||||
|
specifying lower-case "dn". When this field is set to "dn"
|
||||||
|
then the LDAPIdentityProviderUserSearchSpec's Filter field
|
||||||
|
cannot be blank, since the default value of "dn={}" would
|
||||||
|
not work.
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@ -120,9 +131,12 @@ spec:
|
|||||||
in the filter and will be dynamically replaced by the username
|
in the filter and will be dynamically replaced by the username
|
||||||
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
||||||
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
||||||
Optional. When not specified, the default will act as if the
|
Note that the dn (distinguished name) is not an attribute of
|
||||||
Filter were specified as the value from Attributes.Username
|
an entry, so "dn={}" cannot be used. Optional. When not specified,
|
||||||
appended by "={}".
|
the default will act as if the Filter were specified as the
|
||||||
|
value from Attributes.Username appended by "={}". When the Attributes.Username
|
||||||
|
is set to "dn" then the Filter must be explicitly specified,
|
||||||
|
since the default value of "dn={}" would not work.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
6
generated/1.17/README.adoc
generated
6
generated/1.17/README.adoc
generated
@ -808,8 +808,8 @@ Status of an LDAP identity provider.
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default value of "dn={}" would not work.
|
||||||
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -827,7 +827,7 @@ Status of an LDAP identity provider.
|
|||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
||||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Optional. When not specified, the default will act as if the Filter were specified as the value from Attributes.Username appended by "={}".
|
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". 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 the value from Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be explicitly specified, since the default value of "dn={}" would not work.
|
||||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -54,12 +54,18 @@ type LDAPIdentityProviderBindSpec struct {
|
|||||||
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
||||||
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
||||||
// of the user after a successful authentication. This would typically be the same attribute name used in
|
// of the user after a successful authentication. This would typically be the same attribute name used in
|
||||||
// the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
// the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field
|
||||||
|
// is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default
|
||||||
|
// value of "dn={}" would not work.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
|
||||||
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
||||||
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
UniqueID string `json:"uniqueID,omitempty"`
|
UniqueID string `json:"uniqueID,omitempty"`
|
||||||
}
|
}
|
||||||
@ -72,8 +78,10 @@ type LDAPIdentityProviderUserSearchSpec struct {
|
|||||||
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
||||||
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
||||||
// or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
// or "&(objectClass=person)(uid={})". 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 the value from
|
// Optional. When not specified, the default will act as if the Filter were specified as the value from
|
||||||
// Attributes.Username appended by "={}".
|
// Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be
|
||||||
|
// explicitly specified, since the default value of "dn={}" would not work.
|
||||||
// +optional
|
// +optional
|
||||||
Filter string `json:"filter,omitempty"`
|
Filter string `json:"filter,omitempty"`
|
||||||
|
|
||||||
|
@ -97,15 +97,26 @@ spec:
|
|||||||
description: UniqueID specifies the name of the attribute
|
description: UniqueID specifies the name of the attribute
|
||||||
in the LDAP entry which whose value shall be used to uniquely
|
in the LDAP entry which whose value shall be used to uniquely
|
||||||
identify the user within this LDAP provider after a successful
|
identify the user within this LDAP provider after a successful
|
||||||
authentication. E.g. "uidNumber" or "objectGUID".
|
authentication. E.g. "uidNumber" or "objectGUID". The value
|
||||||
|
of this field is case-sensitive and must match the case
|
||||||
|
of the attribute name returned by the LDAP server in the
|
||||||
|
user's entry. Distinguished names can be used by specifying
|
||||||
|
lower-case "dn".
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
description: Username specifies the name of attribute in the
|
description: Username specifies the name of attribute in the
|
||||||
LDAP entry which whose value shall become the username of
|
LDAP entry which whose value shall become the username of
|
||||||
the user after a successful authentication. This would typically
|
the user after a successful authentication. This would typically
|
||||||
be the same attribute name used in the user search filter.
|
be the same attribute name used in the user search filter,
|
||||||
E.g. "mail" or "uid" or "userPrincipalName".
|
although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
The value of this field is case-sensitive and must match
|
||||||
|
the case of the attribute name returned by the LDAP server
|
||||||
|
in the user's entry. Distinguished names can be used by
|
||||||
|
specifying lower-case "dn". When this field is set to "dn"
|
||||||
|
then the LDAPIdentityProviderUserSearchSpec's Filter field
|
||||||
|
cannot be blank, since the default value of "dn={}" would
|
||||||
|
not work.
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@ -120,9 +131,12 @@ spec:
|
|||||||
in the filter and will be dynamically replaced by the username
|
in the filter and will be dynamically replaced by the username
|
||||||
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
||||||
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
||||||
Optional. When not specified, the default will act as if the
|
Note that the dn (distinguished name) is not an attribute of
|
||||||
Filter were specified as the value from Attributes.Username
|
an entry, so "dn={}" cannot be used. Optional. When not specified,
|
||||||
appended by "={}".
|
the default will act as if the Filter were specified as the
|
||||||
|
value from Attributes.Username appended by "={}". When the Attributes.Username
|
||||||
|
is set to "dn" then the Filter must be explicitly specified,
|
||||||
|
since the default value of "dn={}" would not work.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
6
generated/1.18/README.adoc
generated
6
generated/1.18/README.adoc
generated
@ -808,8 +808,8 @@ Status of an LDAP identity provider.
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default value of "dn={}" would not work.
|
||||||
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -827,7 +827,7 @@ Status of an LDAP identity provider.
|
|||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
||||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Optional. When not specified, the default will act as if the Filter were specified as the value from Attributes.Username appended by "={}".
|
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". 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 the value from Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be explicitly specified, since the default value of "dn={}" would not work.
|
||||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -54,12 +54,18 @@ type LDAPIdentityProviderBindSpec struct {
|
|||||||
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
||||||
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
||||||
// of the user after a successful authentication. This would typically be the same attribute name used in
|
// of the user after a successful authentication. This would typically be the same attribute name used in
|
||||||
// the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
// the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field
|
||||||
|
// is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default
|
||||||
|
// value of "dn={}" would not work.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
|
||||||
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
||||||
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
UniqueID string `json:"uniqueID,omitempty"`
|
UniqueID string `json:"uniqueID,omitempty"`
|
||||||
}
|
}
|
||||||
@ -72,8 +78,10 @@ type LDAPIdentityProviderUserSearchSpec struct {
|
|||||||
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
||||||
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
||||||
// or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
// or "&(objectClass=person)(uid={})". 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 the value from
|
// Optional. When not specified, the default will act as if the Filter were specified as the value from
|
||||||
// Attributes.Username appended by "={}".
|
// Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be
|
||||||
|
// explicitly specified, since the default value of "dn={}" would not work.
|
||||||
// +optional
|
// +optional
|
||||||
Filter string `json:"filter,omitempty"`
|
Filter string `json:"filter,omitempty"`
|
||||||
|
|
||||||
|
@ -97,15 +97,26 @@ spec:
|
|||||||
description: UniqueID specifies the name of the attribute
|
description: UniqueID specifies the name of the attribute
|
||||||
in the LDAP entry which whose value shall be used to uniquely
|
in the LDAP entry which whose value shall be used to uniquely
|
||||||
identify the user within this LDAP provider after a successful
|
identify the user within this LDAP provider after a successful
|
||||||
authentication. E.g. "uidNumber" or "objectGUID".
|
authentication. E.g. "uidNumber" or "objectGUID". The value
|
||||||
|
of this field is case-sensitive and must match the case
|
||||||
|
of the attribute name returned by the LDAP server in the
|
||||||
|
user's entry. Distinguished names can be used by specifying
|
||||||
|
lower-case "dn".
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
description: Username specifies the name of attribute in the
|
description: Username specifies the name of attribute in the
|
||||||
LDAP entry which whose value shall become the username of
|
LDAP entry which whose value shall become the username of
|
||||||
the user after a successful authentication. This would typically
|
the user after a successful authentication. This would typically
|
||||||
be the same attribute name used in the user search filter.
|
be the same attribute name used in the user search filter,
|
||||||
E.g. "mail" or "uid" or "userPrincipalName".
|
although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
The value of this field is case-sensitive and must match
|
||||||
|
the case of the attribute name returned by the LDAP server
|
||||||
|
in the user's entry. Distinguished names can be used by
|
||||||
|
specifying lower-case "dn". When this field is set to "dn"
|
||||||
|
then the LDAPIdentityProviderUserSearchSpec's Filter field
|
||||||
|
cannot be blank, since the default value of "dn={}" would
|
||||||
|
not work.
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@ -120,9 +131,12 @@ spec:
|
|||||||
in the filter and will be dynamically replaced by the username
|
in the filter and will be dynamically replaced by the username
|
||||||
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
||||||
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
||||||
Optional. When not specified, the default will act as if the
|
Note that the dn (distinguished name) is not an attribute of
|
||||||
Filter were specified as the value from Attributes.Username
|
an entry, so "dn={}" cannot be used. Optional. When not specified,
|
||||||
appended by "={}".
|
the default will act as if the Filter were specified as the
|
||||||
|
value from Attributes.Username appended by "={}". When the Attributes.Username
|
||||||
|
is set to "dn" then the Filter must be explicitly specified,
|
||||||
|
since the default value of "dn={}" would not work.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
6
generated/1.19/README.adoc
generated
6
generated/1.19/README.adoc
generated
@ -808,8 +808,8 @@ Status of an LDAP identity provider.
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default value of "dn={}" would not work.
|
||||||
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -827,7 +827,7 @@ Status of an LDAP identity provider.
|
|||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
||||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Optional. When not specified, the default will act as if the Filter were specified as the value from Attributes.Username appended by "={}".
|
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". 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 the value from Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be explicitly specified, since the default value of "dn={}" would not work.
|
||||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -54,12 +54,18 @@ type LDAPIdentityProviderBindSpec struct {
|
|||||||
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
||||||
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
||||||
// of the user after a successful authentication. This would typically be the same attribute name used in
|
// of the user after a successful authentication. This would typically be the same attribute name used in
|
||||||
// the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
// the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field
|
||||||
|
// is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default
|
||||||
|
// value of "dn={}" would not work.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
|
||||||
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
||||||
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
UniqueID string `json:"uniqueID,omitempty"`
|
UniqueID string `json:"uniqueID,omitempty"`
|
||||||
}
|
}
|
||||||
@ -72,8 +78,10 @@ type LDAPIdentityProviderUserSearchSpec struct {
|
|||||||
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
||||||
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
||||||
// or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
// or "&(objectClass=person)(uid={})". 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 the value from
|
// Optional. When not specified, the default will act as if the Filter were specified as the value from
|
||||||
// Attributes.Username appended by "={}".
|
// Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be
|
||||||
|
// explicitly specified, since the default value of "dn={}" would not work.
|
||||||
// +optional
|
// +optional
|
||||||
Filter string `json:"filter,omitempty"`
|
Filter string `json:"filter,omitempty"`
|
||||||
|
|
||||||
|
@ -97,15 +97,26 @@ spec:
|
|||||||
description: UniqueID specifies the name of the attribute
|
description: UniqueID specifies the name of the attribute
|
||||||
in the LDAP entry which whose value shall be used to uniquely
|
in the LDAP entry which whose value shall be used to uniquely
|
||||||
identify the user within this LDAP provider after a successful
|
identify the user within this LDAP provider after a successful
|
||||||
authentication. E.g. "uidNumber" or "objectGUID".
|
authentication. E.g. "uidNumber" or "objectGUID". The value
|
||||||
|
of this field is case-sensitive and must match the case
|
||||||
|
of the attribute name returned by the LDAP server in the
|
||||||
|
user's entry. Distinguished names can be used by specifying
|
||||||
|
lower-case "dn".
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
description: Username specifies the name of attribute in the
|
description: Username specifies the name of attribute in the
|
||||||
LDAP entry which whose value shall become the username of
|
LDAP entry which whose value shall become the username of
|
||||||
the user after a successful authentication. This would typically
|
the user after a successful authentication. This would typically
|
||||||
be the same attribute name used in the user search filter.
|
be the same attribute name used in the user search filter,
|
||||||
E.g. "mail" or "uid" or "userPrincipalName".
|
although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
The value of this field is case-sensitive and must match
|
||||||
|
the case of the attribute name returned by the LDAP server
|
||||||
|
in the user's entry. Distinguished names can be used by
|
||||||
|
specifying lower-case "dn". When this field is set to "dn"
|
||||||
|
then the LDAPIdentityProviderUserSearchSpec's Filter field
|
||||||
|
cannot be blank, since the default value of "dn={}" would
|
||||||
|
not work.
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@ -120,9 +131,12 @@ spec:
|
|||||||
in the filter and will be dynamically replaced by the username
|
in the filter and will be dynamically replaced by the username
|
||||||
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
||||||
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
||||||
Optional. When not specified, the default will act as if the
|
Note that the dn (distinguished name) is not an attribute of
|
||||||
Filter were specified as the value from Attributes.Username
|
an entry, so "dn={}" cannot be used. Optional. When not specified,
|
||||||
appended by "={}".
|
the default will act as if the Filter were specified as the
|
||||||
|
value from Attributes.Username appended by "={}". When the Attributes.Username
|
||||||
|
is set to "dn" then the Filter must be explicitly specified,
|
||||||
|
since the default value of "dn={}" would not work.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
6
generated/1.20/README.adoc
generated
6
generated/1.20/README.adoc
generated
@ -808,8 +808,8 @@ Status of an LDAP identity provider.
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
| *`username`* __string__ | Username specifies the name of attribute in the LDAP entry which whose value shall become the username of the user after a successful authentication. This would typically be the same attribute name used in the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default value of "dn={}" would not work.
|
||||||
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
| *`uniqueID`* __string__ | UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID". The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -827,7 +827,7 @@ Status of an LDAP identity provider.
|
|||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
| *`base`* __string__ | Base is the DN that should be used as the search base when searching for users. E.g. "ou=users,dc=example,dc=com".
|
||||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters. Optional. When not specified, the default will act as if the Filter were specified as the value from Attributes.Username appended by "={}".
|
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})". 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 the value from Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be explicitly specified, since the default value of "dn={}" would not work.
|
||||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-supervisor-idp-v1alpha1-ldapidentityproviderusersearchattributesspec[$$LDAPIdentityProviderUserSearchAttributesSpec$$]__ | Attributes specifies how the user's information should be read from the LDAP entry which was found as the result of the user search.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -54,12 +54,18 @@ type LDAPIdentityProviderBindSpec struct {
|
|||||||
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
||||||
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
||||||
// of the user after a successful authentication. This would typically be the same attribute name used in
|
// of the user after a successful authentication. This would typically be the same attribute name used in
|
||||||
// the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
// the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field
|
||||||
|
// is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default
|
||||||
|
// value of "dn={}" would not work.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
|
||||||
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
||||||
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
UniqueID string `json:"uniqueID,omitempty"`
|
UniqueID string `json:"uniqueID,omitempty"`
|
||||||
}
|
}
|
||||||
@ -72,8 +78,10 @@ type LDAPIdentityProviderUserSearchSpec struct {
|
|||||||
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
||||||
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
||||||
// or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
// or "&(objectClass=person)(uid={})". 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 the value from
|
// Optional. When not specified, the default will act as if the Filter were specified as the value from
|
||||||
// Attributes.Username appended by "={}".
|
// Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be
|
||||||
|
// explicitly specified, since the default value of "dn={}" would not work.
|
||||||
// +optional
|
// +optional
|
||||||
Filter string `json:"filter,omitempty"`
|
Filter string `json:"filter,omitempty"`
|
||||||
|
|
||||||
|
@ -97,15 +97,26 @@ spec:
|
|||||||
description: UniqueID specifies the name of the attribute
|
description: UniqueID specifies the name of the attribute
|
||||||
in the LDAP entry which whose value shall be used to uniquely
|
in the LDAP entry which whose value shall be used to uniquely
|
||||||
identify the user within this LDAP provider after a successful
|
identify the user within this LDAP provider after a successful
|
||||||
authentication. E.g. "uidNumber" or "objectGUID".
|
authentication. E.g. "uidNumber" or "objectGUID". The value
|
||||||
|
of this field is case-sensitive and must match the case
|
||||||
|
of the attribute name returned by the LDAP server in the
|
||||||
|
user's entry. Distinguished names can be used by specifying
|
||||||
|
lower-case "dn".
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
description: Username specifies the name of attribute in the
|
description: Username specifies the name of attribute in the
|
||||||
LDAP entry which whose value shall become the username of
|
LDAP entry which whose value shall become the username of
|
||||||
the user after a successful authentication. This would typically
|
the user after a successful authentication. This would typically
|
||||||
be the same attribute name used in the user search filter.
|
be the same attribute name used in the user search filter,
|
||||||
E.g. "mail" or "uid" or "userPrincipalName".
|
although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
The value of this field is case-sensitive and must match
|
||||||
|
the case of the attribute name returned by the LDAP server
|
||||||
|
in the user's entry. Distinguished names can be used by
|
||||||
|
specifying lower-case "dn". When this field is set to "dn"
|
||||||
|
then the LDAPIdentityProviderUserSearchSpec's Filter field
|
||||||
|
cannot be blank, since the default value of "dn={}" would
|
||||||
|
not work.
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@ -120,9 +131,12 @@ spec:
|
|||||||
in the filter and will be dynamically replaced by the username
|
in the filter and will be dynamically replaced by the username
|
||||||
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
for which the search is being run. E.g. "mail={}" or "&(objectClass=person)(uid={})".
|
||||||
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
||||||
Optional. When not specified, the default will act as if the
|
Note that the dn (distinguished name) is not an attribute of
|
||||||
Filter were specified as the value from Attributes.Username
|
an entry, so "dn={}" cannot be used. Optional. When not specified,
|
||||||
appended by "={}".
|
the default will act as if the Filter were specified as the
|
||||||
|
value from Attributes.Username appended by "={}". When the Attributes.Username
|
||||||
|
is set to "dn" then the Filter must be explicitly specified,
|
||||||
|
since the default value of "dn={}" would not work.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
@ -54,12 +54,18 @@ type LDAPIdentityProviderBindSpec struct {
|
|||||||
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
type LDAPIdentityProviderUserSearchAttributesSpec struct {
|
||||||
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
// Username specifies the name of attribute in the LDAP entry which whose value shall become the username
|
||||||
// of the user after a successful authentication. This would typically be the same attribute name used in
|
// of the user after a successful authentication. This would typically be the same attribute name used in
|
||||||
// the user search filter. E.g. "mail" or "uid" or "userPrincipalName".
|
// the user search filter, although it can be different. E.g. "mail" or "uid" or "userPrincipalName".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn". When this field
|
||||||
|
// is set to "dn" then the LDAPIdentityProviderUserSearchSpec's Filter field cannot be blank, since the default
|
||||||
|
// value of "dn={}" would not work.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
|
||||||
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
// UniqueID specifies the name of the attribute in the LDAP entry which whose value shall be used to uniquely
|
||||||
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
// identify the user within this LDAP provider after a successful authentication. E.g. "uidNumber" or "objectGUID".
|
||||||
|
// The value of this field is case-sensitive and must match the case of the attribute name returned by the LDAP
|
||||||
|
// server in the user's entry. Distinguished names can be used by specifying lower-case "dn".
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
UniqueID string `json:"uniqueID,omitempty"`
|
UniqueID string `json:"uniqueID,omitempty"`
|
||||||
}
|
}
|
||||||
@ -72,8 +78,10 @@ type LDAPIdentityProviderUserSearchSpec struct {
|
|||||||
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
// Filter is the LDAP search filter which should be applied when searching for users. The pattern "{}" must occur
|
||||||
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
// in the filter and will be dynamically replaced by the username for which the search is being run. E.g. "mail={}"
|
||||||
// or "&(objectClass=person)(uid={})". For more information about LDAP filters, see https://ldap.com/ldap-filters.
|
// or "&(objectClass=person)(uid={})". 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 the value from
|
// Optional. When not specified, the default will act as if the Filter were specified as the value from
|
||||||
// Attributes.Username appended by "={}".
|
// Attributes.Username appended by "={}". When the Attributes.Username is set to "dn" then the Filter must be
|
||||||
|
// explicitly specified, since the default value of "dn={}" would not work.
|
||||||
// +optional
|
// +optional
|
||||||
Filter string `json:"filter,omitempty"`
|
Filter string `json:"filter,omitempty"`
|
||||||
|
|
||||||
|
@ -180,6 +180,11 @@ func (p *Provider) TestAuthenticateUser(ctx context.Context, testUsername string
|
|||||||
|
|
||||||
// Authenticate a user and return their mapped username, groups, and UID. Implements authenticators.UserAuthenticator.
|
// Authenticate a user and return their mapped username, groups, and UID. Implements authenticators.UserAuthenticator.
|
||||||
func (p *Provider) AuthenticateUser(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
|
func (p *Provider) AuthenticateUser(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
|
||||||
|
if p.UserSearch.UsernameAttribute == distinguishedNameAttributeName && len(p.UserSearch.Filter) == 0 {
|
||||||
|
// LDAP search filters do not allow searching by DN.
|
||||||
|
return nil, false, fmt.Errorf(`must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`)
|
||||||
|
}
|
||||||
|
|
||||||
conn, err := p.dial(ctx)
|
conn, err := p.dial(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf(`error dialing host "%s": %w`, p.Host, err)
|
return nil, false, fmt.Errorf(`error dialing host "%s": %w`, p.Host, err)
|
||||||
@ -269,9 +274,13 @@ func (p *Provider) userSearchRequestedAttributes() []string {
|
|||||||
func (p *Provider) userSearchFilter(username string) string {
|
func (p *Provider) userSearchFilter(username string) string {
|
||||||
safeUsername := p.escapeUsernameForSearchFilter(username)
|
safeUsername := p.escapeUsernameForSearchFilter(username)
|
||||||
if len(p.UserSearch.Filter) == 0 {
|
if len(p.UserSearch.Filter) == 0 {
|
||||||
return fmt.Sprintf("%s=%s", p.UserSearch.UsernameAttribute, safeUsername)
|
return fmt.Sprintf("(%s=%s)", p.UserSearch.UsernameAttribute, safeUsername)
|
||||||
}
|
}
|
||||||
return strings.ReplaceAll(p.UserSearch.Filter, userSearchFilterInterpolationLocationMarker, safeUsername)
|
filter := strings.ReplaceAll(p.UserSearch.Filter, userSearchFilterInterpolationLocationMarker, safeUsername)
|
||||||
|
if strings.HasPrefix(filter, "(") && strings.HasSuffix(filter, ")") {
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
return "(" + filter + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) escapeUsernameForSearchFilter(username string) string {
|
func (p *Provider) escapeUsernameForSearchFilter(username string) string {
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
testHost = "ldap.example.com:8443"
|
testHost = "ldap.example.com:8443"
|
||||||
testBindUsername = "some-bind-username"
|
testBindUsername = "cn=some-bind-username,dc=pinniped,dc=dev"
|
||||||
testBindPassword = "some-bind-password"
|
testBindPassword = "some-bind-password"
|
||||||
testUpstreamUsername = "some-upstream-username"
|
testUpstreamUsername = "some-upstream-username"
|
||||||
testUpstreamPassword = "some-upstream-password"
|
testUpstreamPassword = "some-upstream-password"
|
||||||
@ -39,7 +39,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testUserSearchFilterInterpolated = fmt.Sprintf("some-filter=%s-and-more-filter=%s", testUpstreamUsername, testUpstreamUsername)
|
testUserSearchFilterInterpolated = fmt.Sprintf("(some-filter=%s-and-more-filter=%s)", testUpstreamUsername, testUpstreamUsername)
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAuthenticateUser(t *testing.T) {
|
func TestAuthenticateUser(t *testing.T) {
|
||||||
@ -87,6 +87,7 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
setupMocks func(conn *mockldapconn.MockConn)
|
setupMocks func(conn *mockldapconn.MockConn)
|
||||||
dialError error
|
dialError error
|
||||||
wantError string
|
wantError string
|
||||||
|
wantToSkipDial bool
|
||||||
wantAuthResponse *authenticator.Response
|
wantAuthResponse *authenticator.Response
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -115,13 +116,44 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
wantAuthResponse: &authenticator.Response{
|
wantAuthResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: testSearchResultUsernameAttributeValue,
|
Name: testSearchResultUsernameAttributeValue,
|
||||||
Groups: []string{}, // We don't support group search yet. Coming soon!
|
|
||||||
UID: testSearchResultUIDAttributeValue,
|
UID: testSearchResultUIDAttributeValue,
|
||||||
|
Groups: []string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when the UsernameAttribute is dn",
|
name: "when the user search filter is already wrapped by parenthesis then it is not wrapped again",
|
||||||
|
username: testUpstreamUsername,
|
||||||
|
password: testUpstreamPassword,
|
||||||
|
provider: provider(func(p *Provider) {
|
||||||
|
p.UserSearch.Filter = "(" + testUserSearchFilter + ")"
|
||||||
|
}),
|
||||||
|
setupMocks: func(conn *mockldapconn.MockConn) {
|
||||||
|
conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1)
|
||||||
|
conn.EXPECT().Search(expectedSearch(nil)).Return(&ldap.SearchResult{
|
||||||
|
Entries: []*ldap.Entry{
|
||||||
|
{
|
||||||
|
DN: testSearchResultDNValue,
|
||||||
|
Attributes: []*ldap.EntryAttribute{
|
||||||
|
ldap.NewEntryAttribute(testUserSearchUsernameAttribute, []string{testSearchResultUsernameAttributeValue}),
|
||||||
|
ldap.NewEntryAttribute(testUserSearchUIDAttribute, []string{testSearchResultUIDAttributeValue}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil).Times(1)
|
||||||
|
conn.EXPECT().Bind(testSearchResultDNValue, testUpstreamPassword).Times(1)
|
||||||
|
conn.EXPECT().Close().Times(1)
|
||||||
|
},
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{
|
||||||
|
Name: testSearchResultUsernameAttributeValue,
|
||||||
|
UID: testSearchResultUIDAttributeValue,
|
||||||
|
Groups: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute is dn and there is a user search filter provided",
|
||||||
username: testUpstreamUsername,
|
username: testUpstreamUsername,
|
||||||
password: testUpstreamPassword,
|
password: testUpstreamPassword,
|
||||||
provider: provider(func(p *Provider) {
|
provider: provider(func(p *Provider) {
|
||||||
@ -147,8 +179,8 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
wantAuthResponse: &authenticator.Response{
|
wantAuthResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: testSearchResultDNValue,
|
Name: testSearchResultDNValue,
|
||||||
Groups: []string{}, // We don't support group search yet. Coming soon!
|
|
||||||
UID: testSearchResultUIDAttributeValue,
|
UID: testSearchResultUIDAttributeValue,
|
||||||
|
Groups: []string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -179,8 +211,8 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
wantAuthResponse: &authenticator.Response{
|
wantAuthResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: testSearchResultUsernameAttributeValue,
|
Name: testSearchResultUsernameAttributeValue,
|
||||||
Groups: []string{}, // We don't support group search yet. Coming soon!
|
|
||||||
UID: testSearchResultDNValue,
|
UID: testSearchResultDNValue,
|
||||||
|
Groups: []string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -194,7 +226,7 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
setupMocks: func(conn *mockldapconn.MockConn) {
|
setupMocks: func(conn *mockldapconn.MockConn) {
|
||||||
conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1)
|
conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1)
|
||||||
conn.EXPECT().Search(expectedSearch(func(r *ldap.SearchRequest) {
|
conn.EXPECT().Search(expectedSearch(func(r *ldap.SearchRequest) {
|
||||||
r.Filter = testUserSearchUsernameAttribute + "=" + testUpstreamUsername
|
r.Filter = "(" + testUserSearchUsernameAttribute + "=" + testUpstreamUsername + ")"
|
||||||
})).Return(&ldap.SearchResult{
|
})).Return(&ldap.SearchResult{
|
||||||
Entries: []*ldap.Entry{
|
Entries: []*ldap.Entry{
|
||||||
{
|
{
|
||||||
@ -212,8 +244,8 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
wantAuthResponse: &authenticator.Response{
|
wantAuthResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: testSearchResultUsernameAttributeValue,
|
Name: testSearchResultUsernameAttributeValue,
|
||||||
Groups: []string{}, // We don't support group search yet. Coming soon!
|
|
||||||
UID: testSearchResultUIDAttributeValue,
|
UID: testSearchResultUIDAttributeValue,
|
||||||
|
Groups: []string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -225,7 +257,7 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
setupMocks: func(conn *mockldapconn.MockConn) {
|
setupMocks: func(conn *mockldapconn.MockConn) {
|
||||||
conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1)
|
conn.EXPECT().Bind(testBindUsername, testBindPassword).Times(1)
|
||||||
conn.EXPECT().Search(expectedSearch(func(r *ldap.SearchRequest) {
|
conn.EXPECT().Search(expectedSearch(func(r *ldap.SearchRequest) {
|
||||||
r.Filter = fmt.Sprintf("some-filter=%s-and-more-filter=%s", `a&b|c\28d\29e\5cf\2ag`, `a&b|c\28d\29e\5cf\2ag`)
|
r.Filter = fmt.Sprintf("(some-filter=%s-and-more-filter=%s)", `a&b|c\28d\29e\5cf\2ag`, `a&b|c\28d\29e\5cf\2ag`)
|
||||||
})).Return(&ldap.SearchResult{
|
})).Return(&ldap.SearchResult{
|
||||||
Entries: []*ldap.Entry{
|
Entries: []*ldap.Entry{
|
||||||
{
|
{
|
||||||
@ -243,18 +275,28 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
wantAuthResponse: &authenticator.Response{
|
wantAuthResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: testSearchResultUsernameAttributeValue,
|
Name: testSearchResultUsernameAttributeValue,
|
||||||
Groups: []string{}, // We don't support group search yet. Coming soon!
|
|
||||||
UID: testSearchResultUIDAttributeValue,
|
UID: testSearchResultUIDAttributeValue,
|
||||||
|
Groups: []string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// TODO are LDAP attribute names case sensitive? do we need any special handling for case?
|
|
||||||
{
|
{
|
||||||
name: "when dial fails",
|
name: "when dial fails",
|
||||||
provider: provider(nil),
|
provider: provider(nil),
|
||||||
dialError: errors.New("some dial error"),
|
dialError: errors.New("some dial error"),
|
||||||
wantError: fmt.Sprintf(`error dialing host "%s": some dial error`, testHost),
|
wantError: fmt.Sprintf(`error dialing host "%s": some dial error`, testHost),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute is dn and there is not a user search filter provided",
|
||||||
|
username: testUpstreamUsername,
|
||||||
|
password: testUpstreamPassword,
|
||||||
|
provider: provider(func(p *Provider) {
|
||||||
|
p.UserSearch.UsernameAttribute = "dn"
|
||||||
|
p.UserSearch.Filter = ""
|
||||||
|
}),
|
||||||
|
wantToSkipDial: true,
|
||||||
|
wantError: `must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "when binding as the bind user returns an error",
|
name: "when binding as the bind user returns an error",
|
||||||
provider: provider(nil),
|
provider: provider(nil),
|
||||||
@ -507,7 +549,7 @@ func TestAuthenticateUser(t *testing.T) {
|
|||||||
|
|
||||||
authResponse, authenticated, err := tt.provider.AuthenticateUser(context.Background(), tt.username, tt.password)
|
authResponse, authenticated, err := tt.provider.AuthenticateUser(context.Background(), tt.username, tt.password)
|
||||||
|
|
||||||
require.True(t, dialWasAttempted, "AuthenticateUser was supposed to try to dial, but didn't")
|
require.Equal(t, !tt.wantToSkipDial, dialWasAttempted)
|
||||||
|
|
||||||
if tt.wantError != "" {
|
if tt.wantError != "" {
|
||||||
require.EqualError(t, err, tt.wantError)
|
require.EqualError(t, err, tt.wantError)
|
||||||
|
608
test/integration/ldapsearch_test.go
Normal file
608
test/integration/ldapsearch_test.go
Normal file
@ -0,0 +1,608 @@
|
|||||||
|
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
|
|
||||||
|
"go.pinniped.dev/internal/certauthority"
|
||||||
|
"go.pinniped.dev/internal/upstreamldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLDAPSearch(t *testing.T) {
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
cancelFunc() // this will send SIGKILL to the docker process, just in case
|
||||||
|
})
|
||||||
|
|
||||||
|
port := localhostPort(t)
|
||||||
|
caBundle := dockerRunLDAPServer(ctx, t, port)
|
||||||
|
|
||||||
|
provider := func(editFunc func(p *upstreamldap.Provider)) *upstreamldap.Provider {
|
||||||
|
provider := &upstreamldap.Provider{
|
||||||
|
Name: "test-ldap-provider",
|
||||||
|
Host: "127.0.0.1:" + port,
|
||||||
|
CABundle: caBundle,
|
||||||
|
BindUsername: "cn=admin,dc=pinniped,dc=dev",
|
||||||
|
BindPassword: "password",
|
||||||
|
UserSearch: &upstreamldap.UserSearch{
|
||||||
|
Base: "ou=users,dc=pinniped,dc=dev",
|
||||||
|
Filter: "", // defaults to UsernameAttribute={}, i.e. "cn={}" in this case
|
||||||
|
UsernameAttribute: "cn",
|
||||||
|
UIDAttribute: "uidNumber",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if editFunc != nil {
|
||||||
|
editFunc(provider)
|
||||||
|
}
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
pinnyPassword := "password123" // from the LDIF file below
|
||||||
|
wallyPassword := "password456" // from the LDIF file below
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
provider *upstreamldap.Provider
|
||||||
|
wantError string
|
||||||
|
wantAuthResponse *authenticator.Response
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "happy path",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(nil),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy path as a different user",
|
||||||
|
username: "wally",
|
||||||
|
password: wallyPassword,
|
||||||
|
provider: provider(nil),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "wally", UID: "1001", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "using a different user search base",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.Base = "dc=pinniped,dc=dev" }),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the user search filter is already wrapped by parenthesis",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.Filter = "(cn={})" }),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute is dn and a user search filter is provided",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.UsernameAttribute = "dn"
|
||||||
|
p.UserSearch.Filter = "cn={}"
|
||||||
|
}),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "cn=pinny,ou=users,dc=pinniped,dc=dev", UID: "1000", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the user search filter allows for different ways of logging in and the first one is used",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.Filter = "(|(cn={})(mail={}))"
|
||||||
|
}),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the user search filter allows for different ways of logging in and the second one is used",
|
||||||
|
username: "pinny.ldap@example.com",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.Filter = "(|(cn={})(mail={}))"
|
||||||
|
}),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UIDAttribute is dn",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UIDAttribute = "dn" }),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "cn=pinny,ou=users,dc=pinniped,dc=dev", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UIDAttribute is sn",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UIDAttribute = "sn" }),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "pinny", UID: "Seal", Groups: []string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute is sn",
|
||||||
|
username: "seAl", // note that this is not case-sensitive! sn=Seal
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UsernameAttribute = "sn" }),
|
||||||
|
wantAuthResponse: &authenticator.Response{
|
||||||
|
User: &user.DefaultInfo{Name: "Seal", UID: "1000", Groups: []string{}}, // note that the final answer is case-sensitive
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute is dn and there is no user search filter provided",
|
||||||
|
username: "cn=pinny,ou=users,dc=pinniped,dc=dev",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.UsernameAttribute = "dn"
|
||||||
|
p.UserSearch.Filter = ""
|
||||||
|
}),
|
||||||
|
wantError: `must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the bind user username is not a valid DN",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.BindUsername = "invalid-dn" }),
|
||||||
|
wantError: `error binding as "invalid-dn" before user search: LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the bind user username is wrong",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.BindUsername = "cn=wrong,dc=pinniped,dc=dev" }),
|
||||||
|
wantError: `error binding as "cn=wrong,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the bind user password is wrong",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.BindPassword = "wrong-password" }),
|
||||||
|
wantError: `error binding as "cn=admin,dc=pinniped,dc=dev" before user search: LDAP Result Code 49 "Invalid Credentials": `,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the end user password is wrong",
|
||||||
|
username: "pinny",
|
||||||
|
password: "wrong-pinny-password",
|
||||||
|
provider: provider(nil),
|
||||||
|
wantError: `error binding for user "pinny" using provided password against DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 49 "Invalid Credentials": `,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the end user username is wrong",
|
||||||
|
username: "wrong-username",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(nil),
|
||||||
|
wantError: `searching for user "wrong-username" resulted in 0 search results, but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the user search filter does not compile",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.Filter = "*" }),
|
||||||
|
wantError: `error searching for user "pinny": LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when there are too many search results for the user",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.Filter = "objectClass=*" // overly broad search filter
|
||||||
|
}),
|
||||||
|
wantError: `error searching for user "pinny": LDAP Result Code 4 "Size Limit Exceeded": `,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the server is unreachable",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.Host = "127.0.0.1:27534" }), // hopefully this port is not in use on the host running tests
|
||||||
|
wantError: `error dialing host "127.0.0.1:27534": LDAP Result Code 200 "Network Error": dial tcp 127.0.0.1:27534: connect: connection refused`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the server is not parsable",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.Host = "too:many:ports" }),
|
||||||
|
wantError: `error dialing host "too:many:ports": LDAP Result Code 200 "Network Error": address too:many:ports: too many colons in address`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the CA bundle is not parsable",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.CABundle = []byte("invalid-pem") }),
|
||||||
|
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": could not parse CA bundle`, port),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the CA bundle does not cause the host to be trusted",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.CABundle = nil }),
|
||||||
|
wantError: fmt.Sprintf(`error dialing host "127.0.0.1:%s": LDAP Result Code 200 "Network Error": x509: certificate signed by unknown authority`, port),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute attribute has multiple values in the entry",
|
||||||
|
username: "wally.ldap@example.com",
|
||||||
|
password: wallyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UsernameAttribute = "mail" }),
|
||||||
|
wantError: `found 2 values for attribute "mail" while searching for user "wally.ldap@example.com", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UIDAttribute attribute has multiple values in the entry",
|
||||||
|
username: "wally",
|
||||||
|
password: wallyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UIDAttribute = "mail" }),
|
||||||
|
wantError: `found 2 values for attribute "mail" while searching for user "wally", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute attribute is not found in the entry",
|
||||||
|
username: "wally",
|
||||||
|
password: wallyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.Filter = "cn={}"
|
||||||
|
p.UserSearch.UsernameAttribute = "attr-does-not-exist"
|
||||||
|
}),
|
||||||
|
wantError: `found 0 values for attribute "attr-does-not-exist" while searching for user "wally", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UIDAttribute attribute is not found in the entry",
|
||||||
|
username: "wally",
|
||||||
|
password: wallyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UIDAttribute = "attr-does-not-exist" }),
|
||||||
|
wantError: `found 0 values for attribute "attr-does-not-exist" while searching for user "wally", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute has the wrong case",
|
||||||
|
username: "Seal",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UsernameAttribute = "SN" }), // this is case-sensitive
|
||||||
|
wantError: `found 0 values for attribute "SN" while searching for user "Seal", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UIDAttribute has the wrong case",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.UIDAttribute = "SN" }), // this is case-sensitive
|
||||||
|
wantError: `found 0 values for attribute "SN" while searching for user "pinny", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UsernameAttribute is DN and has the wrong case",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.UsernameAttribute = "DN" // dn must be lower-case
|
||||||
|
p.UserSearch.Filter = "cn={}"
|
||||||
|
}),
|
||||||
|
wantError: `found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the UIDAttribute is DN and has the wrong case",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) {
|
||||||
|
p.UserSearch.UIDAttribute = "DN" // dn must be lower-case
|
||||||
|
}),
|
||||||
|
wantError: `found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the search base is invalid",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.Base = "invalid-base" }),
|
||||||
|
wantError: `error searching for user "pinny": LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the search base does not exist",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.Base = "ou=does-not-exist,dc=pinniped,dc=dev" }),
|
||||||
|
wantError: `error searching for user "pinny": LDAP Result Code 32 "No Such Object": `,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the search base causes no search results",
|
||||||
|
username: "pinny",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(func(p *upstreamldap.Provider) { p.UserSearch.Base = "ou=groups,dc=pinniped,dc=dev" }),
|
||||||
|
wantError: `searching for user "pinny" resulted in 0 search results, but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when there is no username specified",
|
||||||
|
username: "",
|
||||||
|
password: pinnyPassword,
|
||||||
|
provider: provider(nil),
|
||||||
|
wantError: `searching for user "" resulted in 0 search results, but expected 1 result`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when there is no password specified",
|
||||||
|
username: "pinny",
|
||||||
|
password: "",
|
||||||
|
provider: provider(nil),
|
||||||
|
wantError: `error binding for user "pinny" using provided password against DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 206 "Empty password not allowed by the client": ldap: empty password not allowed by the client`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when the user has no password in their entry",
|
||||||
|
username: "olive",
|
||||||
|
password: "anything",
|
||||||
|
provider: provider(nil),
|
||||||
|
wantError: `error binding for user "olive" using provided password against DN "cn=olive,ou=users,dc=pinniped,dc=dev": LDAP Result Code 49 "Invalid Credentials": `,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
tt := test
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
authResponse, authenticated, err := tt.provider.AuthenticateUser(ctx, tt.username, tt.password)
|
||||||
|
|
||||||
|
if tt.wantError != "" {
|
||||||
|
require.EqualError(t, err, tt.wantError)
|
||||||
|
require.False(t, authenticated)
|
||||||
|
require.Nil(t, authResponse)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, authenticated)
|
||||||
|
require.Equal(t, tt.wantAuthResponse, authResponse)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func localhostPort(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
unusedPortGrabbingListener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recentlyClaimedHostAndPort := unusedPortGrabbingListener.Addr().String()
|
||||||
|
require.NoError(t, unusedPortGrabbingListener.Close())
|
||||||
|
|
||||||
|
splitHostAndPort := strings.Split(recentlyClaimedHostAndPort, ":")
|
||||||
|
require.Len(t, splitHostAndPort, 2)
|
||||||
|
|
||||||
|
return splitHostAndPort[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func dockerRunLDAPServer(ctx context.Context, t *testing.T, hostPort string) []byte {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
_, err := exec.LookPath("docker")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ca, err := certauthority.New("Test LDAP CA", time.Hour*24)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
certPEM, keyPEM, err := ca.IssueServerCertPEM(nil, []net.IP{net.ParseIP("127.0.0.1")}, time.Hour*24)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tempDir, err := ioutil.TempDir("", "pinniped-test-*")
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := os.Remove(tempDir)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
writeToNewTempFile(t, tempDir, "cert.pem", certPEM)
|
||||||
|
writeToNewTempFile(t, tempDir, "key.pem", keyPEM)
|
||||||
|
writeToNewTempFile(t, tempDir, "ca.pem", ca.Bundle())
|
||||||
|
writeToNewTempFile(t, tempDir, "test.ldif", []byte(testLDIF))
|
||||||
|
|
||||||
|
dockerArgs := []string{
|
||||||
|
"run",
|
||||||
|
"-e", "BITNAMI_DEBUG=true",
|
||||||
|
"-e", "LDAP_ADMIN_USERNAME=admin",
|
||||||
|
"-e", "LDAP_ADMIN_PASSWORD=password",
|
||||||
|
"-e", "LDAP_ENABLE_TLS=yes",
|
||||||
|
"-e", "LDAP_TLS_CERT_FILE=/inputs/cert.pem",
|
||||||
|
"-e", "LDAP_TLS_KEY_FILE=/inputs/key.pem",
|
||||||
|
"-e", "LDAP_TLS_CA_FILE=/inputs/ca.pem",
|
||||||
|
"-e", "LDAP_CUSTOM_LDIF_DIR=/inputs",
|
||||||
|
"-e", "LDAP_ROOT=dc=pinniped,dc=dev",
|
||||||
|
"-v", tempDir + ":/inputs",
|
||||||
|
"-p", hostPort + ":1636",
|
||||||
|
"-m", "64m",
|
||||||
|
"--rm", // automatically delete the container when finished
|
||||||
|
"docker.io/bitnami/openldap",
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("Starting:", "docker", strings.Join(dockerArgs, " "))
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(ctx, "docker", dockerArgs...)
|
||||||
|
|
||||||
|
var stdoutBuf, stderrBuf syncBuffer
|
||||||
|
cmd.Stdout = &stdoutBuf
|
||||||
|
cmd.Stderr = &stderrBuf
|
||||||
|
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
|
||||||
|
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
// docker requires an interrupt signal to end the container.
|
||||||
|
// This t.Cleanup is registered after the one that cancels the context, so this one will happen first.
|
||||||
|
err := cmd.Process.Signal(os.Interrupt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
time.Sleep(time.Second) // give a moment before we move on, because we'll send SIGKILL in a later t.Cleanup
|
||||||
|
})
|
||||||
|
|
||||||
|
earlyTerminationCh := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
err = cmd.Wait()
|
||||||
|
earlyTerminationCh <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
terminatedEarly := false
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
t.Log("Waiting for slapd to start...")
|
||||||
|
// This substring is contained in the last line of output before the server starts.
|
||||||
|
if strings.Contains(stderrBuf.String(), " slapd starting\n") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-earlyTerminationCh:
|
||||||
|
terminatedEarly = true
|
||||||
|
return true
|
||||||
|
default: // ignore when this non-blocking read found no message
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, 2*time.Minute, time.Second)
|
||||||
|
|
||||||
|
require.Falsef(t, terminatedEarly, "docker command ended sooner than expected")
|
||||||
|
|
||||||
|
t.Log("Detected LDAP server has started successfully")
|
||||||
|
return ca.Bundle()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeToNewTempFile(t *testing.T, dir string, filename string, contents []byte) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
filePath := path.Join(dir, filename)
|
||||||
|
|
||||||
|
err := ioutil.WriteFile(filePath, contents, 0644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := os.Remove(filePath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var testLDIF = `
|
||||||
|
# ** CAUTION: Blank lines separate entries in the LDIF format! Do not remove them! ***
|
||||||
|
# Here's a good explaination of LDIF:
|
||||||
|
# https://www.digitalocean.com/community/tutorials/how-to-use-ldif-files-to-make-changes-to-an-openldap-system
|
||||||
|
|
||||||
|
# pinniped.dev (organization, root)
|
||||||
|
dn: dc=pinniped,dc=dev
|
||||||
|
objectClass: dcObject
|
||||||
|
objectClass: organization
|
||||||
|
dc: pinniped
|
||||||
|
o: example
|
||||||
|
|
||||||
|
# users, pinniped.dev (organization unit)
|
||||||
|
dn: ou=users,dc=pinniped,dc=dev
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: users
|
||||||
|
|
||||||
|
# groups, pinniped.dev (organization unit)
|
||||||
|
dn: ou=groups,dc=pinniped,dc=dev
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: groups
|
||||||
|
|
||||||
|
# beach-groups, groups, pinniped.dev (organization unit)
|
||||||
|
dn: ou=beach-groups,ou=groups,dc=pinniped,dc=dev
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: beach-groups
|
||||||
|
|
||||||
|
# pinny, users, pinniped.dev (user)
|
||||||
|
dn: cn=pinny,ou=users,dc=pinniped,dc=dev
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
objectClass: posixAccount
|
||||||
|
objectClass: shadowAccount
|
||||||
|
cn: pinny
|
||||||
|
sn: Seal
|
||||||
|
givenName: Pinny
|
||||||
|
mail: pinny.ldap@example.com
|
||||||
|
userPassword: password123
|
||||||
|
uid: pinny
|
||||||
|
uidNumber: 1000
|
||||||
|
gidNumber: 1000
|
||||||
|
homeDirectory: /home/pinny
|
||||||
|
loginShell: /bin/bash
|
||||||
|
gecos: pinny-the-seal
|
||||||
|
|
||||||
|
# wally, users, pinniped.dev
|
||||||
|
dn: cn=wally,ou=users,dc=pinniped,dc=dev
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
objectClass: posixAccount
|
||||||
|
objectClass: shadowAccount
|
||||||
|
cn: wally
|
||||||
|
sn: Walrus
|
||||||
|
givenName: Wally
|
||||||
|
mail: wally.ldap@example.com
|
||||||
|
mail: wally.alternate@example.com
|
||||||
|
userPassword: password456
|
||||||
|
uid: wally
|
||||||
|
uidNumber: 1001
|
||||||
|
gidNumber: 1001
|
||||||
|
homeDirectory: /home/wally
|
||||||
|
loginShell: /bin/bash
|
||||||
|
gecos: wally-the-walrus
|
||||||
|
|
||||||
|
# olive, users, pinniped.dev (user without password)
|
||||||
|
dn: cn=olive,ou=users,dc=pinniped,dc=dev
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
objectClass: posixAccount
|
||||||
|
objectClass: shadowAccount
|
||||||
|
cn: olive
|
||||||
|
sn: Boston Terrier
|
||||||
|
givenName: Olive
|
||||||
|
mail: olive.ldap@example.com
|
||||||
|
uid: olive
|
||||||
|
uidNumber: 1002
|
||||||
|
gidNumber: 1002
|
||||||
|
homeDirectory: /home/olive
|
||||||
|
loginShell: /bin/bash
|
||||||
|
gecos: olive-the-dog
|
||||||
|
|
||||||
|
# ball-game-players, beach-groups, groups, pinniped.dev (group of users)
|
||||||
|
dn: cn=ball-game-players,ou=beach-groups,ou=groups,dc=pinniped,dc=dev
|
||||||
|
cn: ball-game-players
|
||||||
|
objectClass: groupOfNames
|
||||||
|
member: cn=pinny,ou=users,dc=pinniped,dc=dev
|
||||||
|
member: cn=olive,ou=users,dc=pinniped,dc=dev
|
||||||
|
|
||||||
|
# seals, groups, pinniped.dev (group of users)
|
||||||
|
dn: cn=seals,ou=groups,dc=pinniped,dc=dev
|
||||||
|
cn: seals
|
||||||
|
objectClass: groupOfNames
|
||||||
|
member: cn=pinny,ou=users,dc=pinniped,dc=dev
|
||||||
|
|
||||||
|
# walruses, groups, pinniped.dev (group of users)
|
||||||
|
dn: cn=walruses,ou=groups,dc=pinniped,dc=dev
|
||||||
|
cn: walruses
|
||||||
|
objectClass: groupOfNames
|
||||||
|
member: cn=wally,ou=users,dc=pinniped,dc=dev
|
||||||
|
|
||||||
|
# pinnipeds, users, pinniped.dev (group of groups)
|
||||||
|
dn: cn=pinnipeds,ou=groups,dc=pinniped,dc=dev
|
||||||
|
cn: pinnipeds
|
||||||
|
objectClass: groupOfNames
|
||||||
|
member: cn=seals,ou=groups,dc=pinniped,dc=dev
|
||||||
|
member: cn=walruses,ou=groups,dc=pinniped,dc=dev
|
||||||
|
|
||||||
|
# mammals, groups, pinniped.dev (group of both groups and users)
|
||||||
|
dn: cn=mammals,ou=groups,dc=pinniped,dc=dev
|
||||||
|
cn: mammals
|
||||||
|
objectClass: groupOfNames
|
||||||
|
member: cn=pinninpeds,ou=groups,dc=pinniped,dc=dev
|
||||||
|
member: cn=olive,ou=users,dc=pinniped,dc=dev
|
||||||
|
`
|
Loading…
Reference in New Issue
Block a user