summaryrefslogtreecommitdiff
path: root/internal/authentication/ldap_user_provider_test.go
diff options
context:
space:
mode:
authorJames Elliott <james-d-elliott@users.noreply.github.com>2025-02-22 17:40:08 +1100
committerGitHub <noreply@github.com>2025-02-22 06:40:08 +0000
commit34932a845ec6a090147c37f8d5ddac9f334888d2 (patch)
tree15c94be40e31ed1cd9a862af4f22b45e696f7534 /internal/authentication/ldap_user_provider_test.go
parent7d3c2b1dedc415f4a4b80a0035a819ecf91894ec (diff)
feat(authentication): additional and custom attributes (#8078)
This facilitates adding additional attributes to the Authelia authentication backends as well as custom attributes based on the Common Expression Language. This will be utilized in the future to facilitate additional features. Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
Diffstat (limited to 'internal/authentication/ldap_user_provider_test.go')
-rw-r--r--internal/authentication/ldap_user_provider_test.go857
1 files changed, 857 insertions, 0 deletions
diff --git a/internal/authentication/ldap_user_provider_test.go b/internal/authentication/ldap_user_provider_test.go
index 0918aee5a..04a37e5f2 100644
--- a/internal/authentication/ldap_user_provider_test.go
+++ b/internal/authentication/ldap_user_provider_test.go
@@ -3,6 +3,7 @@ package authentication
import (
"errors"
"fmt"
+ "net/url"
"testing"
"time"
@@ -11,6 +12,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"golang.org/x/text/encoding/unicode"
+ "golang.org/x/text/language"
"github.com/authelia/authelia/v4/internal/clock"
"github.com/authelia/authelia/v4/internal/configuration/schema"
@@ -1046,6 +1048,7 @@ func TestShouldCombineUsernameFilterAndUsersFilter(t *testing.T) {
assert.EqualError(t, err, "user not found")
}
+//nolint:unparam
func createSearchResultWithAttributes(attributes ...*ldap.EntryAttribute) *ldap.SearchResult {
return &ldap.SearchResult{
Entries: []*ldap.Entry{
@@ -1162,6 +1165,731 @@ func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) {
assert.Equal(t, details.Username, "john")
}
+func TestLDAPUserProvider_GetDetailsExtended_ShouldPass(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ StreetAddress: "street",
+ FamilyName: "sn",
+ MiddleName: "middle",
+ GivenName: "givenName",
+ Nickname: "nickname",
+ Gender: "gender",
+ Birthdate: "birthDate",
+ Website: "website",
+ Profile: "profile",
+ Picture: "picture",
+ ZoneInfo: "zoneinfo",
+ Locale: "locale",
+ PhoneNumber: "phone",
+ PhoneExtension: "ext",
+ Locality: "locality",
+ Region: "region",
+ PostalCode: "postCode",
+ Country: "c",
+ Extra: map[string]schema.AuthenticationBackendLDAPAttributesAttribute{
+ "exampleStr": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: false,
+ ValueType: ValueTypeString,
+ },
+ },
+ "exampleStrMV": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: true,
+ ValueType: ValueTypeString,
+ },
+ },
+ "exampleInt": {
+ Name: "exampleIntChangedAttributeName",
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: false,
+ ValueType: ValueTypeInteger,
+ },
+ },
+ "exampleIntMV": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: true,
+ ValueType: ValueTypeInteger,
+ },
+ },
+ "exampleBool": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: false,
+ ValueType: ValueTypeBoolean,
+ },
+ },
+ "exampleBoolMV": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: true,
+ ValueType: ValueTypeBoolean,
+ },
+ },
+ "exampleEmptyStringInt": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: false,
+ ValueType: ValueTypeInteger,
+ },
+ },
+ "exampleEmptyStringBoolean": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: false,
+ ValueType: ValueTypeBoolean,
+ },
+ },
+ },
+ },
+ 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(&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{},
+ },
+ {
+ Name: "memberOf",
+ Values: []string{},
+ },
+ {
+ Name: "street",
+ Values: []string{"123 Banksia Ln"},
+ },
+ {
+ Name: "sn",
+ Values: []string{"Smith"},
+ },
+ {
+ Name: "middle",
+ Values: []string{"Jacob"},
+ },
+ {
+ Name: "givenName",
+ Values: []string{"John"},
+ },
+ {
+ Name: "nickname",
+ Values: []string{"Johny"},
+ },
+ {
+ Name: "gender",
+ Values: []string{"male"},
+ },
+ {
+ Name: "birthDate",
+ Values: []string{"2/2/2021"},
+ },
+ {
+ Name: "website",
+ Values: []string{"https://authelia.com"},
+ },
+ {
+ Name: "profile",
+ Values: []string{"https://authelia.com/profile/jsmith.html"},
+ },
+ {
+ Name: "picture",
+ Values: []string{"https://authelia.com/picture/jsmith.jpg"},
+ },
+ {
+ Name: "zoneinfo",
+ Values: []string{"Australia/Melbourne"},
+ },
+ {
+ Name: "locale",
+ Values: []string{"en-AU"},
+ },
+ {
+ Name: "phone",
+ Values: []string{"+1 (604) 555-1234"},
+ },
+ {
+ Name: "ext",
+ Values: []string{"5678"},
+ },
+ {
+ Name: "locality",
+ Values: []string{"Melbourne"},
+ },
+ {
+ Name: "region",
+ Values: []string{"Victoria"},
+ },
+ {
+ Name: "postCode",
+ Values: []string{"2000"},
+ },
+ {
+ Name: "c",
+ Values: []string{"Australia"},
+ },
+ {
+ Name: "exampleStr",
+ Values: []string{"abc"},
+ },
+ {
+ Name: "exampleStrMV",
+ Values: []string{"abc", "123"},
+ },
+ {
+ Name: "exampleInt",
+ Values: []string{"123"},
+ },
+ {
+ Name: "exampleIntMV",
+ Values: []string{"1023879012731.5", "123"},
+ },
+ {
+ Name: "exampleBool",
+ Values: []string{"true"},
+ },
+ {
+ Name: "exampleBoolMV",
+ Values: []string{"true", "false"},
+ },
+ {
+ Name: "exampleEmptyStringInt",
+ Values: []string{""},
+ },
+ {
+ Name: "exampleEmptyStringBoolean",
+ Values: []string{""},
+ },
+ },
+ },
+ },
+ }, nil)
+
+ searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
+
+ gomock.InOrder(dialURL, connBind, searchProfile, searchGroup, connClose)
+
+ enAU := language.MustParse("en-AU")
+ website, _ := url.Parse("https://authelia.com")
+ profile, _ := url.Parse("https://authelia.com/profile/jsmith.html")
+ picture, _ := url.Parse("https://authelia.com/picture/jsmith.jpg")
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Equal(t,
+ &UserDetailsExtended{
+ GivenName: "John",
+ FamilyName: "Smith",
+ MiddleName: "Jacob",
+ Nickname: "Johny",
+ Profile: profile,
+ Picture: picture,
+ Website: website,
+ Gender: "male",
+ Birthdate: "2/2/2021",
+ ZoneInfo: "Australia/Melbourne",
+ Locale: &enAU,
+ PhoneNumber: "+1 (604) 555-1234",
+ PhoneExtension: "5678",
+ Address: &UserDetailsAddress{
+ StreetAddress: "123 Banksia Ln",
+ Locality: "Melbourne",
+ Region: "Victoria",
+ PostalCode: "2000",
+ Country: "Australia",
+ },
+ Extra: map[string]any{
+ "exampleStr": "abc",
+ "exampleStrMV": []any{"abc", "123"},
+ "exampleIntChangedAttributeName": float64(123),
+ "exampleIntMV": []any{1023879012731.5, float64(123)},
+ "exampleBool": true,
+ "exampleBoolMV": []any{true, false},
+ },
+ UserDetails: &UserDetails{Username: "john", DisplayName: "", Emails: []string{}, Groups: []string(nil)},
+ }, details)
+
+ assert.NoError(t, err)
+}
+
+func TestLDAPUserProvider_GetDetailsExtended_ShouldParseError(t *testing.T) {
+ testCases := []struct {
+ name string
+ valueType string
+ multiValued bool
+ err string
+ }{
+ {
+ "ShouldHandleBadInteger",
+ ValueTypeInteger,
+ false,
+ "cannot parse 'example' with value 'abc' as integer: strconv.ParseFloat: parsing \"abc\": invalid syntax",
+ },
+ {
+ "ShouldHandleBadIntegerMV",
+ ValueTypeInteger,
+ true,
+ "cannot parse 'example' with value 'abc' as integer: strconv.ParseFloat: parsing \"abc\": invalid syntax",
+ },
+ {
+ "ShouldHandleBadBoolean",
+ ValueTypeBoolean,
+ false,
+ "cannot parse 'example' with value 'abc' as boolean: strconv.ParseBool: parsing \"abc\": invalid syntax",
+ },
+ {
+ "ShouldHandleBadBooleanMV",
+ ValueTypeBoolean,
+ true,
+ "cannot parse 'example' with value 'abc' as boolean: strconv.ParseBool: parsing \"abc\": invalid syntax",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ StreetAddress: "street",
+ Extra: map[string]schema.AuthenticationBackendLDAPAttributesAttribute{
+ "example": {
+ AuthenticationBackendExtraAttribute: schema.AuthenticationBackendExtraAttribute{
+ MultiValued: tc.multiValued,
+ ValueType: tc.valueType,
+ },
+ },
+ },
+ },
+ 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(&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{},
+ },
+ {
+ Name: "memberOf",
+ Values: []string{},
+ },
+ {
+ Name: "street",
+ Values: []string{"123 Banksia Ln"},
+ },
+ {
+ Name: "example",
+ Values: []string{"abc"},
+ },
+ },
+ },
+ },
+ }, nil)
+
+ gomock.InOrder(dialURL, connBind, searchProfile, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, tc.err)
+ })
+ }
+}
+
+func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadPictureURL(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ Picture: "photoURL",
+ },
+ 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(&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{},
+ },
+ {
+ Name: "memberOf",
+ Values: []string{},
+ },
+ {
+ Name: "photoURL",
+ Values: []string{"bad_+URL"},
+ },
+ },
+ },
+ },
+ }, nil)
+
+ searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
+
+ gomock.InOrder(dialURL, connBind, searchProfile, searchGroup, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "error occurred parsing user details for 'john': failed to parse the picture attribute 'photoURL' with value 'bad_+URL': parse \"bad_+URL\": invalid URI for request")
+}
+
+func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadProfileURL(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ Profile: "profile",
+ },
+ 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(&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{},
+ },
+ {
+ Name: "memberOf",
+ Values: []string{},
+ },
+ {
+ Name: "profile",
+ Values: []string{"bad_+URL"},
+ },
+ },
+ },
+ },
+ }, nil)
+
+ searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
+
+ gomock.InOrder(dialURL, connBind, searchProfile, searchGroup, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "error occurred parsing user details for 'john': failed to parse the profile attribute 'profile' with value 'bad_+URL': parse \"bad_+URL\": invalid URI for request")
+}
+
+func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadWebsiteURL(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ Website: "www",
+ },
+ 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(&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{},
+ },
+ {
+ Name: "memberOf",
+ Values: []string{},
+ },
+ {
+ Name: "www",
+ Values: []string{"bad_+URL"},
+ },
+ },
+ },
+ },
+ }, nil)
+
+ searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
+
+ gomock.InOrder(dialURL, connBind, searchProfile, searchGroup, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "error occurred parsing user details for 'john': failed to parse the website attribute 'www' with value 'bad_+URL': parse \"bad_+URL\": invalid URI for request")
+}
+
+func TestLDAPUserProvider_GetDetailsExtended_ShouldErrorBadLocale(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ Locale: "locale",
+ },
+ 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(&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{},
+ },
+ {
+ Name: "memberOf",
+ Values: []string{},
+ },
+ {
+ Name: "locale",
+ Values: []string{"ba12390-n2m3jkn123&!@#!_+"},
+ },
+ },
+ },
+ },
+ }, nil)
+
+ searchGroup := mockClient.EXPECT().Search(gomock.Any()).Return(createSearchResultWithAttributes(), nil)
+
+ gomock.InOrder(dialURL, connBind, searchProfile, searchGroup, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "error occurred parsing user details for 'john': failed to parse the locale attribute 'locale' with value 'ba12390-n2m3jkn123&!@#!_+': language: tag is not well-formed")
+}
+
func TestLDAPUserProvider_GetDetails_ShouldReturnOnUserError(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@@ -1210,6 +1938,135 @@ func TestLDAPUserProvider_GetDetails_ShouldReturnOnUserError(t *testing.T) {
assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: failed to search")
}
+func TestLDAPUserProvider_GetDetailsExtendedShouldReturnOnBindError(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ },
+ 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(fmt.Errorf("bad bind"))
+
+ connClose := mockClient.EXPECT().Close().Return(nil)
+
+ gomock.InOrder(dialURL, connBind, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "bind failed with error: bad bind")
+}
+
+func TestLDAPUserProvider_GetDetailsExtendedShouldReturnOnDialError(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ },
+ 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(nil, fmt.Errorf("failed to dial"))
+
+ gomock.InOrder(dialURL)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "dial failed with error: failed to dial")
+}
+
+func TestLDAPUserProvider_GetDetailsExtendedShouldReturnOnUserError(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ mockFactory := NewMockLDAPClientFactory(ctrl)
+ mockClient := NewMockLDAPClient(ctrl)
+
+ provider := NewLDAPUserProviderWithFactory(
+ schema.AuthenticationBackendLDAP{
+ Address: testLDAPAddress,
+ User: "cn=admin,dc=example,dc=com",
+ Password: "password",
+ Attributes: schema.AuthenticationBackendLDAPAttributes{
+ Username: "uid",
+ Mail: "mail",
+ DisplayName: "displayName",
+ MemberOf: "memberOf",
+ },
+ 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, fmt.Errorf("failed to search"))
+
+ gomock.InOrder(dialURL, connBind, searchProfile, connClose)
+
+ details, err := provider.GetDetailsExtended("john")
+ assert.Nil(t, details)
+ assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: failed to search")
+}
+
func TestLDAPUserProvider_GetDetails_ShouldReturnOnGroupsError(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()