2019-12-06 15:15:54 +07:00
package authentication
import (
2020-12-03 12:23:52 +07:00
"errors"
2021-07-02 06:16:16 +07:00
"fmt"
2019-12-06 15:15:54 +07:00
"testing"
2020-03-19 11:22:46 +07:00
"github.com/go-ldap/ldap/v3"
2020-05-05 02:39:25 +07:00
"github.com/golang/mock/gomock"
2020-01-21 02:34:53 +07:00
"github.com/stretchr/testify/assert"
2019-12-06 15:15:54 +07:00
"github.com/stretchr/testify/require"
2021-07-13 18:12:50 +07:00
"golang.org/x/text/encoding/unicode"
2020-04-05 19:37:21 +07:00
2021-08-11 08:04:35 +07:00
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/utils"
2019-12-06 15:15:54 +07:00
)
func TestShouldCreateRawConnectionWhenSchemeIsLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2019-12-06 15:15:54 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
2022-05-02 08:51:38 +07:00
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
2021-01-04 17:28:55 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2019-12-06 15:15:54 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2019-12-06 15:15:54 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2019-12-06 15:15:54 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind )
2022-05-02 08:51:38 +07:00
_ , err := ldapClient . connect ( )
2019-12-06 15:15:54 +07:00
require . NoError ( t , err )
}
func TestShouldCreateTLSConnectionWhenSchemeIsLDAPS ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2019-12-06 15:15:54 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
2022-05-02 08:51:38 +07:00
URL : "ldaps://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
2021-01-04 17:28:55 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2019-12-06 15:15:54 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldaps://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2019-12-06 15:15:54 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2019-12-06 15:15:54 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind )
2022-05-02 08:51:38 +07:00
_ , err := ldapClient . connect ( )
2019-12-06 15:15:54 +07:00
require . NoError ( t , err )
}
2020-01-21 02:34:53 +07:00
2020-03-31 05:36:04 +07:00
func TestEscapeSpecialCharsFromUserInput ( t * testing . T ) {
2022-01-31 12:25:15 +07:00
// No escape.
2022-05-02 08:51:38 +07:00
assert . Equal ( t , "xyz" , ldapEscape ( "xyz" ) )
2020-01-21 02:34:53 +07:00
2022-01-31 12:25:15 +07:00
// Escape.
2022-05-02 08:51:38 +07:00
assert . Equal ( t , "test\\,abc" , ldapEscape ( "test,abc" ) )
assert . Equal ( t , "test\\5cabc" , ldapEscape ( "test\\abc" ) )
assert . Equal ( t , "test\\2aabc" , ldapEscape ( "test*abc" ) )
assert . Equal ( t , "test \\28abc\\29" , ldapEscape ( "test (abc)" ) )
assert . Equal ( t , "test\\#abc" , ldapEscape ( "test#abc" ) )
assert . Equal ( t , "test\\+abc" , ldapEscape ( "test+abc" ) )
assert . Equal ( t , "test\\<abc" , ldapEscape ( "test<abc" ) )
assert . Equal ( t , "test\\>abc" , ldapEscape ( "test>abc" ) )
assert . Equal ( t , "test\\;abc" , ldapEscape ( "test;abc" ) )
assert . Equal ( t , "test\\\"abc" , ldapEscape ( "test\"abc" ) )
assert . Equal ( t , "test\\=abc" , ldapEscape ( "test=abc" ) )
assert . Equal ( t , "test\\,\\5c\\28abc\\29" , ldapEscape ( "test,\\(abc)" ) )
2020-03-31 05:36:04 +07:00
}
func TestEscapeSpecialCharsInGroupsFilter ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2020-01-21 02:34:53 +07:00
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
2021-01-04 17:28:55 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldaps://127.0.0.1:389" ,
GroupsFilter : "(|(member={dn})(uid={username})(uid={input}))" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-03-31 05:36:04 +07:00
profile := ldapUserProfile {
2020-06-19 17:50:21 +07:00
DN : "cn=john (external),dc=example,dc=com" ,
Username : "john" ,
DisplayName : "John Doe" ,
Emails : [ ] string { "john.doe@authelia.com" } ,
2020-03-31 05:36:04 +07:00
}
2021-01-04 17:28:55 +07:00
filter , _ := ldapClient . resolveGroupsFilter ( "john" , & profile )
2020-03-31 05:36:04 +07:00
assert . Equal ( t , "(|(member=cn=john \\28external\\29,dc=example,dc=com)(uid=john)(uid=john))" , filter )
2021-01-04 17:28:55 +07:00
filter , _ = ldapClient . resolveGroupsFilter ( "john#=(abc,def)" , & profile )
2020-03-31 05:36:04 +07:00
assert . Equal ( t , "(|(member=cn=john \\28external\\29,dc=example,dc=com)(uid=john)(uid=john\\#\\=\\28abc\\,def\\29))" , filter )
2020-01-21 02:34:53 +07:00
}
2021-07-02 06:16:16 +07:00
type ExtendedSearchRequestMatcher struct {
filter string
baseDN string
scope int
derefAliases int
typesOnly bool
attributes [ ] string
}
func NewExtendedSearchRequestMatcher ( filter , base string , scope , derefAliases int , typesOnly bool , attributes [ ] string ) * ExtendedSearchRequestMatcher {
return & ExtendedSearchRequestMatcher { filter , base , scope , derefAliases , typesOnly , attributes }
}
func ( e * ExtendedSearchRequestMatcher ) Matches ( x interface { } ) bool {
sr := x . ( * ldap . SearchRequest )
if e . filter != sr . Filter || e . baseDN != sr . BaseDN || e . scope != sr . Scope || e . derefAliases != sr . DerefAliases ||
e . typesOnly != sr . TypesOnly || utils . IsStringSlicesDifferent ( e . attributes , sr . Attributes ) {
return false
}
return true
}
func ( e * ExtendedSearchRequestMatcher ) String ( ) string {
return fmt . Sprintf ( "baseDN: %s, filter %s" , e . baseDN , e . filter )
}
func TestShouldCheckLDAPServerExtensions ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-07-02 06:16:16 +07:00
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-07-02 06:16:16 +07:00
nil ,
mockFactory )
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-02 06:16:16 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2021-07-02 06:16:16 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2021-07-02 06:16:16 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
2021-07-02 06:16:16 +07:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
2022-05-10 11:38:36 +07:00
Values : [ ] string { ldapOIDExtensionPwdModifyExOp , ldapOIDExtensionTLS } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connClose := mockClient . EXPECT ( ) . Close ( )
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
err := ldapClient . StartupCheck ( )
assert . NoError ( t , err )
assert . True ( t , ldapClient . features . Extensions . PwdModifyExOp )
assert . True ( t , ldapClient . features . Extensions . TLS )
assert . False ( t , ldapClient . features . ControlTypes . MsftPwdPolHints )
assert . False ( t , ldapClient . features . ControlTypes . MsftPwdPolHintsDeprecated )
}
func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntry ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp , ldapOIDExtensionTLS } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
{ } ,
} ,
} , nil )
connClose := mockClient . EXPECT ( ) . Close ( )
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
err := ldapClient . StartupCheck ( )
assert . NoError ( t , err )
assert . False ( t , ldapClient . features . Extensions . PwdModifyExOp )
assert . False ( t , ldapClient . features . Extensions . TLS )
assert . False ( t , ldapClient . features . ControlTypes . MsftPwdPolHints )
assert . False ( t , ldapClient . features . ControlTypes . MsftPwdPolHintsDeprecated )
}
func TestShouldCheckLDAPServerControlTypes ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
2021-07-02 06:16:16 +07:00
} ,
} ,
} ,
} ,
} , nil )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2021-11-23 16:45:38 +07:00
err := ldapClient . StartupCheck ( )
2021-07-02 06:16:16 +07:00
assert . NoError ( t , err )
2022-05-10 11:38:36 +07:00
assert . False ( t , ldapClient . features . Extensions . PwdModifyExOp )
assert . False ( t , ldapClient . features . Extensions . TLS )
assert . True ( t , ldapClient . features . ControlTypes . MsftPwdPolHints )
assert . True ( t , ldapClient . features . ControlTypes . MsftPwdPolHintsDeprecated )
2021-07-02 06:16:16 +07:00
}
2022-05-10 11:38:36 +07:00
func TestShouldNotEnablePasswdModifyExtensionOrControlTypes ( t * testing . T ) {
2021-07-02 06:16:16 +07:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-07-02 06:16:16 +07:00
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-07-02 06:16:16 +07:00
nil ,
mockFactory )
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-02 06:16:16 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2021-07-02 06:16:16 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2021-07-02 06:16:16 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
2021-07-02 06:16:16 +07:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
2022-05-10 11:38:36 +07:00
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
2021-07-02 06:16:16 +07:00
} ,
} ,
} ,
} , nil )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2021-11-23 16:45:38 +07:00
err := ldapClient . StartupCheck ( )
2021-07-02 06:16:16 +07:00
assert . NoError ( t , err )
2022-05-10 11:38:36 +07:00
assert . False ( t , ldapClient . features . Extensions . PwdModifyExOp )
assert . False ( t , ldapClient . features . Extensions . TLS )
assert . False ( t , ldapClient . features . ControlTypes . MsftPwdPolHints )
assert . False ( t , ldapClient . features . ControlTypes . MsftPwdPolHintsDeprecated )
2021-07-02 06:16:16 +07:00
}
func TestShouldReturnCheckServerConnectError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-07-02 06:16:16 +07:00
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-07-02 06:16:16 +07:00
nil ,
mockFactory )
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , errors . New ( "could not connect" ) )
2021-07-02 06:16:16 +07:00
2021-11-23 16:45:38 +07:00
err := ldapClient . StartupCheck ( )
2022-05-02 08:51:38 +07:00
assert . EqualError ( t , err , "dial failed with error: could not connect" )
2021-07-02 06:16:16 +07:00
2022-05-10 11:38:36 +07:00
assert . False ( t , ldapClient . features . Extensions . PwdModifyExOp )
2021-07-02 06:16:16 +07:00
}
func TestShouldReturnCheckServerSearchError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-07-02 06:16:16 +07:00
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-07-02 06:16:16 +07:00
nil ,
mockFactory )
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-02 06:16:16 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2021-07-02 06:16:16 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2021-07-02 06:16:16 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
2021-07-02 06:16:16 +07:00
Return ( nil , errors . New ( "could not perform the search" ) )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2021-11-23 16:45:38 +07:00
err := ldapClient . StartupCheck ( )
2021-07-02 06:16:16 +07:00
assert . EqualError ( t , err , "could not perform the search" )
2022-05-10 11:38:36 +07:00
assert . False ( t , ldapClient . features . Extensions . PwdModifyExOp )
2021-07-02 06:16:16 +07:00
}
2020-01-21 02:34:53 +07:00
type SearchRequestMatcher struct {
expected string
}
func NewSearchRequestMatcher ( expected string ) * SearchRequestMatcher {
return & SearchRequestMatcher { expected }
}
func ( srm * SearchRequestMatcher ) Matches ( x interface { } ) bool {
sr := x . ( * ldap . SearchRequest )
return sr . Filter == srm . expected
}
func ( srm * SearchRequestMatcher ) String ( ) string {
return ""
}
func TestShouldEscapeUserInput ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-01-21 02:34:53 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 11:38:36 +07:00
PermitReferrals : true ,
2021-01-04 17:28:55 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-01-21 02:34:53 +07:00
2022-05-10 11:38:36 +07:00
mockClient . EXPECT ( ) .
2020-03-15 14:10:25 +07:00
// Here we ensure that the input has been correctly escaped.
2020-03-31 05:36:04 +07:00
Search ( NewSearchRequestMatcher ( "(|(uid=john\\=abc)(mail=john\\=abc))" ) ) .
2020-03-15 14:10:25 +07:00
Return ( & ldap . SearchResult { } , nil )
2020-01-21 02:34:53 +07:00
2022-05-10 11:38:36 +07:00
_ , err := ldapClient . getUserProfile ( mockClient , "john=abc" )
2020-12-03 12:23:52 +07:00
require . Error ( t , err )
assert . EqualError ( t , err , "user not found" )
2020-03-15 14:10:25 +07:00
}
func TestShouldCombineUsernameFilterAndUsersFilter ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-03-15 14:10:25 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
UsernameAttribute : "uid" ,
UsersFilter : "(&({username_attribute}={input})(&(objectCategory=person)(objectClass=user)))" ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2022-05-10 11:38:36 +07:00
PermitReferrals : true ,
2021-01-04 17:28:55 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-01-21 02:34:53 +07:00
2021-08-05 11:17:07 +07:00
assert . True ( t , ldapClient . usersFilterReplacementInput )
2022-05-10 11:38:36 +07:00
mockClient . EXPECT ( ) .
2020-03-15 14:10:25 +07:00
Search ( NewSearchRequestMatcher ( "(&(uid=john)(&(objectCategory=person)(objectClass=user)))" ) ) .
2020-01-21 02:34:53 +07:00
Return ( & ldap . SearchResult { } , nil )
2022-05-10 11:38:36 +07:00
_ , err := ldapClient . getUserProfile ( mockClient , "john" )
2020-12-03 12:23:52 +07:00
require . Error ( t , err )
assert . EqualError ( t , err , "user not found" )
2020-01-21 02:34:53 +07:00
}
2020-02-28 05:21:07 +07:00
func createSearchResultWithAttributes ( attributes ... * ldap . EntryAttribute ) * ldap . SearchResult {
return & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 08:05:17 +07:00
{ Attributes : attributes } ,
2020-02-28 05:21:07 +07:00
} ,
}
}
func createSearchResultWithAttributeValues ( values ... string ) * ldap . SearchResult {
return createSearchResultWithAttributes ( & ldap . EntryAttribute {
Values : values ,
} )
}
func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-02-28 05:21:07 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 11:38:36 +07:00
PermitReferrals : true ,
2021-01-04 17:28:55 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-02-28 05:21:07 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2020-02-28 05:21:07 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2020-02-28 05:21:07 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2020-03-15 14:10:25 +07:00
Return ( nil )
2020-02-28 05:21:07 +07:00
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-02-28 05:21:07 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
2020-02-28 05:21:07 +07:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributes ( ) , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfile := mockClient . EXPECT ( ) .
2020-02-28 05:21:07 +07:00
Search ( gomock . Any ( ) ) .
2020-03-15 14:10:25 +07:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
2020-06-19 17:50:21 +07:00
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2020-06-19 17:50:21 +07:00
Values : [ ] string { "John Doe" } ,
} ,
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
2020-02-28 05:21:07 +07:00
details , err := ldapClient . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
2020-06-19 17:50:21 +07:00
assert . Equal ( t , details . DisplayName , "John Doe" )
2020-03-15 14:10:25 +07:00
assert . Equal ( t , details . Username , "john" )
2020-02-28 05:21:07 +07:00
}
func TestShouldNotCrashWhenEmailsAreNotRetrievedFromLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-02-28 05:21:07 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-02-28 05:21:07 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2020-02-28 05:21:07 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2020-02-28 05:21:07 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2020-03-15 14:10:25 +07:00
Return ( nil )
2020-02-28 05:21:07 +07:00
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-02-28 05:21:07 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
2020-02-28 05:21:07 +07:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributeValues ( "group1" , "group2" ) , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfile := mockClient . EXPECT ( ) .
2020-02-28 05:21:07 +07:00
Search ( gomock . Any ( ) ) .
2020-03-15 14:10:25 +07:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
2020-02-28 05:21:07 +07:00
details , err := ldapClient . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { } )
2020-03-15 14:10:25 +07:00
assert . Equal ( t , details . Username , "john" )
}
func TestShouldReturnUsernameFromLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-03-15 14:10:25 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-03-15 14:10:25 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2020-03-15 14:10:25 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2020-03-15 14:10:25 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-03-15 14:10:25 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
2020-03-15 14:10:25 +07:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributeValues ( "group1" , "group2" ) , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfile := mockClient . EXPECT ( ) .
2020-03-15 14:10:25 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
2020-06-19 17:50:21 +07:00
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2020-06-19 17:50:21 +07:00
Values : [ ] string { "John Doe" } ,
} ,
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
2020-04-09 08:05:17 +07:00
{
2020-03-15 14:10:25 +07:00
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
2020-03-15 14:10:25 +07:00
details , err := ldapClient . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
2020-06-19 17:50:21 +07:00
assert . Equal ( t , details . DisplayName , "John Doe" )
2020-03-15 14:10:25 +07:00
assert . Equal ( t , details . Username , "John" )
2020-02-28 05:21:07 +07:00
}
2020-12-03 12:23:52 +07:00
2022-05-10 11:38:36 +07:00
func TestShouldReturnUsernameFromLDAPWithReferrals ( t * testing . T ) {
2021-01-04 17:28:55 +07:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
2021-01-04 17:28:55 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 11:38:36 +07:00
PermitReferrals : true ,
2021-01-04 17:28:55 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2022-05-10 11:38:36 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2021-07-06 16:13:17 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributeValues ( "group1" , "group2" ) , nil )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
2021-07-13 18:12:50 +07:00
Return ( & ldap . SearchResult {
2022-05-10 11:38:36 +07:00
Entries : [ ] * ldap . Entry { } ,
Referrals : [ ] string { "ldap://192.168.2.1" } ,
2021-07-13 18:12:50 +07:00
} , nil )
2021-07-06 16:13:17 +07:00
2022-05-10 11:38:36 +07:00
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.2.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
connBindReferral := mockClientReferral . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfileReferral := mockClientReferral . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2021-07-13 18:12:50 +07:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
2021-01-04 17:28:55 +07:00
} ,
} ,
} ,
2021-07-13 18:12:50 +07:00
} ,
} , nil )
2022-05-10 11:38:36 +07:00
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , searchGroups , connClose )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
details , err := ldapClient . GetDetails ( "john" )
2021-07-13 18:12:50 +07:00
require . NoError ( t , err )
2022-05-10 11:38:36 +07:00
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "John" )
2021-07-13 18:12:50 +07:00
}
2022-05-10 11:38:36 +07:00
func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndResult ( t * testing . T ) {
2021-07-13 18:12:50 +07:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
mockClientReferralAlt := NewMockLDAPClient ( ctrl )
2021-07-13 18:12:50 +07:00
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
2022-05-10 11:38:36 +07:00
UsernameAttribute : "uid" ,
2021-07-13 18:12:50 +07:00
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
2022-05-10 11:38:36 +07:00
UsersFilter : "uid={input}" ,
2021-07-13 18:12:50 +07:00
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 11:38:36 +07:00
PermitReferrals : true ,
2021-07-13 18:12:50 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-07-13 18:12:50 +07:00
nil ,
mockFactory )
2022-05-10 11:38:36 +07:00
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2021-01-04 17:28:55 +07:00
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributeValues ( "group1" , "group2" ) , nil )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry { } ,
Referrals : [ ] string { "ldap://192.168.2.1" } ,
} , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.2.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
connBindReferral := mockClientReferral . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
searchProfileReferral := mockClientReferral . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
2021-07-13 18:12:50 +07:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
2022-05-10 11:38:36 +07:00
DN : "uid=test,dc=example,dc=com" ,
2021-07-13 18:12:50 +07:00
Attributes : [ ] * ldap . EntryAttribute {
{
2022-05-10 11:38:36 +07:00
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
2021-07-13 18:12:50 +07:00
} ,
} ,
} ,
} ,
} , nil )
2022-05-10 11:38:36 +07:00
dialURLReferralAlt := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferralAlt , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
connBindReferralAlt := mockClientReferralAlt . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connCloseReferralAlt := mockClientReferralAlt . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfileReferralAlt := mockClientReferralAlt . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
2022-05-10 11:38:36 +07:00
DN : "uid=test,dc=example,dc=com" ,
2021-07-13 18:12:50 +07:00
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2021-07-13 18:12:50 +07:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
2022-05-10 11:38:36 +07:00
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , dialURLReferralAlt , connBindReferralAlt , searchProfileReferralAlt , connCloseReferralAlt , searchGroups , connClose )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
details , err := ldapClient . GetDetails ( "john" )
2021-07-13 18:12:50 +07:00
require . NoError ( t , err )
2022-05-10 11:38:36 +07:00
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "John" )
2021-07-13 18:12:50 +07:00
}
2022-05-10 11:38:36 +07:00
func TestShouldReturnUsernameFromLDAPWithReferralsErr ( t * testing . T ) {
2021-07-13 18:12:50 +07:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
2021-07-13 18:12:50 +07:00
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
2022-05-10 11:38:36 +07:00
User : "cn=admin,dc=example,dc=com" ,
2021-07-13 18:12:50 +07:00
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 11:38:36 +07:00
PermitReferrals : true ,
2021-07-13 18:12:50 +07:00
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-07-13 18:12:50 +07:00
nil ,
mockFactory )
2022-05-10 11:38:36 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2021-07-13 18:12:50 +07:00
Return ( nil )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributeValues ( "group1" , "group2" ) , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult { } , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
connBindReferral := mockClientReferral . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2021-07-13 18:12:50 +07:00
Return ( nil )
2022-05-10 11:38:36 +07:00
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfileReferral := mockClientReferral . EXPECT ( ) .
2021-07-13 18:12:50 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
2022-05-10 11:38:36 +07:00
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , searchGroups , connClose )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
details , err := ldapClient . GetDetails ( "john" )
2021-07-06 16:13:17 +07:00
require . NoError ( t , err )
2021-01-04 17:28:55 +07:00
2022-05-10 11:38:36 +07:00
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "John" )
2021-01-04 17:28:55 +07:00
}
2022-05-10 11:38:36 +07:00
func TestShouldNotUpdateUserPasswordConnect ( t * testing . T ) {
2021-01-04 17:28:55 +07:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
} ,
false ,
nil ,
mockFactory )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( nil , errors . New ( "tcp timeout" ) )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: dial failed with error: tcp timeout" )
}
func TestShouldNotUpdateUserPasswordGetDetails ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
} ,
false ,
nil ,
mockFactory )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( nil , & ldap . Error { ResultCode : ldap . LDAPResultProtocolError , Err : errors . New ( "permission error" ) } )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: cannot find user DN of user 'john'. Cause: LDAP Result Code 2 \"Protocol Error\": permission error" )
}
func TestShouldUpdateUserPassword ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
nil ,
)
modifyRequest . Replace ( ldapAttributeUserPassword , [ ] string { "password" } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
modify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , modify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordMSAD ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
pwdEncoded , _ := utf16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
modifyRequest . Replace ( ldapAttributeUnicodePwd , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
modify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , modify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordMSADWithReferrals ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
pwdEncoded , _ := utf16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
modifyRequest . Replace ( ldapAttributeUnicodePwd , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
modify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
connBindReferral := mockClientReferral . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
modifyReferral := mockClientReferral . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , modify , dialURLReferral , connBindReferral , modifyReferral , connCloseReferral , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralConnectErr ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
pwdEncoded , _ := utf16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
modifyRequest . Replace ( ldapAttributeUnicodePwd , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
modify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( nil , errors . New ( "tcp timeout" ) )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , modify , dialURLReferral , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: error occurred connecting to referred LDAP server 'ldap://192.168.0.1': dial failed with error: tcp timeout. Original Error: LDAP Result Code 10 \"Referral\": error occurred" )
}
func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralModifyErr ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
pwdEncoded , _ := utf16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
modifyRequest . Replace ( ldapAttributeUnicodePwd , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
modify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
connBindReferral := mockClientReferral . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
modifyReferral := mockClientReferral . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( & ldap . Error {
ResultCode : ldap . LDAPResultBusy ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , modify , dialURLReferral , connBindReferral , modifyReferral , connCloseReferral , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: error occurred performing modify on referred LDAP server 'ldap://192.168.0.1': LDAP Result Code 51 \"Busy\": error occurred. Original Error: LDAP Result Code 10 \"Referral\": error occurred" )
}
func TestShouldUpdateUserPasswordMSADWithoutReferrals ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
pwdEncoded , _ := utf16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
modifyRequest . Replace ( ldapAttributeUnicodePwd , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
modify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , modify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: LDAP Result Code 10 \"Referral\": error occurred" )
}
func TestShouldUpdateUserPasswordPasswdModifyExtension ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
pwdModifyRequest := ldap . NewPasswordModifyRequest (
"uid=test,dc=example,dc=com" ,
"" ,
"password" ,
)
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( nil , nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferrals ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
false ,
nil ,
mockFactory )
pwdModifyRequest := ldap . NewPasswordModifyRequest (
"uid=test,dc=example,dc=com" ,
"" ,
"password" ,
)
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( & ldap . PasswordModifyResult {
Referral : "ldap://192.168.0.1" ,
} , & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
connBindReferral := mockClientReferral . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
passwdModifyReferral := mockClientReferral . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( & ldap . PasswordModifyResult { } , nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , dialURLReferral , connBindReferral , passwdModifyReferral , connCloseReferral , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordPasswdModifyExtensionWithoutReferrals ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
} ,
false ,
nil ,
mockFactory )
pwdModifyRequest := ldap . NewPasswordModifyRequest (
"uid=test,dc=example,dc=com" ,
"" ,
"password" ,
)
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( & ldap . PasswordModifyResult {
Referral : "ldap://192.168.0.1" ,
} , & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: LDAP Result Code 10 \"Referral\": error occurred" )
}
func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralConnectErr ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
false ,
nil ,
mockFactory )
pwdModifyRequest := ldap . NewPasswordModifyRequest (
"uid=test,dc=example,dc=com" ,
"" ,
"password" ,
)
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( & ldap . PasswordModifyResult {
Referral : "ldap://192.168.0.1" ,
} , & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( nil , errors . New ( "tcp timeout" ) )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , dialURLReferral , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: error occurred connecting to referred LDAP server 'ldap://192.168.0.1': dial failed with error: tcp timeout. Original Error: LDAP Result Code 10 \"Referral\": error occurred" )
}
func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralPasswordModifyErr ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
false ,
nil ,
mockFactory )
pwdModifyRequest := ldap . NewPasswordModifyRequest (
"uid=test,dc=example,dc=com" ,
"" ,
"password" ,
)
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { ldapOIDExtensionPwdModifyExOp } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( & ldap . PasswordModifyResult {
Referral : "ldap://192.168.0.1" ,
} , & ldap . Error {
ResultCode : ldap . LDAPResultReferral ,
Err : errors . New ( "error occurred" ) ,
Packet : & testBERPacketReferral ,
} )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferral , nil )
connBindReferral := mockClientReferral . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
passwdModifyReferral := mockClientReferral . EXPECT ( ) .
PasswordModify ( pwdModifyRequest ) .
Return ( nil , & ldap . Error {
ResultCode : ldap . LDAPResultBusy ,
Err : errors . New ( "too busy" ) ,
Packet : & testBERPacketReferral ,
} )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , dialURLReferral , connBindReferral , passwdModifyReferral , connCloseReferral , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . EqualError ( t , err , "unable to update password. Cause: error occurred performing password modify on referred LDAP server 'ldap://192.168.0.1': LDAP Result Code 51 \"Busy\": too busy. Original Error: LDAP Result Code 10 \"Referral\": error occurred" )
}
func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHints ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "sAMAccountName" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "cn={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
utf16 := unicode . UTF16 ( unicode . LittleEndian , unicode . IgnoreBOM )
pwdEncoded , _ := utf16 . NewEncoder ( ) . String ( "\"password\"" )
modifyRequest := ldap . NewModifyRequest (
"cn=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
modifyRequest . Replace ( "unicodePwd" , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHints , ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "cn=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "sAMAccountName" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
assert . NoError ( t , err )
}
func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHintsDeprecated ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "sAMAccountName" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "cn={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
utf16 := unicode . UTF16 ( unicode . LittleEndian , unicode . IgnoreBOM )
pwdEncoded , _ := utf16 . NewEncoder ( ) . String ( "\"password\"" )
modifyRequest := ldap . NewModifyRequest (
"cn=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHintsDeprecated } } ,
)
modifyRequest . Replace ( "unicodePwd" , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { ldapOIDControlMsftServerPolicyHintsDeprecated } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "cn=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "sAMAccountName" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordActiveDirectory ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "activedirectory" ,
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "sAMAccountName" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "cn={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
utf16 := unicode . UTF16 ( unicode . LittleEndian , unicode . IgnoreBOM )
pwdEncoded , _ := utf16 . NewEncoder ( ) . String ( "\"password\"" )
modifyRequest := ldap . NewModifyRequest (
"cn=test,dc=example,dc=com" ,
nil ,
)
modifyRequest . Replace ( "unicodePwd" , [ ] string { pwdEncoded } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "cn=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "sAMAccountName" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordBasic ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
Implementation : "custom" ,
URL : "ldap://127.0.0.1:389" ,
User : "uid=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
nil ,
)
modifyRequest . Replace ( "userPassword" , [ ] string { "password" } )
dialURLOIDs := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBindOIDs := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "uid=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connCloseOIDs := mockClient . EXPECT ( ) . Close ( )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "uid=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
passwdModify := mockClient . EXPECT ( ) .
Modify ( modifyRequest ) .
Return ( nil )
gomock . InOrder ( dialURLOIDs , connBindOIDs , searchOIDs , connCloseOIDs , dialURL , connBind , searchProfile , passwdModify , connClose )
err := ldapClient . StartupCheck ( )
require . NoError ( t , err )
err = ldapClient . UpdatePassword ( "john" , "password" )
require . NoError ( t , err )
}
func TestShouldReturnErrorWhenMultipleUsernameAttributes ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
bind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
search := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" , "Jacob" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
client , err := ldapClient . connect ( )
assert . NoError ( t , err )
profile , err := ldapClient . getUserProfile ( client , "john" )
assert . Nil ( t , profile )
assert . EqualError ( t , err , "user 'john' has 2 values for for attribute 'uid' but the attribute must be a single value attribute" )
}
func TestShouldReturnErrorWhenZeroUsernameAttributes ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
bind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
search := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
client , err := ldapClient . connect ( )
assert . NoError ( t , err )
profile , err := ldapClient . getUserProfile ( client , "john" )
assert . Nil ( t , profile )
assert . EqualError ( t , err , "user 'john' must have value for attribute 'uid'" )
}
func TestShouldReturnErrorWhenUsernameAttributeNotReturned ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
bind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
search := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
client , err := ldapClient . connect ( )
assert . NoError ( t , err )
profile , err := ldapClient . getUserProfile ( client , "john" )
assert . Nil ( t , profile )
assert . EqualError ( t , err , "user 'john' must have value for attribute 'uid'" )
}
func TestShouldReturnErrorWhenMultipleUsersFound ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "(|(uid={input})(uid=*))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
bind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
search := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
{
DN : "uid=sam,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "sam" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
client , err := ldapClient . connect ( )
assert . NoError ( t , err )
profile , err := ldapClient . getUserProfile ( client , "john" )
assert . Nil ( t , profile )
assert . EqualError ( t , err , "there were 2 users found when searching for 'john' but there should only be 1" )
}
func TestShouldReturnErrorWhenNoDN ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "(|(uid={input})(uid=*))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
bind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
search := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
client , err := ldapClient . connect ( )
assert . NoError ( t , err )
profile , err := ldapClient . getUserProfile ( client , "john" )
assert . Nil ( t , profile )
assert . EqualError ( t , err , "user 'john' must have a distinguished name but the result returned an empty distinguished name" )
}
func TestShouldCheckValidUserPassword ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-01-04 17:28:55 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
gomock . InOrder (
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
2022-05-10 11:38:36 +07:00
mockClient . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2021-01-04 17:28:55 +07:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil ) ,
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
Bind ( gomock . Eq ( "uid=test,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
2022-05-10 11:38:36 +07:00
mockClient . EXPECT ( ) . Close ( ) . Times ( 2 ) ,
2021-01-04 17:28:55 +07:00
)
valid , err := ldapClient . CheckUserPassword ( "john" , "password" )
assert . True ( t , valid )
require . NoError ( t , err )
}
2022-05-10 11:38:36 +07:00
func TestShouldNotCheckValidUserPasswordWithConnectError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
ldapClient := newLDAPUserProvider (
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
DisplayNameAttribute : "displayName" ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
bind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( & ldap . Error { ResultCode : ldap . LDAPResultInvalidCredentials , Err : errors . New ( "invalid username or password" ) } )
gomock . InOrder ( dialURL , bind , mockClient . EXPECT ( ) . Close ( ) )
valid , err := ldapClient . CheckUserPassword ( "john" , "password" )
assert . False ( t , valid )
assert . EqualError ( t , err , "bind failed with error: LDAP Result Code 49 \"Invalid Credentials\": invalid username or password" )
}
2021-01-04 17:28:55 +07:00
func TestShouldCheckInvalidUserPassword ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-01-04 17:28:55 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
gomock . InOrder (
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
2022-05-10 11:38:36 +07:00
mockClient . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2021-01-04 17:28:55 +07:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
} ,
} ,
} ,
} ,
} , nil ) ,
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
Bind ( gomock . Eq ( "uid=test,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2021-12-02 17:28:16 +07:00
Return ( errors . New ( "invalid username or password" ) ) ,
2022-05-10 11:38:36 +07:00
mockClient . EXPECT ( ) . Close ( ) . Times ( 2 ) ,
2021-01-04 17:28:55 +07:00
)
valid , err := ldapClient . CheckUserPassword ( "john" , "password" )
assert . False ( t , valid )
2022-05-02 08:51:38 +07:00
require . EqualError ( t , err , "authentication failed. Cause: bind failed with error: invalid username or password" )
2021-01-04 17:28:55 +07:00
}
2020-12-03 12:23:52 +07:00
func TestShouldCallStartTLSWhenEnabled ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-12-03 12:23:52 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-12-03 12:23:52 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2020-12-03 12:23:52 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connStartTLS := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
StartTLS ( ldapClient . tlsConfig )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-12-03 12:23:52 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributes ( ) , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfile := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2020-12-03 12:23:52 +07:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connStartTLS , connBind , searchProfile , searchGroups , connClose )
2020-12-03 12:23:52 +07:00
details , err := ldapClient . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "john" )
}
2021-01-04 17:28:55 +07:00
func TestShouldParseDynamicConfiguration ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
2021-01-04 17:28:55 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-04-16 08:44:37 +07:00
UsersFilter : "(&(|({username_attribute}={input})({mail_attribute}={input})({display_name_attribute}={input}))(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!pwdLastSet=0))" ,
GroupsFilter : "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))" ,
2021-01-04 17:28:55 +07:00
AdditionalUsersDN : "ou=users" ,
AdditionalGroupsDN : "ou=groups" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2021-08-05 11:17:07 +07:00
assert . True ( t , ldapClient . groupsFilterReplacementInput )
assert . True ( t , ldapClient . groupsFilterReplacementUsername )
assert . True ( t , ldapClient . groupsFilterReplacementDN )
assert . True ( t , ldapClient . usersFilterReplacementInput )
2022-05-02 08:51:38 +07:00
assert . Equal ( t , "(&(|(uid={input})(mail={input})(displayName={input}))(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!pwdLastSet=0))" , ldapClient . config . UsersFilter )
assert . Equal ( t , "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))" , ldapClient . config . GroupsFilter )
2021-04-12 08:10:50 +07:00
assert . Equal ( t , "ou=users,dc=example,dc=com" , ldapClient . usersBaseDN )
assert . Equal ( t , "ou=groups,dc=example,dc=com" , ldapClient . groupsBaseDN )
2021-01-04 17:28:55 +07:00
}
2020-12-03 12:23:52 +07:00
func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-12-03 12:23:52 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldap://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
TLS : & schema . TLSConfig {
SkipVerify : true ,
} ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-12-03 12:23:52 +07:00
2021-08-05 11:17:07 +07:00
assert . False ( t , ldapClient . groupsFilterReplacementInput )
assert . False ( t , ldapClient . groupsFilterReplacementUsername )
assert . False ( t , ldapClient . groupsFilterReplacementDN )
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2020-12-03 12:23:52 +07:00
2022-05-10 11:38:36 +07:00
connBind := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 11:38:36 +07:00
connStartTLS := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
StartTLS ( ldapClient . tlsConfig )
2022-05-10 11:38:36 +07:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-12-03 12:23:52 +07:00
2022-05-10 11:38:36 +07:00
searchGroups := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributes ( ) , nil )
2021-07-13 18:12:50 +07:00
2022-05-10 11:38:36 +07:00
searchProfile := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 11:17:07 +07:00
Name : "displayName" ,
2020-12-03 12:23:52 +07:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 18:12:50 +07:00
gomock . InOrder ( dialURL , connStartTLS , connBind , searchProfile , searchGroups , connClose )
2020-12-03 12:23:52 +07:00
details , err := ldapClient . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "john" )
}
func TestShouldReturnLDAPSAlreadySecuredWhenStartTLSAttempted ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 11:38:36 +07:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-12-03 12:23:52 +07:00
2021-07-02 06:16:16 +07:00
ldapClient := newLDAPUserProvider (
2021-01-04 17:28:55 +07:00
schema . LDAPAuthenticationBackendConfiguration {
URL : "ldaps://127.0.0.1:389" ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
UsernameAttribute : "uid" ,
MailAttribute : "mail" ,
2021-08-05 11:17:07 +07:00
DisplayNameAttribute : "displayName" ,
2021-01-04 17:28:55 +07:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
TLS : & schema . TLSConfig {
SkipVerify : true ,
} ,
} ,
2021-09-17 16:53:59 +07:00
false ,
2021-01-04 17:28:55 +07:00
nil ,
mockFactory )
2020-12-03 12:23:52 +07:00
2021-07-13 18:12:50 +07:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 17:28:55 +07:00
DialURL ( gomock . Eq ( "ldaps://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 11:38:36 +07:00
Return ( mockClient , nil )
2020-12-03 12:23:52 +07:00
2022-05-10 11:38:36 +07:00
connStartTLS := mockClient . EXPECT ( ) .
2020-12-03 12:23:52 +07:00
StartTLS ( ldapClient . tlsConfig ) .
Return ( errors . New ( "LDAP Result Code 200 \"Network Error\": ldap: already encrypted" ) )
2022-05-10 11:38:36 +07:00
gomock . InOrder ( dialURL , connStartTLS , mockClient . EXPECT ( ) . Close ( ) )
2021-07-13 18:12:50 +07:00
2020-12-03 12:23:52 +07:00
_ , err := ldapClient . GetDetails ( "john" )
2022-05-02 08:51:38 +07:00
assert . EqualError ( t , err , "starttls failed with error: LDAP Result Code 200 \"Network Error\": ldap: already encrypted" )
2020-12-03 12:23:52 +07:00
}