Skip to content

Commit 2161f84

Browse files
committed
WIP: Using middleware to change auth object params
Authorize can be changed dynamically with middlewares.
1 parent 30e2031 commit 2161f84

File tree

4 files changed

+34
-29
lines changed

4 files changed

+34
-29
lines changed

coderd/coderd.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ func New(options *Options) (http.Handler, func()) {
8181

8282
authRolesMiddleware := httpmw.ExtractUserRoles(options.Database)
8383

84-
authorize := func(actions ...rbac.Action) func(http.Handler) http.Handler {
85-
return httpmw.Authorize(api.Logger, api.Authorizer, actions...)
84+
authorize := func(f http.HandlerFunc, actions rbac.Action) func(http.Handler) http.Handler {
85+
return httpmw.Authorize(api.Logger, api.Authorizer, actions)
8686
}
8787

8888
r := chi.NewRouter()
@@ -121,8 +121,6 @@ func New(options *Options) (http.Handler, func()) {
121121
apiKeyMiddleware,
122122
httpmw.ExtractOrganizationParam(options.Database),
123123
authRolesMiddleware,
124-
// All authorize() functions will be scoped to this organization
125-
httpmw.InOrg(httpmw.OrganizationParam),
126124
)
127125
r.Get("/", api.organization)
128126
r.Get("/provisionerdaemons", api.provisionerDaemonsByOrganization)
@@ -143,7 +141,8 @@ func New(options *Options) (http.Handler, func()) {
143141
})
144142
r.Route("/members", func(r chi.Router) {
145143
r.Route("/roles", func(r chi.Router) {
146-
r.With(httpmw.Object(rbac.ResourceUserRole), authorize(rbac.ActionCreate, rbac.ActionDelete)).Get("/", api.assignableOrgRoles)
144+
r.Use(httpmw.Object(rbac.ResourceUserRole))
145+
r.Get("/", authorize(api.assignableOrgRoles, rbac.ActionCreate))
147146
})
148147
r.Route("/{user}", func(r chi.Router) {
149148
r.Use(

coderd/httpmw/authorize.go

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@ type AuthObject struct {
2727

2828
// Object is that base static object the above functions can modify.
2929
Object rbac.Object
30-
//// Actions are the various actions the middleware will check can be done on the object.
31-
//Actions []rbac.Action
3230
}
3331

34-
func WithOwner(owner func(r *http.Request) database.User) func(http.Handler) http.Handler {
32+
func RBACWithOwner(owner func(r *http.Request) database.User) func(http.Handler) http.Handler {
3533
return func(next http.Handler) http.Handler {
3634
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
3735
ao := GetAuthObject(r)
@@ -45,7 +43,7 @@ func WithOwner(owner func(r *http.Request) database.User) func(http.Handler) htt
4543
}
4644
}
4745

48-
func InOrg(org func(r *http.Request) database.Organization) func(http.Handler) http.Handler {
46+
func RBACInOrg(org func(r *http.Request) database.Organization) func(http.Handler) http.Handler {
4947
return func(next http.Handler) http.Handler {
5048
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
5149
ao := GetAuthObject(r)
@@ -61,13 +59,18 @@ func InOrg(org func(r *http.Request) database.Organization) func(http.Handler) h
6159

6260
// Authorize allows for static object & action authorize checking. If the object is a static object, this is an easy way
6361
// to enforce the route.
64-
func Authorize(logger slog.Logger, auth *rbac.RegoAuthorizer, actions ...rbac.Action) func(http.Handler) http.Handler {
62+
func Authorize(logger slog.Logger, auth *rbac.RegoAuthorizer, action rbac.Action) func(http.Handler) http.Handler {
6563
return func(next http.Handler) http.Handler {
6664
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
6765
roles := UserRoles(r)
6866
args := GetAuthObject(r)
6967

7068
object := args.Object
69+
organization, ok := r.Context().Value(organizationParamContextKey{}).(database.Organization)
70+
if ok {
71+
object = object.InOrg(organization.ID)
72+
}
73+
7174
if args.InOrg != nil {
7275
object.InOrg(args.InOrg(r))
7376
}
@@ -79,26 +82,24 @@ func Authorize(logger slog.Logger, auth *rbac.RegoAuthorizer, actions ...rbac.Ac
7982
}
8083

8184
// Error on the first action that fails
82-
for _, act := range actions {
83-
err := auth.AuthorizeByRoleName(r.Context(), roles.ID.String(), roles.Roles, act, object)
84-
if err != nil {
85-
var internalError *rbac.UnauthorizedError
86-
if xerrors.As(err, internalError) {
87-
logger = logger.With(slog.F("internal", internalError.Internal()))
88-
}
89-
logger.Warn(r.Context(), "unauthorized",
90-
slog.F("roles", roles.Roles),
91-
slog.F("user_id", roles.ID),
92-
slog.F("username", roles.Username),
93-
slog.F("route", r.URL.Path),
94-
slog.F("action", act),
95-
slog.F("object", object),
96-
)
97-
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
98-
Message: err.Error(),
99-
})
100-
return
85+
err := auth.AuthorizeByRoleName(r.Context(), roles.ID.String(), roles.Roles, action, object)
86+
if err != nil {
87+
var internalError *rbac.UnauthorizedError
88+
if xerrors.As(err, internalError) {
89+
logger = logger.With(slog.F("internal", internalError.Internal()))
10190
}
91+
logger.Warn(r.Context(), "unauthorized",
92+
slog.F("roles", roles.Roles),
93+
slog.F("user_id", roles.ID),
94+
slog.F("username", roles.Username),
95+
slog.F("route", r.URL.Path),
96+
slog.F("action", action),
97+
slog.F("object", object),
98+
)
99+
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
100+
Message: err.Error(),
101+
})
102+
return
102103
}
103104
next.ServeHTTP(rw, r)
104105
})

coderd/httpmw/organizationparam.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ func ExtractOrganizationParam(db database.Store) func(http.Handler) http.Handler
7777

7878
ctx := context.WithValue(r.Context(), organizationParamContextKey{}, organization)
7979
ctx = context.WithValue(ctx, organizationMemberParamContextKey{}, organizationMember)
80+
81+
next = RBACInOrg(func(r *http.Request) database.Organization {
82+
return organization
83+
})(next)
8084
next.ServeHTTP(rw, r.WithContext(ctx))
8185
})
8286
}

coderd/rbac/authz.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func (a RegoAuthorizer) AuthorizeByRoleName(ctx context.Context, subjectID strin
5050
}
5151
roles = append(roles, r)
5252
}
53+
5354
return a.Authorize(ctx, subjectID, roles, action, object)
5455
}
5556

0 commit comments

Comments
 (0)