server

package
v0.0.0-...-bf6ee12 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package server implements a Policy Decision Point (PDP) for the OpenID AuthZEN Authorization API 1.0 over the normative HTTPS + JSON binding.

Users supply a PDP implementation (the decision logic) and obtain an http.Handler from NewHandler that wires the standard routes: the Access Evaluation API (Section 6), the Access Evaluations / batch API (Section 7), the Subject, Resource, and Action Search APIs (Section 8), and the well-known metadata document (Section 9). The handler enforces the transport rules of Section 10.1: POST with Content-Type application/json, HTTP 200 with a JSON body on success, and the documented status codes on error. A deny is a successful HTTP 200 with {"decision": false}; it is never an HTTP error (Section 10.1.2).

OpenID AuthZEN Authorization API 1.0, Section 10 (Transport). https://openid.net/specs/authorization-api-1_0.html#name-transport

Index

Examples

Constants

View Source
const (
	// DefaultReadTimeout bounds the time to read the entire request, including
	// the body. Caps slow-body (slow-read) attacks.
	DefaultReadTimeout = 10 * time.Second
	// DefaultReadHeaderTimeout bounds the time to read request headers. This is
	// the primary slowloris defense (a client that dribbles headers forever).
	DefaultReadHeaderTimeout = 5 * time.Second
	// DefaultWriteTimeout bounds the time from the end of the request header
	// read to the end of the response write. Caps slow-read clients that refuse
	// to drain the response.
	DefaultWriteTimeout = 15 * time.Second
	// DefaultIdleTimeout bounds how long a keep-alive connection may sit idle
	// between requests before being closed, reclaiming idle connections.
	DefaultIdleTimeout = 120 * time.Second
	// DefaultMaxHeaderBytes caps the size of request headers, bounding header
	// memory per connection. Mirrors net/http's own default but stated
	// explicitly for clarity.
	DefaultMaxHeaderBytes = 1 << 20 // 1 MiB
)

Hardened *http.Server timeout defaults. Go's zero-value http.Server applies NO timeouts, which leaves a PDP exposed to slowloris (slow header trickle) and slow-read/slow-body denial-of-service attacks: a handful of connections that send or read one byte at a time can pin server goroutines indefinitely. These defaults bound every phase of a connection's lifetime. All are configurable via ServerOptions.

The values are deliberately generous enough for normal JSON request/response exchanges yet small enough to reclaim resources from stalled peers.

View Source
const (
	// DefaultMaxBodyBytes caps the number of bytes a handler will read from a
	// request body before rejecting it with HTTP 413. It defends the PDP
	// against unbounded, pre-authentication request bodies (a DoS vector).
	// Override with WithMaxBodyBytes.
	DefaultMaxBodyBytes int64 = 1 << 20 // 1 MiB

	// DefaultMaxBatchSize caps the number of member evaluations accepted by the
	// Access Evaluations (batch) API before fan-out. A request exceeding it is
	// rejected with HTTP 400, bounding the work a single request can schedule.
	// Override with WithMaxBatchSize.
	DefaultMaxBatchSize = 1000
)

Transport-hardening defaults. All are configurable via HandlerOptions; the constants document the sane zero-value fallbacks applied by NewHandler.

Variables

This section is empty.

Functions

func EvaluateBatch

func EvaluateBatch(ctx context.Context, pdp PDP, req *authzen.EvaluationsRequest, opts ...BatchOption) (*authzen.EvaluationsResponse, error)

EvaluateBatch is the default Access Evaluations implementation. It resolves the top-level subject/action/resource/context defaults onto each member (Section 7.1.1), then evaluates them one at a time honoring the requested evaluations_semantic (Section 7.1.2.1):

  • execute_all (default): evaluate every member and return all decisions in request order;
  • deny_on_first_deny: stop at and include the first deny (logical AND);
  • permit_on_first_permit: stop at and include the first permit (logical OR).

Per-evaluation resilience (Section 7.2.1): a backend error from a single member does NOT fail the whole boxcar. The offending member is given a fail-safe closed decision (decision=false) with the error surfaced in that item's response context under the "error" key ({status, message}), and the remaining members still evaluate. For deny_on_first_deny an errored member is a deny and therefore short-circuits; for permit_on_first_permit it is not a permit and evaluation continues. Decisions default closed (Section 5.5).

Error hygiene: the per-member "error" object NEVER carries the raw backend error message by default, since that can leak internal detail to the caller (the same risk addressed for top-level HTTP 500s). Instead it carries a generic message and a correlation id, while the full detail is logged server-side against that id via the configured slog logger. Pass WithBatchVerboseErrors(true) (wired from the handler's WithVerboseErrors) to include the real message in the response - intended only for trusted/debug environments. Configure the logger with WithBatchErrorLogger; when unset it defaults to slog.Default().

A genuine request-wide failure (a cancelled or expired context) is returned as a non-nil error, which the handler maps to HTTP 500; that is the only condition that fails the entire request.

OpenID AuthZEN Authorization API 1.0, Section 7 (Access Evaluations API) and Section 7.2.1 (Errors in batch). https://openid.net/specs/authorization-api-1_0.html#name-access-evaluations-api

func NewServer

func NewServer(addr string, h http.Handler, opts ...ServerOption) *http.Server

NewServer builds a production-hardened *http.Server for an AuthZEN handler (or any http.Handler). Unlike a zero-value http.Server, it sets ReadTimeout, ReadHeaderTimeout, WriteTimeout, and IdleTimeout so that slow or stalled peers cannot exhaust server resources (slowloris and slow-read DoS); see the Default* constants for the rationale of each. It also pins a minimum TLS version of 1.2 in the default TLSConfig.

Transport security: AuthZEN mandates the HTTPS + JSON binding (Section 10.1), so serve this with TLS in production:

srv := server.NewServer(":8443", handler)
log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))

The default TLSConfig sets MinVersion = tls.VersionTLS12; override it with WithTLSConfig to pin TLS 1.3, configure cipher suites, or supply certificates via GetCertificate. For plain HTTP (for example behind a TLS-terminating load balancer) call srv.ListenAndServe instead; the TLSConfig is then ignored.

OpenID AuthZEN Authorization API 1.0, Section 10.1 (Transport): "The Access Evaluation API is a JSON/HTTPS API." https://openid.net/specs/authorization-api-1_0.html#name-transport

Example

ExampleNewServer shows constructing a hardened HTTP server for an AuthZEN handler. In production, serve it over TLS with srv.ListenAndServeTLS.

h := server.NewHandler(stubPDP{})
srv := server.NewServer(":8443", h)

fmt.Println(srv.Addr)
fmt.Println(srv.ReadHeaderTimeout)
fmt.Println(srv.TLSConfig.MinVersion == tls.VersionTLS12)

// In production:
//   log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
Output:
:8443
5s
true

Types

type BatchEvaluator

type BatchEvaluator interface {
	EvaluateBatch(ctx context.Context, req *authzen.EvaluationsRequest) (*authzen.EvaluationsResponse, error)
}

BatchEvaluator is an optional interface a PDP may implement to handle the Access Evaluations (batch) API directly, for example to evaluate members in parallel. When a PDP does not implement it, the handler falls back to EvaluateBatch.

OpenID AuthZEN Authorization API 1.0, Section 7 (Access Evaluations API). https://openid.net/specs/authorization-api-1_0.html#name-access-evaluations-api

type BatchOption

type BatchOption func(*batchConfig)

BatchOption configures EvaluateBatch, primarily its per-member error hygiene.

func WithBatchErrorLogger

func WithBatchErrorLogger(l *slog.Logger) BatchOption

WithBatchErrorLogger sets the slog.Logger used to record the full detail of a per-member backend error (against the correlation id surfaced to the caller). A nil logger resets to slog.Default(). The handler wires its own logger here so batch and top-level errors land in the same place.

func WithBatchVerboseErrors

func WithBatchVerboseErrors(enabled bool) BatchOption

WithBatchVerboseErrors controls whether a per-member error context carries the real backend error message. It defaults to false (the message is redacted to a generic string plus a correlation id). Enable it only in trusted/debug environments; the handler wires this from WithVerboseErrors.

OpenID AuthZEN Authorization API 1.0, Section 7.2.1 (Errors in batch). https://openid.net/specs/authorization-api-1_0.html

type Handler

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

Handler is an http.Handler that serves the AuthZEN APIs for a PDP. Build one with NewHandler.

func NewHandler

func NewHandler(pdp PDP, opts ...HandlerOption) *Handler

NewHandler builds an http.Handler serving the AuthZEN APIs for pdp. Routing uses net/http.ServeMux. Each API path is matched regardless of method so the handler can return JSON errors with correct status codes (405 for the wrong method, 415 for the wrong media type, ...); a catch-all route returns a JSON 404 for unknown paths.

OpenID AuthZEN Authorization API 1.0, Section 10.1 (Transport), Table 1. https://openid.net/specs/authorization-api-1_0.html#name-transport

func (*Handler) ServeHTTP

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

ServeHTTP implements http.Handler.

type HandlerOption

type HandlerOption func(*Handler)

HandlerOption configures a Handler built with NewHandler.

func WithErrorLogger

func WithErrorLogger(l *slog.Logger) HandlerOption

WithErrorLogger sets the slog.Logger used to record server-side error and panic detail. A nil logger resets to slog.Default().

func WithEvaluationPath

func WithEvaluationPath(p string) HandlerOption

WithEvaluationPath overrides the Access Evaluation route (default /access/v1/evaluation).

func WithEvaluationsPath

func WithEvaluationsPath(p string) HandlerOption

WithEvaluationsPath overrides the Access Evaluations route (default /access/v1/evaluations).

func WithMaxBatchSize

func WithMaxBatchSize(n int) HandlerOption

WithMaxBatchSize overrides the cap on the number of member evaluations accepted by the Access Evaluations (batch) API. A request exceeding the cap is rejected with HTTP 400 before any fan-out. A non-positive value resets the cap to DefaultMaxBatchSize.

OpenID AuthZEN Authorization API 1.0, Section 7 (Access Evaluations API). https://openid.net/specs/authorization-api-1_0.html#name-access-evaluations-api

func WithMaxBodyBytes

func WithMaxBodyBytes(n int64) HandlerOption

WithMaxBodyBytes overrides the per-request body cap enforced by every body-reading handler. A request whose body exceeds the cap is rejected with HTTP 413 (Payload Too Large) before the PDP is invoked. A non-positive value resets the cap to DefaultMaxBodyBytes.

func WithMetadata

func WithMetadata(md *authzen.Metadata) HandlerOption

WithMetadata configures the document served at /.well-known/authzen-configuration. When no metadata is configured the well-known endpoint responds 404, signaling that discovery is unsupported.

OpenID AuthZEN Authorization API 1.0, Section 9 (Metadata). https://openid.net/specs/authorization-api-1_0.html#name-metadata

func WithSearchActionPath

func WithSearchActionPath(p string) HandlerOption

WithSearchActionPath overrides the Action Search route (default /access/v1/search/action).

func WithSearchResourcePath

func WithSearchResourcePath(p string) HandlerOption

WithSearchResourcePath overrides the Resource Search route (default /access/v1/search/resource).

func WithSearchSubjectPath

func WithSearchSubjectPath(p string) HandlerOption

WithSearchSubjectPath overrides the Subject Search route (default /access/v1/search/subject).

func WithVerboseErrors

func WithVerboseErrors(enabled bool) HandlerOption

WithVerboseErrors controls whether client-facing error bodies carry the underlying error detail. It defaults to false: clients receive a generic message while the detail is logged server-side with a correlation id. Enable it only in trusted/debug environments (Section 10.1.2).

type PDP

type PDP interface {
	// Evaluate decides a single Access Evaluation request (Section 6).
	Evaluate(ctx context.Context, req *authzen.EvaluationRequest) (*authzen.EvaluationResponse, error)
	// SearchSubjects answers a Subject Search (Section 8.4).
	SearchSubjects(ctx context.Context, req *authzen.SubjectSearchRequest) (*authzen.SubjectSearchResponse, error)
	// SearchResources answers a Resource Search (Section 8.5).
	SearchResources(ctx context.Context, req *authzen.ResourceSearchRequest) (*authzen.ResourceSearchResponse, error)
	// SearchActions answers an Action Search (Section 8.6).
	SearchActions(ctx context.Context, req *authzen.ActionSearchRequest) (*authzen.ActionSearchResponse, error)
}

PDP is the decision logic a user implements. The handler adapts these methods to the HTTPS + JSON binding. Implementations receive requests that have already passed the package's structural validation (the REQUIRED fields are present), and return the corresponding response or a non-nil error. A returned error is mapped to HTTP 500; to deny access, return a response with Decision == false and HTTP 200 (Section 10.1.2), not an error.

Batch evaluation is optional: an implementation that also satisfies BatchEvaluator handles /access/v1/evaluations itself; otherwise the handler derives the batch result by looping Evaluate via EvaluateBatch, honoring the requested evaluations_semantic.

OpenID AuthZEN Authorization API 1.0, Section 6, Section 8. https://openid.net/specs/authorization-api-1_0.html

type ServerOption

type ServerOption func(*serverConfig)

ServerOption configures the *http.Server returned by NewServer.

func WithIdleTimeout

func WithIdleTimeout(d time.Duration) ServerOption

WithIdleTimeout overrides DefaultIdleTimeout. A non-positive value resets it to the default.

func WithMaxHeaderBytes

func WithMaxHeaderBytes(n int) ServerOption

WithMaxHeaderBytes overrides DefaultMaxHeaderBytes. A non-positive value resets it to the default.

func WithReadHeaderTimeout

func WithReadHeaderTimeout(d time.Duration) ServerOption

WithReadHeaderTimeout overrides DefaultReadHeaderTimeout. A non-positive value resets it to the default.

func WithReadTimeout

func WithReadTimeout(d time.Duration) ServerOption

WithReadTimeout overrides DefaultReadTimeout. A non-positive value resets it to the default.

func WithTLSConfig

func WithTLSConfig(cfg *tls.Config) ServerOption

WithTLSConfig replaces the default *tls.Config (which pins a minimum of TLS 1.2). A nil value resets to the secure default. The returned server still requires the caller to invoke ListenAndServeTLS (or serve behind a TLS terminator); setting TLSConfig alone does not enable TLS.

func WithWriteTimeout

func WithWriteTimeout(d time.Duration) ServerOption

WithWriteTimeout overrides DefaultWriteTimeout. A non-positive value resets it to the default.

Jump to

Keyboard shortcuts

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