Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 13 additions & 20 deletions app/controlplane/internal/service/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ func NewOrganizationService(muc *biz.MembershipUseCase, ouc *biz.OrganizationUse
}
}

// Create persists an organization with a given name and associate it to the current user.
// Create persists an organization with a given name and associates it with the current user.
func (s *OrganizationService) Create(ctx context.Context, req *pb.OrganizationServiceCreateRequest) (*pb.OrganizationServiceCreateResponse, error) {
currentUser, err := requireCurrentUser(ctx)
currentUser, _, err := requireCurrentUserOrAPIToken(ctx)
if err != nil {
return nil, err
}
Expand All @@ -65,8 +65,11 @@ func (s *OrganizationService) Create(ctx context.Context, req *pb.OrganizationSe
return nil, handleUseCaseErr(err, s.log)
}

if _, err := s.membershipUC.Create(ctx, org.ID, currentUser.ID, biz.WithMembershipRole(authz.RoleOwner), biz.WithCurrentMembership()); err != nil {
return nil, handleUseCaseErr(err, s.log)
// Add membership if invoker is a user
if currentUser != nil {
if _, err := s.membershipUC.Create(ctx, org.ID, currentUser.ID, biz.WithMembershipRole(authz.RoleOwner), biz.WithCurrentMembership()); err != nil {
return nil, handleUseCaseErr(err, s.log)
}
}

return &pb.OrganizationServiceCreateResponse{Result: bizOrgToPb(org)}, nil
Expand Down Expand Up @@ -211,25 +214,15 @@ func (s *OrganizationService) UpdateMembership(ctx context.Context, req *pb.Orga
}

func (s *OrganizationService) canCreateOrganization(ctx context.Context) (bool, error) {
// Restricted org creation is disabled, allow creation
if !s.authz.RestrictOrgCreation {
// if org creation restriction is disabled, allow creation to all users
if !s.authz.RestrictOrgCreation && entities.CurrentUser(ctx) != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, more clear now, thanks

return true, nil
}

m := entities.CurrentMembership(ctx)
for _, rm := range m.Resources {
if rm.ResourceType != authz.ResourceTypeInstance {
continue
}

pass, err := s.authz.Enforce(ctx, string(rm.Role), authz.PolicyOrganizationCreate)
if err != nil {
return false, handleUseCaseErr(err, s.log)
}
if pass {
return true, nil
}
// otherwise, check for permissions (both users and API tokens)
if err := s.checkPolicy(ctx, authz.PolicyOrganizationCreate); err != nil {
return false, err
}

return false, nil
return true, nil
}
32 changes: 32 additions & 0 deletions app/controlplane/internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,38 @@ func (s *service) visibleProjects(ctx context.Context) []uuid.UUID {
return projects
}

// checkPolicy Checks a policy against a user or a token
func (s *service) checkPolicy(ctx context.Context, policy *authz.Policy) error {
// Token case
sub := usercontext.CurrentAuthzSubject(ctx)
if sub != "" {
ok, err := s.authz.Enforce(ctx, sub, policy)
if err != nil {
return handleUseCaseErr(err, s.log)
}
if ok {
return nil
}
}

// Other cases
m := entities.CurrentMembership(ctx)
if m == nil {
return errors.Forbidden("forbidden", "not allowed")
}
for _, rm := range m.Resources {
pass, err := s.authz.Enforce(ctx, string(rm.Role), authz.PolicyOrganizationCreate)
if err != nil {
return handleUseCaseErr(err, s.log)
}
if pass {
return nil
}
}

return errors.Forbidden("forbidden", "not allowed")
}

// isUserOrgAdmin checks if the current user is an org admin or owner
func isUserOrgAdmin(ctx context.Context) bool {
userRole := usercontext.CurrentAuthzSubject(ctx)
Expand Down
3 changes: 2 additions & 1 deletion app/controlplane/pkg/authz/authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,8 @@ var ServerOperationsMap = map[string][]*Policy{
"/controlplane.v1.ContextService/Current": {PolicyOrganizationRead},
// Listing, create or selecting an organization does not have any required permissions,
// since all the permissions here are in the context of an organization
// Create new organization
// Create new organization. No user required at middleware level. The endpoint will handle
// it based on diverse conditions
"/controlplane.v1.OrganizationService/Create": {},
// Delete an organization makes checks at the service level since the
// user can explicitly set the org they want to delete and might not be the current one
Expand Down
Loading