Skip to content

Commit

Permalink
fix: check permission on keys before create/update
Browse files Browse the repository at this point in the history
  • Loading branch information
ishanarya0 committed Jun 19, 2024
1 parent 455e4c7 commit 6e0bdb8
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 60 deletions.
8 changes: 6 additions & 2 deletions core/servicedata/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (s Service) CreateKey(ctx context.Context, key Key) (Key, error) {
key.ProjectSlug = prj.Slug

// create URN
key.URN = key.CreateURN()
key.URN = CreateURN(key.ProjectSlug, key.Name)

// Transaction for postgres repository
// TODO find way to use transaction for spicedb
Expand Down Expand Up @@ -160,6 +160,10 @@ func (s Service) CreateKey(ctx context.Context, key Key) (Key, error) {
return createdServiceDataKey, nil
}

func (s Service) GetKeyByURN(ctx context.Context, urn string) (Key, error) {
return s.repository.GetKeyByURN(ctx, urn)
}

func (s Service) Upsert(ctx context.Context, sd ServiceData) (ServiceData, error) {
if sd.Key.Name == "" {
return ServiceData{}, ErrInvalidDetail
Expand All @@ -176,7 +180,7 @@ func (s Service) Upsert(ctx context.Context, sd ServiceData) (ServiceData, error
}
sd.Key.ProjectSlug = prj.Slug

sd.Key.URN = sd.Key.CreateURN()
sd.Key.URN = CreateURN(sd.Key.ProjectSlug, sd.Key.Name)

sd.Key, err = s.repository.GetKeyByURN(ctx, sd.Key.URN)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions core/servicedata/servicedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ type Filter struct {
Project string
}

func (key Key) CreateURN() string {
return fmt.Sprintf("%s:servicedata_key:%s", key.ProjectSlug, key.Name)
func CreateURN(projectSlug, keyName string) string {
return fmt.Sprintf("%s:servicedata_key:%s", projectSlug, keyName)
}

func (key Key) ToKeyLogData() KeyLogData {
Expand Down
67 changes: 65 additions & 2 deletions internal/api/v1beta1/mocks/relation_service.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 54 additions & 13 deletions internal/api/v1beta1/mocks/servicedata_service.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/api/v1beta1/relation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type RelationService interface {
DeleteV2(ctx context.Context, rel relation.RelationV2) error
GetRelationByFields(ctx context.Context, rel relation.RelationV2) (relation.RelationV2, error)
LookupResources(ctx context.Context, resourceType, permission, subjectType, subjectID string) ([]string, error)
CheckPermission(ctx context.Context, usr user.User, resourceNS namespace.Namespace, resourceIdxa string, action action.Action) (bool, error)
}

var grpcRelationNotFoundErr = status.Errorf(codes.NotFound, "relation doesn't exist")
Expand Down
1 change: 1 addition & 0 deletions internal/api/v1beta1/servicedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type ServiceDataService interface {
CreateKey(ctx context.Context, key servicedata.Key) (servicedata.Key, error)
Upsert(ctx context.Context, serviceData servicedata.ServiceData) (servicedata.ServiceData, error)
Get(ctx context.Context, filter servicedata.Filter) ([]servicedata.ServiceData, error)
GetKeyByURN(ctx context.Context, urn string) (servicedata.Key, error)
}

func (h Handler) CreateServiceDataKey(ctx context.Context, request *shieldv1beta1.CreateServiceDataKeyRequest) (*shieldv1beta1.CreateServiceDataKeyResponse, error) {
Expand Down
62 changes: 51 additions & 11 deletions internal/api/v1beta1/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/goto/shield/core/action"
"github.com/goto/shield/core/namespace"
"github.com/goto/shield/core/project"
"github.com/goto/shield/core/relation"
"github.com/goto/shield/core/servicedata"
Expand Down Expand Up @@ -47,7 +49,7 @@ func (h Handler) ListUsers(ctx context.Context, request *shieldv1beta1.ListUsers
currentUser, err := h.userService.FetchCurrentUser(ctx)
if err != nil {
logger.Error(err.Error())
return nil, grpcInternalServerError
return nil, grpcUnauthenticated
}

servicedataKeyResourceIds, err := h.relationService.LookupResources(ctx, schema.ServiceDataKeyNamespace, schema.ViewPermission, schema.UserPrincipal, currentUser.ID)
Expand Down Expand Up @@ -94,14 +96,9 @@ func (h Handler) ListUsers(ctx context.Context, request *shieldv1beta1.ListUsers
func (h Handler) CreateUser(ctx context.Context, request *shieldv1beta1.CreateUserRequest) (*shieldv1beta1.CreateUserResponse, error) {
logger := grpczap.Extract(ctx)

currentUserEmail, ok := user.GetEmailFromContext(ctx)
if !ok {
return nil, grpcUnauthenticated
}

currentUserEmail = strings.TrimSpace(currentUserEmail)
if currentUserEmail == "" {
logger.Error(ErrEmptyEmailID.Error())
currentUser, err := h.userService.FetchCurrentUser(ctx)
if err != nil {
logger.Error(err.Error())
return nil, grpcUnauthenticated
}

Expand All @@ -111,9 +108,8 @@ func (h Handler) CreateUser(ctx context.Context, request *shieldv1beta1.CreateUs

email := strings.TrimSpace(request.GetBody().GetEmail())
if email == "" {
email = currentUserEmail
return nil, grpcBadBodyError
}

if !isValidEmail(email) {
return nil, user.ErrInvalidEmail
}
Expand All @@ -124,6 +120,22 @@ func (h Handler) CreateUser(ctx context.Context, request *shieldv1beta1.CreateUs
return nil, grpcBadBodyError
}

for k, _ := range metaDataMap {

Check failure on line 123 in internal/api/v1beta1/user.go

View workflow job for this annotation

GitHub Actions / golangci

File is not `gofmt`-ed with `-s` (gofmt)
urn := servicedata.CreateURN(h.serviceDataConfig.DefaultServiceDataProject, k)
key, err := h.serviceDataService.GetKeyByURN(ctx, urn)
if err != nil {
return nil, err
}

permission, err := h.relationService.CheckPermission(ctx, currentUser, namespace.Namespace{ID: schema.ServiceDataKeyNamespace}, key.ResourceID, action.Action{ID: schema.EditPermission})
if err != nil {
return nil, err
}
if !permission {
return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("you are not authorized to update %s key", k))
}
}

// TODO might need to check the valid email form
newUser, err := h.userService.Create(ctx, user.User{
Name: request.GetBody().GetName(),
Expand Down Expand Up @@ -219,6 +231,12 @@ func (h Handler) CreateMetadataKey(ctx context.Context, request *shieldv1beta1.C
func (h Handler) GetUser(ctx context.Context, request *shieldv1beta1.GetUserRequest) (*shieldv1beta1.GetUserResponse, error) {
logger := grpczap.Extract(ctx)

_, err := h.userService.FetchCurrentUser(ctx)
if err != nil {
logger.Error(err.Error())
return nil, grpcUnauthenticated
}

fetchedUser, err := h.userService.Get(ctx, request.GetId())
if err != nil {
logger.Error(err.Error())
Expand Down Expand Up @@ -306,6 +324,12 @@ func (h Handler) UpdateUser(ctx context.Context, request *shieldv1beta1.UpdateUs
logger := grpczap.Extract(ctx)
var updatedUser user.User

currentUser, err := h.userService.FetchCurrentUser(ctx)
if err != nil {
logger.Error(err.Error())
return nil, grpcUnauthenticated
}

if strings.TrimSpace(request.GetId()) == "" {
return nil, grpcUserNotFoundError
}
Expand All @@ -328,6 +352,22 @@ func (h Handler) UpdateUser(ctx context.Context, request *shieldv1beta1.UpdateUs
return nil, grpcBadBodyError
}

for k, _ := range metaDataMap {
urn := servicedata.CreateURN(h.serviceDataConfig.DefaultServiceDataProject, k)
key, err := h.serviceDataService.GetKeyByURN(ctx, urn)
if err != nil {
return nil, err
}

permission, err := h.relationService.CheckPermission(ctx, currentUser, namespace.Namespace{ID: schema.ServiceDataKeyNamespace}, key.ResourceID, action.Action{ID: schema.EditPermission})
if err != nil {
return nil, err
}
if !permission {
return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("you are not authorized to update %s key", k))
}
}

id := request.GetId()
if uuid.IsValid(id) {
updatedUser, err = h.userService.UpdateByID(ctx, user.User{
Expand Down
Loading

0 comments on commit 6e0bdb8

Please sign in to comment.