2019-12-06 08:15:54 +00:00
package authentication
import (
2020-12-03 05:23:52 +00:00
"errors"
2021-07-01 23:16:16 +00:00
"fmt"
2019-12-06 08:15:54 +00:00
"testing"
2022-12-21 10:31:21 +00:00
"time"
2019-12-06 08:15:54 +00:00
2020-03-19 04:22:46 +00:00
"github.com/go-ldap/ldap/v3"
2020-05-04 19:39:25 +00:00
"github.com/golang/mock/gomock"
2020-01-20 19:34:53 +00:00
"github.com/stretchr/testify/assert"
2019-12-06 08:15:54 +00:00
"github.com/stretchr/testify/require"
2021-07-13 11:12:50 +00:00
"golang.org/x/text/encoding/unicode"
2020-04-05 12:37:21 +00:00
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/utils"
2019-12-06 08:15:54 +00:00
)
2023-06-18 04:40:38 +00:00
func TestNewLDAPUserProvider ( t * testing . T ) {
provider := NewLDAPUserProvider ( schema . AuthenticationBackend { LDAP : & schema . LDAPAuthenticationBackend { } } , nil )
assert . NotNil ( t , provider )
}
func TestNewLDAPUserProviderWithFactoryWithoutFactory ( t * testing . T ) {
provider := NewLDAPUserProviderWithFactory ( schema . LDAPAuthenticationBackend { } , false , nil , nil )
assert . NotNil ( t , provider )
assert . IsType ( t , & ProductionLDAPClientFactory { } , provider . factory )
}
2019-12-06 08:15:54 +00:00
func TestShouldCreateRawConnectionWhenSchemeIsLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2019-12-06 08:15:54 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-05-07 06:39:17 +00:00
Address : testLDAPAddress ,
2022-05-02 01:51:38 +00:00
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2019-12-06 08:15:54 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2019-12-06 08:15:54 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2019-12-06 08:15:54 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind )
2022-12-21 10:31:21 +00:00
_ , err := provider . connect ( )
2019-12-06 08:15:54 +00:00
require . NoError ( t , err )
}
func TestShouldCreateTLSConnectionWhenSchemeIsLDAPS ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2019-12-06 08:15:54 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-05-07 06:39:17 +00:00
Address : testLDAPSAddress ,
2022-05-02 01:51:38 +00:00
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2019-12-06 08:15:54 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldaps://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2019-12-06 08:15:54 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2019-12-06 08:15:54 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind )
2022-12-21 10:31:21 +00:00
_ , err := provider . connect ( )
2019-12-06 08:15:54 +00:00
require . NoError ( t , err )
}
2020-01-20 19:34:53 +00:00
2020-03-30 22:36:04 +00:00
func TestEscapeSpecialCharsFromUserInput ( t * testing . T ) {
2022-01-31 05:25:15 +00:00
// No escape.
2022-05-02 01:51:38 +00:00
assert . Equal ( t , "xyz" , ldapEscape ( "xyz" ) )
2020-01-20 19:34:53 +00:00
2022-01-31 05:25:15 +00:00
// Escape.
2022-05-02 01:51:38 +00: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-30 22:36:04 +00:00
}
func TestEscapeSpecialCharsInGroupsFilter ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2020-01-20 19:34:53 +00:00
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
2021-01-04 10:28:55 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-05-07 06:39:17 +00:00
Address : testLDAPSAddress ,
2021-01-04 10:28:55 +00:00
GroupsFilter : "(|(member={dn})(uid={username})(uid={input}))" ,
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-03-30 22:36:04 +00:00
profile := ldapUserProfile {
2020-06-19 10:50:21 +00:00
DN : "cn=john (external),dc=example,dc=com" ,
Username : "john" ,
DisplayName : "John Doe" ,
Emails : [ ] string { "john.doe@authelia.com" } ,
2020-03-30 22:36:04 +00:00
}
2022-12-21 10:31:21 +00:00
filter := provider . resolveGroupsFilter ( "john" , & profile )
2020-03-30 22:36:04 +00:00
assert . Equal ( t , "(|(member=cn=john \\28external\\29,dc=example,dc=com)(uid=john)(uid=john))" , filter )
2022-12-21 10:31:21 +00:00
filter = provider . resolveGroupsFilter ( "john#=(abc,def)" , & profile )
2020-03-30 22:36:04 +00:00
assert . Equal ( t , "(|(member=cn=john \\28external\\29,dc=example,dc=com)(uid=john)(uid=john\\#\\=\\28abc\\,def\\29))" , filter )
2020-01-20 19:34:53 +00:00
}
2023-06-18 04:40:38 +00:00
func TestResolveGroupsFilter ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
testCases := [ ] struct {
name string
have schema . LDAPAuthenticationBackend
input string
profile ldapUserProfile
expected string
} {
{
"ShouldResolveEmptyFilter" ,
schema . LDAPAuthenticationBackend { } ,
"" ,
ldapUserProfile { } ,
"" ,
} ,
{
"ShouldResolveMemberOfRDNFilter" ,
schema . LDAPAuthenticationBackend {
GroupsFilter : "(|{memberof:rdn})" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
GroupName : "cn" ,
MemberOf : "memberOf" ,
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
} ,
} ,
"" ,
ldapUserProfile {
MemberOf : [ ] string { "CN=abc,DC=example,DC=com" , "CN=xyz,DC=example,DC=com" } ,
} ,
"(|(CN=abc)(CN=xyz))" ,
} ,
{
"ShouldResolveMemberOfDNFilter" ,
schema . LDAPAuthenticationBackend {
GroupsFilter : "(|{memberof:dn})" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
GroupName : "cn" ,
MemberOf : "memberOf" ,
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
} ,
} ,
"" ,
ldapUserProfile {
MemberOf : [ ] string { "CN=abc,DC=example,DC=com" , "CN=xyz,DC=example,DC=com" } ,
} ,
"(|(distinguishedName=CN=abc,DC=example,DC=com)(distinguishedName=CN=xyz,DC=example,DC=com))" ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
provider := NewLDAPUserProviderWithFactory (
tc . have ,
false ,
nil ,
mockFactory )
assert . Equal ( t , tc . expected , provider . resolveGroupsFilter ( "" , & tc . profile ) )
} )
}
}
2021-07-01 23:16:16 +00: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 }
}
2022-10-05 05:05:23 +00:00
func ( e * ExtendedSearchRequestMatcher ) Matches ( x any ) bool {
2021-07-01 23:16:16 +00:00
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 )
}
2023-06-18 04:40:38 +00:00
func TestShouldCheckLDAPEpochFilters ( t * testing . T ) {
type have struct {
users string
attr schema . LDAPAuthenticationAttributes
}
type expected struct {
dtgeneralized bool
dtmsftnt bool
dtunix bool
}
testCases := [ ] struct {
name string
have have
expected expected
} {
{
"ShouldNotEnableAny" ,
have { } ,
expected { } ,
} ,
{
"ShouldNotEnableMSFTNT" ,
have {
users : "(abc={date-time:microsoft-nt})" ,
} ,
expected {
dtmsftnt : true ,
} ,
} ,
{
"ShouldNotEnableUnix" ,
have {
users : "(abc={date-time:unix})" ,
} ,
expected {
dtunix : true ,
} ,
} ,
{
"ShouldNotEnableGeneralized" ,
have {
users : "(abc={date-time:generalized})" ,
} ,
expected {
dtgeneralized : true ,
} ,
} ,
}
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
UsersFilter : tc . have . users ,
Attributes : tc . have . attr ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
assert . Equal ( t , tc . expected . dtgeneralized , provider . usersFilterReplacementDateTimeGeneralized )
assert . Equal ( t , tc . expected . dtmsftnt , provider . usersFilterReplacementDateTimeMicrosoftNTTimeEpoch )
assert . Equal ( t , tc . expected . dtunix , provider . usersFilterReplacementDateTimeUnixEpoch )
} )
}
}
2021-07-01 23:16:16 +00:00
func TestShouldCheckLDAPServerExtensions ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-07-01 23:16:16 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-07-01 23:16:16 +00:00
nil ,
mockFactory )
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-01 23:16:16 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2021-07-01 23:16:16 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2021-07-01 23:16:16 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
2021-07-01 23:16:16 +00:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
2022-05-10 04:38:36 +00:00
Values : [ ] string { ldapOIDExtensionPwdModifyExOp , ldapOIDExtensionTLS } ,
} ,
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
} ,
} ,
} ,
} , nil )
connClose := mockClient . EXPECT ( ) . Close ( )
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
assert . True ( t , provider . features . Extensions . PwdModifyExOp )
assert . True ( t , provider . features . Extensions . TLS )
2022-05-10 04:38:36 +00:00
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . ControlTypes . MsftPwdPolHints )
assert . False ( t , provider . features . ControlTypes . MsftPwdPolHintsDeprecated )
2022-05-10 04:38:36 +00:00
}
func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntry ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . Extensions . PwdModifyExOp )
assert . False ( t , provider . features . Extensions . TLS )
2022-05-10 04:38:36 +00:00
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . ControlTypes . MsftPwdPolHints )
assert . False ( t , provider . features . ControlTypes . MsftPwdPolHintsDeprecated )
2022-05-10 04:38:36 +00:00
}
func TestShouldCheckLDAPServerControlTypes ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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-01 23:16:16 +00:00
} ,
} ,
} ,
} ,
} , nil )
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2021-07-01 23:16:16 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . Extensions . PwdModifyExOp )
assert . False ( t , provider . features . Extensions . TLS )
2022-05-10 04:38:36 +00:00
2022-12-21 10:31:21 +00:00
assert . True ( t , provider . features . ControlTypes . MsftPwdPolHints )
assert . True ( t , provider . features . ControlTypes . MsftPwdPolHintsDeprecated )
2021-07-01 23:16:16 +00:00
}
2022-05-10 04:38:36 +00:00
func TestShouldNotEnablePasswdModifyExtensionOrControlTypes ( t * testing . T ) {
2021-07-01 23:16:16 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-07-01 23:16:16 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-07-01 23:16:16 +00:00
nil ,
mockFactory )
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-01 23:16:16 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2021-07-01 23:16:16 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2021-07-01 23:16:16 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
2021-07-01 23:16:16 +00:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : ldapSupportedExtensionAttribute ,
Values : [ ] string { } ,
} ,
2022-05-10 04:38:36 +00:00
{
Name : ldapSupportedControlAttribute ,
Values : [ ] string { } ,
} ,
2021-07-01 23:16:16 +00:00
} ,
} ,
} ,
} , nil )
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2021-07-01 23:16:16 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . Extensions . PwdModifyExOp )
assert . False ( t , provider . features . Extensions . TLS )
2022-05-10 04:38:36 +00:00
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . ControlTypes . MsftPwdPolHints )
assert . False ( t , provider . features . ControlTypes . MsftPwdPolHintsDeprecated )
2021-07-01 23:16:16 +00:00
}
func TestShouldReturnCheckServerConnectError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-07-01 23:16:16 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-07-01 23:16:16 +00:00
nil ,
mockFactory )
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , errors . New ( "could not connect" ) )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-02 01:51:38 +00:00
assert . EqualError ( t , err , "dial failed with error: could not connect" )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . Extensions . PwdModifyExOp )
2021-07-01 23:16:16 +00:00
}
func TestShouldReturnCheckServerSearchError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-07-01 23:16:16 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-07-01 23:16:16 +00:00
nil ,
mockFactory )
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-01 23:16:16 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2021-07-01 23:16:16 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2021-07-01 23:16:16 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
searchOIDs := mockClient . EXPECT ( ) .
Search ( NewExtendedSearchRequestMatcher ( "(objectClass=*)" , "" , ldap . ScopeBaseObject , ldap . NeverDerefAliases , false , [ ] string { ldapSupportedExtensionAttribute , ldapSupportedControlAttribute } ) ) .
2021-07-01 23:16:16 +00:00
Return ( nil , errors . New ( "could not perform the search" ) )
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-10-01 20:44:18 +00:00
assert . EqualError ( t , err , "error occurred during RootDSE search: could not perform the search" )
2021-07-01 23:16:16 +00:00
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . features . Extensions . PwdModifyExOp )
2021-07-01 23:16:16 +00:00
}
2023-06-18 04:40:38 +00:00
func TestShouldPermitRootDSEFailure ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
PermitFeatureDetectionFailure : true ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
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 ( nil , errors . New ( "could not perform the search" ) )
connClose := mockClient . EXPECT ( ) . Close ( )
gomock . InOrder ( dialURL , connBind , searchOIDs , connClose )
err := provider . StartupCheck ( )
assert . NoError ( t , err )
}
2020-01-20 19:34:53 +00:00
type SearchRequestMatcher struct {
expected string
}
func NewSearchRequestMatcher ( expected string ) * SearchRequestMatcher {
return & SearchRequestMatcher { expected }
}
2022-10-05 05:05:23 +00:00
func ( srm * SearchRequestMatcher ) Matches ( x any ) bool {
2020-01-20 19:34:53 +00:00
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 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-01-20 19:34:53 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(|({username_attribute}={input})({mail_attribute}={input}))" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
Password : "password" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-01-20 19:34:53 +00:00
2022-05-10 04:38:36 +00:00
mockClient . EXPECT ( ) .
2020-03-15 07:10:25 +00:00
// Here we ensure that the input has been correctly escaped.
2020-03-30 22:36:04 +00:00
Search ( NewSearchRequestMatcher ( "(|(uid=john\\=abc)(mail=john\\=abc))" ) ) .
2020-03-15 07:10:25 +00:00
Return ( & ldap . SearchResult { } , nil )
2020-01-20 19:34:53 +00:00
2022-12-21 10:31:21 +00:00
_ , err := provider . getUserProfile ( mockClient , "john=abc" )
2020-12-03 05:23:52 +00:00
require . Error ( t , err )
assert . EqualError ( t , err , "user not found" )
2020-03-15 07:10:25 +00:00
}
2022-05-15 06:37:23 +00:00
func TestShouldReturnEmailWhenAttributeSameAsUsername ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "mail" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "(&({username_attribute}={input})(objectClass=inetOrgPerson))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-15 06:37:23 +00:00
} ,
false ,
nil ,
mockFactory )
2023-06-18 04:40:38 +00:00
assert . Equal ( t , [ ] string { "mail" , "displayName" , "memberOf" } , provider . usersAttributes )
2022-05-15 06:37:23 +00:00
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 ( NewSearchRequestMatcher ( "(&(mail=john@example.com)(objectClass=inetOrgPerson))" ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=john,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "mail" ,
Values : [ ] string { "john@example.com" } ,
} ,
{
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-15 06:37:23 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john@example.com" )
2022-05-15 06:37:23 +00:00
assert . NoError ( t , err )
require . NotNil ( t , profile )
assert . Equal ( t , "uid=john,dc=example,dc=com" , profile . DN )
assert . Equal ( t , "john@example.com" , profile . Username )
assert . Equal ( t , "John Doe" , profile . DisplayName )
require . Len ( t , profile . Emails , 1 )
assert . Equal ( t , "john@example.com" , profile . Emails [ 0 ] )
}
func TestShouldReturnUsernameAndBlankDisplayNameWhenAttributesTheSame ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "uid" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-15 06:37:23 +00:00
} ,
false ,
nil ,
mockFactory )
2023-06-18 04:40:38 +00:00
assert . Equal ( t , [ ] string { "uid" , "mail" , "memberOf" } , provider . usersAttributes )
2022-05-15 06:37:23 +00:00
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 ( NewSearchRequestMatcher ( "(&(|(uid=john@example.com)(mail=john@example.com))(objectClass=inetOrgPerson))" ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=john,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "john@example.com" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-15 06:37:23 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john@example.com" )
2022-05-15 06:37:23 +00:00
assert . NoError ( t , err )
require . NotNil ( t , profile )
assert . Equal ( t , "uid=john,dc=example,dc=com" , profile . DN )
assert . Equal ( t , "john" , profile . Username )
assert . Equal ( t , "john" , profile . DisplayName )
require . Len ( t , profile . Emails , 1 )
assert . Equal ( t , "john@example.com" , profile . Emails [ 0 ] )
}
func TestShouldReturnBlankEmailAndDisplayNameWhenAttrsLenZero ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-15 06:37:23 +00:00
} ,
false ,
nil ,
mockFactory )
2023-06-18 04:40:38 +00:00
assert . Equal ( t , [ ] string { "uid" , "mail" , "displayName" , "memberOf" } , provider . usersAttributes )
2022-05-15 06:37:23 +00:00
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 ( NewSearchRequestMatcher ( "(&(|(uid=john@example.com)(mail=john@example.com))(objectClass=inetOrgPerson))" ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=john,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { } ,
} ,
{
Name : "displayName" ,
Values : [ ] string { } ,
} ,
2023-06-18 04:40:38 +00:00
{
Name : "memberOf" ,
Values : [ ] string { } ,
} ,
2022-05-15 06:37:23 +00:00
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , bind , search )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-15 06:37:23 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john@example.com" )
2022-05-15 06:37:23 +00:00
assert . NoError ( t , err )
require . NotNil ( t , profile )
assert . Equal ( t , "uid=john,dc=example,dc=com" , profile . DN )
assert . Equal ( t , "john" , profile . Username )
assert . Equal ( t , "" , profile . DisplayName )
assert . Len ( t , profile . Emails , 0 )
}
2020-03-15 07:10:25 +00:00
func TestShouldCombineUsernameFilterAndUsersFilter ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-03-15 07:10:25 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
UsersFilter : "(&({username_attribute}={input})(&(objectCategory=person)(objectClass=user)))" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-01-20 19:34:53 +00:00
2023-06-18 04:40:38 +00:00
assert . Equal ( t , [ ] string { "uid" , "mail" , "displayName" , "memberOf" } , provider . usersAttributes )
2022-05-15 06:37:23 +00:00
2022-12-21 10:31:21 +00:00
assert . True ( t , provider . usersFilterReplacementInput )
2021-08-05 04:17:07 +00:00
2022-05-10 04:38:36 +00:00
mockClient . EXPECT ( ) .
2020-03-15 07:10:25 +00:00
Search ( NewSearchRequestMatcher ( "(&(uid=john)(&(objectCategory=person)(objectClass=user)))" ) ) .
2020-01-20 19:34:53 +00:00
Return ( & ldap . SearchResult { } , nil )
2022-12-21 10:31:21 +00:00
_ , err := provider . getUserProfile ( mockClient , "john" )
2020-12-03 05:23:52 +00:00
require . Error ( t , err )
assert . EqualError ( t , err , "user not found" )
2020-01-20 19:34:53 +00:00
}
2020-02-27 22:21:07 +00:00
func createSearchResultWithAttributes ( attributes ... * ldap . EntryAttribute ) * ldap . SearchResult {
return & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 01:05:17 +00:00
{ Attributes : attributes } ,
2020-02-27 22:21:07 +00:00
} ,
}
}
2023-06-18 04:40:38 +00:00
func createGroupSearchResultModeFilter ( name string , groupNames ... string ) * ldap . SearchResult {
result := & ldap . SearchResult {
Entries : make ( [ ] * ldap . Entry , len ( groupNames ) ) ,
}
for i , groupName := range groupNames {
result . Entries [ i ] = & ldap . Entry { Attributes : [ ] * ldap . EntryAttribute { { Name : name , Values : [ ] string { groupName } } } }
}
return result
}
func createGroupSearchResultModeFilterWithDN ( name string , groupNames [ ] string , groupDNs [ ] string ) * ldap . SearchResult {
if len ( groupNames ) != len ( groupDNs ) {
panic ( "input sizes mismatch" )
}
result := & ldap . SearchResult {
Entries : make ( [ ] * ldap . Entry , len ( groupNames ) ) ,
}
for i , groupName := range groupNames {
result . Entries [ i ] = & ldap . Entry {
DN : groupDNs [ i ] ,
Attributes : [ ] * ldap . EntryAttribute { { Name : name , Values : [ ] string { groupName } } } ,
}
}
return result
2020-02-27 22:21:07 +00:00
}
func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-02-27 22:21:07 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-02-27 22:21:07 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2020-02-27 22:21:07 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2020-02-27 22:21:07 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2020-03-15 07:10:25 +00:00
Return ( nil )
2020-02-27 22:21:07 +00:00
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-02-27 22:21:07 +00:00
2022-05-10 04:38:36 +00:00
searchGroups := mockClient . EXPECT ( ) .
2020-02-27 22:21:07 +00:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributes ( ) , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
2020-02-27 22:21:07 +00:00
Search ( gomock . Any ( ) ) .
2020-03-15 07:10:25 +00:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 01:05:17 +00:00
{
2020-03-15 07:10:25 +00:00
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
2020-06-19 10:50:21 +00:00
{
2021-08-05 04:17:07 +00:00
Name : "displayName" ,
2020-06-19 10:50:21 +00:00
Values : [ ] string { "John Doe" } ,
} ,
2020-04-09 01:05:17 +00:00
{
2020-03-15 07:10:25 +00:00
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
2020-04-09 01:05:17 +00:00
{
2020-03-15 07:10:25 +00:00
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
2020-02-27 22:21:07 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2020-02-27 22:21:07 +00:00
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
2020-06-19 10:50:21 +00:00
assert . Equal ( t , details . DisplayName , "John Doe" )
2020-03-15 07:10:25 +00:00
assert . Equal ( t , details . Username , "john" )
2020-02-27 22:21:07 +00:00
}
2023-06-18 04:40:38 +00:00
func TestLDAPUserProvider_GetDetails_ShouldReturnOnUserError ( t * testing . T ) {
2020-02-27 22:21:07 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-02-27 22:21:07 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
2021-01-04 10:28:55 +00:00
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2023-06-18 04:40:38 +00:00
PermitReferrals : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-02-27 22:21:07 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2020-02-27 22:21:07 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2020-02-27 22:21:07 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2020-03-15 07:10:25 +00:00
Return ( nil )
2020-02-27 22:21:07 +00:00
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-02-27 22:21:07 +00:00
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
2020-02-27 22:21:07 +00:00
Search ( gomock . Any ( ) ) .
2023-06-18 04:40:38 +00:00
Return ( nil , fmt . Errorf ( "failed to search" ) )
2020-03-15 07:10:25 +00:00
2023-06-18 04:40:38 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , connClose )
2020-02-27 22:21:07 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2023-06-18 04:40:38 +00:00
assert . Nil ( t , details )
assert . EqualError ( t , err , "cannot find user DN of user 'john'. Cause: failed to search" )
2020-03-15 07:10:25 +00:00
}
2023-06-18 04:40:38 +00:00
func TestLDAPUserProvider_GetDetails_ShouldReturnOnGroupsError ( t * testing . T ) {
2020-03-15 07:10:25 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-03-15 07:10:25 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-03-15 07:10:25 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2020-03-15 07:10:25 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2020-03-15 07:10:25 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-03-15 07:10:25 +00:00
2022-05-10 04:38:36 +00:00
searchGroups := mockClient . EXPECT ( ) .
2020-03-15 07:10:25 +00:00
Search ( gomock . Any ( ) ) .
2023-06-18 04:40:38 +00:00
Return ( nil , fmt . Errorf ( "failed to search groups" ) )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
2020-03-15 07:10:25 +00:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
2020-04-09 01:05:17 +00:00
{
2020-03-15 07:10:25 +00:00
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
2020-06-19 10:50:21 +00:00
{
2021-08-05 04:17:07 +00:00
Name : "displayName" ,
2020-06-19 10:50:21 +00:00
Values : [ ] string { "John Doe" } ,
} ,
2020-04-09 01:05:17 +00:00
{
2020-03-15 07:10:25 +00:00
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
2020-04-09 01:05:17 +00:00
{
2020-03-15 07:10:25 +00:00
Name : "uid" ,
2023-06-18 04:40:38 +00:00
Values : [ ] string { "john" } ,
2020-03-15 07:10:25 +00:00
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
2020-03-15 07:10:25 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2020-03-15 07:10:25 +00:00
2023-06-18 04:40:38 +00:00
assert . Nil ( t , details )
assert . EqualError ( t , err , "unable to retrieve groups of user 'john'. Cause: failed to search groups" )
2020-02-27 22:21:07 +00:00
}
2020-12-03 05:23:52 +00:00
2023-06-18 04:40:38 +00:00
func TestShouldNotCrashWhenEmailsAreNotRetrievedFromLDAP ( t * testing . T ) {
2021-01-04 10:28:55 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-01-04 10:28:55 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "displayName" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2022-05-10 04:38:36 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2021-07-06 09:13:17 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
2023-06-18 04:40:38 +00:00
Return ( createGroupSearchResultModeFilter ( provider . config . Attributes . GroupName , "group1" , "group2" ) , nil )
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "uid" ,
2023-06-18 04:40:38 +00:00
Values : [ ] string { "john" } ,
2021-01-04 10:28:55 +00:00
} ,
} ,
} ,
2021-07-13 11:12:50 +00:00
} ,
} , nil )
2023-06-18 04:40:38 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
2021-07-13 11:12:50 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2021-07-13 11:12:50 +00:00
require . NoError ( t , err )
2022-05-10 04:38:36 +00:00
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
2023-06-18 04:40:38 +00:00
assert . ElementsMatch ( t , details . Emails , [ ] string { } )
assert . Equal ( t , details . Username , "john" )
2021-07-13 11:12:50 +00:00
}
2023-06-18 04:40:38 +00:00
func TestShouldUnauthenticatedBind ( t * testing . T ) {
2021-07-13 11:12:50 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-07-13 11:12:50 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "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 )
connBind := mockClient . EXPECT ( ) .
UnauthenticatedBind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( createGroupSearchResultModeFilter ( provider . config . Attributes . GroupName , "group1" , "group2" ) , nil )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { "group1" , "group2" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { } )
assert . Equal ( t , details . Username , "john" )
}
func TestShouldReturnUsernameFromLDAP ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
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 )
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( createGroupSearchResultModeFilter ( provider . config . Attributes . GroupName , "group1" , "group2" ) , nil )
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 )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
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" )
}
func TestShouldReturnUsernameFromLDAPSearchModeMemberOfRDN ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
GroupSearchMode : "memberof" ,
UsersFilter : "uid={input}" ,
GroupsFilter : "(|{memberof:rdn})" ,
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 )
connClose := mockClient . EXPECT ( ) . Close ( )
requestGroups := ldap . NewSearchRequest (
provider . groupsBaseDN , ldap . ScopeWholeSubtree , ldap . NeverDerefAliases ,
0 , 0 , false , "(|(CN=admins)(CN=users))" , provider . groupsAttributes , nil ,
)
// This ensures the filtering works correctly in the following ways:
// Item 1 (0th element), has the wrong case.
// Item 2 (1st element), has the wrong DN.
searchGroups := mockClient . EXPECT ( ) .
Search ( requestGroups ) .
Return ( createGroupSearchResultModeFilterWithDN ( provider . config . Attributes . GroupName , [ ] string { "admins" , "notadmins" , "users" } , [ ] string { "CN=ADMINS,OU=groups,DC=example,DC=com" , "CN=notadmins,OU=wronggroups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" } ) , nil )
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" } ,
} ,
{
Name : "memberOf" ,
Values : [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { "admins" , "users" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "John" )
}
func TestShouldReturnUsernameFromLDAPSearchModeMemberOfDN ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "CN=Administrator,CN=Users,DC=example,DC=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
GroupSearchMode : "memberof" ,
UsersFilter : "sAMAccountName={input}" ,
GroupsFilter : "(|{memberof:dn})" ,
AdditionalUsersDN : "CN=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=Administrator,CN=Users,DC=example,DC=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
requestGroups := ldap . NewSearchRequest (
provider . groupsBaseDN , ldap . ScopeWholeSubtree , ldap . NeverDerefAliases ,
0 , 0 , false , "(|(distinguishedName=CN=admins,OU=groups,DC=example,DC=com)(distinguishedName=CN=users,OU=groups,DC=example,DC=com))" , provider . groupsAttributes , nil ,
)
searchGroups := mockClient . EXPECT ( ) .
Search ( requestGroups ) .
Return ( createGroupSearchResultModeFilterWithDN ( provider . config . Attributes . GroupName , [ ] string { "admins" , "admins" , "users" } , [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=admins,OU=wronggroups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" } ) , nil )
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 : "sAMAccountName" ,
Values : [ ] string { "John" } ,
} ,
{
Name : "memberOf" ,
Values : [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Groups , [ ] string { "admins" , "users" } )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "John" )
}
func TestShouldReturnErrSearchMemberOf ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "CN=Administrator,CN=Users,DC=example,DC=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
GroupSearchMode : "memberof" ,
UsersFilter : "sAMAccountName={input}" ,
GroupsFilter : "(|{memberof:dn})" ,
AdditionalUsersDN : "CN=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=Administrator,CN=Users,DC=example,DC=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connClose := mockClient . EXPECT ( ) . Close ( )
requestGroups := ldap . NewSearchRequest (
provider . groupsBaseDN , ldap . ScopeWholeSubtree , ldap . NeverDerefAliases ,
0 , 0 , false , "(|(distinguishedName=CN=admins,OU=groups,DC=example,DC=com)(distinguishedName=CN=users,OU=groups,DC=example,DC=com))" , provider . groupsAttributes , nil ,
)
searchGroups := mockClient . EXPECT ( ) .
Search ( requestGroups ) .
Return ( nil , fmt . Errorf ( "failed to get groups" ) )
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 : "sAMAccountName" ,
Values : [ ] string { "John" } ,
} ,
{
Name : "memberOf" ,
Values : [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
assert . Nil ( t , details )
assert . EqualError ( t , err , "unable to retrieve groups of user 'john'. Cause: failed to get groups" )
}
func TestShouldReturnErrUnknownSearchMode ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "CN=Administrator,CN=Users,DC=example,DC=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
GroupSearchMode : "bad" ,
UsersFilter : "sAMAccountName={input}" ,
GroupsFilter : "(|{memberof:dn})" ,
AdditionalUsersDN : "CN=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=Administrator,CN=Users,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 : "sAMAccountName" ,
Values : [ ] string { "John" } ,
} ,
{
Name : "memberOf" ,
Values : [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , connClose )
details , err := provider . GetDetails ( "john" )
assert . Nil ( t , details )
assert . EqualError ( t , err , "could not perform group search with mode 'bad' as it's unknown" )
}
func TestShouldSkipEmptyAttributesSearchModeMemberOf ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "CN=Administrator,CN=Users,DC=example,DC=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
GroupSearchMode : "memberof" ,
UsersFilter : "sAMAccountName={input}" ,
GroupsFilter : "(|{memberof:dn})" ,
AdditionalUsersDN : "CN=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=Administrator,CN=Users,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 : "sAMAccountName" ,
Values : [ ] string { "John" } ,
} ,
{
Name : "memberOf" ,
Values : [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" , "CN=multi,OU=groups,DC=example,DC=com" } ,
} ,
} ,
} ,
} ,
} , nil )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=grp,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute { } ,
} ,
{
DN : "CN=users,OU=groups,DC=example,DC=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "cn" ,
Values : [ ] string { } ,
} ,
} ,
} ,
{
DN : "CN=admins,OU=groups,DC=example,DC=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "cn" ,
Values : [ ] string { "" } ,
} ,
} ,
} ,
{
DN : "CN=multi,OU=groups,DC=example,DC=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "cn" ,
Values : [ ] string { "a" , "b" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
assert . NoError ( t , err )
assert . NotNil ( t , details )
}
func TestShouldSkipEmptyAttributesSearchModeFilter ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "CN=Administrator,CN=Users,DC=example,DC=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
GroupSearchMode : "filter" ,
UsersFilter : "sAMAccountName={input}" ,
GroupsFilter : "(|{memberof:dn})" ,
AdditionalUsersDN : "CN=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=Administrator,CN=Users,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 : "sAMAccountName" ,
Values : [ ] string { "John" } ,
} ,
{
Name : "memberOf" ,
Values : [ ] string { "CN=admins,OU=groups,DC=example,DC=com" , "CN=users,OU=groups,DC=example,DC=com" , "CN=multi,OU=groups,DC=example,DC=com" } ,
} ,
} ,
} ,
} ,
} , nil )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=grp,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute { } ,
} ,
{
DN : "CN=users,OU=groups,DC=example,DC=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "cn" ,
Values : [ ] string { } ,
} ,
} ,
} ,
{
DN : "CN=admins,OU=groups,DC=example,DC=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "cn" ,
Values : [ ] string { "" } ,
} ,
} ,
} ,
{
DN : "CN=multi,OU=groups,DC=example,DC=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
Name : "cn" ,
Values : [ ] string { "a" , "b" } ,
} ,
} ,
} ,
} ,
} , nil )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
assert . NoError ( t , err )
assert . NotNil ( t , details )
}
func TestShouldSkipEmptyGroupsResultMemberOf ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
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 )
connClose := mockClient . EXPECT ( ) . Close ( )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{ } ,
} ,
} , nil )
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 )
gomock . InOrder ( dialURL , connBind , searchProfile , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
assert . ElementsMatch ( t , details . Emails , [ ] string { "test@example.com" } )
assert . Equal ( t , details . DisplayName , "John Doe" )
assert . Equal ( t , details . Username , "John" )
}
func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndResult ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
mockClientReferralAlt := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2021-07-13 11:12:50 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-07-13 11:12:50 +00:00
nil ,
mockFactory )
2022-05-10 04:38:36 +00:00
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2021-01-04 10:28:55 +00:00
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
2023-06-18 04:40:38 +00:00
Return ( createGroupSearchResultModeFilter ( provider . config . Attributes . GroupName , "group1" , "group2" ) , nil )
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry { } ,
2023-06-18 04:40:38 +00:00
Referrals : [ ] string { "ldap://192.168.0.1" } ,
2022-05-10 04:38:36 +00:00
} , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
dialURLReferral := mockFactory . EXPECT ( ) .
2023-06-18 04:40:38 +00:00
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 ( )
searchProfileReferral := mockClientReferral . 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 )
dialURLReferralAlt := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( mockClientReferralAlt , nil )
connBindReferralAlt := mockClientReferralAlt . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
connCloseReferralAlt := mockClientReferralAlt . EXPECT ( ) . Close ( )
searchProfileReferralAlt := mockClientReferralAlt . 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 )
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , dialURLReferralAlt , connBindReferralAlt , searchProfileReferralAlt , connCloseReferralAlt , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
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" )
}
func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndNoResult ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
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 )
connClose := mockClient . EXPECT ( ) . Close ( )
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( createGroupSearchResultModeFilter ( provider . config . Attributes . GroupName , "group1" , "group2" ) , nil )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( nil , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClientReferral , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
connBindReferral := mockClientReferral . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
searchProfileReferral := mockClientReferral . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
2021-07-13 11:12:50 +00:00
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
2022-05-10 04:38:36 +00:00
DN : "uid=test,dc=example,dc=com" ,
2021-07-13 11:12:50 +00:00
Attributes : [ ] * ldap . EntryAttribute {
{
2022-05-10 04:38:36 +00:00
Name : "displayName" ,
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "John" } ,
2021-07-13 11:12:50 +00:00
} ,
} ,
} ,
} ,
} , nil )
2023-06-18 04:40:38 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , searchGroups , connClose )
details , err := provider . GetDetails ( "john" )
require . NoError ( t , err )
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" )
}
func TestShouldReturnDialErrDuringReferralSearchUsernameFromLDAPWithReferralsInErrorAndNoResult ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
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 )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( nil , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
dialURLReferral := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://192.168.0.1" ) , gomock . Any ( ) ) .
Return ( nil , fmt . Errorf ( "failed to connect" ) )
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connClose )
details , err := provider . GetDetails ( "john" )
assert . Nil ( t , details )
assert . EqualError ( t , err , "cannot find user DN of user 'john'. Cause: error occurred connecting to referred LDAP server 'ldap://192.168.0.1': dial failed with error: failed to connect" )
}
func TestShouldReturnSearchErrDuringReferralSearchUsernameFromLDAPWithReferralsInErrorAndNoResult ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
} ,
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 )
connClose := mockClient . EXPECT ( ) . Close ( )
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( nil , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , 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 ( )
searchProfileReferral := mockClientReferral . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( nil , fmt . Errorf ( "not found" ) )
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , connClose )
details , err := provider . GetDetails ( "john" )
assert . Nil ( t , details )
assert . EqualError ( t , err , "cannot find user DN of user 'john'. Cause: error occurred performing search on referred LDAP server 'ldap://192.168.0.1': not found" )
}
func TestShouldNotReturnUsernameFromLDAPWithReferralsInErrorAndReferralsNotPermitted ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
} ,
false ,
nil ,
mockFactory )
dialURL := mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil )
2021-07-13 11:12:50 +00:00
2023-06-18 04:40:38 +00:00
connBind := mockClient . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2023-06-18 04:40:38 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
2023-06-18 04:40:38 +00:00
searchProfile := mockClient . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
Search ( gomock . Any ( ) ) .
2023-06-18 04:40:38 +00:00
Return ( nil , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
2021-07-13 11:12:50 +00:00
2023-06-18 04:40:38 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , connClose )
2021-07-13 11:12:50 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2023-06-18 04:40:38 +00:00
assert . EqualError ( t , err , "cannot find user DN of user 'john'. Cause: LDAP Result Code 10 \"Referral\": referral" )
assert . Nil ( t , details )
2021-07-13 11:12:50 +00:00
}
2022-05-10 04:38:36 +00:00
func TestShouldReturnUsernameFromLDAPWithReferralsErr ( t * testing . T ) {
2021-07-13 11:12:50 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
mockClientReferral := NewMockLDAPClient ( ctrl )
2021-07-13 11:12:50 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2021-07-13 11:12:50 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-07-13 11:12:50 +00:00
nil ,
mockFactory )
2022-05-10 04:38:36 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-07-13 11:12:50 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2021-07-13 11:12:50 +00:00
Return ( nil )
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchGroups := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
2023-06-18 04:40:38 +00:00
Return ( createGroupSearchResultModeFilter ( provider . config . Attributes . GroupName , "group1" , "group2" ) , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult { } , & ldap . Error { ResultCode : ldap . LDAPResultReferral , Err : errors . New ( "referral" ) , Packet : & testBERPacketReferral } )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00: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 11:12:50 +00:00
Return ( nil )
2022-05-10 04:38:36 +00:00
connCloseReferral := mockClientReferral . EXPECT ( ) . Close ( )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchProfileReferral := mockClientReferral . EXPECT ( ) .
2021-07-13 11:12:50 +00: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 04:38:36 +00:00
gomock . InOrder ( dialURL , connBind , searchProfile , dialURLReferral , connBindReferral , searchProfileReferral , connCloseReferral , searchGroups , connClose )
2021-07-13 11:12:50 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2021-07-06 09:13:17 +00:00
require . NoError ( t , err )
2021-01-04 10:28:55 +00:00
2022-05-10 04:38:36 +00: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 10:28:55 +00:00
}
2022-05-10 04:38:36 +00:00
func TestShouldNotUpdateUserPasswordConnect ( t * testing . T ) {
2021-01-04 10:28:55 +00:00
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordMSAD ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
2023-05-25 02:26:19 +00:00
pwdEncoded , _ := encodingUTF16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2022-05-10 04:38:36 +00:00
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
2023-05-25 02:26:19 +00:00
pwdEncoded , _ := encodingUTF16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralConnectErr ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2022-05-10 04:38:36 +00:00
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
2023-05-25 02:26:19 +00:00
pwdEncoded , _ := encodingUTF16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2022-05-10 04:38:36 +00:00
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
2023-05-25 02:26:19 +00:00
pwdEncoded , _ := encodingUTF16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
2022-05-10 04:38:36 +00:00
} ,
false ,
nil ,
mockFactory )
modifyRequest := ldap . NewModifyRequest (
"uid=test,dc=example,dc=com" ,
[ ] ldap . Control { & controlMsftServerPolicyHints { ldapOIDControlMsftServerPolicyHints } } ,
)
2023-05-25 02:26:19 +00:00
pwdEncoded , _ := encodingUTF16LittleEndian . NewEncoder ( ) . String ( fmt . Sprintf ( "\"%s\"" , "password" ) )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordPasswdModifyExtensionWithoutReferrals ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : false ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
PermitReferrals : true ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "cn={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
}
func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHintsDeprecated ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "cn={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordActiveDirectory ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "activedirectory" ,
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
DistinguishedName : "distinguishedName" ,
Username : "sAMAccountName" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "cn={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
}
func TestShouldUpdateUserPasswordBasic ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Implementation : "custom" ,
Address : testLDAPAddress ,
User : "uid=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
err := provider . StartupCheck ( )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
2022-12-21 10:31:21 +00:00
err = provider . UpdatePassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
require . NoError ( t , err )
}
func TestShouldReturnErrorWhenMultipleUsernameAttributes ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "(|(uid={input})(uid=*))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john" )
2022-05-10 04:38:36 +00:00
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 )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "(|(uid={input})(uid=*))" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 )
2022-12-21 10:31:21 +00:00
client , err := provider . connect ( )
2022-05-10 04:38:36 +00:00
assert . NoError ( t , err )
2022-12-21 10:31:21 +00:00
profile , err := provider . getUserProfile ( client , "john" )
2022-05-10 04:38:36 +00:00
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 10:28:55 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
gomock . InOrder (
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
2022-05-10 04:38:36 +00:00
mockClient . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 04:17:07 +00:00
Name : "displayName" ,
2021-01-04 10:28:55 +00: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 04:38:36 +00:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
Bind ( gomock . Eq ( "uid=test,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
2022-05-10 04:38:36 +00:00
mockClient . EXPECT ( ) . Close ( ) . Times ( 2 ) ,
2021-01-04 10:28:55 +00:00
)
2022-12-21 10:31:21 +00:00
valid , err := provider . CheckUserPassword ( "john" , "password" )
2021-01-04 10:28:55 +00:00
assert . True ( t , valid )
require . NoError ( t , err )
}
2022-05-10 04:38:36 +00:00
func TestShouldNotCheckValidUserPasswordWithConnectError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2022-05-10 04:38:36 +00:00
} ,
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 ( ) )
2022-12-21 10:31:21 +00:00
valid , err := provider . CheckUserPassword ( "john" , "password" )
2022-05-10 04:38:36 +00:00
assert . False ( t , valid )
assert . EqualError ( t , err , "bind failed with error: LDAP Result Code 49 \"Invalid Credentials\": invalid username or password" )
}
2023-06-18 04:40:38 +00:00
func TestShouldNotCheckValidUserPasswordWithGetProfileError ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
provider := NewLDAPUserProviderWithFactory (
schema . LDAPAuthenticationBackend {
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
} ,
false ,
nil ,
mockFactory )
gomock . InOrder (
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
mockClient . EXPECT ( ) .
Search ( gomock . Any ( ) ) .
Return ( nil , & ldap . Error { ResultCode : ldap . LDAPResultBusy , Err : errors . New ( "directory server busy" ) } ) ,
mockClient . EXPECT ( ) . Close ( ) ,
)
valid , err := provider . CheckUserPassword ( "john" , "password" )
assert . False ( t , valid )
assert . EqualError ( t , err , "cannot find user DN of user 'john'. Cause: LDAP Result Code 51 \"Busy\": directory server busy" )
}
2021-01-04 10:28:55 +00:00
func TestShouldCheckInvalidUserPassword ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2021-01-04 10:28:55 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
gomock . InOrder (
mockFactory . EXPECT ( ) .
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil ) ,
2022-05-10 04:38:36 +00:00
mockClient . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 04:17:07 +00:00
Name : "displayName" ,
2021-01-04 10:28:55 +00: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 04:38:36 +00:00
Return ( mockClient , nil ) ,
mockClient . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
Bind ( gomock . Eq ( "uid=test,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
2021-12-02 10:28:16 +00:00
Return ( errors . New ( "invalid username or password" ) ) ,
2022-05-10 04:38:36 +00:00
mockClient . EXPECT ( ) . Close ( ) . Times ( 2 ) ,
2021-01-04 10:28:55 +00:00
)
2022-12-21 10:31:21 +00:00
valid , err := provider . CheckUserPassword ( "john" , "password" )
2021-01-04 10:28:55 +00:00
assert . False ( t , valid )
2022-05-02 01:51:38 +00:00
require . EqualError ( t , err , "authentication failed. Cause: bind failed with error: invalid username or password" )
2021-01-04 10:28:55 +00:00
}
2020-12-03 05:23:52 +00:00
func TestShouldCallStartTLSWhenEnabled ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-12-03 05:23:52 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-12-03 05:23:52 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2020-12-03 05:23:52 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
connStartTLS := mockClient . EXPECT ( ) .
2022-12-21 10:31:21 +00:00
StartTLS ( provider . tlsConfig )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
searchGroups := mockClient . EXPECT ( ) .
2020-12-03 05:23:52 +00:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributes ( ) , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
2020-12-03 05:23:52 +00:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 04:17:07 +00:00
Name : "displayName" ,
2020-12-03 05:23:52 +00:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
} ,
} ,
} ,
} , nil )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connStartTLS , connBind , searchProfile , searchGroups , connClose )
2020-12-03 05:23:52 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2020-12-03 05:23:52 +00:00
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 10:28:55 +00:00
func TestShouldParseDynamicConfiguration ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
2021-01-04 10:28:55 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "(&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpiresM>={date-time:microsoft-nt})(accountExpiresU>={date-time:unix})(accountExpiresG>={date-time:generalized})))" ,
GroupsFilter : "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))" ,
AdditionalUsersDN : "ou=users" ,
AdditionalGroupsDN : "ou=groups" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
2021-01-04 10:28:55 +00:00
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2022-12-21 10:31:21 +00:00
clock := & utils . TestingClock { }
2021-08-05 04:17:07 +00:00
2022-12-21 10:31:21 +00:00
provider . clock = clock
2021-08-05 04:17:07 +00:00
2022-12-21 10:31:21 +00:00
clock . Set ( time . Unix ( 1670250519 , 0 ) )
assert . True ( t , provider . groupsFilterReplacementInput )
assert . True ( t , provider . groupsFilterReplacementUsername )
assert . True ( t , provider . groupsFilterReplacementDN )
assert . True ( t , provider . usersFilterReplacementInput )
assert . True ( t , provider . usersFilterReplacementDateTimeGeneralized )
assert . True ( t , provider . usersFilterReplacementDateTimeMicrosoftNTTimeEpoch )
2023-06-18 04:40:38 +00:00
assert . Equal ( t , "(&(|(uid={input})(mail={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpiresM>={date-time:microsoft-nt})(accountExpiresU>={date-time:unix})(accountExpiresG>={date-time:generalized})))" , provider . config . UsersFilter )
2022-12-21 10:31:21 +00:00
assert . Equal ( t , "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))" , provider . config . GroupsFilter )
assert . Equal ( t , "ou=users,dc=example,dc=com" , provider . usersBaseDN )
assert . Equal ( t , "ou=groups,dc=example,dc=com" , provider . groupsBaseDN )
2023-06-18 04:40:38 +00:00
assert . Equal ( t , "(&(|(uid=test@example.com)(mail=test@example.com))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpiresM>=133147241190000000)(accountExpiresU>=1670250519)(accountExpiresG>=20221205142839.0Z)))" , provider . resolveUsersFilter ( "test@example.com" ) )
2022-12-21 10:31:21 +00:00
assert . Equal ( t , "(&(|(member=cn=admin,dc=example,dc=com)(member=test@example.com)(member=test))(objectClass=group))" , provider . resolveGroupsFilter ( "test@example.com" , & ldapUserProfile { Username : "test" , DN : "cn=admin,dc=example,dc=com" } ) )
2021-01-04 10:28:55 +00:00
}
2020-12-03 05:23:52 +00:00
func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue ( t * testing . T ) {
ctrl := gomock . NewController ( t )
defer ctrl . Finish ( )
2022-05-10 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-12-03 05:23:52 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
GroupName : "cn" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
2021-01-04 10:28:55 +00:00
TLS : & schema . TLSConfig {
SkipVerify : true ,
} ,
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-12-03 05:23:52 +00:00
2022-12-21 10:31:21 +00:00
assert . False ( t , provider . groupsFilterReplacementInput )
assert . False ( t , provider . groupsFilterReplacementUsername )
assert . False ( t , provider . groupsFilterReplacementDN )
2021-08-05 04:17:07 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldap://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
connBind := mockClient . EXPECT ( ) .
2020-12-03 05:23:52 +00:00
Bind ( gomock . Eq ( "cn=admin,dc=example,dc=com" ) , gomock . Eq ( "password" ) ) .
Return ( nil )
2022-05-10 04:38:36 +00:00
connStartTLS := mockClient . EXPECT ( ) .
2022-12-21 10:31:21 +00:00
StartTLS ( provider . tlsConfig )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
connClose := mockClient . EXPECT ( ) . Close ( )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
searchGroups := mockClient . EXPECT ( ) .
2020-12-03 05:23:52 +00:00
Search ( gomock . Any ( ) ) .
Return ( createSearchResultWithAttributes ( ) , nil )
2021-07-13 11:12:50 +00:00
2022-05-10 04:38:36 +00:00
searchProfile := mockClient . EXPECT ( ) .
2020-12-03 05:23:52 +00:00
Search ( gomock . Any ( ) ) .
Return ( & ldap . SearchResult {
Entries : [ ] * ldap . Entry {
{
DN : "uid=test,dc=example,dc=com" ,
Attributes : [ ] * ldap . EntryAttribute {
{
2021-08-05 04:17:07 +00:00
Name : "displayName" ,
2020-12-03 05:23:52 +00:00
Values : [ ] string { "John Doe" } ,
} ,
{
Name : "mail" ,
Values : [ ] string { "test@example.com" } ,
} ,
{
Name : "uid" ,
Values : [ ] string { "john" } ,
} ,
2023-06-18 04:40:38 +00:00
{
Name : "memberOf" ,
Values : [ ] string { "CN=example,DC=corp,DC=com" } ,
} ,
2020-12-03 05:23:52 +00:00
} ,
} ,
} ,
} , nil )
2021-07-13 11:12:50 +00:00
gomock . InOrder ( dialURL , connStartTLS , connBind , searchProfile , searchGroups , connClose )
2020-12-03 05:23:52 +00:00
2022-12-21 10:31:21 +00:00
details , err := provider . GetDetails ( "john" )
2020-12-03 05:23:52 +00:00
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 04:38:36 +00:00
mockFactory := NewMockLDAPClientFactory ( ctrl )
mockClient := NewMockLDAPClient ( ctrl )
2020-12-03 05:23:52 +00:00
2022-12-21 10:31:21 +00:00
provider := NewLDAPUserProviderWithFactory (
2022-10-17 10:51:59 +00:00
schema . LDAPAuthenticationBackend {
2023-06-18 04:40:38 +00:00
Address : testLDAPSAddress ,
User : "cn=admin,dc=example,dc=com" ,
Password : "password" ,
Attributes : schema . LDAPAuthenticationAttributes {
Username : "uid" ,
Mail : "mail" ,
DisplayName : "displayName" ,
MemberOf : "memberOf" ,
} ,
UsersFilter : "uid={input}" ,
AdditionalUsersDN : "ou=users" ,
BaseDN : "dc=example,dc=com" ,
StartTLS : true ,
2021-01-04 10:28:55 +00:00
TLS : & schema . TLSConfig {
SkipVerify : true ,
} ,
} ,
2021-09-17 09:53:59 +00:00
false ,
2021-01-04 10:28:55 +00:00
nil ,
mockFactory )
2020-12-03 05:23:52 +00:00
2021-07-13 11:12:50 +00:00
dialURL := mockFactory . EXPECT ( ) .
2021-01-04 10:28:55 +00:00
DialURL ( gomock . Eq ( "ldaps://127.0.0.1:389" ) , gomock . Any ( ) ) .
2022-05-10 04:38:36 +00:00
Return ( mockClient , nil )
2020-12-03 05:23:52 +00:00
2022-05-10 04:38:36 +00:00
connStartTLS := mockClient . EXPECT ( ) .
2022-12-21 10:31:21 +00:00
StartTLS ( provider . tlsConfig ) .
2020-12-03 05:23:52 +00:00
Return ( errors . New ( "LDAP Result Code 200 \"Network Error\": ldap: already encrypted" ) )
2022-05-10 04:38:36 +00:00
gomock . InOrder ( dialURL , connStartTLS , mockClient . EXPECT ( ) . Close ( ) )
2021-07-13 11:12:50 +00:00
2022-12-21 10:31:21 +00:00
_ , err := provider . GetDetails ( "john" )
2022-05-02 01:51:38 +00:00
assert . EqualError ( t , err , "starttls failed with error: LDAP Result Code 200 \"Network Error\": ldap: already encrypted" )
2020-12-03 05:23:52 +00:00
}