[#5674] fixed realtime auth 403 error on resubscribe
This commit is contained in:
parent
f5c6b9652f
commit
78e6a8996f
|
@ -3,6 +3,8 @@
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> **This is a prerelease intended for test and experimental purposes only!**
|
> **This is a prerelease intended for test and experimental purposes only!**
|
||||||
|
|
||||||
|
- Fixed realtime 403 API error on resubscribe ([#5674](https://github.com/pocketbase/pocketbase/issues/5674)).
|
||||||
|
|
||||||
- Fixed the auto OAuth2 avatar mapped field assignment when the OAuth2 provider doesn't return an avatar URL ([#5673](https://github.com/pocketbase/pocketbase/pull/5673)).
|
- Fixed the auto OAuth2 avatar mapped field assignment when the OAuth2 provider doesn't return an avatar URL ([#5673](https://github.com/pocketbase/pocketbase/pull/5673)).
|
||||||
_In case the avatar retrieval fails and the mapped record field "Required" option is not set, the error is silenced and only logged with WARN level._
|
_In case the avatar retrieval fails and the mapped record field "Required" option is not set, the error is silenced and only logged with WARN level._
|
||||||
|
|
||||||
|
|
|
@ -185,10 +185,9 @@ func realtimeSetSubscriptions(e *core.RequestEvent) error {
|
||||||
return e.NotFoundError("Missing or invalid client id.", err)
|
return e.NotFoundError("Missing or invalid client id.", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the previous request was authorized
|
// for now allow only guest->auth upgrades and any other auth change is forbidden
|
||||||
oldAuthId := extractAuthIdFromGetter(client)
|
clientAuth, _ := client.Get(RealtimeClientAuthKey).(*core.Record)
|
||||||
newAuthId := extractAuthIdFromGetter(e)
|
if clientAuth != nil && !isSameAuth(clientAuth, e.Auth) {
|
||||||
if oldAuthId != "" && oldAuthId != newAuthId {
|
|
||||||
return e.ForbiddenError("The current and the previous request authorization don't match.", nil)
|
return e.ForbiddenError("The current and the previous request authorization don't match.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,8 +534,8 @@ func realtimeBroadcastRecord(app core.App, action string, record *core.Record, d
|
||||||
// ignore the auth record email visibility checks
|
// ignore the auth record email visibility checks
|
||||||
// for auth owner, superuser or manager
|
// for auth owner, superuser or manager
|
||||||
if collection.IsAuth() {
|
if collection.IsAuth() {
|
||||||
authId := extractAuthIdFromGetter(client)
|
clientAuth, _ := client.Get(RealtimeClientAuthKey).(*core.Record)
|
||||||
if authId == cleanRecord.Id ||
|
if isSameAuth(clientAuth, cleanRecord) ||
|
||||||
realtimeCanAccessRecord(app, cleanRecord, requestInfo, collection.ManageRule) {
|
realtimeCanAccessRecord(app, cleanRecord, requestInfo, collection.ManageRule) {
|
||||||
cleanRecord.IgnoreEmailVisibility(true)
|
cleanRecord.IgnoreEmailVisibility(true)
|
||||||
}
|
}
|
||||||
|
@ -681,17 +680,16 @@ func realtimeUnsetDryCachedRecord(app core.App, action string, record *core.Reco
|
||||||
return group.Wait()
|
return group.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
type getter interface {
|
func isSameAuth(authA, authB *core.Record) bool {
|
||||||
Get(string) any
|
if authA == nil {
|
||||||
}
|
return authB == nil
|
||||||
|
|
||||||
func extractAuthIdFromGetter(val getter) string {
|
|
||||||
record, _ := val.Get(RealtimeClientAuthKey).(*core.Record)
|
|
||||||
if record != nil {
|
|
||||||
return record.Id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
if authB == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return authA.Id == authB.Id && authA.Collection().Id == authB.Collection().Id
|
||||||
}
|
}
|
||||||
|
|
||||||
// realtimeCanAccessRecord checks if the subscription client has access to the specified record model.
|
// realtimeCanAccessRecord checks if the subscription client has access to the specified record model.
|
||||||
|
|
|
@ -233,7 +233,7 @@ func TestRealtimeSubscribe(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "existing client - authorized superuser",
|
Name: "existing client - guest -> authorized superuser",
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: "/api/realtime",
|
URL: "/api/realtime",
|
||||||
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
|
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
|
||||||
|
@ -257,7 +257,7 @@ func TestRealtimeSubscribe(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "existing client - authorized regular record",
|
Name: "existing client - guest -> authorized regular auth record",
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: "/api/realtime",
|
URL: "/api/realtime",
|
||||||
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
|
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
|
||||||
|
@ -280,6 +280,38 @@ func TestRealtimeSubscribe(t *testing.T) {
|
||||||
resetClient()
|
resetClient()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "existing client - same auth",
|
||||||
|
Method: http.MethodPost,
|
||||||
|
URL: "/api/realtime",
|
||||||
|
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
|
||||||
|
Headers: map[string]string{
|
||||||
|
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.ZT3F0Z3iM-xbGgSG3LEKiEzHrPHr8t8IuHLZGGNuxLo",
|
||||||
|
},
|
||||||
|
ExpectedStatus: 204,
|
||||||
|
ExpectedEvents: map[string]int{
|
||||||
|
"*": 0,
|
||||||
|
"OnRealtimeSubscribeRequest": 1,
|
||||||
|
},
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
// the same user as the auth token
|
||||||
|
user, err := app.FindAuthRecordByEmail("users", "test@example.com")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Set(apis.RealtimeClientAuthKey, user)
|
||||||
|
|
||||||
|
app.SubscriptionsBroker().Register(client)
|
||||||
|
},
|
||||||
|
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
|
||||||
|
authRecord, _ := client.Get(apis.RealtimeClientAuthKey).(*core.Record)
|
||||||
|
if authRecord == nil {
|
||||||
|
t.Errorf("Expected auth record model, got nil")
|
||||||
|
}
|
||||||
|
resetClient()
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "existing client - mismatched auth",
|
Name: "existing client - mismatched auth",
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
|
|
Loading…
Reference in New Issue