From 56b756e16bc8ad08cd7d4449082d3efa80b14a6f Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Mon, 14 Oct 2024 14:31:39 +0300 Subject: [PATCH] [#5673] added check for empty OAuth2User.AvatarURL --- apis/record_auth_with_oauth2.go | 12 +++-- apis/record_auth_with_oauth2_test.go | 79 ++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/apis/record_auth_with_oauth2.go b/apis/record_auth_with_oauth2.go index fc8873c0..022818e2 100644 --- a/apis/record_auth_with_oauth2.go +++ b/apis/record_auth_with_oauth2.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "maps" "net/http" "time" @@ -236,7 +237,11 @@ func oauth2Submit(e *core.RecordAuthWithOAuth2RequestEvent, optExternalAuth *cor oldCanAssignUsername(txApp, e.Collection, e.OAuth2User.Username) { payload[e.Collection.OAuth2.MappedFields.Username] = e.OAuth2User.Username } - if _, ok := payload[e.Collection.OAuth2.MappedFields.AvatarURL]; !ok && e.Collection.OAuth2.MappedFields.AvatarURL != "" { + if _, ok := payload[e.Collection.OAuth2.MappedFields.AvatarURL]; !ok && + // no existing OAuth2 mapping + e.Collection.OAuth2.MappedFields.AvatarURL != "" && + // non-empty OAuth2 avatar url + e.OAuth2User.AvatarURL != "" { mappedField := e.Collection.Fields.GetByName(e.Collection.OAuth2.MappedFields.AvatarURL) if mappedField != nil && mappedField.Type() == core.FieldTypeFile { // download the avatar if the mapped field is a file @@ -246,9 +251,10 @@ func oauth2Submit(e *core.RecordAuthWithOAuth2RequestEvent, optExternalAuth *cor return filesystem.NewFileFromURL(ctx, e.OAuth2User.AvatarURL) }() if err != nil { - return err + txApp.Logger().Warn("Failed to retrieve OAuth2 avatar", slog.String("error", err.Error())) + } else { + payload[e.Collection.OAuth2.MappedFields.AvatarURL] = avatarFile } - payload[e.Collection.OAuth2.MappedFields.AvatarURL] = avatarFile } else { // otherwise - assign the url string payload[e.Collection.OAuth2.MappedFields.AvatarURL] = e.OAuth2User.AvatarURL diff --git a/apis/record_auth_with_oauth2_test.go b/apis/record_auth_with_oauth2_test.go index 7d226ce5..81804d61 100644 --- a/apis/record_auth_with_oauth2_test.go +++ b/apis/record_auth_with_oauth2_test.go @@ -1109,6 +1109,85 @@ func TestRecordAuthWithOAuth2(t *testing.T) { "OnRecordValidate": 4, }, }, + { + Name: "creating user (with mapped OAuth2 avatarURL field but empty OAuth2User.avatarURL value)", + Method: http.MethodPost, + URL: "/api/collections/users/auth-with-oauth2", + Body: strings.NewReader(`{ + "provider": "test", + "code":"123", + "redirectURL": "https://example.com" + }`), + BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + usersCol, err := app.FindCollectionByNameOrId("users") + if err != nil { + t.Fatal(err) + } + + // register the test provider + auth.Providers["test"] = func() auth.Provider { + return &oauth2MockProvider{ + AuthUser: &auth.AuthUser{ + Id: "oauth2_id", + Email: "oauth2@example.com", + AvatarURL: "", + }, + Token: &oauth2.Token{AccessToken: "abc"}, + } + } + + // add the test provider in the collection + usersCol.MFA.Enabled = false + usersCol.OAuth2.Enabled = true + usersCol.OAuth2.Providers = []core.OAuth2ProviderConfig{{ + Name: "test", + ClientId: "123", + ClientSecret: "456", + }} + usersCol.OAuth2.MappedFields = core.OAuth2KnownFields{ + AvatarURL: "avatar", + } + if err := app.Save(usersCol); err != nil { + t.Fatal(err) + } + }, + ExpectedStatus: 200, + ExpectedContent: []string{ + `"email":"oauth2@example.com"`, + `"emailVisibility":false`, + `"verified":true`, + `"avatar":""`, + }, + NotExpectedContent: []string{ + // hidden fields + `"tokenKey"`, + `"password"`, + }, + ExpectedEvents: map[string]int{ + "*": 0, + "OnRecordAuthWithOAuth2Request": 1, + "OnRecordAuthRequest": 1, + "OnRecordCreateRequest": 1, + "OnRecordEnrich": 2, // the auth response and from the create request + // --- + "OnModelCreate": 3, // record + authOrigins + externalAuths + "OnModelCreateExecute": 3, + "OnModelAfterCreateSuccess": 3, + "OnRecordCreate": 3, + "OnRecordCreateExecute": 3, + "OnRecordAfterCreateSuccess": 3, + // --- + "OnModelUpdate": 1, // created record verified state change + "OnModelUpdateExecute": 1, + "OnModelAfterUpdateSuccess": 1, + "OnRecordUpdate": 1, + "OnRecordUpdateExecute": 1, + "OnRecordAfterUpdateSuccess": 1, + // --- + "OnModelValidate": 4, + "OnRecordValidate": 4, + }, + }, { Name: "creating user (with mapped OAuth2 fields and avatarURL->non-file field)", Method: http.MethodPost,