diff --git a/user/manager.go b/user/manager.go index 34d96403..79fbe26b 100644 --- a/user/manager.go +++ b/user/manager.go @@ -639,6 +639,13 @@ func (a *Manager) Authorize(user *User, topic string, perm Permission) error { if user != nil && user.Role == RoleAdmin { return nil // Admin can do everything } + // A user always has full access to their own sync topic, which the apps use + // to sync subscriptions/settings across devices. Without this, an + // auth-default-access of "deny-all" locks the user out of their own sync + // topic (no ACL entry is created for it at user creation). See #733. + if user != nil && user.SyncTopic != "" && topic == user.SyncTopic { + return nil + } username := Everyone if user != nil { username = user.Name diff --git a/user/manager_test.go b/user/manager_test.go index 6d13929e..6e5a6a05 100644 --- a/user/manager_test.go +++ b/user/manager_test.go @@ -129,6 +129,13 @@ func TestManager_FullScenario_Default_DenyAll(t *testing.T) { require.Nil(t, a.Authorize(ben, "announcements", PermissionRead)) require.Equal(t, ErrUnauthorized, a.Authorize(ben, "announcements", PermissionWrite)) + // User has full access to their own sync topic, even under deny-all, + // but not to another user's sync topic (#733) + require.Nil(t, a.Authorize(ben, ben.SyncTopic, PermissionRead)) + require.Nil(t, a.Authorize(ben, ben.SyncTopic, PermissionWrite)) + require.Equal(t, ErrUnauthorized, a.Authorize(ben, john.SyncTopic, PermissionRead)) + require.Equal(t, ErrUnauthorized, a.Authorize(ben, john.SyncTopic, PermissionWrite)) + // User john should have // "deny" to mytopic_deny*, // "ro" to mytopic_ro*,