From 2975e4bd8ddaba00bb51a16bc0ccded4983863c1 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Mon, 23 Jun 2025 14:01:24 +0000 Subject: [PATCH] rbac: add spindle and spindle member ops Signed-off-by: oppiliappan --- rbac/rbac.go | 30 ++++++++++++++++++++++++++++++ rbac/rbac_test.go | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- rbac/util.go | 10 ++++++++++ 3 file(s) changed, 188 insertion(s)(+), 2 deletion(s)(-) diff --git a/rbac/rbac.go b/rbac/rbac.go --- a/rbac/rbac.go +++ b/rbac/rbac.go @@ -90,6 +90,12 @@ _, err = e.E.AddGroupingPolicy("server:owner", "server:member", spindle) return err } +func (e *Enforcer) RemoveSpindle(spindle string) error { + spindle = intoSpindle(spindle) + _, err := e.E.DeleteDomains(spindle) + return err +} + func (e *Enforcer) GetKnotsForUser(did string) ([]string, error) { keepFunc := isNotSpindle stripFunc := unSpindle @@ -106,16 +112,32 @@ func (e *Enforcer) AddKnotOwner(domain, owner string) error { return e.addOwner(domain, owner) } +func (e *Enforcer) RemoveKnotOwner(domain, owner string) error { + return e.removeOwner(domain, owner) +} + func (e *Enforcer) AddKnotMember(domain, member string) error { return e.addMember(domain, member) } +func (e *Enforcer) RemoveKnotMember(domain, member string) error { + return e.removeMember(domain, member) +} + func (e *Enforcer) AddSpindleOwner(domain, owner string) error { return e.addOwner(intoSpindle(domain), owner) } +func (e *Enforcer) RemoveSpindleOwner(domain, owner string) error { + return e.removeOwner(intoSpindle(domain), owner) +} + func (e *Enforcer) AddSpindleMember(domain, member string) error { return e.addMember(intoSpindle(domain), member) +} + +func (e *Enforcer) RemoveSpindleMember(domain, member string) error { + return e.removeMember(intoSpindle(domain), member) } func repoPolicies(member, domain, repo string) [][]string { @@ -194,6 +216,14 @@ } slices.Sort(membersWithoutRoles) return slices.Compact(membersWithoutRoles), nil +} + +func (e *Enforcer) GetKnotUsersByRole(role, domain string) ([]string, error) { + return e.GetUserByRole(role, domain) +} + +func (e *Enforcer) GetSpindleUsersByRole(role, domain string) ([]string, error) { + return e.GetUserByRole(role, intoSpindle(domain)) } func (e *Enforcer) GetUserByRoleInRepo(role, domain, repo string) ([]string, error) { diff --git a/rbac/rbac_test.go b/rbac/rbac_test.go --- a/rbac/rbac_test.go +++ b/rbac/rbac_test.go @@ -214,13 +214,24 @@ knots2, _ := e.GetKnotsForUser("did:plc:bar") assert.Contains(t, knots2, "example.com") } -func TestGetUserByRole(t *testing.T) { +func TestGetKnotUsersByRole(t *testing.T) { e := setup(t) _ = e.AddKnot("example.com") _ = e.AddKnotMember("example.com", "did:plc:foo") _ = e.AddKnotOwner("example.com", "did:plc:bar") - members, _ := e.GetUserByRole("server:member", "example.com") + members, _ := e.GetKnotUsersByRole("server:member", "example.com") + assert.Contains(t, members, "did:plc:foo") + assert.Contains(t, members, "did:plc:bar") // due to inheritance +} + +func TestGetSpindleUsersByRole(t *testing.T) { + e := setup(t) + _ = e.AddSpindle("example.com") + _ = e.AddSpindleMember("example.com", "did:plc:foo") + _ = e.AddSpindleOwner("example.com", "did:plc:bar") + + members, _ := e.GetSpindleUsersByRole("server:member", "example.com") assert.Contains(t, members, "did:plc:foo") assert.Contains(t, members, "did:plc:bar") // due to inheritance } @@ -301,3 +312,138 @@ ok, err = e.IsSpindleMember("did:plc:foo", "s.com") assert.NoError(t, err) assert.True(t, ok) } + +func TestRemoveKnotOwner(t *testing.T) { + e := setup(t) + + err := e.AddKnot("k.com") + assert.NoError(t, err) + + err = e.AddKnotOwner("k.com", "did:plc:foo") + assert.NoError(t, err) + + knots, err := e.GetKnotsForUser("did:plc:foo") + assert.NoError(t, err) + assert.ElementsMatch(t, []string{ + "k.com", + }, knots) + + err = e.RemoveKnotOwner("k.com", "did:plc:foo") + assert.NoError(t, err) + + knots, err = e.GetKnotsForUser("did:plc:foo") + assert.NoError(t, err) + assert.Empty(t, knots) +} + +func TestRemoveKnotMember(t *testing.T) { + e := setup(t) + + err := e.AddKnot("k.com") + assert.NoError(t, err) + + err = e.AddKnotOwner("k.com", "did:plc:foo") + assert.NoError(t, err) + + err = e.AddKnotMember("k.com", "did:plc:bar") + assert.NoError(t, err) + + knots, err := e.GetKnotsForUser("did:plc:bar") + assert.NoError(t, err) + assert.ElementsMatch(t, []string{ + "k.com", + }, knots) + + err = e.RemoveKnotMember("k.com", "did:plc:bar") + assert.NoError(t, err) + + knots, err = e.GetKnotsForUser("did:plc:bar") + assert.NoError(t, err) + assert.Empty(t, knots) +} + +func TestRemoveSpindleOwner(t *testing.T) { + e := setup(t) + + err := e.AddSpindle("s.com") + assert.NoError(t, err) + + err = e.AddSpindleOwner("s.com", "did:plc:foo") + assert.NoError(t, err) + + spindles, err := e.GetSpindlesForUser("did:plc:foo") + assert.NoError(t, err) + assert.ElementsMatch(t, []string{ + "s.com", + }, spindles) + + err = e.RemoveSpindleOwner("s.com", "did:plc:foo") + assert.NoError(t, err) + + spindles, err = e.GetSpindlesForUser("did:plc:foo") + assert.NoError(t, err) + assert.Empty(t, spindles) +} + +func TestRemoveSpindleMember(t *testing.T) { + e := setup(t) + + err := e.AddSpindle("s.com") + assert.NoError(t, err) + + err = e.AddSpindleOwner("s.com", "did:plc:foo") + assert.NoError(t, err) + + err = e.AddSpindleMember("s.com", "did:plc:bar") + assert.NoError(t, err) + + spindles, err := e.GetSpindlesForUser("did:plc:foo") + assert.NoError(t, err) + assert.ElementsMatch(t, []string{ + "s.com", + }, spindles) + + spindles, err = e.GetSpindlesForUser("did:plc:bar") + assert.NoError(t, err) + assert.ElementsMatch(t, []string{ + "s.com", + }, spindles) + + err = e.RemoveSpindleMember("s.com", "did:plc:bar") + assert.NoError(t, err) + + spindles, err = e.GetSpindlesForUser("did:plc:bar") + assert.NoError(t, err) + assert.Empty(t, spindles) +} + +func TestRemoveSpindle(t *testing.T) { + e := setup(t) + + err := e.AddSpindle("s.com") + assert.NoError(t, err) + + err = e.AddSpindleOwner("s.com", "did:plc:foo") + assert.NoError(t, err) + + err = e.AddSpindleMember("s.com", "did:plc:bar") + assert.NoError(t, err) + + users, err := e.GetSpindleUsersByRole("server:member", "s.com") + assert.NoError(t, err) + assert.ElementsMatch(t, []string{ + "did:plc:foo", + "did:plc:bar", + }, users) + + err = e.RemoveSpindle("s.com") + assert.NoError(t, err) + + // TODO: see this issue https://github.com/casbin/casbin/issues/1492 + // s, err := e.E.GetAllDomains() + // assert.Empty(t, s) + + spindles, err := e.GetSpindleUsersByRole("server:member", "s.com") + assert.NoError(t, err) + assert.Empty(t, spindles) +} diff --git a/rbac/util.go b/rbac/util.go --- a/rbac/util.go +++ b/rbac/util.go @@ -29,8 +29,18 @@ _, err := e.E.AddGroupingPolicy(owner, "server:owner", domain) return err } +func (e *Enforcer) removeOwner(domain, owner string) error { + _, err := e.E.RemoveGroupingPolicy(owner, "server:owner", domain) + return err +} + func (e *Enforcer) addMember(domain, member string) error { _, err := e.E.AddGroupingPolicy(member, "server:member", domain) + return err +} + +func (e *Enforcer) removeMember(domain, member string) error { + _, err := e.E.RemoveGroupingPolicy(member, "server:member", domain) return err } -- tangled.sh