handler

package
v1.16.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

README

pkg/handler

This package is the API application layer for identity.

Intent

The handler layer sits below middleware and above the persisted Kubernetes resources.

It is where the identity API turns:

  • authenticated and authorized request context
  • OpenAPI request/response models
  • persisted CRD-backed storage

into resource-specific behaviour.

At the top level, handler.go is mostly transport glue: it performs the final handler-level RBAC checks, reads request bodies, delegates to resource-specific clients, and normalizes response/error handling. The real package behaviour lives in the per-resource handler clients beneath it.

Shared Handler Model

Most handler clients are expected to follow the same broad pattern:

  1. resolve scope
  2. load current state where mutation is involved
  3. convert user-facing request shape into required stored shape
  4. merge system-owned metadata and derived context
  5. write back with conflict detection
  6. convert stored state back into user-facing read models

This is not a blind REST-to-CRD translation layer. The handler layer is allowed to enforce local application invariants, reconcile related state, and reject requests that would create obviously broken cross-resource relationships.

Conventions

Read / Modify / Write

Mutable API operations are intended to follow an explicit read/modify/write model.

That means the handler does not treat the request body as a full authoritative replacement for the stored object. Instead it:

  • reads the current object
  • computes the desired user-controlled changes
  • preserves or re-applies system-owned metadata and derived state
  • writes the result back with concurrency protection

That final write step is a semantic requirement, not a preference for one Kubernetes client method over another. A full Update() and an optimistic-locking Patch() are both valid so long as the operation preserves the read/modify/write conflict-detection model.

This is the main reason many clients have both generate(...) and update-specific merge logic.

Read Shapes Should Inform Write Shapes

The API is intended to make read/modify/write practical for clients too.

Where possible, read models should be close enough to update models that a caller can:

  • read an object
  • change the fields they control
  • send it back as an update

System-owned or derived fields may be separated, but the user-controlled structure should stay duck-typable across read and write forms where practical.

Scope First, Storage Second

Handler clients generally resolve logical scope before touching storage.

Examples:

  • organizations resolve visible tenancy roots
  • organization-scoped clients resolve the parent organization and its current namespace
  • project-scoped clients resolve the project namespace before reading or writing child resources

That keeps the user-facing scope model separate from raw Kubernetes access.

Conversion Boundary

Handlers are responsible for the explicit boundary between:

  • OpenAPI request/response types
  • stored CRD resource shapes

This is why most clients have convert(...), convertList(...), and generate(...) helpers. The external API model and the persisted storage model are related, but they are not the same thing.

Shared Metadata Discipline

Handlers use the shared conversion and identity metadata helpers from core and local pkg/handler/common rather than inventing per-client metadata rules.

That includes:

  • resource naming and scoped metadata generation
  • organization/project labels
  • creator/modifier identity metadata
  • metadata merge behaviour during updates
Bad-Path Taxonomy

The handler layer should be secure by default when surfacing bad-path behaviour.

The status-code taxonomy is expected to follow these broad rules:

  • 400: the request shape or protocol-level structure is wrong
  • 422: the request is structurally valid but semantically wrong for the domain model
  • 401: authentication failed
  • 403: the caller is authenticated but not allowed to perform the operation
  • 404: the addressed resource is absent from the visible model
  • 409: the request is valid but conflicts with current state, including lost-update and uniqueness conflicts
  • 5XX: the fault is on the server side and the client cannot reasonably fix it

The disclosure model matters as much as the status code:

  • 4XX responses should be useful enough for honest clients to recover
  • 5XX responses should make it clear the problem is ours, not the caller's
  • 403, 404, and some 422 paths must be careful not to reveal policy structure, tenant layout, or resource existence unnecessarily
  • status-code, body, header, redirect, and timing differences can all become attacker-visible discrepancy factors

So this layer should prefer secure-by-default concealment where more specific error detail would turn the API into an enumeration or policy oracle.

Cross-Resource Consistency

Many handler clients do more than mutate one object.

Examples include:

  • users, which coordinate global users, organization users, and groups
  • serviceaccounts, which coordinate service accounts, groups, and token lifecycle
  • groups, which coordinate members, roles, and project references
  • quotas and allocations, which together implement a small accounting subsystem

So a recurring responsibility of the handler layer is manual cross-resource consistency maintenance.

Shared Caveat: Atomicity

This layer is built on Kubernetes objects, not an ACID database.

That has an important consequence: many handler-level invariants are only enforceable on a best-effort basis.

Across the package, the common limitations are:

  • multi-object updates are not truly transactional
  • referential integrity is maintained in application logic rather than by the backing store
  • partial failure can leave consistency gaps that later reconciliation or follow-up writes must repair

This is a systemic property of the storage model, not just an isolated flaw in one client.

Package Map

  • organizations: tenancy-root visibility and current v1 namespace handoff
  • roles: filtered user-facing role catalogue
  • users: global identity plus organization membership
  • serviceaccounts: organization-local non-human identities with token rotation
  • groups: primary local delegation unit
  • projects: project-scoped selection of delegation units
  • oauth2providers: organization-scoped upstream provider configuration for the built-in auth flow
  • quotas: organization-wide capacity contract
  • allocations: consumption ledger checked against quotas
  • pkg/middleware, which establishes the trusted request context that handlers consume
  • ../core/pkg/server, which documents the generic server and request-processing foundation beneath identity's service-specific handler layer
  • ../core/pkg/server/conversion, which provides shared metadata and API/storage conversion helpers used heavily here
  • pkg/apis/unikorn/v1alpha1, which defines the persisted resource contract the handlers read and write

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HandleError

func HandleError(w http.ResponseWriter, r *http.Request, err error)

HandleError is called when the router has trouble parsong paths.

func MethodNotAllowed

func MethodNotAllowed(w http.ResponseWriter, r *http.Request)

MethodNotAllowed is called from the router when a method is not found for a path.

func NotFound

func NotFound(w http.ResponseWriter, r *http.Request)

NotFound is called from the router when a path is not found.

Types

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

func New

func New(client client.Client, directclient client.Client, namespace string, issuer *jose.JWTIssuer, oauth2 *oauth2.Authenticator, userdb *userdb.UserDatabase, rbac *rbac.RBAC, options *Options) (*Handler, error)

func (*Handler) DeleteApiV1OrganizationsOrganizationID added in v1.4.0

func (h *Handler) DeleteApiV1OrganizationsOrganizationID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDGroupsGroupid added in v0.2.6

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDGroupsGroupid(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, groupID openapi.GroupidParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDOauth2providersProviderID added in v0.2.6

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDOauth2providersProviderID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, providerID openapi.Oauth2ProvderIDParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDProjectsProjectID added in v0.2.6

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDProjectsProjectID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDProjectsProjectIDAllocationsAllocationID added in v0.2.53

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDProjectsProjectIDAllocationsAllocationID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, allocationID openapi.AllocationIDParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDProjectsProjectIDReferencesReference added in v1.9.0

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDProjectsProjectIDReferencesReference(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, reference openapi.ReferenceParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDServiceaccountsServiceAccountID added in v0.2.49

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDServiceaccountsServiceAccountID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, serviceAccountID openapi.ServiceAccountIDParameter)

func (*Handler) DeleteApiV1OrganizationsOrganizationIDUsersUserID added in v0.2.51

func (h *Handler) DeleteApiV1OrganizationsOrganizationIDUsersUserID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, userID openapi.UserIDParameter)

func (*Handler) GetApiV1Acl added in v0.2.47

func (h *Handler) GetApiV1Acl(w http.ResponseWriter, r *http.Request)

func (*Handler) GetApiV1Oauth2providers added in v0.2.5

func (h *Handler) GetApiV1Oauth2providers(w http.ResponseWriter, r *http.Request)

func (*Handler) GetApiV1Organizations added in v0.1.3

func (h *Handler) GetApiV1Organizations(w http.ResponseWriter, r *http.Request, params openapi.GetApiV1OrganizationsParams)

func (*Handler) GetApiV1OrganizationsOrganizationID added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDAcl added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDAcl(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDGroups added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDGroups(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDGroupsGroupid added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDGroupsGroupid(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, groupID openapi.GroupidParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDOauth2providers added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDOauth2providers(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDProjects added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjects(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectID added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectIDAllocationsAllocationID added in v0.2.53

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectIDAllocationsAllocationID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, allocationID openapi.AllocationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDQuotas added in v0.2.53

func (h *Handler) GetApiV1OrganizationsOrganizationIDQuotas(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDRoles added in v0.2.6

func (h *Handler) GetApiV1OrganizationsOrganizationIDRoles(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDServiceaccounts added in v0.2.49

func (h *Handler) GetApiV1OrganizationsOrganizationIDServiceaccounts(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1OrganizationsOrganizationIDUsers added in v0.2.49

func (h *Handler) GetApiV1OrganizationsOrganizationIDUsers(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) GetApiV1Signup added in v0.2.52

func (h *Handler) GetApiV1Signup(w http.ResponseWriter, r *http.Request)

func (*Handler) GetOauth2V2Authorization

func (h *Handler) GetOauth2V2Authorization(w http.ResponseWriter, r *http.Request)

func (*Handler) GetOauth2V2Jwks

func (h *Handler) GetOauth2V2Jwks(w http.ResponseWriter, r *http.Request)

func (*Handler) GetOauth2V2Userinfo added in v0.1.14

func (h *Handler) GetOauth2V2Userinfo(w http.ResponseWriter, r *http.Request)

func (*Handler) GetOidcCallback

func (h *Handler) GetOidcCallback(w http.ResponseWriter, r *http.Request)

func (*Handler) GetWellKnownOpenidConfiguration

func (h *Handler) GetWellKnownOpenidConfiguration(w http.ResponseWriter, r *http.Request)

func (*Handler) GetWellKnownOpenidProtectedResource added in v1.14.0

func (h *Handler) GetWellKnownOpenidProtectedResource(w http.ResponseWriter, r *http.Request)

func (*Handler) PostApiV1Organizations added in v0.1.13

func (h *Handler) PostApiV1Organizations(w http.ResponseWriter, r *http.Request)

func (*Handler) PostApiV1OrganizationsOrganizationIDGroups added in v0.2.6

func (h *Handler) PostApiV1OrganizationsOrganizationIDGroups(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PostApiV1OrganizationsOrganizationIDOauth2providers added in v0.2.6

func (h *Handler) PostApiV1OrganizationsOrganizationIDOauth2providers(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PostApiV1OrganizationsOrganizationIDProjects added in v0.2.6

func (h *Handler) PostApiV1OrganizationsOrganizationIDProjects(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDAllocations added in v0.2.53

func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDAllocations(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter)

func (*Handler) PostApiV1OrganizationsOrganizationIDServiceaccounts added in v0.2.49

func (h *Handler) PostApiV1OrganizationsOrganizationIDServiceaccounts(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PostApiV1OrganizationsOrganizationIDServiceaccountsServiceAccountIDRotate added in v0.2.49

func (h *Handler) PostApiV1OrganizationsOrganizationIDServiceaccountsServiceAccountIDRotate(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, serviceAccountID openapi.ServiceAccountIDParameter)

func (*Handler) PostApiV1OrganizationsOrganizationIDUsers added in v0.2.49

func (h *Handler) PostApiV1OrganizationsOrganizationIDUsers(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PostOauth2V2Authorization added in v0.2.57

func (h *Handler) PostOauth2V2Authorization(w http.ResponseWriter, r *http.Request)

func (*Handler) PostOauth2V2Login

func (h *Handler) PostOauth2V2Login(w http.ResponseWriter, r *http.Request)

func (*Handler) PostOauth2V2Onboard added in v0.2.59

func (h *Handler) PostOauth2V2Onboard(w http.ResponseWriter, r *http.Request)

func (*Handler) PostOauth2V2Token

func (h *Handler) PostOauth2V2Token(w http.ResponseWriter, r *http.Request)

func (*Handler) PostOauth2V2Userinfo added in v0.2.57

func (h *Handler) PostOauth2V2Userinfo(w http.ResponseWriter, r *http.Request)

func (*Handler) PutApiV1OrganizationsOrganizationID added in v0.2.6

func (h *Handler) PutApiV1OrganizationsOrganizationID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDGroupsGroupid added in v0.2.6

func (h *Handler) PutApiV1OrganizationsOrganizationIDGroupsGroupid(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, groupID openapi.GroupidParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDOauth2providersProviderID added in v0.2.6

func (h *Handler) PutApiV1OrganizationsOrganizationIDOauth2providersProviderID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, providerID openapi.Oauth2ProvderIDParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDProjectsProjectID added in v0.2.6

func (h *Handler) PutApiV1OrganizationsOrganizationIDProjectsProjectID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDProjectsProjectIDAllocationsAllocationID added in v0.2.53

func (h *Handler) PutApiV1OrganizationsOrganizationIDProjectsProjectIDAllocationsAllocationID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, allocationID openapi.AllocationIDParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDProjectsProjectIDReferencesReference added in v1.9.0

func (h *Handler) PutApiV1OrganizationsOrganizationIDProjectsProjectIDReferencesReference(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, reference openapi.ReferenceParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDQuotas added in v0.2.53

func (h *Handler) PutApiV1OrganizationsOrganizationIDQuotas(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDServiceaccountsServiceAccountID added in v0.2.49

func (h *Handler) PutApiV1OrganizationsOrganizationIDServiceaccountsServiceAccountID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, serviceAccountID openapi.ServiceAccountIDParameter)

func (*Handler) PutApiV1OrganizationsOrganizationIDUsersUserID added in v0.2.51

func (h *Handler) PutApiV1OrganizationsOrganizationIDUsersUserID(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, userID openapi.UserIDParameter)

type Options

type Options struct {
	// cacheMaxAge defines the max age for cachable items e.g. images and
	// flavors don't change all that often.
	CacheMaxAge time.Duration

	// Options contains options shared across multiple handler components.
	Issuer common.IssuerValue

	// ServiceAccounts define any service account tunables.
	ServiceAccounts serviceaccounts.Options

	// Users define any user tunables.
	Users users.Options
}

Options defines configurable handler options.

func (*Options) AddFlags

func (o *Options) AddFlags(f *pflag.FlagSet)

AddFlags adds the options flags to the given flag set.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL