Skip to content

Commit

Permalink
feat(backend): fine grained perms (#21)
Browse files Browse the repository at this point in the history
Signed-off-by: David van der Spek <vanderspek.david@gmail.com>
  • Loading branch information
davidspek committed Apr 14, 2023
1 parent 41dbe69 commit fd88154
Show file tree
Hide file tree
Showing 29 changed files with 3,812 additions and 2,300 deletions.
27 changes: 27 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
run:
timeout: 10m
issues-exit-code: 1
tests: true
linters:
disable-all: true
enable:
# default linters
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused

# additional linters
- errorlint
- errname
- gocyclo
- goimports
- misspell
- gofmt
- importas
- goconst
- gocritic
- misspell
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ COPY format/ format/
COPY graph/ graph/
COPY handlers/ handlers/
COPY utils/ utils/
COPY consts/ consts/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o server server.go
Expand Down
9 changes: 8 additions & 1 deletion TODO.txt
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
Create seed for first admin user and seed organization into Keto
Make rules more fine-grained
Use authorizer instead of hydrator for checking tenants
Expand what is now the hydrator to more smartly parse the method and URL so hydrate the tenants more accurately (for example: if it is a get request to mimir we will look for all tenants the user can read metrics from)
Add policy checking for login bindings on OAuth2 Client login
Start using https://github.com/ory/herodot for our webhook endpoints
Add policy fine-grained checking for our API
Allow for Bearer token and HTTP basic auth to work
If a request already contains a tenant header, rather than hydrating all tenants a user/client has access to check if the user/tenant has access to that tenant and don't modify the headers
104 changes: 35 additions & 69 deletions clients/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

rts "github.com/ory/keto/proto/ory/keto/relation_tuples/v1alpha2"
px "github.com/ory/x/pointerx"
"github.com/pluralsh/trace-shield/consts"
"github.com/pluralsh/trace-shield/graph/model"
)

Expand Down Expand Up @@ -59,7 +60,7 @@ func (c *ClientWrapper) MutateGroup(ctx context.Context, name string, members []
return &model.Group{
Name: name,
Organization: &model.Organization{
Name: "main", //TODO: decide whether to hardcode this or not
Name: consts.MainOrganizationName, //TODO: decide whether to hardcode this or not
},
}, nil
}
Expand Down Expand Up @@ -97,6 +98,16 @@ func userIdInListOfUsers(users []*model.User, userId string) bool {
return false
}

// function that checks if a group is in a []*model.Group
func groupNameInListOfGroups(groups []*model.Group, groupId string) bool {
for _, group := range groups {
if group.Name == groupId {
return true
}
}
return false
}

// function that checks if a string is in a []string
func stringContains(list []string, s string) bool {
for _, u := range list {
Expand All @@ -111,18 +122,9 @@ func stringContains(list []string, s string) bool {
func (c *ClientWrapper) IsUserInGroup(ctx context.Context, groupName string, userId string) (bool, error) {
log := c.Log.WithName("IsUserInGroup").WithValues("Name", groupName)

userTuple := &rts.RelationTuple{
Namespace: "Group",
Object: groupName,
Relation: "members",
Subject: rts.NewSubjectSet(
"User",
userId,
"",
),
}
group := model.NewGroup(groupName)

_, err := c.KetoClient.Check(ctx, userTuple)
_, err := c.KetoClient.Check(ctx, group.GetUserTuple(userId))
if err != nil {
return false, fmt.Errorf("failed to check tuple: %w", err)
}
Expand All @@ -135,18 +137,9 @@ func (c *ClientWrapper) IsUserInGroup(ctx context.Context, groupName string, use
func (c *ClientWrapper) CreateGroupInKeto(ctx context.Context, name string) error {
log := c.Log.WithName("CreateGroupInKeto").WithValues("Name", name)

groupTuple := &rts.RelationTuple{
Namespace: "Group",
Object: name,
Relation: "organizations",
Subject: rts.NewSubjectSet(
"Organization",
"main", //TODO: decide whether to hardcode this or not
"",
),
}
group := model.NewGroup(name)

err := c.KetoClient.CreateTuple(ctx, groupTuple)
err := c.KetoClient.CreateTuple(ctx, group.GetOrganizationTuple())
if err != nil {
return fmt.Errorf("failed to create tuple: %w", err)
}
Expand All @@ -159,18 +152,9 @@ func (c *ClientWrapper) CreateGroupInKeto(ctx context.Context, name string) erro
func (c *ClientWrapper) AddUserToGroupInKeto(ctx context.Context, groupName string, userId string) error {
log := c.Log.WithName("AddUserToGroupInKeto").WithValues("Name", groupName)

userTuple := &rts.RelationTuple{
Namespace: "Group",
Object: groupName,
Relation: "members",
Subject: rts.NewSubjectSet(
"User",
userId,
"",
),
}
group := model.NewGroup(groupName)

err := c.KetoClient.CreateTuple(ctx, userTuple)
err := c.KetoClient.CreateTuple(ctx, group.GetUserTuple(userId))
if err != nil {
return fmt.Errorf("failed to create tuple: %w", err)
}
Expand All @@ -183,18 +167,9 @@ func (c *ClientWrapper) AddUserToGroupInKeto(ctx context.Context, groupName stri
func (c *ClientWrapper) RemoveUserFromGroupInKeto(ctx context.Context, groupName string, userId string) error {
log := c.Log.WithName("RemoveUserFromGroupInKeto").WithValues("Name", groupName)

userTuple := &rts.RelationTuple{
Namespace: "Group",
Object: groupName,
Relation: "members",
Subject: rts.NewSubjectSet(
"User",
userId,
"",
),
}
group := model.NewGroup(groupName)

err := c.KetoClient.DeleteTuple(ctx, userTuple)
err := c.KetoClient.DeleteTuple(ctx, group.GetUserTuple(userId))
if err != nil {
return fmt.Errorf("failed to delete tuple: %w", err)
}
Expand All @@ -208,9 +183,9 @@ func (c *ClientWrapper) GetGroupMembersInKeto(ctx context.Context, groupName str
log := c.Log.WithName("GetGroupMembersInKeto").WithValues("Name", groupName)

query := rts.RelationQuery{
Namespace: px.Ptr("Group"),
Namespace: px.Ptr(consts.GroupNamespace.String()),
Object: px.Ptr(groupName),
Relation: px.Ptr("members"),
Relation: px.Ptr(consts.GroupRelationMembers.String()),
Subject: nil,
}

Expand Down Expand Up @@ -260,7 +235,7 @@ func (c *ClientWrapper) GetGroupFromName(ctx context.Context, groupName string)
return &model.Group{
Name: groupName,
Organization: &model.Organization{
Name: "main", //TODO: decide whether to hardcode this or not
Name: consts.MainOrganizationName, //TODO: decide whether to hardcode this or not
},
}, nil
}
Expand All @@ -270,12 +245,12 @@ func (c *ClientWrapper) GroupExistsInKeto(ctx context.Context, groupName string)
log := c.Log.WithName("GroupExistsInKeto").WithValues("Name", groupName)

query := rts.RelationQuery{
Namespace: px.Ptr("Group"),
Namespace: px.Ptr(consts.GroupNamespace.String()),
Object: px.Ptr(groupName),
Relation: px.Ptr("organizations"),
Relation: px.Ptr(consts.ObjectRelationOrganizations.String()),
Subject: rts.NewSubjectSet(
"Organization",
"main", //TODO: decide whether to hardcode this or not
consts.OrganizationNamespace.String(),
consts.MainOrganizationName, //TODO: decide whether to hardcode this or not
"",
),
}
Expand All @@ -298,12 +273,12 @@ func (c *ClientWrapper) ListGroupsInKeto(ctx context.Context) ([]*model.Group, e
log := c.Log.WithName("ListGroupsInKeto")

query := rts.RelationQuery{
Namespace: px.Ptr("Group"),
Namespace: px.Ptr(consts.GroupNamespace.String()),
Object: nil,
Relation: px.Ptr("organizations"),
Relation: px.Ptr(consts.ObjectRelationOrganizations.String()),
Subject: rts.NewSubjectSet(
"Organization",
"main", //TODO: decide whether to hardcode this or not
consts.OrganizationNamespace.String(),
consts.MainOrganizationName, //TODO: decide whether to hardcode this or not
"",
),
}
Expand Down Expand Up @@ -331,22 +306,13 @@ func (c *ClientWrapper) ListGroupsInKeto(ctx context.Context) ([]*model.Group, e
return outputGroups, nil
}

// funtion that deletes a group in keto
// function that deletes a group in keto
func (c *ClientWrapper) DeleteGroup(ctx context.Context, groupName string) (*model.Group, error) {
log := c.Log.WithName("DeleteGroup").WithValues("Name", groupName)

tuple := &rts.RelationTuple{
Namespace: "Group",
Object: groupName,
Relation: "organizations",
Subject: rts.NewSubjectSet(
"Organization",
"main", //TODO: decide whether to hardcode this or not
"",
),
}
group := model.NewGroup(groupName)

err := c.KetoClient.DeleteTuple(ctx, tuple)
err := c.KetoClient.DeleteTuple(ctx, group.GetOrganizationTuple())
if err != nil {
log.Error(err, "Failed to delete tuple")
return nil, err
Expand All @@ -356,7 +322,7 @@ func (c *ClientWrapper) DeleteGroup(ctx context.Context, groupName string) (*mod
return &model.Group{
Name: groupName,
Organization: &model.Organization{
Name: "main", //TODO: decide whether to hardcode this or not
Name: consts.MainOrganizationName, //TODO: decide whether to hardcode this or not
},
}, nil
}
4 changes: 3 additions & 1 deletion clients/keto.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ func (cd *KetoConnectionDetails) dialOptions() (opts []grpc.DialOption) {
if cd.token != "" {
opts = append(opts,
grpc.WithPerRPCCredentials(
oauth.NewOauthAccess(&oauth2.Token{AccessToken: cd.token})))
oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: cd.token})},
),
)
}
if cd.authority != "" {
opts = append(opts, grpc.WithAuthority(cd.authority))
Expand Down
Loading

0 comments on commit fd88154

Please sign in to comment.