Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add case insensitive user attribute keys configs for LDAP #132

Merged
merged 5 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
jimlambrt marked this conversation as resolved.
Show resolved Hide resolved
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
Loading