Skip to content

Commit

Permalink
feat: support middleware group slug (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
mabdh authored Oct 5, 2023
1 parent 1e1effa commit 7a71e4f
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 11 deletions.
2 changes: 1 addition & 1 deletion cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func StartServer(logger *log.Zap, cfg *config.Shield) error {
}

// serving proxies
cbs, cps, err := serveProxies(ctx, logger, cfg.App.IdentityProxyHeader, cfg.App.UserIDHeader, cfg.Proxy, deps.ResourceService, deps.RelationService, deps.UserService, deps.ProjectService, deps.RelationAdapter)
cbs, cps, err := serveProxies(ctx, logger, cfg.App.IdentityProxyHeader, cfg.App.UserIDHeader, cfg.Proxy, deps.ResourceService, deps.RelationService, deps.UserService, deps.GroupService, deps.ProjectService, deps.RelationAdapter)
if err != nil {
return err
}
Expand Down
7 changes: 5 additions & 2 deletions cmd/serve_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"

"github.com/goto/salt/log"
"github.com/goto/shield/core/group"
"github.com/goto/shield/core/project"
"github.com/goto/shield/core/relation"
"github.com/goto/shield/core/resource"
Expand Down Expand Up @@ -34,6 +35,7 @@ func serveProxies(
resourceService *resource.Service,
relationService *relation.Service,
userService *user.Service,
groupService *group.Service,
projectService *project.Service,
relationAdapter *adapter.Relation,
) ([]func() error, []func(ctx context.Context) error, error) {
Expand Down Expand Up @@ -66,7 +68,7 @@ func serveProxies(

ruleService := rule.NewService(ruleBlobRepository)

middlewarePipeline := buildMiddlewarePipeline(logger, h2cProxy, identityProxyHeaderKey, userIDHeaderKey, resourceService, userService, ruleService, projectService)
middlewarePipeline := buildMiddlewarePipeline(logger, h2cProxy, identityProxyHeaderKey, userIDHeaderKey, resourceService, userService, groupService, ruleService, projectService)

cps := proxy.Serve(ctx, logger, svcConfig, middlewarePipeline)
cleanUpProxies = append(cleanUpProxies, cps)
Expand All @@ -93,12 +95,13 @@ func buildMiddlewarePipeline(
identityProxyHeaderKey, userIDHeaderKey string,
resourceService *resource.Service,
userService *user.Service,
groupService *group.Service,
ruleService *rule.Service,
projectService *project.Service,
) http.Handler {
// Note: execution order is bottom up
prefixWare := prefix.New(logger, proxy)
casbinAuthz := authz.New(logger, prefixWare, userIDHeaderKey, resourceService, userService)
casbinAuthz := authz.New(logger, prefixWare, userIDHeaderKey, resourceService, userService, groupService)
basicAuthn := basic_auth.New(logger, casbinAuthz)
attributeExtractor := attributes.New(logger, basicAuthn, identityProxyHeaderKey, projectService)
matchWare := rulematch.New(logger, attributeExtractor, rulematch.NewRouteMatcher(ruleService))
Expand Down
43 changes: 38 additions & 5 deletions internal/proxy/middleware/authz/authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import (
"github.com/mitchellh/mapstructure"

"github.com/goto/shield/core/action"
"github.com/goto/shield/core/group"
"github.com/goto/shield/core/resource"
"github.com/goto/shield/core/user"
"github.com/goto/shield/internal/proxy/middleware"
"github.com/goto/shield/internal/schema"
"github.com/goto/shield/pkg/body_extractor"
"github.com/goto/shield/pkg/uuid"
)

type ResourceService interface {
Expand All @@ -25,12 +28,17 @@ type UserService interface {
FetchCurrentUser(ctx context.Context) (user.User, error)
}

type GroupService interface {
GetBySlug(ctx context.Context, slug string) (group.Group, error)
}

type Authz struct {
log log.Logger
userIDHeaderKey string
next http.Handler
resourceService ResourceService
userService UserService
groupService GroupService
}

type Config struct {
Expand All @@ -50,13 +58,15 @@ func New(
next http.Handler,
userIDHeaderKey string,
resourceService ResourceService,
userService UserService) *Authz {
userService UserService,
groupService GroupService) *Authz {
return &Authz{
log: log,
userIDHeaderKey: userIDHeaderKey,
next: next,
resourceService: resourceService,
userService: userService,
groupService: groupService,
}
}

Expand Down Expand Up @@ -209,10 +219,13 @@ func (c *Authz) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

isAuthorized := false
for _, permission := range config.Permissions {
isAuthorized, err = c.resourceService.CheckAuthz(req.Context(), resource.Resource{
Name: permissionAttributes[permission.Attribute].(string),
NamespaceID: permission.Namespace,
}, action.Action{
res, err := c.preparePermissionResource(req.Context(), permission, permissionAttributes)
if err != nil {
c.log.Error("error while preparing permission resource", "err", err)
c.notAllowed(rw, err)
return
}
isAuthorized, err = c.resourceService.CheckAuthz(req.Context(), res, action.Action{
ID: permission.Name,
})
if err != nil {
Expand All @@ -235,6 +248,26 @@ func (c *Authz) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
c.next.ServeHTTP(rw, req)
}

func (c Authz) preparePermissionResource(ctx context.Context, perm Permission, attrs map[string]interface{}) (resource.Resource, error) {
resourceName := attrs[perm.Attribute].(string)
res := resource.Resource{
Name: resourceName,
NamespaceID: perm.Namespace,
}

if perm.Namespace == schema.GroupNamespace {
// resolve group id from slug
if !uuid.IsValid(resourceName) {
grp, err := c.groupService.GetBySlug(ctx, resourceName)
if err != nil {
return resource.Resource{}, err
}
res.Name = grp.ID
}
}
return res, nil
}

func (w Authz) notAllowed(rw http.ResponseWriter, err error) {
if err != nil {
switch {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e_test/smoke/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (s *EndToEndProxySmokeTestSuite) TestProxyToEchoServer() {
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(reqBodyBytes))
s.Require().NoError(err)

req.Header.Set(testbench.IdentityHeader, "member2[email protected]")
req.Header.Set(testbench.IdentityHeader, "admin1-group1-org1@gotocompany.com")
req.Header.Set("X-Shield-Org", s.orgID)

res, err := http.DefaultClient.Do(req)
Expand Down
2 changes: 1 addition & 1 deletion test/e2e_test/testbench/spicedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func migrateSpiceDB(logger log.Logger, network *docker.Network, pool *dockertest
return err
}

if err := resource.Expire(120); err != nil {
if err := resource.Expire(360); err != nil {
return err
}

Expand Down
13 changes: 12 additions & 1 deletion test/e2e_test/testbench/testdata/configs/rules/rule.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
rules:
- backends:
- name: entropy
target: "http://localhost:51266"
target: "http://localhost:60127"
frontends:
- name: ping
path: "/api/ping"
Expand Down Expand Up @@ -40,6 +40,17 @@ rules:
- name: create_resource_group_slug
path: "/api/resource_slug"
method: "POST"
middlewares:
- name: authz
config:
attributes:
owner_group:
value: org1-group1
type: constant
permissions:
- name: view
namespace: shield/group
attribute: owner_group
hooks:
- name: authz
config:
Expand Down
11 changes: 11 additions & 0 deletions test/e2e_test/testbench/testdata/configs/rules/rule.yamltpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ rules:
- name: create_resource_group_slug
path: "/api/resource_slug"
method: "POST"
middlewares:
- name: authz
config:
attributes:
owner_group:
value: org1-group1
type: constant
permissions:
- name: view
namespace: shield/group
attribute: owner_group
hooks:
- name: authz
config:
Expand Down

0 comments on commit 7a71e4f

Please sign in to comment.