Skip to content

Commit

Permalink
Merge pull request #132 from hashicorp/ldap-userattrs-tolower
Browse files Browse the repository at this point in the history
Add case insensitive user attribute keys configs for LDAP
  • Loading branch information
jasonodonnell authored Mar 27, 2024
2 parents faa330b + a19ed94 commit 0d02560
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 11 deletions.
8 changes: 6 additions & 2 deletions ldap/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ type Attribute struct {
// the WithGroups option is specified, it will also return the user's groups
// from the directory.
//
// Supported options: WithUserAttributes, WithGroups, WithDialer, WithURLs
// Supported options: WithUserAttributes, WithGroups, WithDialer, WithURLs, WithLowerUserAttributeKeys
func (c *Client) Authenticate(ctx context.Context, username, password string, opt ...Option) (*AuthResult, error) {
const op = "ldap.(Client).Authenticate"
if username == "" {
Expand Down Expand Up @@ -273,7 +273,11 @@ func (c *Client) Authenticate(ctx context.Context, username, password string, op
return nil, fmt.Errorf("%s: failed to get user attributes: %w", op, err)
}
for _, a := range attrs {
userAttrs[a.Name] = a.Vals
name := a.Name
if c.conf.LowerUserAttributeKeys || opts.withLowerUserAttributeKeys {
name = strings.ToLower(a.Name)
}
userAttrs[name] = a.Vals
}
}
if !opts.withGroups && !c.conf.IncludeUserGroups {
Expand Down
43 changes: 43 additions & 0 deletions ldap/client_exported_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,49 @@ func TestClient_Authenticate(t *testing.T) {
},
wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
},
{
name: "success-with-user-attributes-lower-case-keys",
username: "alice",
password: "password",
clientConfig: &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
Certificates: []string{td.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
ExcludedUserAttributes: []string{"password", "memberof"},
IncludeUserAttributes: true,
LowerUserAttributeKeys: true,
},
opts: []ldap.Option{ldap.WithUserAttributes()},
wantUserAttributes: map[string][]string{
"email": {"alice@example.com"},
"name": {"alice"},
"tokengroups": {"\x01\x00\x00\x00\x00\x00\x00\x01"},
},
wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
},
{
name: "success-with-user-attributes-lower-case-keys-opt",
username: "alice",
password: "password",
clientConfig: &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
Certificates: []string{td.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
ExcludedUserAttributes: []string{"password", "memberof"},
IncludeUserAttributes: true,
},
opts: []ldap.Option{ldap.WithUserAttributes(), ldap.WithLowerUserAttributeKeys()},
wantUserAttributes: map[string][]string{
"email": {"alice@example.com"},
"name": {"alice"},
"tokengroups": {"\x01\x00\x00\x00\x00\x00\x00\x01"},
},
wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
},
{
name: "success-include-user-groups",
username: "alice",
Expand Down
5 changes: 5 additions & 0 deletions ldap/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ type ClientConfig struct {
// AD (unicodePwd) will always be excluded.
ExcludedUserAttributes []string

// LowerUserAttributeKeys optionally specifies that the authenticating user's
// DN and attributes be included in AuthResult use lowercase key names rather
// than the default camel case.
LowerUserAttributeKeys bool

// IncludeUserGroups optionally specifies that the authenticating user's
// group membership be included an authentication AuthResult.
IncludeUserGroups bool
Expand Down
31 changes: 22 additions & 9 deletions ldap/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ package ldap
type Option func(interface{})

type configOptions struct {
withURLs []string
withInsecureTLS bool
withTLSMinVersion string
withTLSMaxVersion string
withCertificates []string
withClientTLSCert string
withClientTLSKey string
withGroups bool
withUserAttributes bool
withURLs []string
withInsecureTLS bool
withTLSMinVersion string
withTLSMaxVersion string
withCertificates []string
withClientTLSCert string
withClientTLSKey string
withGroups bool
withUserAttributes bool
withLowerUserAttributeKeys bool
}

func configDefaults() configOptions {
Expand Down Expand Up @@ -75,6 +76,18 @@ func WithUserAttributes() Option {
}
}

// WithLowerUserAttributeKeys returns a User Attribute map where the keys
// are all cast to lower case. This is necessary for some clients, such as Vault,
// where user configured user attribute key names have always been stored lower case.
func WithLowerUserAttributeKeys() Option {
return func(o interface{}) {
switch v := o.(type) {
case *configOptions:
v.withLowerUserAttributeKeys = true
}
}
}

func withTLSMinVersion(version string) Option {
return func(o interface{}) {
switch v := o.(type) {
Expand Down

0 comments on commit 0d02560

Please sign in to comment.