diff --git a/user/manager.go b/user/manager.go index 324b7684..123edf84 100644 --- a/user/manager.go +++ b/user/manager.go @@ -161,7 +161,7 @@ const ( FROM user_access a JOIN user u ON u.id = a.user_id WHERE (u.user = ? OR u.user = ?) AND ? LIKE a.topic ESCAPE '\' - ORDER BY u.user DESC + ORDER BY u.user DESC, LENGTH(a.topic) DESC, a.write DESC ` insertUserQuery = ` @@ -197,13 +197,13 @@ const ( selectUserAllAccessQuery = ` SELECT user_id, topic, read, write FROM user_access - ORDER BY write DESC, read DESC, topic + ORDER BY LENGTH(topic) DESC, write DESC, read DESC, topic ` selectUserAccessQuery = ` SELECT topic, read, write FROM user_access WHERE user_id = (SELECT id FROM user WHERE user = ?) - ORDER BY write DESC, read DESC, topic + ORDER BY LENGTH(topic) DESC, write DESC, read DESC, topic ` selectUserReservationsQuery = ` SELECT a_user.topic, a_user.read, a_user.write, a_everyone.read AS everyone_read, a_everyone.write AS everyone_write diff --git a/user/manager_test.go b/user/manager_test.go index 468dc36a..9e645bff 100644 --- a/user/manager_test.go +++ b/user/manager_test.go @@ -20,10 +20,15 @@ func TestManager_FullScenario_Default_DenyAll(t *testing.T) { a := newTestManagerFromFile(t, filepath.Join(t.TempDir(), "user.db"), "", PermissionDenyAll, DefaultUserPasswordBcryptCost, DefaultUserStatsQueueWriterInterval) require.Nil(t, a.AddUser("phil", "phil", RoleAdmin)) require.Nil(t, a.AddUser("ben", "ben", RoleUser)) + require.Nil(t, a.AddUser("john", "john", RoleUser)) require.Nil(t, a.AllowAccess("ben", "mytopic", PermissionReadWrite)) require.Nil(t, a.AllowAccess("ben", "readme", PermissionRead)) require.Nil(t, a.AllowAccess("ben", "writeme", PermissionWrite)) require.Nil(t, a.AllowAccess("ben", "everyonewrite", PermissionDenyAll)) // How unfair! + require.Nil(t, a.AllowAccess("john", "*", PermissionRead)) + require.Nil(t, a.AllowAccess("john", "mytopic*", PermissionReadWrite)) + require.Nil(t, a.AllowAccess("john", "mytopic_ro*", PermissionRead)) + require.Nil(t, a.AllowAccess("john", "mytopic_deny*", PermissionDenyAll)) require.Nil(t, a.AllowAccess(Everyone, "announcements", PermissionRead)) require.Nil(t, a.AllowAccess(Everyone, "everyonewrite", PermissionReadWrite)) require.Nil(t, a.AllowAccess(Everyone, "up*", PermissionWrite)) // Everyone can write to /up* @@ -47,12 +52,27 @@ func TestManager_FullScenario_Default_DenyAll(t *testing.T) { benGrants, err := a.Grants("ben") require.Nil(t, err) require.Equal(t, []Grant{ + {"everyonewrite", PermissionDenyAll}, {"mytopic", PermissionReadWrite}, {"writeme", PermissionWrite}, {"readme", PermissionRead}, - {"everyonewrite", PermissionDenyAll}, }, benGrants) + john, err := a.Authenticate("john", "john") + require.Nil(t, err) + require.Equal(t, "john", john.Name) + require.True(t, strings.HasPrefix(john.Hash, "$2a$10$")) + require.Equal(t, RoleUser, john.Role) + + johnGrants, err := a.Grants("john") + require.Nil(t, err) + require.Equal(t, []Grant{ + {"mytopic_deny*", PermissionDenyAll}, + {"mytopic_ro*", PermissionRead}, + {"mytopic*", PermissionReadWrite}, + {"*", PermissionRead}, + }, johnGrants) + notben, err := a.Authenticate("ben", "this is wrong") require.Nil(t, notben) require.Equal(t, ErrUnauthenticated, err) @@ -78,6 +98,20 @@ 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 john should have + // "deny" to mytopic_deny*, + // "ro" to mytopic_ro*, + // "rw" to mytopic*, + // "ro" to the rest + require.Equal(t, ErrUnauthorized, a.Authorize(john, "mytopic_deny_case", PermissionRead)) + require.Equal(t, ErrUnauthorized, a.Authorize(john, "mytopic_deny_case", PermissionWrite)) + require.Nil(t, a.Authorize(john, "mytopic_ro_test_case", PermissionRead)) + require.Equal(t, ErrUnauthorized, a.Authorize(john, "mytopic_ro_test_case", PermissionWrite)) + require.Nil(t, a.Authorize(john, "mytopic_case1", PermissionRead)) + require.Nil(t, a.Authorize(john, "mytopic_case1", PermissionWrite)) + require.Nil(t, a.Authorize(john, "readme", PermissionRead)) + require.Equal(t, ErrUnauthorized, a.Authorize(john, "writeme", PermissionWrite)) + // Everyone else can do barely anything require.Equal(t, ErrUnauthorized, a.Authorize(nil, "sometopicnotinthelist", PermissionRead)) require.Equal(t, ErrUnauthorized, a.Authorize(nil, "sometopicnotinthelist", PermissionWrite)) @@ -227,10 +261,10 @@ func TestManager_UserManagement(t *testing.T) { benGrants, err := a.Grants("ben") require.Nil(t, err) require.Equal(t, []Grant{ + {"everyonewrite", PermissionDenyAll}, {"mytopic", PermissionReadWrite}, {"writeme", PermissionWrite}, {"readme", PermissionRead}, - {"everyonewrite", PermissionDenyAll}, }, benGrants) everyone, err := a.User(Everyone) @@ -1101,10 +1135,10 @@ func TestMigrationFrom1(t *testing.T) { require.Equal(t, syncTopicLength, len(ben.SyncTopic)) require.NotEqual(t, ben.SyncTopic, phil.SyncTopic) require.Equal(t, 2, len(benGrants)) - require.Equal(t, "stats", benGrants[0].TopicPattern) - require.Equal(t, PermissionReadWrite, benGrants[0].Allow) - require.Equal(t, "secret", benGrants[1].TopicPattern) - require.Equal(t, PermissionRead, benGrants[1].Allow) + require.Equal(t, "secret", benGrants[0].TopicPattern) + require.Equal(t, PermissionRead, benGrants[0].Allow) + require.Equal(t, "stats", benGrants[1].TopicPattern) + require.Equal(t, PermissionReadWrite, benGrants[1].Allow) require.Equal(t, "u_everyone", everyone.ID) require.Equal(t, Everyone, everyone.Name) @@ -1225,9 +1259,9 @@ func TestMigrationFrom4(t *testing.T) { require.Nil(t, err) require.Equal(t, 4, len(everyoneGrants)) - require.Equal(t, "down_*", everyoneGrants[0].TopicPattern) - require.Equal(t, "left_*", everyoneGrants[1].TopicPattern) - require.Equal(t, "mytopic_", everyoneGrants[2].TopicPattern) + require.Equal(t, "mytopic_", everyoneGrants[0].TopicPattern) + require.Equal(t, "down_*", everyoneGrants[1].TopicPattern) + require.Equal(t, "left_*", everyoneGrants[2].TopicPattern) require.Equal(t, "up*", everyoneGrants[3].TopicPattern) // Check they are stored correctly in the database