mirror of
https://github.com/hanzoai/commerce.git
synced 2026-10-30 15:08:42 +00:00
IsSuperAdmin folded the case of the home org and fell back to the owner claim, the org of the application that minted the token, and the money bits were granted on X-User-Owner == admin. Cloud writes X-User-Owner for an admin-org application and an admin-org person's API key as well as for a person, so either could mint money and edit the catalog here while being nobody in the rest of the same process. Every gate now reads X-User-IsAdmin, which the edge strips and writes from authz.Claims.Sudo alone; the standalone EdgeAuth decides it with that predicate over the verified token's signed membership set. X-User-IsAdmin no longer doubles as the org-admin bit, which is X-User-IsOrgAdmin. No machine is SuperAdmin. Global admin is SuperAdmin wherever it named this predicate.
62 lines
2.6 KiB
Go
62 lines
2.6 KiB
Go
// Copyright (c) 2014-present Hanzo AI, Inc.
|
|
// Licensed under MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.
|
|
|
|
package middleware
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/zap-proto/zip"
|
|
|
|
"github.com/hanzoai/commerce/middleware/iammiddleware"
|
|
"github.com/hanzoai/commerce/util/json/http"
|
|
)
|
|
|
|
// MayReadPlatform is THE single predicate for "may this caller READ cross-org
|
|
// PLATFORM (god-view) data" — the business metrics, vendor costs, and any other
|
|
// aggregate that spans every tenant. It admits exactly the principals a
|
|
// platform god-view trusts, and fails closed for everyone else:
|
|
//
|
|
// a Hanzo PLATFORM SuperAdmin — auth.IAMClaims.IsSuperAdmin(): the identity edge's
|
|
// authz.Claims.Sudo verdict (X-User-IsAdmin), a PERSON whose own org is the
|
|
// reserved "admin" org. No machine is one, so an admin-org application or API key
|
|
// reads nothing here.
|
|
//
|
|
// Three admissions this used to have are gone. An application under the admin
|
|
// org, and an admin-org person's key, were admitted on the org alone. A shared
|
|
// COMMERCE_SERVICE_TOKEN, compared against a bearer here, was commerce
|
|
// authenticating callers on its own with a secret IAM had never seen. And "the Admin permission bit with no IAM
|
|
// Subject", which was meant to spot that token structurally, admitted exactly the
|
|
// thing it was argued not to — a legacy per-org access token holding Admin has
|
|
// no Subject either — so an org owner's old token could read the fleet's revenue.
|
|
//
|
|
// It deliberately does NOT admit the org-level Admin bit (permission.Admin) held
|
|
// by an org OWNER: the gateway mints permission.Admin from a tenant's own
|
|
// IsAdmin (edgeauth.permsHeader), so gating cross-org reads on that bit would let
|
|
// ANY org owner read the whole fleet's revenue. Only a SuperAdmin may. This is
|
|
// the same org-admin-vs-SuperAdmin anti-conflation
|
|
// PlatformOnly/MayMintMoney enforce for the money-MINT side.
|
|
//
|
|
// Reads c["permissions"] without MustGet so a handler mounted without the token
|
|
// gate fails closed (false) rather than panicking. Fail-closed: none present → false.
|
|
func MayReadPlatform(c *zip.Ctx) bool {
|
|
claims := iammiddleware.GetIAMClaims(c) // non-nil by contract
|
|
if claims.IsSuperAdmin() {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// RequirePlatformAdmin is MayReadPlatform as a route guard: it admits the same
|
|
// principal and writes the 403 for everyone else, so a handler that calls it and
|
|
// returns on false has already answered.
|
|
func RequirePlatformAdmin(c *zip.Ctx) bool {
|
|
if MayReadPlatform(c) {
|
|
return true
|
|
}
|
|
_ = http.Fail(c, 403,
|
|
"This operation requires platform-administrator credentials.",
|
|
errors.New("cross-org god-view: caller is not a platform admin"))
|
|
return false
|
|
}
|