Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rbac middleware system #6103

Merged
merged 13 commits into from
Mar 21, 2022
4 changes: 3 additions & 1 deletion engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (api *API) InitRouter() {
api.Router.SetHeaderFunc = service.DefaultHeaders
api.Router.Middlewares = append(api.Router.Middlewares, api.tracingMiddleware, api.jwtMiddleware)
api.Router.DefaultAuthMiddleware = api.authMiddleware
api.Router.PostAuthMiddlewares = append(api.Router.PostAuthMiddlewares, api.xsrfMiddleware, api.maintenanceMiddleware)
api.Router.PostAuthMiddlewares = append(api.Router.PostAuthMiddlewares, api.xsrfMiddleware, api.maintenanceMiddleware, api.rbacMiddleware)
api.Router.PostMiddlewares = append(api.Router.PostMiddlewares, service.TracingPostMiddleware)

r := api.Router
Expand Down Expand Up @@ -449,6 +449,8 @@ func (api *API) InitRouter() {
r.Handle("/template/{groupName}/{templateSlug}/instance/{instanceID}", Scope(sdk.AuthConsumerScopeTemplate), r.DELETE(api.deleteTemplateInstanceHandler))
r.Handle("/template/{groupName}/{templateSlug}/usage", Scope(sdk.AuthConsumerScopeTemplate), r.GET(api.getTemplateUsageHandler))

r.Handle("/v2/project/{projectKey}/vcs", nil, r.POSTv2(api.addVCSOnProjectHandler))

//Not Found handler
r.Mux.NotFoundHandler = http.HandlerFunc(r.NotFoundHandler)

Expand Down
33 changes: 33 additions & 0 deletions engine/api/rbac/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package rbac

import (
"context"

"github.com/go-gorp/gorp"
"github.com/rockbears/log"

"github.com/ovh/cds/engine/api/project"
"github.com/ovh/cds/sdk"
)

func ProjectExist(ctx context.Context, db *gorp.DbMap, vars map[string]string) error {
log.Debug(ctx, "Rbac.ProjectExist")
sguiheux marked this conversation as resolved.
Show resolved Hide resolved
projectKey := vars["projectKey"]
exist, err := project.Exist(db, projectKey)
if err != nil {
return err
}
log.Info(ctx, "Result")
sguiheux marked this conversation as resolved.
Show resolved Hide resolved
if !exist {
return sdk.WithStack(sdk.ErrNotFound)
}
return nil
}

func ProjectManage(ctx context.Context, db *gorp.DbMap, vars map[string]string) error {
log.Debug(ctx, "Rbac.ProjectManage")
projectKey := vars["projectKey"]
// TODO Check role manage project
log.Debug(ctx, "Checking manage project role on %s", projectKey)
return nil
}
19 changes: 19 additions & 0 deletions engine/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,13 @@ func (r *Router) computeScopeDetails() {
// create temporary map of scopes, for each scope we will create a map of routes with methods.
m := make(map[sdk.AuthConsumerScope]map[string]map[string]struct{})

routeLoop:
for uri, cfg := range r.mapRouterConfigs {
for _, v := range cfg.Config {
if v.SkipCleanVariable {
continue routeLoop
}
}
var err error
uri, err = docSDK.CleanAndCheckURL(uri)
if err != nil {
Expand Down Expand Up @@ -490,6 +496,19 @@ func (r *Router) GET(h service.HandlerFunc, cfg ...service.HandlerConfigParam) *
return &rc
}

func (r *Router) POSTv2(h service.HandlerFuncV2, cfg ...service.HandlerConfigParam) *service.HandlerConfig {
var rc service.HandlerConfig
handler, rbacCheckers := h()
rc.Handler = handler
rc.RbacCheckers = rbacCheckers
rc.SkipCleanVariable = true
rc.Method = "POST"
for _, c := range cfg {
c(&rc)
}
return &rc
}

// POST will set given handler only for POST request
func (r *Router) POST(h service.HandlerFunc, cfg ...service.HandlerConfigParam) *service.HandlerConfig {
var rc service.HandlerConfig
Expand Down
19 changes: 19 additions & 0 deletions engine/api/router_middleware_rbac.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package api

import (
"context"
"net/http"

"github.com/gorilla/mux"

"github.com/ovh/cds/engine/service"
)

func (api *API) rbacMiddleware(ctx context.Context, _ http.ResponseWriter, req *http.Request, rc *service.HandlerConfig) (context.Context, error) {
for _, checker := range rc.RbacCheckers {
if err := checker(ctx, api.mustDB(), mux.Vars(req)); err != nil {
sguiheux marked this conversation as resolved.
Show resolved Hide resolved
return ctx, err
sguiheux marked this conversation as resolved.
Show resolved Hide resolved
}
}
return ctx, nil
}
28 changes: 28 additions & 0 deletions engine/api/v2_project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package api

import (
"context"
"github.com/gorilla/mux"
"github.com/ovh/cds/engine/api/rbac"
"github.com/rockbears/log"
"net/http"

"github.com/ovh/cds/engine/service"
)

func (api *API) addVCSOnProjectHandler() (service.Handler, []service.RbacChecker) {
sguiheux marked this conversation as resolved.
Show resolved Hide resolved
sguiheux marked this conversation as resolved.
Show resolved Hide resolved
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
pKey := vars["projKey"]

// my handler
log.Info(ctx, "My project: %s", pKey)
sguiheux marked this conversation as resolved.
Show resolved Hide resolved

return nil
}
permChecker := []service.RbacChecker{
rbac.ProjectExist,
rbac.ProjectManage,
}
return handler, permChecker
}
5 changes: 5 additions & 0 deletions engine/service/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sync"
"time"

"github.com/go-gorp/gorp"
"github.com/rockbears/log"
"gopkg.in/spacemonkeygo/httpsig.v0"

Expand All @@ -22,6 +23,7 @@ import (

// Handler defines the HTTP handler used in CDS engine
type Handler func(ctx context.Context, w http.ResponseWriter, r *http.Request) error
type RbacChecker func(ctx context.Context, db *gorp.DbMap, vars map[string]string) error
sguiheux marked this conversation as resolved.
Show resolved Hide resolved

// AsynchronousHandler defines the HTTP asynchronous handler used in CDS engine
type AsynchronousHandler func(ctx context.Context, r *http.Request) error
Expand All @@ -31,6 +33,7 @@ type Middleware func(ctx context.Context, w http.ResponseWriter, req *http.Reque

// HandlerFunc defines the way to instantiate a handler
type HandlerFunc func() Handler
type HandlerFuncV2 func() (Handler, []RbacChecker)

// AsynchronousHandlerFunc defines the way to instantiate a handler
type AsynchronousHandlerFunc func() AsynchronousHandler
Expand All @@ -54,6 +57,8 @@ type HandlerConfig struct {
AllowedScopes []sdk.AuthConsumerScope
PermissionLevel int
CleanURL string
RbacCheckers []RbacChecker
SkipCleanVariable bool
}

// Accepted is a helper function used by asynchronous handlers
Expand Down