Allow alias dereferencing in LDAP searches (#18230)
* impr(auth/ldap): allow to dereference aliases in searches * docs: add documentation for LDAP alias dereferencing * chore(auth/ldap): add changelog entry for PR 18230 * chore: run formatter * fix: update default LDAP configuration with new default * Update website/content/docs/auth/ldap.mdx Co-authored-by: tjperry07 <tjperry07@users.noreply.github.com> * docs(ldap): add alias dereferencing to API docs for LDAP --------- Co-authored-by: tjperry07 <tjperry07@users.noreply.github.com>
This commit is contained in:
parent
809957aac0
commit
078a245939
|
@ -1231,6 +1231,7 @@ func TestLdapAuthBackend_ConfigUpgrade(t *testing.T) {
|
|||
UsePre111GroupCNBehavior: new(bool),
|
||||
RequestTimeout: cfg.RequestTimeout,
|
||||
UsernameAsAlias: false,
|
||||
DerefAliases: "never",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
auth/ldap: allow configuration of alias dereferencing in LDAP search
|
||||
```
|
|
@ -119,10 +119,11 @@ func (c *Client) makeLdapSearchRequest(cfg *ConfigEntry, conn Connection, userna
|
|||
c.Logger.Debug("discovering user", "userdn", cfg.UserDN, "filter", renderedFilter)
|
||||
}
|
||||
ldapRequest := &ldap.SearchRequest{
|
||||
BaseDN: cfg.UserDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
Filter: renderedFilter,
|
||||
SizeLimit: 2, // Should be only 1 result. Any number larger (2 or more) means access denied.
|
||||
BaseDN: cfg.UserDN,
|
||||
DerefAliases: ldapDerefAliasMap[cfg.DerefAliases],
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
Filter: renderedFilter,
|
||||
SizeLimit: 2, // Should be only 1 result. Any number larger (2 or more) means access denied.
|
||||
Attributes: []string{
|
||||
cfg.UserAttr, // Return only needed attributes
|
||||
},
|
||||
|
@ -274,10 +275,11 @@ func (c *Client) GetUserDN(cfg *ConfigEntry, conn Connection, bindDN, username s
|
|||
c.Logger.Debug("searching upn", "userdn", cfg.UserDN, "filter", filter)
|
||||
}
|
||||
result, err := conn.Search(&ldap.SearchRequest{
|
||||
BaseDN: cfg.UserDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
Filter: filter,
|
||||
SizeLimit: math.MaxInt32,
|
||||
BaseDN: cfg.UserDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
DerefAliases: ldapDerefAliasMap[cfg.DerefAliases],
|
||||
Filter: filter,
|
||||
SizeLimit: math.MaxInt32,
|
||||
})
|
||||
if err != nil {
|
||||
return userDN, fmt.Errorf("LDAP search failed for detecting user: %w", err)
|
||||
|
@ -335,9 +337,10 @@ func (c *Client) performLdapFilterGroupsSearch(cfg *ConfigEntry, conn Connection
|
|||
}
|
||||
|
||||
result, err := conn.Search(&ldap.SearchRequest{
|
||||
BaseDN: cfg.GroupDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
Filter: renderedQuery.String(),
|
||||
BaseDN: cfg.GroupDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
DerefAliases: ldapDerefAliasMap[cfg.DerefAliases],
|
||||
Filter: renderedQuery.String(),
|
||||
Attributes: []string{
|
||||
cfg.GroupAttr,
|
||||
},
|
||||
|
@ -393,9 +396,10 @@ func (c *Client) performLdapFilterGroupsSearchPaging(cfg *ConfigEntry, conn Pagi
|
|||
}
|
||||
|
||||
result, err := conn.SearchWithPaging(&ldap.SearchRequest{
|
||||
BaseDN: cfg.GroupDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
Filter: renderedQuery.String(),
|
||||
BaseDN: cfg.GroupDN,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
DerefAliases: ldapDerefAliasMap[cfg.DerefAliases],
|
||||
Filter: renderedQuery.String(),
|
||||
Attributes: []string{
|
||||
cfg.GroupAttr,
|
||||
},
|
||||
|
@ -442,9 +446,10 @@ func sidBytesToString(b []byte) (string, error) {
|
|||
|
||||
func (c *Client) performLdapTokenGroupsSearch(cfg *ConfigEntry, conn Connection, userDN string) ([]*ldap.Entry, error) {
|
||||
result, err := conn.Search(&ldap.SearchRequest{
|
||||
BaseDN: userDN,
|
||||
Scope: ldap.ScopeBaseObject,
|
||||
Filter: "(objectClass=*)",
|
||||
BaseDN: userDN,
|
||||
Scope: ldap.ScopeBaseObject,
|
||||
DerefAliases: ldapDerefAliasMap[cfg.DerefAliases],
|
||||
Filter: "(objectClass=*)",
|
||||
Attributes: []string{
|
||||
"tokenGroups",
|
||||
},
|
||||
|
@ -470,9 +475,10 @@ func (c *Client) performLdapTokenGroupsSearch(cfg *ConfigEntry, conn Connection,
|
|||
}
|
||||
|
||||
groupResult, err := conn.Search(&ldap.SearchRequest{
|
||||
BaseDN: fmt.Sprintf("<SID=%s>", sidString),
|
||||
Scope: ldap.ScopeBaseObject,
|
||||
Filter: "(objectClass=*)",
|
||||
BaseDN: fmt.Sprintf("<SID=%s>", sidString),
|
||||
Scope: ldap.ScopeBaseObject,
|
||||
DerefAliases: ldapDerefAliasMap[cfg.DerefAliases],
|
||||
Filter: "(objectClass=*)",
|
||||
Attributes: []string{
|
||||
"1.1", // RFC no attributes
|
||||
},
|
||||
|
|
|
@ -13,8 +13,17 @@ import (
|
|||
"github.com/hashicorp/vault/sdk/framework"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
)
|
||||
|
||||
var ldapDerefAliasMap = map[string]int{
|
||||
"never": ldap.NeverDerefAliases,
|
||||
"finding": ldap.DerefFindingBaseObj,
|
||||
"searching": ldap.DerefInSearching,
|
||||
"always": ldap.DerefAlways,
|
||||
}
|
||||
|
||||
// ConfigFields returns all the config fields that can potentially be used by the LDAP client.
|
||||
// Not all fields will be used by every integration.
|
||||
func ConfigFields() map[string]*framework.FieldSchema {
|
||||
|
@ -226,6 +235,13 @@ Default: ({{.UserAttr}}={{.Username}})`,
|
|||
Description: "Timeout, in seconds, for the connection when making requests against the server before returning back an error.",
|
||||
Default: "90s",
|
||||
},
|
||||
|
||||
"dereference_aliases": {
|
||||
Type: framework.TypeString,
|
||||
Description: "When aliases should be dereferenced on search operations. Accepted values are 'never', 'finding', 'searching', 'always'. Defaults to 'never'.",
|
||||
Default: "never",
|
||||
AllowedValues: []interface{}{"never", "finding", "searching", "always"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,6 +408,10 @@ func NewConfigEntry(existing *ConfigEntry, d *framework.FieldData) (*ConfigEntry
|
|||
cfg.RequestTimeout = d.Get("request_timeout").(int)
|
||||
}
|
||||
|
||||
if _, ok := d.Raw["dereference_aliases"]; ok || !hadExisting {
|
||||
cfg.DerefAliases = d.Get("dereference_aliases").(string)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
|
@ -418,6 +438,7 @@ type ConfigEntry struct {
|
|||
UseTokenGroups bool `json:"use_token_groups"`
|
||||
UsePre111GroupCNBehavior *bool `json:"use_pre111_group_cn_behavior"`
|
||||
RequestTimeout int `json:"request_timeout"`
|
||||
DerefAliases string `json:"dereference_aliases"`
|
||||
|
||||
// These json tags deviate from snake case because there was a past issue
|
||||
// where the tag was being ignored, causing it to be jsonified as "CaseSensitiveNames", etc.
|
||||
|
@ -456,6 +477,7 @@ func (c *ConfigEntry) PasswordlessMap() map[string]interface{} {
|
|||
"anonymous_group_search": c.AnonymousGroupSearch,
|
||||
"request_timeout": c.RequestTimeout,
|
||||
"username_as_alias": c.UsernameAsAlias,
|
||||
"dereference_aliases": c.DerefAliases,
|
||||
}
|
||||
if c.CaseSensitiveNames != nil {
|
||||
m["case_sensitive_names"] = *c.CaseSensitiveNames
|
||||
|
|
|
@ -168,6 +168,7 @@ var jsonConfigDefault = []byte(`
|
|||
"use_pre111_group_cn_behavior": null,
|
||||
"username_as_alias": false,
|
||||
"request_timeout": 90,
|
||||
"dereference_aliases": "never",
|
||||
"CaseSensitiveNames": false,
|
||||
"ClientTLSCert": "",
|
||||
"ClientTLSKey": ""
|
||||
|
|
|
@ -91,6 +91,9 @@ This endpoint configures the LDAP auth method.
|
|||
returning _user_ objects, use: `memberOf`. The default is `cn`.
|
||||
- `username_as_alias` `(bool: false)` - If set to true, forces the auth method
|
||||
to use the username passed by the user as the alias name.
|
||||
- `dereference_aliases` `(string: never)` - When aliases should be dereferenced
|
||||
on search operations. Accepted values are 'never', 'finding', 'searching',
|
||||
'always'. Defaults to 'never'.
|
||||
|
||||
@include 'tokenfields.mdx'
|
||||
|
||||
|
|
|
@ -133,6 +133,10 @@ There are two alternate methods of resolving the user object used to authenticat
|
|||
|
||||
@include 'ldap-auth-userfilter-warning.mdx'
|
||||
|
||||
#### Alias Dereferencing
|
||||
|
||||
- `dereference_aliases` (string, optional) - Control how aliases are dereferenced when performing the search. Possible values are: `never`, `finding`, `searching`, and `always`. `finding` will only dereference aliases during name resolution of the base. `searching` will dereference aliases after name resolution.
|
||||
|
||||
#### Binding - User Principal Name (AD)
|
||||
|
||||
- `upndomain` (string, optional) - userPrincipalDomain used to construct the UPN string for the authenticating user. The constructed UPN will appear as `[username]@UPNDomain`. Example: `example.com`, which will cause vault to bind as `username@example.com`.
|
||||
|
|
Loading…
Reference in New Issue