Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7171268

Browse files
Emyrkpull[bot]
authored andcommitted
feat: Add cachable authorizer to elimate duplicate rbac calls (#6107)
* feat: Add cachable authorizer to elimate duplicate rbac calls Cache is context bound, so only prevents duplicate rbac calls in the same request context.
1 parent 5641c67 commit 7171268

File tree

6 files changed

+331
-99
lines changed

6 files changed

+331
-99
lines changed

coderd/coderdtest/authorize.go

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import (
1212
"testing"
1313
"time"
1414

15+
"github.com/coder/coder/cryptorand"
1516
"github.com/go-chi/chi/v5"
17+
"github.com/google/uuid"
18+
"github.com/moby/moby/pkg/namesgenerator"
1619
"github.com/stretchr/testify/assert"
1720
"github.com/stretchr/testify/require"
1821
"golang.org/x/xerrors"
@@ -543,9 +546,7 @@ func (a *AuthTester) Test(ctx context.Context, assertRoute map[string]RouteCheck
543546
}
544547

545548
type authCall struct {
546-
Actor rbac.Subject
547-
Action rbac.Action
548-
Object rbac.Object
549+
rbac.AuthCall
549550

550551
asserted bool
551552
}
@@ -621,9 +622,11 @@ func (r *RecordingAuthorizer) recordAuthorize(subject rbac.Subject, action rbac.
621622
r.Lock()
622623
defer r.Unlock()
623624
r.Called = append(r.Called, authCall{
624-
Actor: subject,
625-
Action: action,
626-
Object: object,
625+
AuthCall: rbac.AuthCall{
626+
Actor: subject,
627+
Action: action,
628+
Object: object,
629+
},
627630
})
628631
}
629632

@@ -743,3 +746,67 @@ func (f *fakePreparedAuthorizer) Authorize(ctx context.Context, object rbac.Obje
743746
func (*fakePreparedAuthorizer) CompileToSQL(_ context.Context, _ regosql.ConvertConfig) (string, error) {
744747
return "not a valid sql string", nil
745748
}
749+
750+
// Random rbac helper funcs
751+
752+
func RandomRBACAction() rbac.Action {
753+
all := rbac.AllActions()
754+
return all[must(cryptorand.Intn(len(all)))]
755+
}
756+
757+
func RandomRBACObject() rbac.Object {
758+
return rbac.Object{
759+
ID: uuid.NewString(),
760+
Owner: uuid.NewString(),
761+
OrgID: uuid.NewString(),
762+
Type: randomRBACType(),
763+
ACLUserList: map[string][]rbac.Action{
764+
namesgenerator.GetRandomName(1): {RandomRBACAction()},
765+
},
766+
ACLGroupList: map[string][]rbac.Action{
767+
namesgenerator.GetRandomName(1): {RandomRBACAction()},
768+
},
769+
}
770+
}
771+
772+
func randomRBACType() string {
773+
all := []string{
774+
rbac.ResourceWorkspace.Type,
775+
rbac.ResourceWorkspaceExecution.Type,
776+
rbac.ResourceWorkspaceApplicationConnect.Type,
777+
rbac.ResourceAuditLog.Type,
778+
rbac.ResourceTemplate.Type,
779+
rbac.ResourceGroup.Type,
780+
rbac.ResourceFile.Type,
781+
rbac.ResourceProvisionerDaemon.Type,
782+
rbac.ResourceOrganization.Type,
783+
rbac.ResourceRoleAssignment.Type,
784+
rbac.ResourceOrgRoleAssignment.Type,
785+
rbac.ResourceAPIKey.Type,
786+
rbac.ResourceUser.Type,
787+
rbac.ResourceUserData.Type,
788+
rbac.ResourceOrganizationMember.Type,
789+
rbac.ResourceWildcard.Type,
790+
rbac.ResourceLicense.Type,
791+
rbac.ResourceDeploymentConfig.Type,
792+
rbac.ResourceReplicas.Type,
793+
rbac.ResourceDebugInfo.Type,
794+
}
795+
return all[must(cryptorand.Intn(len(all)))]
796+
}
797+
798+
func RandomRBACSubject() rbac.Subject {
799+
return rbac.Subject{
800+
ID: uuid.NewString(),
801+
Roles: rbac.RoleNames{rbac.RoleMember()},
802+
Groups: []string{namesgenerator.GetRandomName(1)},
803+
Scope: rbac.ScopeAll,
804+
}
805+
}
806+
807+
func must[T any](value T, err error) T {
808+
if err != nil {
809+
panic(err)
810+
}
811+
return value
812+
}

coderd/coderdtest/authorize_test.go

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"testing"
66

7-
"github.com/moby/moby/pkg/namesgenerator"
87
"github.com/stretchr/testify/require"
98

109
"github.com/coder/coder/coderd/coderdtest"
@@ -34,7 +33,7 @@ func TestAuthzRecorder(t *testing.T) {
3433
rec := &coderdtest.RecordingAuthorizer{
3534
Wrapped: &coderdtest.FakeAuthorizer{},
3635
}
37-
sub := randomSubject()
36+
sub := coderdtest.RandomRBACSubject()
3837
pairs := fuzzAuthz(t, sub, rec, 10)
3938
rec.AssertActor(t, sub, pairs...)
4039
require.NoError(t, rec.AllAsserted(), "all assertions should have been made")
@@ -46,10 +45,10 @@ func TestAuthzRecorder(t *testing.T) {
4645
rec := &coderdtest.RecordingAuthorizer{
4746
Wrapped: &coderdtest.FakeAuthorizer{},
4847
}
49-
a := randomSubject()
48+
a := coderdtest.RandomRBACSubject()
5049
aPairs := fuzzAuthz(t, a, rec, 10)
5150

52-
b := randomSubject()
51+
b := coderdtest.RandomRBACSubject()
5352
bPairs := fuzzAuthz(t, b, rec, 10)
5453

5554
rec.AssertActor(t, b, bPairs...)
@@ -63,12 +62,12 @@ func TestAuthzRecorder(t *testing.T) {
6362
rec := &coderdtest.RecordingAuthorizer{
6463
Wrapped: &coderdtest.FakeAuthorizer{},
6564
}
66-
a := randomSubject()
65+
a := coderdtest.RandomRBACSubject()
6766
aPairs := fuzzAuthz(t, a, rec, 10)
6867

69-
b := randomSubject()
68+
b := coderdtest.RandomRBACSubject()
7069

71-
act, objTy := randomAction(), randomObject().Type
70+
act, objTy := coderdtest.RandomRBACAction(), coderdtest.RandomRBACObject().Type
7271
prep, _ := rec.Prepare(context.Background(), b, act, objTy)
7372
bPairs := fuzzAuthzPrep(t, prep, 10, act, objTy)
7473

@@ -84,7 +83,7 @@ func fuzzAuthzPrep(t *testing.T, prep rbac.PreparedAuthorized, n int, action rba
8483
pairs := make([]coderdtest.ActionObjectPair, 0, n)
8584

8685
for i := 0; i < n; i++ {
87-
obj := randomObject()
86+
obj := coderdtest.RandomRBACObject()
8887
obj.Type = objectType
8988
p := coderdtest.ActionObjectPair{Action: action, Object: obj}
9089
_ = prep.Authorize(context.Background(), p.Object)
@@ -98,37 +97,9 @@ func fuzzAuthz(t *testing.T, sub rbac.Subject, rec rbac.Authorizer, n int) []cod
9897
pairs := make([]coderdtest.ActionObjectPair, 0, n)
9998

10099
for i := 0; i < n; i++ {
101-
p := coderdtest.ActionObjectPair{Action: randomAction(), Object: randomObject()}
100+
p := coderdtest.ActionObjectPair{Action: coderdtest.RandomRBACAction(), Object: coderdtest.RandomRBACObject()}
102101
_ = rec.Authorize(context.Background(), sub, p.Action, p.Object)
103102
pairs = append(pairs, p)
104103
}
105104
return pairs
106105
}
107-
108-
func randomAction() rbac.Action {
109-
return rbac.Action(namesgenerator.GetRandomName(1))
110-
}
111-
112-
func randomObject() rbac.Object {
113-
return rbac.Object{
114-
ID: namesgenerator.GetRandomName(1),
115-
Owner: namesgenerator.GetRandomName(1),
116-
OrgID: namesgenerator.GetRandomName(1),
117-
Type: namesgenerator.GetRandomName(1),
118-
ACLUserList: map[string][]rbac.Action{
119-
namesgenerator.GetRandomName(1): {rbac.ActionRead},
120-
},
121-
ACLGroupList: map[string][]rbac.Action{
122-
namesgenerator.GetRandomName(1): {rbac.ActionRead},
123-
},
124-
}
125-
}
126-
127-
func randomSubject() rbac.Subject {
128-
return rbac.Subject{
129-
ID: namesgenerator.GetRandomName(1),
130-
Roles: rbac.RoleNames{rbac.RoleMember()},
131-
Groups: []string{namesgenerator.GetRandomName(1)},
132-
Scope: rbac.ScopeAll,
133-
}
134-
}

coderd/rbac/action.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ const (
99
ActionUpdate Action = "update"
1010
ActionDelete Action = "delete"
1111
)
12+
13+
// AllActions is a helper function to return all the possible actions types.
14+
func AllActions() []Action {
15+
return []Action{ActionCreate, ActionRead, ActionUpdate, ActionDelete}
16+
}

0 commit comments

Comments
 (0)