diff --git a/user/manager.go b/user/manager.go index c8b1d39e..ea99ede2 100644 --- a/user/manager.go +++ b/user/manager.go @@ -676,6 +676,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 88d7d122..13497a3b 100644 --- a/user/manager_test.go +++ b/user/manager_test.go @@ -130,6 +130,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*,