Skip to content

Commit ed6fd1f

Browse files
committed
WIP
1 parent 8b54ea8 commit ed6fd1f

File tree

4 files changed

+83
-5
lines changed

4 files changed

+83
-5
lines changed

coderd/httpmw/rbac.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package httpmw
2+
3+
//func Can(action rbac.Action, object rbac.Object) func(http.Handler) http.Handler {
4+
// return func(next http.Handler) http.Handler {
5+
// return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
6+
//
7+
// },
8+
// }
9+
//}

coderd/rbac/builtin.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package rbac
2+
3+
import (
4+
"strings"
5+
6+
"golang.org/x/xerrors"
7+
)
8+
9+
const (
10+
Admin = "admin"
11+
Member = "member"
12+
13+
OrganizationMember = "organization-member"
14+
OrganizationAdmin = "organization-admin"
15+
)
16+
17+
// RoleByName returns the permissions associated with a given role name.
18+
// This allows just the role names to be stored.
19+
func RoleByName(name string) (Role, error) {
20+
arr := strings.Split(name, ":")
21+
if len(arr) > 2 {
22+
return Role{}, xerrors.Errorf("too many semicolons in role name")
23+
}
24+
25+
roleName := arr[0]
26+
var scopeID string
27+
if len(arr) > 1 {
28+
scopeID = arr[1]
29+
}
30+
31+
// If the role requires a scope, the scope will be checked at the end
32+
// of the switch statement.
33+
var scopedRole Role
34+
switch roleName {
35+
case Admin:
36+
return RoleAdmin, nil
37+
case Member:
38+
return RoleMember, nil
39+
case OrganizationMember:
40+
scopedRole = RoleOrgMember(scopeID)
41+
case OrganizationAdmin:
42+
scopedRole = RoleOrgAdmin(scopeID)
43+
default:
44+
// No role found
45+
return Role{}, xerrors.Errorf("role %q not found", roleName)
46+
}
47+
48+
// Scoped roles should be checked their scope is set
49+
if scopeID == "" {
50+
return Role{}, xerrors.Errorf("%q requires a scope id", roleName)
51+
}
52+
53+
return scopedRole, nil
54+
}
55+
56+
func RoleName(name string, scopeID string) string {
57+
if scopeID == "" {
58+
return name
59+
}
60+
return name + ":" + scopeID
61+
}

coderd/rbac/example_test.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ func TestExample(t *testing.T) {
2222
user := subject{
2323
UserID: "alice",
2424
Roles: []rbac.Role{
25-
rbac.RoleOrgAdmin("default"),
26-
rbac.RoleMember,
25+
must(rbac.RoleByName(rbac.Member)),
26+
must(rbac.RoleByName(rbac.RoleName(rbac.OrganizationMember, "default"))),
2727
},
2828
}
2929

@@ -52,3 +52,10 @@ func TestExample(t *testing.T) {
5252
require.NoError(t, err, "this user can read workspace '1234'")
5353
})
5454
}
55+
56+
func must[T any](value T, err error) T {
57+
if err != nil {
58+
panic(err)
59+
}
60+
return value
61+
}

coderd/rbac/role.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package rbac
22

33
import "fmt"
44

5+
// Permission is the format passed into the rego.
56
type Permission struct {
67
// Negate makes this a negative permission
78
Negate bool `json:"negate"`
@@ -57,7 +58,7 @@ var (
5758

5859
func RoleOrgDenyAll(orgID string) Role {
5960
return Role{
60-
Name: "org-deny-" + orgID,
61+
Name: RoleName("org-deny", orgID),
6162
Org: map[string][]Permission{
6263
orgID: {
6364
{
@@ -75,7 +76,7 @@ func RoleOrgDenyAll(orgID string) Role {
7576
// organization scope.
7677
func RoleOrgAdmin(orgID string) Role {
7778
return Role{
78-
Name: "org-admin-" + orgID,
79+
Name: RoleName("org-admin:", orgID)
7980
Org: map[string][]Permission{
8081
orgID: {
8182
{
@@ -93,7 +94,7 @@ func RoleOrgAdmin(orgID string) Role {
9394
// organization scope.
9495
func RoleOrgMember(orgID string) Role {
9596
return Role{
96-
Name: "org-member-" + orgID,
97+
Name: RoleName("org-member:" , orgID),
9798
Org: map[string][]Permission{
9899
orgID: {},
99100
},

0 commit comments

Comments
 (0)