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 ¶
- Constants
- func EvaluateBatch(ctx context.Context, pdp PDP, req *authzen.EvaluationsRequest, ...) (*authzen.EvaluationsResponse, error)
- func NewServer(addr string, h http.Handler, opts ...ServerOption) *http.Server
- type BatchEvaluator
- type BatchOption
- type Handler
- type HandlerOption
- func WithErrorLogger(l *slog.Logger) HandlerOption
- func WithEvaluationPath(p string) HandlerOption
- func WithEvaluationsPath(p string) HandlerOption
- func WithMaxBatchSize(n int) HandlerOption
- func WithMaxBodyBytes(n int64) HandlerOption
- func WithMetadata(md *authzen.Metadata) HandlerOption
- func WithSearchActionPath(p string) HandlerOption
- func WithSearchResourcePath(p string) HandlerOption
- func WithSearchSubjectPath(p string) HandlerOption
- func WithVerboseErrors(enabled bool) HandlerOption
- type PDP
- type ServerOption
- func WithIdleTimeout(d time.Duration) ServerOption
- func WithMaxHeaderBytes(n int) ServerOption
- func WithReadHeaderTimeout(d time.Duration) ServerOption
- func WithReadTimeout(d time.Duration) ServerOption
- func WithTLSConfig(cfg *tls.Config) ServerOption
- func WithWriteTimeout(d time.Duration) ServerOption
Examples ¶
Constants ¶
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.
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 ¶
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
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.