Documentation
¶
Overview ¶
Package sandbox runs every AAuth role from aauth-go together for development: an agent provider, a person server, an access server and two demo resources, on real HTTPS origins under a development certificate authority, with consent pages, a message trace, and a signing helper for HTTP clients that cannot sign (Postman, curl).
The sandbox is a development tool. Its keys, certificate authority and automatic consent are for local use only.
Index ¶
- Constants
- Variables
- func IsLoopback(addr string) bool
- func NewClient(cfg Config, ca *CA, addr string) *http.Client
- type CA
- type Config
- type Exchange
- type Message
- type Sandbox
- func (s *Sandbox) CA() *CA
- func (s *Sandbox) Client(from string) *http.Client
- func (s *Sandbox) Config() Config
- func (s *Sandbox) Handler() http.Handler
- func (s *Sandbox) Serve(ctx context.Context, ln net.Listener) error
- func (s *Sandbox) SetAddr(addr string)
- func (s *Sandbox) Signer() *Signer
- func (s *Sandbox) TLSConfig() *tls.Config
- func (s *Sandbox) Trace() *Trace
- type Signer
- type Trace
Constants ¶
const ( RoleAP = "ap" RolePS = "ps" RoleAS = "as" RoleResource = "resource" RoleDocs = "docs" )
Role names.
const ( // ConsentAuto approves every interaction as soon as it is created. ConsentAuto = "auto" // ConsentManual waits for a person at the interaction page, or for // a headless approval at /sandbox/approve. ConsentManual = "manual" )
Consent modes.
const ( PathAgentToken = "/agent-token" // jkt-jwt two-key refresh (enrollment in the walkthrough) PathEnroll = "/enroll" // hwk enrollment and single-key refresh PathPersonToken = "/person" PathToken = "/token" PathPending = "/pending/" PathInteraction = "/interaction" PathJWKS = "/jwks.json" PathApprove = "/sandbox/approve" PathTrace = "/sandbox/trace" )
Paths the sandbox serves, matching the AAuth walkthrough examples.
const ( // HeaderPresent selects how the helper signs: agent (default), // person, auth, hwk, jkt-jwt, or none. HeaderPresent = "X-Sandbox-Present" // HeaderToken is the token to present: required for person and // auth; for agent it replaces the helper's own agent token. HeaderToken = "X-Sandbox-Token" // HeaderCapabilitiesOverride replaces the capabilities the helper // declares to resources (default: interaction); empty declares none. HeaderCapabilitiesOverride = "X-Sandbox-Capabilities" )
Signing helper control headers. The helper removes them before forwarding a request.
const ( PresentAgent = "agent" PresentPerson = "person" PresentAuth = "auth" PresentHWK = "hwk" PresentJKTJWT = "jkt-jwt" PresentNone = "none" )
Presentation modes for HeaderPresent.
const AgentName = "assistant"
AgentName is the local part of the test agent's identifier.
const (
CACertFile = "ca.pem"
)
CA file names in the state directory.
const DefaultDomain = "aauth.test"
DefaultDomain is the parent domain of the default role host names. The .test top-level domain is reserved for testing (RFC 6761).
const DefaultListenAddr = "127.0.0.1:443"
DefaultListenAddr is the roles' default TLS listen address: loopback only, since the roles hand out tokens and approve consent on their own.
const DefaultPerson = "alice"
DefaultPerson is the person every approval acts for.
const DefaultSignerAddr = "127.0.0.1:8099"
DefaultSignerAddr is the signing helper's default listen address.
const HeaderFrom = "X-Sandbox-From"
HeaderFrom names the role that sent a request inside the sandbox. The sandbox's own clients set it; role handlers remove it before serving, and it is never covered by a signature.
Variables ¶
var Roles = []string{RoleAP, RolePS, RoleAS, RoleResource, RoleDocs}
Roles lists the roles in display order.
Functions ¶
func IsLoopback ¶
IsLoopback reports whether the listen address addr (host:port) is a loopback address or localhost. An empty host (":443") listens on every interface and is not loopback.
Types ¶
type CA ¶
type CA struct {
Cert *x509.Certificate
CertPEM []byte
// Replaced says why LoadOrCreateCA replaced the CA that was in the
// state directory (it had no name constraints, was about to expire,
// or did not cover a domain), or is empty. Clients that trusted the
// old CA must trust the new one.
Replaced string
// contains filtered or unexported fields
}
CA is the sandbox's development certificate authority. It is name constrained: it can issue certificates only for its Domains (and their subdomains) and the loopback addresses, so trusting it does not let its key vouch for any other site.
func LoadOrCreateCA ¶
LoadOrCreateCA reads the CA from dir, creating it on first use, and replacing one that has no name constraints, expires within 30 days, or does not cover one of domains. domains are the DNS names the CA may issue for, with their subdomains (default: DefaultDomain); localhost and the loopback addresses are always permitted. The private key is written with mode 0600.
func (*CA) IssueServerCert ¶
func (ca *CA) IssueServerCert(names []string) (tls.Certificate, error)
IssueServerCert issues a TLS certificate for names, plus localhost and the loopback addresses, valid for a year or until the CA expires. The names must sit under the CA's domains.
type Config ¶
type Config struct {
// StateDir holds the certificate authority and role keys (default
// ~/.aauth-sandbox).
StateDir string
// Domain is the parent domain of the role host names (default
// aauth.test); role hosts are <role>.<Domain> unless Hosts sets one.
Domain string
// Hosts overrides a role's host name.
Hosts map[string]string
// Remote maps a role to an external implementation's https origin;
// the sandbox does not serve that role and calls the URL instead.
Remote map[string]string
// Upstreams maps an extra host name to the http or https origin of a
// server outside the sandbox, such as a resource under development.
// The sandbox serves the host over TLS with its CA, records its
// traffic in the trace and passes requests through with their Host
// header, so the server's identifier is https://<host>. A name
// without a dot is under Domain (petstore: petstore.aauth.test).
Upstreams map[string]string
// Consent is ConsentAuto (default) or ConsentManual.
Consent string
// Person is the person approvals act for (default alice).
Person string
// TraceSize bounds the trace (default 2000 exchanges).
TraceSize int
}
Config configures a Sandbox. Zero values take defaults.
func Init ¶
Init creates the certificate authority and every key the sandbox uses in cfg's state directory, if they do not exist. Run it once before starting several sandbox processes that share a state directory, such as one container per role.
func (Config) CADomains ¶
CADomains returns the DNS names the sandbox CA is constrained to: Domain, and each local host name that is not under Domain (a Hosts override or an upstream named outside it).
func (Config) HostsLine ¶
HostsLine returns the /etc/hosts line that points the local role names at this machine.
func (Config) LocalHosts ¶
LocalHosts returns the host names the sandbox serves: its local roles' in role order, then its upstreams' in name order.
func (Config) UpstreamHosts ¶
UpstreamHosts returns the upstream host names in name order.
func (Config) WithDefaults ¶
WithDefaults returns cfg with defaults applied and checked, as New applies them.
type Exchange ¶
type Exchange struct {
Time time.Time `json:"time"`
From string `json:"from"`
To string `json:"to"`
Request Message `json:"request"`
Response Message `json:"response"`
}
Exchange is one request and its response, between two roles.
type Message ¶
type Message struct {
Method string `json:"method,omitempty"`
URL string `json:"url,omitempty"`
Status int `json:"status,omitempty"`
Headers [][2]string `json:"headers,omitempty"`
Body json.RawMessage `json:"body,omitempty"`
}
Message is an HTTP request or response. Headers keep their order; Body is JSON when the body is JSON, and a JSON string otherwise.
type Sandbox ¶
type Sandbox struct {
// contains filtered or unexported fields
}
Sandbox runs the local roles behind one TLS listener, routed by host.
func New ¶
New builds a sandbox: it loads or creates the CA and role keys in cfg.StateDir and configures every local role. Call Serve to start it.
func (*Sandbox) Client ¶
Client returns the HTTP client a role (or "agent") sends requests with: it trusts the sandbox CA and reaches local roles by name.
func (*Sandbox) Handler ¶
Handler routes requests to local roles by host, and serves the trace on every role host to clients other than web pages.
func (*Sandbox) SetAddr ¶
SetAddr sets the address that local role host names are dialed at; Serve sets it from its listener.
type Signer ¶
type Signer struct {
// AnyInterface lets ListenAndServe listen on a non-loopback address.
// Set it only inside a container whose port is published to the
// host's loopback address: the helper signs what it is sent.
AnyInterface bool
// AnyTarget lets the helper sign and forward requests for any https
// host. By default it signs only for the sandbox's own role hosts,
// its upstreams and its remote role origins.
AnyTarget bool
// Hosts are extra Host header names the helper answers to, besides
// localhost and the loopback addresses (and the address it listens
// on). Requests naming any other host are refused, so a web page
// cannot reach the helper by pointing a DNS name at 127.0.0.1.
Hosts []string
// contains filtered or unexported fields
}
Signer is the sandbox's test agent and its signing helper: HTTP clients that cannot sign send requests through it, and it signs them as the agent (RFC 9421 with a Signature-Key) and forwards them.
The agent has a durable key and a current (ephemeral) key. It holds an agent token from the agent provider bound to the current key, obtained by a two-key refresh: a naming JWT signed by the durable key delegating to the current key. An agent token a client obtains through the helper with jkt-jwt is bound to the same current key, so the client can pass it back in X-Sandbox-Token.
func (*Signer) AgentToken ¶
AgentToken returns a current agent token, refreshing it at the agent provider when it is missing or expires within five minutes.
func (*Signer) ListenAndServe ¶
ListenAndServe serves the helper on addr, which must be a loopback address unless AnyInterface is set: the helper signs anything it is sent.
func (*Signer) ServeHTTP ¶
func (sg *Signer) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP serves the helper:
- GET / describes the helper and the agent;
- POST /sign returns the headers that sign a described request;
- any request to /<https URL> is signed and forwarded to that URL, and the response is returned unchanged.
It answers only requests whose Host is a loopback name (or one of Hosts), and refuses requests a browser sends on behalf of a web page (those with Origin, or Sec-Fetch-Site naming another site). OPTIONS is answered without forwarding.