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 empty anonymous group search configs #134

Merged
merged 2 commits into from
Mar 28, 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
12 changes: 10 additions & 2 deletions ldap/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ 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, WithLowerUserAttributeKeys
// Supported options: WithUserAttributes, WithGroups, WithDialer, WithURLs,
// WithLowerUserAttributeKeys, WithEmptyAnonymousGroupSearch
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 @@ -289,7 +290,14 @@ func (c *Client) Authenticate(ctx context.Context, username, password string, op
}

if c.conf.AnonymousGroupSearch {
if err := c.conn.UnauthenticatedBind(userDN); err != nil {
// Some LDAP servers will reject anonymous group searches if userDN is
// included in the query.
dn := userDN
if c.conf.AllowEmptyAnonymousGroupSearch || opts.withEmptyAnonymousGroupSearch {
dn = ""
}

if err := c.conn.UnauthenticatedBind(dn); err != nil {
return nil, fmt.Errorf("%s: group search anonymous bind failed: %w", op, err)
}
}
Expand Down
66 changes: 66 additions & 0 deletions ldap/client_exported_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,72 @@ func TestClient_Authenticate(t *testing.T) {
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
},
{
name: "success-with-anon-bind-groups-empty-userdn",
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,
UseTokenGroups: true,
AnonymousGroupSearch: true,
AllowEmptyAnonymousGroupSearch: true,
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
},
{
name: "success-with-anon-bind-groups-empty-userdn-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,
UseTokenGroups: true,
AnonymousGroupSearch: true,
},
opts: []ldap.Option{ldap.WithGroups(), ldap.WithEmptyAnonymousGroupSearch()},
wantGroups: []string{groups[0].DN},
},
{
name: "success-with-anon-bind-upn-domain-empty-userdn",
username: "eve",
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,
UPNDomain: "example.com",
AnonymousGroupSearch: true,
AllowEmptyAnonymousGroupSearch: true,
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
},
{
name: "success-with-anon-bind-upn-domain-empty-userdn-opt",
username: "eve",
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,
UPNDomain: "example.com",
AnonymousGroupSearch: true,
},
opts: []ldap.Option{ldap.WithGroups(), ldap.WithEmptyAnonymousGroupSearch()},
wantGroups: []string{groups[0].DN},
},
{
name: "success-with-binddn",
username: "alice",
Expand Down
4 changes: 4 additions & 0 deletions ldap/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ type ClientConfig struct {
// for the initial connection test).
AnonymousGroupSearch bool `json:"anonymous_group_search"`

// AllowEmptyAnonymousGroupSearches: if true it removes the userDN from
// unauthenticated group searches (optional).
AllowEmptyAnonymousGroupSearch bool `json:"allow_empty_anonymous_group_search"`

// GroupDN is the distinguished name to use as base when searching for group
// membership (eg: ou=Groups,dc=example,dc=org)
GroupDN string `json:"groupdn"`
Expand Down
31 changes: 21 additions & 10 deletions ldap/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ 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
withLowerUserAttributeKeys bool
withURLs []string
withInsecureTLS bool
withTLSMinVersion string
withTLSMaxVersion string
withCertificates []string
withClientTLSCert string
withClientTLSKey string
withGroups bool
withUserAttributes bool
withLowerUserAttributeKeys bool
withEmptyAnonymousGroupSearch bool
}

func configDefaults() configOptions {
Expand Down Expand Up @@ -88,6 +89,16 @@ func WithLowerUserAttributeKeys() Option {
}
}

// WithEmptyAnonymousGroupSearch removes userDN from anonymous group searches.
func WithEmptyAnonymousGroupSearch() Option {
return func(o interface{}) {
switch v := o.(type) {
case *configOptions:
v.withEmptyAnonymousGroupSearch = true
}
}
}

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