Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/auth/createPermissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type CreatePermissions struct {
Limits Limits `json:"limits"`
Users []UserId `json:"users"`
Roles []Role `json:"roles"`
FromId []string `json:"from"`
FromType []string `json:"from-type"`
TimeToLive uint64 `json:"ttl"`
}

Expand Down
51 changes: 40 additions & 11 deletions cli/auth/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,16 @@ import (
// - WantTo: checks if the current user can perform the given operation on the resource.
// - Grant: grants a share to the resource.
type Resource struct {
Owners map[UserId]struct{} `json:"owner"`
Shares []Share `json:"Shares"`
Mode Mode `json:"mode"`
mu sync.RWMutex
kv jetstream.KeyValue
id *ids.StateId
Expires time.Time
revision uint64
Owners map[UserId]struct{} `json:"owner"`
Shares []Share `json:"Shares"`
Mode Mode `json:"mode"`
mu sync.RWMutex
kv jetstream.KeyValue
id *ids.StateId
AllowedFromTypes []string `json:"allowed_from_types"`
AllowedFromIds []*ids.StateId `json:"allowed_from_ids"`
Expires time.Time
revision uint64
}

// NewResourcePermissions creates a new Resource with the specified owner and mode. If the owner is nil, the resource
Expand Down Expand Up @@ -101,7 +103,7 @@ func (r *Resource) ShareOwnership(newUser UserId, currentUser *User, keepPermiss

r.mu.Lock()
defer r.mu.Unlock()
if currentUser != nil && !keepPermissions {
if !keepPermissions {
delete(r.Owners, currentUser.UserId)
}
r.Owners[newUser] = struct{}{}
Expand All @@ -123,13 +125,13 @@ func (r *Resource) ApplyPerms(id *ids.StateId, ctx context.Context, logger *zap.
}

// CanCreate Load permissions from cache if available, otherwise fetch from external source
func (r *Resource) CanCreate(id *ids.StateId, ctx context.Context, logger *zap.Logger) bool {
func (r *Resource) CanCreate(id *ids.StateId, from *ids.StateId, ctx context.Context, logger *zap.Logger) bool {
perms, err := r.getOrCreatePermissions(id, ctx, logger)
if err != nil {
logger.Error("failed to create permissions", zap.Error(err))
return false
}
return r.isUserPermitted(perms, ctx)
return r.isUserPermitted(perms, ctx) && r.AllowedFrom(from)
}

func (r *Resource) getOrCreatePermissions(id *ids.StateId, ctx context.Context, logger *zap.Logger) (CreatePermissions, error) {
Expand Down Expand Up @@ -158,6 +160,10 @@ func (r *Resource) getOrCreatePermissions(id *ids.StateId, ctx context.Context,

func (r *Resource) isUserPermitted(perms CreatePermissions, ctx context.Context) bool {
r.Mode = perms.Mode
for _, p := range perms.FromId {
r.AllowedFromIds = append(r.AllowedFromIds, ids.ParseStateId(p))
}
r.AllowedFromTypes = perms.FromType
Comment thread
withinboredom marked this conversation as resolved.
r.Expires = time.Now().Add(time.Duration(perms.TimeToLive) * time.Nanosecond)
switch perms.Mode {
case AnonymousMode:
Expand Down Expand Up @@ -219,6 +225,29 @@ func (r *Resource) IsOwner(ctx context.Context) bool {
return false
}

func (r *Resource) AllowedFrom(from *ids.StateId) bool {
if len(r.AllowedFromIds) == 0 && len(r.AllowedFromTypes) == 0 {
return true
}

for _, id := range r.AllowedFromIds {
if id.Kind == from.Kind && id.Id == from.Id {
return true
}
}

for _, t := range r.AllowedFromTypes {
if ent, found := from.ToEntityId(); found && ent.Name == t {
return true
}
if orch, found := from.ToOrchestrationId(); found && orch.InstanceId == t {
return true
}
}

return false
}
Comment thread
withinboredom marked this conversation as resolved.

// WantTo determines if the user is able to perform the specified operation on the resource.
// It accepts the operation to be performed and the context containing the user information.
// If the resource mode is set to AnonymousMode, it allows any operation.
Expand Down
4 changes: 2 additions & 2 deletions cli/auth/resourceManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func GetResourceManager(ctx context.Context, stream jetstream.JetStream) *Resour

// DiscoverResource is a method of the ResourceManager struct that is responsible for discovering a resource based on
// the provided context, state ID, logger, and preventCreation flag
func (r *ResourceManager) DiscoverResource(ctx context.Context, id *ids.StateId, logger *zap.Logger, preventCreation bool) (*Resource, error) {
func (r *ResourceManager) DiscoverResource(ctx context.Context, id *ids.StateId, from *ids.StateId, logger *zap.Logger, preventCreation bool) (*Resource, error) {
currentUser, _ := ctx.Value(appcontext.CurrentUserKey).(*User)

data, err := r.kv.Get(ctx, id.ToSubject().String())
Expand All @@ -58,7 +58,7 @@ func (r *ResourceManager) DiscoverResource(ctx context.Context, id *ids.StateId,
resource.kv = r.kv
resource.id = id
resource.revision = 0
if resource.CanCreate(id, ctx, logger) {
if resource.CanCreate(id, from, ctx, logger) {
err = resource.Update(ctx, logger)
if err != nil {
return nil, err
Expand Down
15 changes: 10 additions & 5 deletions cli/ids/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const (
Orchestration IdKind = "orchestration"
)

var ApiSource *StateId = &StateId{
Id: "--api--",
Kind: "--api--",
}
Comment thread
withinboredom marked this conversation as resolved.

// subjects

type Subject struct {
Expand Down Expand Up @@ -73,12 +78,12 @@ func (id StateId) String() string {
return fmt.Sprintf("%s:%s", id.Kind, id.Id)
}

func (id StateId) Name() string {
func (id StateId) Name() IdKind {
if before, _, found := strings.Cut(id.Id, ":"); found {
return before
return IdKind(before)
}

return string(Activity)
return Activity
}

func (id StateId) ToEntityId() (*EntityId, bool) {
Expand Down Expand Up @@ -174,6 +179,6 @@ func (id *OrchestrationId) ToStateId() *StateId {
}

type StateId struct {
Id string
Kind IdKind
Id string `json:"id,omitempty"`
Kind IdKind `json:"kind,omitempty"`
}
22 changes: 11 additions & 11 deletions cli/lib/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
defer cancel()

rm := auth.GetResourceManager(ctx, js)
res, err := rm.DiscoverResource(ctx, id, logger, true)
res, err := rm.DiscoverResource(ctx, id, ids.ApiSource, logger, true)
if err != nil {
logger.Error("DiscoverResource", zap.Error(err))
panic(err)
Expand Down Expand Up @@ -312,7 +312,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
}

if deleteAfter {
resource, err := rm.DiscoverResource(ctx, id, logger, false)
resource, err := rm.DiscoverResource(ctx, id, ids.ApiSource, logger, false)
if err != nil {
logger.Error("Unable to delete resource", zap.Error(err))
http.Error(writer, "Internal Server Error", http.StatusInternalServerError)
Expand Down Expand Up @@ -354,7 +354,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

r, err := rm.DiscoverResource(ctx, stateId, logger, true)
r, err := rm.DiscoverResource(ctx, stateId, ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "Not Found", http.StatusNotFound)
Expand Down Expand Up @@ -430,7 +430,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

r, err := rm.DiscoverResource(ctx, stateId, logger, true)
r, err := rm.DiscoverResource(ctx, stateId, ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "", http.StatusNotFound)
Expand Down Expand Up @@ -485,7 +485,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

r, err := rm.DiscoverResource(ctx, stateId, logger, true)
r, err := rm.DiscoverResource(ctx, stateId, ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "", http.StatusNotFound)
Expand Down Expand Up @@ -571,7 +571,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
}

logger.Debug("Delete entity", zap.String("id", id.String()))
rs, err := rm.DiscoverResource(ctx, id.ToStateId(), logger, true)
rs, err := rm.DiscoverResource(ctx, id.ToStateId(), ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "Not Found", http.StatusNotFound)
Expand Down Expand Up @@ -682,7 +682,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

r, err := rm.DiscoverResource(ctx, stateId, logger, true)
r, err := rm.DiscoverResource(ctx, stateId, ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "Not Found", http.StatusNotFound)
Expand Down Expand Up @@ -758,7 +758,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

r, err := rm.DiscoverResource(ctx, stateId, logger, true)
r, err := rm.DiscoverResource(ctx, stateId, ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "", http.StatusNotFound)
Expand Down Expand Up @@ -813,7 +813,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

r, err := rm.DiscoverResource(ctx, stateId, logger, true)
r, err := rm.DiscoverResource(ctx, stateId, ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover resource", zap.Error(err))
http.Error(writer, "", http.StatusNotFound)
Expand Down Expand Up @@ -878,7 +878,7 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
return
}

rs, err := rm.DiscoverResource(ctx, id.ToStateId(), logger, true)
rs, err := rm.DiscoverResource(ctx, id.ToStateId(), ids.ApiSource, logger, true)
if err != nil {
logger.Error("Failed to discover a resource for deletion", zap.Error(err))
http.Error(writer, "Not Found", http.StatusNotFound)
Expand Down Expand Up @@ -1032,7 +1032,7 @@ func authorize(
logger.Info("Authenticating with user", zap.Any("user", user))
ctx = auth.DecorateContextWithUser(ctx, user)
}
resource, err := rm.DiscoverResource(ctx, id, logger, preventCreation)
resource, err := rm.DiscoverResource(ctx, id, ids.ApiSource, logger, preventCreation)
if err != nil {
logger.Warn("User attempted to create new resource not authorized to create", zap.Any("id", id.String()), zap.Any("user", auth.GetUserFromContext(ctx)), zap.Error(err))
http.Error(writer, "Not Authorized", http.StatusForbidden)
Expand Down
Loading
Loading