Skip to content

Commit

Permalink
Use service bind for searching LDAP groups (#2534)
Browse files Browse the repository at this point in the history
Fixes #2387
  • Loading branch information
mitchelldavis authored and jefferai committed Apr 18, 2017
1 parent aefb1ce commit a208159
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 6 deletions.
21 changes: 16 additions & 5 deletions builtin/credential/ldap/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,25 +104,36 @@ func (b *backend) Login(req *logical.Request, username string, password string)
// Clean connection
defer c.Close()

bindDN, err := b.getBindDN(cfg, c, username)
userBindDN, err := b.getUserBindDN(cfg, c, username)
if err != nil {
return nil, logical.ErrorResponse(err.Error()), nil
}

if b.Logger().IsDebug() {
b.Logger().Debug("auth/ldap: BindDN fetched", "username", username, "binddn", bindDN)
b.Logger().Debug("auth/ldap: User BindDN fetched", "username", username, "binddn", userBindDN)
}

if cfg.DenyNullBind && len(password) == 0 {
return nil, logical.ErrorResponse("password cannot be of zero length when passwordless binds are being denied"), nil
}

// Try to bind as the login user. This is where the actual authentication takes place.
if err = c.Bind(bindDN, password); err != nil {
if err = c.Bind(userBindDN, password); err != nil {
return nil, logical.ErrorResponse(fmt.Sprintf("LDAP bind failed: %v", err)), nil
}

userDN, err := b.getUserDN(cfg, c, bindDN)
// We re-bind to the BindDN if it's defined because we assume
// the BindDN should be the one to search, not the user logging in.
if cfg.BindDN != "" && cfg.BindPassword != "" {
if err := c.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
return nil, logical.ErrorResponse(fmt.Sprintf("Encountered an error while attempting to re-bind with the BindDN User: %s", err.Error())), nil
}
if b.Logger().IsDebug() {
b.Logger().Debug("auth/ldap: Re-Bound to original BindDN")
}
}

userDN, err := b.getUserDN(cfg, c, userBindDN)
if err != nil {
return nil, logical.ErrorResponse(err.Error()), nil
}
Expand Down Expand Up @@ -218,7 +229,7 @@ func (b *backend) getCN(dn string) string {
* 2. If upndomain is set, the user dn is constructed as 'username@upndomain'. See https://msdn.microsoft.com/en-us/library/cc223499.aspx
*
*/
func (b *backend) getBindDN(cfg *ConfigEntry, c *ldap.Conn, username string) (string, error) {
func (b *backend) getUserBindDN(cfg *ConfigEntry, c *ldap.Conn, username string) (string, error) {
bindDN := ""
if cfg.DiscoverDN || (cfg.BindDN != "" && cfg.BindPassword != "") {
if err := c.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion website/source/docs/auth/ldap.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ There are two alternate methods of resolving the user object used to authenticat

#### Binding - Authenticated Search

* `binddn` (string, optional) - Distinguished name of object to bind when performing user search. Example: `cn=vault,ou=Users,dc=example,dc=com`
* `binddn` (string, optional) - Distinguished name of object to bind when performing user and group search. Example: `cn=vault,ou=Users,dc=example,dc=com`
* `bindpass` (string, optional) - Password to use along with `binddn` when performing user search.
* `userdn` (string, optional) - Base DN under which to perform user search. Example: `ou=Users,dc=example,dc=com`
* `userattr` (string, optional) - Attribute on user attribute object matching the username passed when authenticating. Examples: `sAMAccountName`, `cn`, `uid`
Expand All @@ -146,6 +146,7 @@ Once a user has been authenticated, the LDAP auth backend must know how to resol
* `groupdn` (string, required) - LDAP search base to use for group membership search. This can be the root containing either groups or users. Example: `ou=Groups,dc=example,dc=com`
* `groupattr` (string, optional) - LDAP attribute to follow on objects returned by `groupfilter` in order to enumerate user group membership. Examples: for groupfilter queries returning _group_ objects, use: `cn`. For queries returning _user_ objects, use: `memberOf`. The default is `cn`.

*Note*: When using _Authenticated Search_ for binding parameters (see above) the distinguished name defined for `binddn` is used for the group search. Otherwise, the authenticating user is used to perform the group search.

Use `vault path-help` for more details.

Expand Down

0 comments on commit a208159

Please sign in to comment.