package authentication import ( "fmt" "net/url" "os" "path/filepath" "testing" "github.com/go-crypt/crypt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/text/language" "github.com/authelia/authelia/v4/internal/configuration/schema" "github.com/authelia/authelia/v4/internal/expression" ) func TestDatabaseModel_Read(t *testing.T) { model := &FileDatabaseModel{} dir := t.TempDir() _, err := os.Create(filepath.Join(dir, "users_database.yml")) assert.NoError(t, err) assert.EqualError(t, model.Read(filepath.Join(dir, "users_database.yml")), "no file content") assert.NoError(t, os.Mkdir(filepath.Join(dir, "x"), 0000)) f := filepath.Join(dir, "x", "users_database.yml") assert.EqualError(t, model.Read(f), fmt.Sprintf("failed to read the '%s' file: open %s: permission denied", f, f)) f = filepath.Join(dir, "schema.yml") file, err := os.Create(f) assert.NoError(t, err) _, err = file.WriteString("users:\n\tjohn: {}") assert.NoError(t, err) assert.EqualError(t, model.Read(f), "could not parse the YAML database: yaml: line 2: found character that cannot start any token") } func TestDatabaseModelExtended(t *testing.T) { mustParseURI := func(in string) *url.URL { if u, err := url.ParseRequestURI(in); err != nil { panic(err) } else { return u } } mustParseTag := func(in string) *language.Tag { tag, err := language.Parse(in) if err != nil { panic(err) } return &tag } digest, digestErr := crypt.Decode("$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng") require.NoError(t, digestErr) testCases := []struct { name string have *FileDatabaseUserDetailsModel expected *FileUserDatabaseUserDetails details *UserDetailsExtended extra map[string]expression.ExtraAttribute err string errExtra string }{ { "ShouldHandleEmptyStruct", &FileDatabaseUserDetailsModel{}, nil, nil, nil, "error occurred decoding the password hash for 'example': provided encoded hash has an invalid format: the digest doesn't begin with the delimiter '$' and is not one of the other understood formats", "", }, { "ShouldHandleBadLocale", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", Locale: "Example", }, nil, nil, nil, "error occurred parsing user details for 'example': failed to parse the locale attribute with value 'Example': language: tag is not well-formed", "", }, { "ShouldHandleMinimal", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), }, &UserDetailsExtended{ UserDetails: &UserDetails{ Username: "example", Emails: []string(nil), Groups: []string(nil), }, }, nil, "", "", }, { "ShouldHandleMaximum", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": byte('1'), }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: mustParseURI("https://authelia.com"), Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{"example": byte('1')}, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), Website: mustParseURI("https://authelia.com"), Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": byte('1'), }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: false, ValueType: "boolean", }, }, "", "error occurred validating extra attributes for user 'example': attribute 'example' has the unknown type 'uint8'", }, { "ShouldHandleBadLocale", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en123kn12kj3n123", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": true, }, }, nil, nil, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: false, ValueType: "boolean", }, }, "error occurred parsing user details for 'example': failed to parse the locale attribute with value 'en123kn12kj3n123': language: tag is not well-formed", "", }, { "ShouldHandleBadProfile", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "notascheme://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": "1", }, }, nil, nil, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: false, ValueType: "string", }, }, "error occurred parsing user details for 'example': failed to parse the profile attribute with value 'notascheme://authelia.com/jsmith': invalid URL scheme 'notascheme' for profile attribute", "", }, { "ShouldHandleBadWebsite", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://@@:)!(@*#U!()@#!@.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": 1, }, }, nil, nil, map[string]expression.ExtraAttribute{}, "error occurred parsing user details for 'example': failed to parse the website attribute with value 'https://@@:)!(@*#U!()@#!@.com': parse \"https://@@:)!(@*#U!()@#!@.com\": net/url: invalid userinfo", "error occurred validating extra attributes for user 'example': attribute 'example' is unknown", }, { "ShouldHandleBadPicture", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "ahttps://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": 1, }, }, nil, nil, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: false, ValueType: "integer", }, }, "error occurred parsing user details for 'example': failed to parse the picture attribute with value 'ahttps://authelia.com/jsmith.jpg': invalid URL scheme 'ahttps' for profile attribute", "", }, { "ShouldHandleWrongExtraTypeMismatch", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": 1, }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: mustParseURI("https://authelia.com"), Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{ "example": 1, }, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), Website: mustParseURI("https://authelia.com"), Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": 1, }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: false, ValueType: "boolean", }, }, "", "error occurred validating extra attributes for user 'example': attribute 'example' has the known type 'int' but 'boolean' is the expected type", }, { "ShouldHandleArrayString", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{"abc", "123"}, }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: mustParseURI("https://authelia.com"), Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{ "example": []any{"abc", "123"}, }, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), Website: mustParseURI("https://authelia.com"), Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{"abc", "123"}, }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: true, ValueType: "string", }, }, "", "", }, { "ShouldHandleArrayInteger", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{123, 456}, }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: mustParseURI("https://authelia.com"), Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{ "example": []any{123, 456}, }, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), Website: mustParseURI("https://authelia.com"), Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{123, 456}, }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: true, ValueType: "integer", }, }, "", "", }, { "ShouldHandleArrayBoolean", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{true, false}, }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: mustParseURI("https://authelia.com"), Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{ "example": []any{true, false}, }, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), Website: mustParseURI("https://authelia.com"), Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{true, false}, }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: true, ValueType: "boolean", }, }, "", "", }, { "ShouldHandleArrayBooleanNotArray", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: "https://authelia.com", Profile: "https://authelia.com/jsmith", Picture: "https://authelia.com/jsmith.jpg", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": true, }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", Website: mustParseURI("https://authelia.com"), Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{ "example": true, }, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Profile: mustParseURI("https://authelia.com/jsmith"), Picture: mustParseURI("https://authelia.com/jsmith.jpg"), Website: mustParseURI("https://authelia.com"), Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": true, }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: true, ValueType: "boolean", }, }, "", "error occurred validating extra attributes for user 'example': attribute 'example' has the type 'bool' but '[]boolean' is the expected type", }, { "ShouldHandleArrayByte", &FileDatabaseUserDetailsModel{ Password: "$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng", DisplayName: "John Smith", Email: "jsmith@example.com", Groups: []string{"abc"}, GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: "en-US", PhoneNumber: "129812", PhoneExtension: "123", Address: &FileUserDatabaseUserDetailsAddressModel{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{byte('a'), byte('b')}, }, }, &FileUserDatabaseUserDetails{ Username: "example", Password: schema.NewPasswordDigest(digest), DisplayName: "John Smith", GivenName: "john", MiddleName: "jacob", FamilyName: "smith", Nickname: "johnny", Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Email: "jsmith@example.com", Groups: []string{"abc"}, Address: &FileUserDatabaseUserDetailsAddressModel{StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US"}, Extra: map[string]any{ "example": []any{byte('a'), byte('b')}, }, }, &UserDetailsExtended{ GivenName: "john", FamilyName: "smith", MiddleName: "jacob", Nickname: "johnny", Gender: "male", Birthdate: "2025", ZoneInfo: "unzone", Locale: mustParseTag("en-US"), PhoneNumber: "129812", PhoneExtension: "123", Address: &UserDetailsAddress{ StreetAddress: "123 Baker St", Locality: "Internet", Region: "Online", PostalCode: "98765", Country: "US", }, Extra: map[string]any{ "example": []any{byte('a'), byte('b')}, }, UserDetails: &UserDetails{ Username: "example", DisplayName: "John Smith", Emails: []string{"jsmith@example.com"}, Groups: []string{"abc"}, }, }, map[string]expression.ExtraAttribute{ "example": schema.AuthenticationBackendExtraAttribute{ MultiValued: true, ValueType: "boolean", }, }, "", "error occurred validating extra attributes for user 'example': attribute 'example' has the unknown item type 'uint8'", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { actual, err := tc.have.ToDatabaseUserDetailsModel("example") if len(tc.err) == 0 { assert.NoError(t, err) assert.Equal(t, tc.expected, actual) model := actual.ToUserDetailsModel() assert.Equal(t, tc.have, &model) details := actual.ToExtendedUserDetails() assert.Equal(t, tc.details, details) } else { assert.EqualError(t, err, tc.err) } if tc.extra != nil { if tc.errExtra == "" { assert.NoError(t, tc.have.ValidateExtra("example", tc.extra)) } else { assert.EqualError(t, tc.have.ValidateExtra("example", tc.extra), tc.errExtra) } } }) } }