Use service bind for searching LDAP groups (#2534)

Fixes #2387
This commit is contained in:
Mitch Davis
2017-04-18 14:52:05 -05:00
committed by Jeff Mitchell
parent aefb1ce58d
commit a20815972c
2 changed files with 18 additions and 6 deletions

View File

@@ -104,13 +104,13 @@ 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 {
@@ -118,11 +118,22 @@ func (b *backend) Login(req *logical.Request, username string, password string)
}
// 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
}
@@ -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 {

View File

@@ -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`
@@ -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.