Require set-owner authorization to create OWNER membership

An organization ADMIN could mint an OWNER membership via createUser, which
only gated iam:membership-profile:create and bypassed the owner-only
iam:membership-role:set-owner check that updateMembership already enforces.

Gate the requested role in both createUser entry points (connect resolver
and the MCP CreateUserTool) with an additional set-owner authorization when
the role is OWNER, mirroring updateMembership. Add a regression test that
locks the ADMIN/OWNER privilege boundary the fix relies on.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
This commit is contained in:
Sacha Al Himdani
2026-07-03 17:11:13 +02:00
parent d359eaefaa
commit 2ffeb7f3e8
3 changed files with 83 additions and 0 deletions

View File

@@ -26,6 +26,12 @@ func (r *mutationResolver) CreateUser(ctx context.Context, input types.CreateUse
return nil, err
}
if input.Role == coredata.MembershipRoleOwner {
if _, err := r.authorize(ctx, input.OrganizationID, iam.ActionMembershipRoleSetOwner); err != nil {
return nil, err
}
}
profile, err := r.iam.OrganizationService.CreateUser(
ctx,
&iam.CreateUserRequest{

View File

@@ -2819,6 +2819,12 @@ func (r *Resolver) CreateUserTool(ctx context.Context, req *mcp.CallToolRequest,
return nil, types.CreateUserOutput{}, err
}
if input.Role == coredata.MembershipRoleOwner {
if _, err := r.Authorize(ctx, input.OrganizationID, iam.ActionMembershipRoleSetOwner); err != nil {
return nil, types.CreateUserOutput{}, err
}
}
var contractStart, contractEnd **time.Time
if input.ContractStartDate != nil {
contractStart = &input.ContractStartDate