Example #1
0
// SanitizePolicies performs the common input validation tasks
// which are performed on the list of policies across Vault.
// The resulting collection will have no duplicate elements.
// If 'root' policy was present in the list of policies, then
// all other policies will be ignored, the result will contain
// just the 'root'. In cases where 'root' is not present, if
// 'default' policy is not already present, it will be added
// if addDefault is set to true.
func SanitizePolicies(policies []string, addDefault bool) []string {
	defaultFound := false
	for i, p := range policies {
		policies[i] = strings.ToLower(strings.TrimSpace(p))
		// Eliminate unnamed policies.
		if policies[i] == "" {
			continue
		}

		// If 'root' policy is present, ignore all other policies.
		if policies[i] == "root" {
			policies = []string{"root"}
			defaultFound = true
			break
		}
		if policies[i] == "default" {
			defaultFound = true
		}
	}

	// Always add 'default' except only if the policies contain 'root'.
	if addDefault && (len(policies) == 0 || !defaultFound) {
		policies = append(policies, "default")
	}

	return strutil.RemoveDuplicates(policies)
}
Example #2
0
func (b *backend) Login(req *logical.Request, username string, password string) ([]string, *logical.Response, error) {

	cfg, err := b.Config(req)
	if err != nil {
		return nil, nil, err
	}
	if cfg == nil {
		return nil, logical.ErrorResponse("ldap backend not configured"), nil
	}

	c, err := cfg.DialLDAP()
	if err != nil {
		return nil, logical.ErrorResponse(err.Error()), nil
	}
	if c == nil {
		return nil, logical.ErrorResponse("invalid connection returned from LDAP dial"), nil
	}

	bindDN, err := b.getBindDN(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)
	}

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

	userDN, err := b.getUserDN(cfg, c, bindDN)
	if err != nil {
		return nil, logical.ErrorResponse(err.Error()), nil
	}

	ldapGroups, err := b.getLdapGroups(cfg, c, userDN, username)
	if err != nil {
		return nil, logical.ErrorResponse(err.Error()), nil
	}
	if b.Logger().IsDebug() {
		b.Logger().Debug("auth/ldap: Groups fetched from server", "num_server_groups", len(ldapGroups), "server_groups", ldapGroups)
	}

	ldapResponse := &logical.Response{
		Data: map[string]interface{}{},
	}
	if len(ldapGroups) == 0 {
		errString := fmt.Sprintf(
			"no LDAP groups found in groupDN '%s'; only policies from locally-defined groups available",
			cfg.GroupDN)
		ldapResponse.AddWarning(errString)
	}

	var allGroups []string
	// Import the custom added groups from ldap backend
	user, err := b.User(req.Storage, username)
	if err == nil && user != nil && user.Groups != nil {
		if b.Logger().IsDebug() {
			b.Logger().Debug("auth/ldap: adding local groups", "num_local_groups", len(user.Groups), "local_groups", user.Groups)
		}
		allGroups = append(allGroups, user.Groups...)
	}
	// Merge local and LDAP groups
	allGroups = append(allGroups, ldapGroups...)

	// Retrieve policies
	var policies []string
	for _, groupName := range allGroups {
		group, err := b.Group(req.Storage, groupName)
		if err == nil && group != nil {
			policies = append(policies, group.Policies...)
		}
	}

	// Policies from each group may overlap
	policies = strutil.RemoveDuplicates(policies)

	if len(policies) == 0 {
		errStr := "user is not a member of any authorized group"
		if len(ldapResponse.Warnings()) > 0 {
			errStr = fmt.Sprintf("%s; additionally, %s", errStr, ldapResponse.Warnings()[0])
		}

		ldapResponse.Data["error"] = errStr
		return nil, ldapResponse, nil
	}

	return policies, ldapResponse, nil
}