diff --git a/CHANGELOG.md b/CHANGELOG.md index 0559dbc..122e997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Canonical reference for changes, improvements, and bugfixes for cap. ## Next * feat (oidc): add WithVerifier ([PR #141](https://github.com/hashicorp/cap/pull/141)) +* feat (ldap): add an option to enable sAMAccountname logins when upndomain is set ([PR #146](https://github.com/hashicorp/cap/pull/146)) ## 0.7.0 diff --git a/ldap/client.go b/ldap/client.go index 1c131a6..0c1ffd3 100644 --- a/ldap/client.go +++ b/ldap/client.go @@ -719,8 +719,13 @@ func (c *Client) getUserDN(bindDN, username string) (string, error) { } var userDN string if c.conf.UPNDomain != "" { - // Find the distinguished name for the user if userPrincipalName used for login - filter := fmt.Sprintf("(userPrincipalName=%s@%s)", escapeValue(username), c.conf.UPNDomain) + // Find the distinguished name for the user if userPrincipalName used for login, or sAMAccountName if enabled. + var filter string + if c.conf.EnableSamaccountnameLogin { + filter = fmt.Sprintf("(|(userPrincipalName=%s@%s)(sAMAccountName=%s))", escapeValue(username), c.conf.UPNDomain, escapeValue(username)) + } else { + filter = fmt.Sprintf("(userPrincipalName=%s@%s)", escapeValue(username), c.conf.UPNDomain) + } result, err := c.conn.Search(&ldap.SearchRequest{ BaseDN: c.conf.UserDN, Scope: ldap.ScopeWholeSubtree, diff --git a/ldap/client_exported_test.go b/ldap/client_exported_test.go index 7c7983c..d795f52 100644 --- a/ldap/client_exported_test.go +++ b/ldap/client_exported_test.go @@ -458,6 +458,57 @@ func TestClient_Authenticate(t *testing.T) { opts: []ldap.Option{ldap.WithGroups()}, wantGroups: []string{groups[0].DN}, }, + { + name: "success-with-anon-bind-upn-domain-samaccountname", + 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", + EnableSamaccountnameLogin: true, + }, + opts: []ldap.Option{ldap.WithGroups()}, + wantGroups: []string{groups[0].DN}, + }, + { + name: "success-with-anon-bind-upn-domain-empty-userdn-samaccountname", + 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, + EnableSamaccountnameLogin: true, + }, + opts: []ldap.Option{ldap.WithGroups()}, + wantGroups: []string{groups[0].DN}, + }, + { + name: "success-with-anon-bind-upn-domain-empty-userdn-opt-samaccountname", + 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, + EnableSamaccountnameLogin: true, + }, + opts: []ldap.Option{ldap.WithGroups(), ldap.WithEmptyAnonymousGroupSearch()}, + wantGroups: []string{groups[0].DN}, + }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/ldap/config.go b/ldap/config.go index 6340799..8f05d51 100644 --- a/ldap/config.go +++ b/ldap/config.go @@ -230,6 +230,9 @@ type ClientConfig struct { // the pre 1.1.1 Vault behavior. // see: https://www.vaultproject.io/docs/upgrading/upgrade-to-1.1.1 DeprecatedVaultPre111GroupCNBehavior *bool `json:"use_pre111_group_cn_behavior"` + + // EnableSamaccountnameLogin enables login with sAMAccountName in addition to UserPrincipalName when upndomain is set. + EnableSamaccountnameLogin bool `json:"enable_samaccountname_login"` } func (c *ClientConfig) clone() (*ClientConfig, error) {