diff --git a/internal/authentication/const.go b/internal/authentication/const.go index f93d0ea5b..51dc84db5 100644 --- a/internal/authentication/const.go +++ b/internal/authentication/const.go @@ -2,20 +2,8 @@ package authentication import ( "errors" -) -// Level is the type representing a level of authentication. -type Level int - -const ( - // NotAuthenticated if the user is not authenticated yet. - NotAuthenticated Level = iota - - // OneFactor if the user has passed first factor only. - OneFactor - - // TwoFactor if the user has passed two factors. - TwoFactor + "golang.org/x/text/encoding/unicode" ) const ( @@ -109,3 +97,7 @@ const fileAuthenticationMode = 0600 // OWASP recommends to escape some special characters. // https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.md const specialLDAPRunes = ",#+<>;\"=" + +var ( + encodingUTF16LittleEndian = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) +) diff --git a/internal/authentication/ldap_user_provider.go b/internal/authentication/ldap_user_provider.go index d2bb2603f..5596872c0 100644 --- a/internal/authentication/ldap_user_provider.go +++ b/internal/authentication/ldap_user_provider.go @@ -215,7 +215,7 @@ func (p *LDAPUserProvider) UpdatePassword(username, password string) (err error) modifyRequest := ldap.NewModifyRequest(profile.DN, controls) // The password needs to be enclosed in quotes // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2 - pwdEncoded, _ := utf16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", password)) + pwdEncoded, _ := encodingUTF16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", password)) modifyRequest.Replace(ldapAttributeUnicodePwd, []string{pwdEncoded}) err = p.modify(client, modifyRequest) diff --git a/internal/authentication/ldap_user_provider_test.go b/internal/authentication/ldap_user_provider_test.go index 97c9dc749..7dc7c7e20 100644 --- a/internal/authentication/ldap_user_provider_test.go +++ b/internal/authentication/ldap_user_provider_test.go @@ -1604,7 +1604,7 @@ func TestShouldUpdateUserPasswordMSAD(t *testing.T) { []ldap.Control{&controlMsftServerPolicyHints{ldapOIDControlMsftServerPolicyHints}}, ) - pwdEncoded, _ := utf16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) + pwdEncoded, _ := encodingUTF16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) modifyRequest.Replace(ldapAttributeUnicodePwd, []string{pwdEncoded}) dialURLOIDs := mockFactory.EXPECT(). @@ -1715,7 +1715,7 @@ func TestShouldUpdateUserPasswordMSADWithReferrals(t *testing.T) { []ldap.Control{&controlMsftServerPolicyHints{ldapOIDControlMsftServerPolicyHints}}, ) - pwdEncoded, _ := utf16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) + pwdEncoded, _ := encodingUTF16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) modifyRequest.Replace(ldapAttributeUnicodePwd, []string{pwdEncoded}) dialURLOIDs := mockFactory.EXPECT(). @@ -1843,7 +1843,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralConnectErr(t *test []ldap.Control{&controlMsftServerPolicyHints{ldapOIDControlMsftServerPolicyHints}}, ) - pwdEncoded, _ := utf16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) + pwdEncoded, _ := encodingUTF16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) modifyRequest.Replace(ldapAttributeUnicodePwd, []string{pwdEncoded}) dialURLOIDs := mockFactory.EXPECT(). @@ -1962,7 +1962,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralModifyErr(t *testi []ldap.Control{&controlMsftServerPolicyHints{ldapOIDControlMsftServerPolicyHints}}, ) - pwdEncoded, _ := utf16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) + pwdEncoded, _ := encodingUTF16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) modifyRequest.Replace(ldapAttributeUnicodePwd, []string{pwdEncoded}) dialURLOIDs := mockFactory.EXPECT(). @@ -2094,7 +2094,7 @@ func TestShouldUpdateUserPasswordMSADWithoutReferrals(t *testing.T) { []ldap.Control{&controlMsftServerPolicyHints{ldapOIDControlMsftServerPolicyHints}}, ) - pwdEncoded, _ := utf16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) + pwdEncoded, _ := encodingUTF16LittleEndian.NewEncoder().String(fmt.Sprintf("\"%s\"", "password")) modifyRequest.Replace(ldapAttributeUnicodePwd, []string{pwdEncoded}) dialURLOIDs := mockFactory.EXPECT(). diff --git a/internal/authentication/types.go b/internal/authentication/types.go index df96dc3ad..e210bb10f 100644 --- a/internal/authentication/types.go +++ b/internal/authentication/types.go @@ -6,7 +6,6 @@ import ( "time" "github.com/go-ldap/ldap/v3" - "golang.org/x/text/encoding/unicode" ) // LDAPClientFactory an interface of factory of LDAP clients. @@ -103,4 +102,30 @@ type LDAPSupportedControlTypes struct { MsftPwdPolHintsDeprecated bool } -var utf16LittleEndian = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) +// Level is the type representing a level of authentication. +type Level int + +const ( + // NotAuthenticated if the user is not authenticated yet. + NotAuthenticated Level = iota + + // OneFactor if the user has passed first factor only. + OneFactor + + // TwoFactor if the user has passed two factors. + TwoFactor +) + +// String returns a string representation of an authentication.Level. +func (l Level) String() string { + switch l { + case NotAuthenticated: + return "not_authenticated" + case OneFactor: + return "one_factor" + case TwoFactor: + return "two_factor" + default: + return "invalid" + } +} diff --git a/internal/authentication/types_test.go b/internal/authentication/types_test.go new file mode 100644 index 000000000..99a683843 --- /dev/null +++ b/internal/authentication/types_test.go @@ -0,0 +1,42 @@ +package authentication + +import ( + "net/mail" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUserDetails_Addresses(t *testing.T) { + details := &UserDetails{} + + assert.Equal(t, []mail.Address(nil), details.Addresses()) + + details = &UserDetails{ + DisplayName: "Example", + Emails: []string{"abc@123.com"}, + } + + assert.Equal(t, []mail.Address{{Name: "Example", Address: "abc@123.com"}}, details.Addresses()) + + details = &UserDetails{ + DisplayName: "Example", + Emails: []string{"abc@123.com", "two@apple.com"}, + } + + assert.Equal(t, []mail.Address{{Name: "Example", Address: "abc@123.com"}, {Name: "Example", Address: "two@apple.com"}}, details.Addresses()) + + details = &UserDetails{ + DisplayName: "", + Emails: []string{"abc@123.com"}, + } + + assert.Equal(t, []mail.Address{{Address: "abc@123.com"}}, details.Addresses()) +} + +func TestLevel_String(t *testing.T) { + assert.Equal(t, "one_factor", OneFactor.String()) + assert.Equal(t, "two_factor", TwoFactor.String()) + assert.Equal(t, "not_authenticated", NotAuthenticated.String()) + assert.Equal(t, "invalid", Level(-1).String()) +} diff --git a/internal/authentication/util.go b/internal/authentication/util.go deleted file mode 100644 index 075e45fab..000000000 --- a/internal/authentication/util.go +++ /dev/null @@ -1,15 +0,0 @@ -package authentication - -// String returns a string representation of an authentication.Level. -func (l Level) String() string { - switch l { - case NotAuthenticated: - return "not_authenticated" - case OneFactor: - return "one_factor" - case TwoFactor: - return "two_factor" - default: - return "invalid" - } -}