Documentation
¶
Overview ¶
Package ssf holds the value types shared by every part of SSFgo: subject identifiers (RFC 9493 and OpenID Shared Signals Framework 1.0 §3), the Event contract and Registry that event families such as caep, risc and scim plug into, SSF's own verification and stream-updated events, and the decoded view of a Security Event Token (SET).
This package knows nothing about any particular event family. It never imports caep, risc or scim; they register themselves with a Registry instead.
Encoding and signing SETs is deliberately not exposed here. Applications emit typed events through a Transmitter and receive verified SETs from a Receiver; neither needs to build a JWT by hand.
Index ¶
- Constants
- Variables
- func Register[E Event](r *Registry) error
- func SubjectsEqual(a, b Subject) bool
- func SubjectsMatch(a, b Subject) bool
- func ValidateIssuer(issuer string) error
- func WellKnownURL(issuer string) (string, error)
- type AccountSubject
- type AddSubjectRequest
- type AliasesSubject
- type Assurance
- type Audience
- type AuthorizationScheme
- type ComplexSubject
- type DIDSubject
- type DefaultSubjects
- type Delivery
- type DeliveryMethod
- type EmailSubject
- type Event
- type EventType
- type IPAddressesSubject
- type IssSubSubject
- type JWTIDSubject
- type KeyCustody
- type KeyCustodyAssurance
- type LocalizedText
- type NumericDate
- type OpaqueSubject
- type PhoneNumberSubject
- type ProprietarySubject
- type Registry
- type RemoveSubjectRequest
- type SAMLAssertionIDSubject
- type SCIMSubject
- type SET
- type Secret
- func (s Secret) Format(f fmt.State, verb rune)
- func (s Secret) GoString() string
- func (s Secret) IsZero() bool
- func (s Secret) LogValue() slog.Value
- func (s Secret) MarshalText() ([]byte, error)
- func (s Secret) Reveal() string
- func (s Secret) String() string
- func (s *Secret) UnmarshalText(text []byte) error
- type SignatureAlgorithm
- type StreamConfiguration
- type StreamState
- type StreamStatus
- type StreamUpdated
- type Subject
- type SubjectConstrainedEvent
- type SubjectFormat
- type TransmitterMetadata
- type URISubject
- type Verification
- type VerificationRequest
Examples ¶
Constants ¶
const OAuth2SpecURN = "urn:ietf:rfc:6749" // NOSONAR: a public RFC identifier, not a secret
OAuth2SpecURN is the authorization scheme spec_urn for OAuth 2.0 (RFC 6749). The CAEP Interoperability Profile §2.3.7 requires Transmitters to advertise it.
const SpecVersion = "1_0"
SpecVersion is the "spec_version" SSFgo implements (SSF 1.0 §7.1).
const WellKnownPath = "/.well-known/ssf-configuration"
WellKnownPath is the path segment Transmitter Configuration Metadata is published under (SSF 1.0 §7.2).
Variables ¶
var ErrInvalidEvent = errors.New("ssf: invalid event")
ErrInvalidEvent is wrapped by every error that reports a malformed event object.
var ErrInvalidSubject = errors.New("ssf: invalid subject")
ErrInvalidSubject is wrapped by every error that reports a malformed or incomplete subject.
var ErrSecretSerialization = errors.New("ssf: secret values cannot be marshaled")
ErrSecretSerialization is returned by Secret.MarshalText, so a Secret is never serialized — into a log line, a JSON body, a debug dump — by code that does not know it holds one.
var ErrUnsupportedEventType = errors.New("ssf: unsupported event type")
ErrUnsupportedEventType is returned by Registry.Decode for an event type the registry has no decoder for.
Functions ¶
func Register ¶
Register adds event type E to r. E's zero value supplies the event type URI. Registering a type twice is an error.
func SubjectsEqual ¶
SubjectsEqual reports whether a and b are identical: the same format and the same member values. Aliases compare their identifiers in order.
func SubjectsMatch ¶
SubjectsMatch reports whether a and b match under SSF 1.0 §8.1.3.1. Simple subjects match when they are identical. Two complex subjects match when every member defined in both is identical; a member defined in only one of them acts as a wildcard. A simple subject never matches a complex one.
func ValidateIssuer ¶
ValidateIssuer reports whether issuer is an https URL with no query or fragment (SSF 1.0 §7.1).
func WellKnownURL ¶
WellKnownURL returns where issuer publishes its Transmitter Configuration Metadata: "/.well-known/ssf-configuration" inserted between the host and any path, with a trailing "/" removed first (SSF 1.0 §7.2).
Example ¶
A Transmitter's metadata is at a well-known location derived from its issuer (SSF 1.0 §7.2).
package main
import (
"fmt"
ssf "github.com/idfoundry/ssfgo"
)
func main() {
u, err := ssf.WellKnownURL("https://idp.example.com/tenants/acme")
if err != nil {
panic(err)
}
fmt.Println(u)
}
Output: https://idp.example.com/.well-known/ssf-configuration/tenants/acme
Types ¶
type AccountSubject ¶
type AccountSubject struct {
// URI is the "acct" URI, such as "acct:alice@example.com". Required.
URI string
}
AccountSubject identifies a subject by an "acct" URI (RFC 9493 §3.2.1).
func (AccountSubject) Format ¶
func (AccountSubject) Format() SubjectFormat
Format implements Subject.
func (AccountSubject) MarshalJSON ¶
func (s AccountSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (AccountSubject) Validate ¶
func (s AccountSubject) Validate() error
Validate implements Subject.
type AddSubjectRequest ¶
type AddSubjectRequest struct {
// StreamID is the stream to add the subject to. Required.
StreamID string
// Subject is the subject to add. Required.
Subject Subject
// Verified is nil when the Receiver did not say; the Transmitter
// should then assume the subject was verified.
Verified *bool
}
AddSubjectRequest is the body of an Add Subject request (SSF 1.0 §8.1.3.2).
func (AddSubjectRequest) MarshalJSON ¶
func (r AddSubjectRequest) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (*AddSubjectRequest) UnmarshalJSON ¶
func (r *AddSubjectRequest) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
type AliasesSubject ¶
type AliasesSubject struct {
// Identifiers are the subject's identifiers, one or more.
Identifiers []Subject
}
AliasesSubject identifies one subject by several Subject Identifiers (RFC 9493 §3.2.8). Its identifiers may not themselves be aliases or complex subjects.
func (AliasesSubject) Format ¶
func (AliasesSubject) Format() SubjectFormat
Format implements Subject.
func (AliasesSubject) MarshalJSON ¶
func (s AliasesSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (AliasesSubject) Validate ¶
func (s AliasesSubject) Validate() error
Validate implements Subject.
type Assurance ¶
type Assurance uint8
Assurance is the deployment a Transmitter, Receiver or Revoker is configured for. It is required: there is no default, and the zero value is invalid.
const ( // AssuranceDevelopment accepts what tests and local development use: // in-memory stores, loopback hosts. AssuranceDevelopment Assurance = iota + 1 // AssuranceProduction refuses them: every store must declare it is // durable (storage.Capabilities), and, when the deployment is // horizontally scaled, consistent across instances; every signing key // must be declared durable (KeyCustody); the issuer and endpoints // configured must not be loopback hosts. AssuranceProduction )
type Audience ¶
type Audience []string
Audience is a JWT "aud" value: one string or an array of strings (RFC 7519 §4.1.3). It encodes a single value as a string, and no values as an empty array rather than null, so every encoding decodes again.
func (Audience) MarshalJSON ¶
MarshalJSON implements json.Marshaler.
func (*Audience) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler.
type AuthorizationScheme ¶
type AuthorizationScheme struct {
// SpecURN is the URN of the specification defining the scheme, such
// as OAuth2SpecURN.
SpecURN string `json:"spec_urn"`
}
AuthorizationScheme names a scheme protecting the stream management API (SSF 1.0 §7.1.1).
type ComplexSubject ¶
type ComplexSubject struct {
// User is the "user" member; nil if absent.
User Subject
// Device is the "device" member; nil if absent.
Device Subject
// Session is the "session" member; nil if absent.
Session Subject
// Application is the "application" member; nil if absent.
Application Subject
// Tenant is the "tenant" member; nil if absent.
Tenant Subject
// OrgUnit is the "org_unit" member; nil if absent.
OrgUnit Subject
// Group is the "group" member; nil if absent.
Group Subject
// Additional maps further member names to their subjects.
Additional map[string]Subject
}
ComplexSubject describes one Subject Principal through several of its attributes (SSF 1.0 §3.3). At least one member must be set. Members are simple subjects: a ComplexSubject never nests another.
Additional carries member names beyond those SSF 1.0 §3.3 lists; its keys must not repeat a named member or "format".
func (ComplexSubject) Format ¶
func (ComplexSubject) Format() SubjectFormat
Format implements Subject.
func (ComplexSubject) MarshalJSON ¶
func (s ComplexSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. Defined members are encoded in SSF 1.0 §3.3 order, followed by Additional members sorted by name.
func (ComplexSubject) Validate ¶
func (s ComplexSubject) Validate() error
Validate implements Subject.
type DIDSubject ¶
type DIDSubject struct {
// URL is the DID URL, such as "did:example:123456". Required.
URL string
}
DIDSubject identifies a subject by a Decentralized Identifier URL (RFC 9493 §3.2.6).
func (DIDSubject) MarshalJSON ¶
func (s DIDSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
type DefaultSubjects ¶
type DefaultSubjects string
DefaultSubjects says whether newly created streams include every appropriate subject or none (SSF 1.0 §7.1).
const ( // DefaultSubjectsAll adds every appropriate subject to new streams; // Receivers remove the ones they do not want. DefaultSubjectsAll DefaultSubjects = "ALL" // DefaultSubjectsNone adds no subjects to new streams; Receivers add // the ones they want. DefaultSubjectsNone DefaultSubjects = "NONE" )
type Delivery ¶
type Delivery struct {
// Method is the "method" member: DeliveryPush or DeliveryPoll.
Method DeliveryMethod `json:"method"`
// EndpointURL is where the Transmitter pushes SETs (push, set by the
// Receiver) or where the Receiver polls for them (poll, set by the
// Transmitter).
EndpointURL string `json:"endpoint_url,omitempty"`
// AuthorizationHeader is the push-only Authorization header value
// the Transmitter sends with every push request (SSF 1.0 §6.1.1).
AuthorizationHeader Secret `json:"authorization_header,omitzero"`
}
Delivery is a stream's "delivery" member (SSF 1.0 §6.1).
func (Delivery) LogValue ¶
LogValue implements slog.LogValuer: a logged Delivery withholds its Authorization header, which a JSON handler would otherwise take from MarshalJSON.
func (Delivery) MarshalJSON ¶
MarshalJSON implements json.Marshaler. A Delivery's JSON is its wire form (SSF 1.0 §6.1), and so includes the Authorization header: it is for the protocol and for storage, never for a log.
type DeliveryMethod ¶
type DeliveryMethod string
DeliveryMethod identifies how SETs are delivered on a stream (SSF 1.0 §6.1).
const ( // DeliveryPush is push-based delivery over HTTP (RFC 8935). DeliveryPush DeliveryMethod = "urn:ietf:rfc:8935" // DeliveryPoll is poll-based delivery over HTTP (RFC 8936). DeliveryPoll DeliveryMethod = "urn:ietf:rfc:8936" )
type EmailSubject ¶
type EmailSubject struct {
// Email is the email address. Required.
Email string
}
EmailSubject identifies a subject by email address (RFC 9493 §3.2.2). Addresses are compared exactly; a Receiver that needs provider-specific canonicalization (RFC 9493 §3.2.2.1) applies it itself.
func (EmailSubject) MarshalJSON ¶
func (s EmailSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (EmailSubject) Validate ¶
func (s EmailSubject) Validate() error
Validate implements Subject. It checks only that the address has a non-empty local part and domain; RFC 5322 addr-spec syntax is otherwise the Transmitter's responsibility.
type Event ¶
type Event interface {
EventType() EventType
// Validate reports whether every member the event type requires is
// present and every member present has a permitted value.
Validate() error
}
Event is one event family's typed representation of an event object — the value under its EventType in a SET's "events" claim. It does not include the subject: SSF 1.0 §3.1 carries the primary subject in the SET's top-level "sub_id" claim.
Implementations are value types whose JSON encoding is the event object, and whose EventType does not depend on the receiver's value, so the zero value reports its type.
type EventType ¶
type EventType string
EventType is an event type URI, the key of a SET's "events" claim (RFC 8417 §2.2).
const ( // VerificationEventType is the verification event (SSF 1.0 §8.1.4.1). VerificationEventType EventType = "https://schemas.openid.net/secevent/ssf/event-type/verification" // StreamUpdatedEventType is the stream-updated event (SSF 1.0 §8.1.5). StreamUpdatedEventType EventType = "https://schemas.openid.net/secevent/ssf/event-type/stream-updated" )
Event types defined by SSF 1.0 itself.
type IPAddressesSubject ¶
type IPAddressesSubject struct {
// Addresses are the observed IPv4 or IPv6 addresses, one or more.
Addresses []netip.Addr
}
IPAddressesSubject identifies a subject by the IP addresses the Transmitter observed for it (SSF 1.0 §3.5.3).
func (IPAddressesSubject) Format ¶
func (IPAddressesSubject) Format() SubjectFormat
Format implements Subject.
func (IPAddressesSubject) MarshalJSON ¶
func (s IPAddressesSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (IPAddressesSubject) Validate ¶
func (s IPAddressesSubject) Validate() error
Validate implements Subject.
type IssSubSubject ¶
type IssSubSubject struct {
// Issuer is the "iss" of the subject's issuer. Required.
Issuer string
// Subject is the "sub", unique within Issuer. Required.
Subject string
}
IssSubSubject identifies a subject by issuer and subject (RFC 9493 §3.2.3).
func (IssSubSubject) Format ¶
func (IssSubSubject) Format() SubjectFormat
Format implements Subject.
func (IssSubSubject) MarshalJSON ¶
func (s IssSubSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (IssSubSubject) Validate ¶
func (s IssSubSubject) Validate() error
Validate implements Subject.
type JWTIDSubject ¶
type JWTIDSubject struct {
// Issuer is the JWT's "iss". Required.
Issuer string
// JWTID is the JWT's "jti". Required.
JWTID string
}
JWTIDSubject identifies a JWT by its issuer and "jti" (SSF 1.0 §3.5.1).
func (JWTIDSubject) MarshalJSON ¶
func (s JWTIDSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
type KeyCustody ¶
type KeyCustody struct {
// Durable means the key survives a process restart: held by a KMS or
// an HSM, or loaded from durable storage, rather than generated at
// startup.
Durable bool
// CrossInstanceConsistent means every instance of a horizontally
// scaled deployment uses the same key.
CrossInstanceConsistent bool
}
KeyCustody is what is declared about how a private key is held. Under AssuranceProduction a Transmitter's signing keys, and a Receiver's private_key_jwt key, must be declared durable — and, when the deployment is horizontally scaled, shared by every instance — because nothing about a crypto.Signer says whether its key survives a restart.
A Transmitter signs SETs when it queues them, so a signing key made afresh at each start strands every SET queued before a restart: the Receiver no longer finds its key, and rejects it. Instances with keys of their own sign SETs that only some JWKS documents verify.
type KeyCustodyAssurance ¶
type KeyCustodyAssurance interface {
KeyCustody() KeyCustody
}
KeyCustodyAssurance is implemented by a crypto.Signer that declares how its key is held — a KMS or HSM client, say. A key that neither implements it nor has custody declared for it in its configuration counts as neither durable nor shared.
type LocalizedText ¶
LocalizedText is a JSON object mapping BCP 47 language tags (RFC 5646) to human-readable text, as used by CAEP's "reason_admin" and "reason_user" (CAEP 1.0 §2).
A nil or empty LocalizedText means "absent": use it with the `omitempty` struct tag. When present it must hold at least one entry.
func (*LocalizedText) UnmarshalJSON ¶
func (t *LocalizedText) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. It rejects anything but a JSON object of strings — CAEP 1.0 §2 does not permit a bare string.
func (LocalizedText) Validate ¶
func (t LocalizedText) Validate() error
Validate reports whether t is non-empty and every key is a plausible language tag. The tag grammar is not checked in full.
type NumericDate ¶
NumericDate is a JSON number of seconds since the Unix epoch (RFC 7519 §2), as used by "iat" and CAEP's "event_timestamp".
The zero value means "absent": use it with the `omitzero` struct tag. Encoding truncates to whole seconds; decoding accepts fractional seconds.
func NewNumericDate ¶
func NewNumericDate(t time.Time) NumericDate
NewNumericDate returns t as a NumericDate truncated to whole seconds.
func (NumericDate) MarshalJSON ¶
func (d NumericDate) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (*NumericDate) UnmarshalJSON ¶
func (d *NumericDate) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler. It rejects anything but a JSON number, including a numeric string.
type OpaqueSubject ¶
type OpaqueSubject struct {
// ID is the opaque identifier. Required.
ID string
}
OpaqueSubject identifies a subject by an opaque string (RFC 9493 §3.2.4). SSF's verification and stream-updated events use it to carry a stream ID.
func (OpaqueSubject) Format ¶
func (OpaqueSubject) Format() SubjectFormat
Format implements Subject.
func (OpaqueSubject) MarshalJSON ¶
func (s OpaqueSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (OpaqueSubject) Validate ¶
func (s OpaqueSubject) Validate() error
Validate implements Subject.
type PhoneNumberSubject ¶
type PhoneNumberSubject struct {
// PhoneNumber is the number in E.164 form, with its "+" prefix, such
// as "+12065550100". Required.
PhoneNumber string
}
PhoneNumberSubject identifies a subject by telephone number (RFC 9493 §3.2.5).
func (PhoneNumberSubject) Format ¶
func (PhoneNumberSubject) Format() SubjectFormat
Format implements Subject.
func (PhoneNumberSubject) MarshalJSON ¶
func (s PhoneNumberSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (PhoneNumberSubject) Validate ¶
func (s PhoneNumberSubject) Validate() error
Validate implements Subject. It requires the international prefix "+" (RFC 9493 §3.2.5) but does not otherwise police E.164 formatting.
type ProprietarySubject ¶
type ProprietarySubject struct {
// FormatName is the "format" member. Required.
FormatName SubjectFormat
// Members maps each other member's name to its raw JSON value.
Members map[string]json.RawMessage
}
ProprietarySubject carries a Subject Identifier whose format is agreed between Transmitter and Receiver out of band (SSF 1.0 §3.4). Members holds every member except "format", as raw JSON.
func (ProprietarySubject) Format ¶
func (s ProprietarySubject) Format() SubjectFormat
Format implements Subject.
func (ProprietarySubject) MarshalJSON ¶
func (s ProprietarySubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. Members are sorted by name.
func (ProprietarySubject) Validate ¶
func (s ProprietarySubject) Validate() error
Validate implements Subject.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps event type URIs to decoders. There is no global registry: a Receiver is given one, and a Transmitter derives the event types it supports from one. NewRegistry returns a registry that already holds SSF's own events; event families add theirs with Register — for example caep.Register(r) and risc.Register(r).
A Registry is safe for concurrent use.
func NewRegistry ¶
func NewRegistry() *Registry
NewRegistry returns a registry holding SSF 1.0's verification and stream-updated events.
func (*Registry) Decode ¶
Decode decodes and validates the event object payload as typ. It returns an error wrapping ErrUnsupportedEventType if typ is not registered.
type RemoveSubjectRequest ¶
type RemoveSubjectRequest struct {
// StreamID is the stream to remove the subject from. Required.
StreamID string
// Subject is the subject to remove. Required.
Subject Subject
}
RemoveSubjectRequest is the body of a Remove Subject request (SSF 1.0 §8.1.3.3).
func (RemoveSubjectRequest) MarshalJSON ¶
func (r RemoveSubjectRequest) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (*RemoveSubjectRequest) UnmarshalJSON ¶
func (r *RemoveSubjectRequest) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
type SAMLAssertionIDSubject ¶
type SAMLAssertionIDSubject struct {
// Issuer is the assertion's Issuer. Required.
Issuer string
// AssertionID is the assertion's ID. Required.
AssertionID string
}
SAMLAssertionIDSubject identifies a SAML 2.0 assertion (SSF 1.0 §3.5.2).
func (SAMLAssertionIDSubject) Format ¶
func (SAMLAssertionIDSubject) Format() SubjectFormat
Format implements Subject.
func (SAMLAssertionIDSubject) MarshalJSON ¶
func (s SAMLAssertionIDSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (SAMLAssertionIDSubject) Validate ¶
func (s SAMLAssertionIDSubject) Validate() error
Validate implements Subject.
type SCIMSubject ¶
type SCIMSubject struct {
// URI is the resource's path relative to the SCIM service provider's
// base URI, such as "/Users/2b2f880af6674ac284bae9381673d462".
// Required.
URI string
// ExternalID is the resource's "externalId", if known.
ExternalID string
// ID is the resource's "id", which RFC 9967 allows alongside URI for
// backwards compatibility.
ID string
// Attributes holds further members — SCIM attributes unique within the
// service provider, such as "userName" or "emails" — as raw JSON. Its
// keys must not be "format", "uri", "externalId" or "id".
Attributes map[string]json.RawMessage
}
SCIMSubject identifies a SCIM resource (RFC 9967 §2.1).
func (SCIMSubject) MarshalJSON ¶
func (s SCIMSubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler. Attributes follow the modelled members, sorted by name.
type SET ¶
type SET struct {
// Issuer is the "iss" claim: the Transmitter's issuer identifier.
Issuer string
// Audience is the "aud" claim. It holds at least one value.
Audience []string
// JWTID is the "jti" claim, unique per SET.
JWTID string
// IssuedAt is the "iat" claim.
IssuedAt time.Time
// TransactionID is the optional "txn" claim (SSF 1.0 §4.1.9). SETs
// caused by the same underlying occurrence may share it.
TransactionID string
// Subject is the "sub_id" claim (SSF 1.0 §3.1).
Subject Subject
// Event is the single entry of the "events" claim.
Event Event
}
SET is the content of a Security Event Token (RFC 8417) as profiled by SSF 1.0 §4: one event about one primary subject.
A Receiver hands handlers a SET only after verifying its signature, issuer, audience and freshness. A Transmitter builds SETs itself from the events an application emits; applications never construct or sign one directly.
type Secret ¶
type Secret struct {
// contains filtered or unexported fields
}
Secret holds a credential — a client secret, a push Authorization header — that must not reach a log, an error message or a debug dump by accident. Every fmt verb, LogValue and MarshalText withhold it, as does fmt printing a struct that holds a Secret in an unexported field; Reveal is the only way to read it, at the point it is sent.
A Secret can be decoded, and compared with ==. A wire type that must carry one, such as Delivery, reveals it in its own MarshalJSON.
Example ¶
A Secret is withheld wherever it is printed or logged; Reveal gives it up where it is sent.
package main
import (
"fmt"
ssf "github.com/idfoundry/ssfgo"
)
func main() {
header := ssf.NewSecret("Bearer s3cret")
fmt.Printf("%v %+v %#v\n", header, ssf.Delivery{AuthorizationHeader: header}, header)
fmt.Println(header.Reveal())
}
Output: [REDACTED] {Method: EndpointURL: AuthorizationHeader:[REDACTED]} ssf.Secret([REDACTED]) Bearer s3cret
func (Secret) Format ¶
Format implements fmt.Formatter, so every verb — %d and %x included — prints the placeholder, and %#v the GoString.
func (Secret) LogValue ¶
LogValue implements slog.LogValuer, so a Secret logged as an attribute is withheld.
func (Secret) MarshalText ¶
MarshalText always fails, so a Secret in a struct cannot be serialized by encoding/json or encoding/xml without a MarshalJSON that reveals it on purpose.
func (*Secret) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler: a Secret can be read from the wire.
type SignatureAlgorithm ¶
type SignatureAlgorithm uint8
SignatureAlgorithm is the closed set of JWS algorithms SSFgo signs and verifies Security Event Tokens with. A SET's "alg" header is untrusted input: a Receiver states which algorithms it accepts before any signature is checked, rather than trusting whatever the header claims.
Every asymmetric algorithm of RFC 7518 §3.1 is supported, and EdDSA with Ed25519. HMAC and "none" never are: a SET is verified with the Transmitter's published public keys, never a shared secret.
const ( // RS256 is RSASSA-PKCS1-v1_5 using SHA-256 (RFC 7518 §3.3), with a // minimum 2048-bit modulus. The CAEP Interoperability Profile §2.6 // requires every event to be signed with it. RS256 SignatureAlgorithm // PS256 is RSASSA-PSS using SHA-256 and MGF1 with SHA-256 // (RFC 7518 §3.5), with a minimum 2048-bit modulus. PS256 // ES256 is ECDSA using the P-256 curve and SHA-256 (RFC 7518 §3.4). ES256 // EdDSA is pure EdDSA using Ed25519 (RFC 8037 §3.1). EdDSA // RS384 is RSASSA-PKCS1-v1_5 using SHA-384 (RFC 7518 §3.3). RS384 // RS512 is RSASSA-PKCS1-v1_5 using SHA-512 (RFC 7518 §3.3). RS512 // PS384 is RSASSA-PSS using SHA-384 and MGF1 with SHA-384 // (RFC 7518 §3.5). PS384 // PS512 is RSASSA-PSS using SHA-512 and MGF1 with SHA-512 // (RFC 7518 §3.5). PS512 // ES384 is ECDSA using the P-384 curve and SHA-384 (RFC 7518 §3.4). ES384 // ES512 is ECDSA using the P-521 curve and SHA-512 (RFC 7518 §3.4). ES512 )
func ParseSignatureAlgorithm ¶
func ParseSignatureAlgorithm(alg string) (SignatureAlgorithm, error)
ParseSignatureAlgorithm maps a JOSE "alg" header value to a SignatureAlgorithm. It rejects every value outside the closed set, including "none" and every HMAC algorithm. Matching is exact: "rs256" is not RS256.
func SignatureAlgorithms ¶
func SignatureAlgorithms() []SignatureAlgorithm
SignatureAlgorithms returns every algorithm SSFgo supports, in the order of their constants.
func (SignatureAlgorithm) IsValid ¶
func (a SignatureAlgorithm) IsValid() bool
IsValid reports whether a is one of the algorithms SSFgo supports.
func (SignatureAlgorithm) String ¶
func (a SignatureAlgorithm) String() string
String returns the JOSE "alg" header value for a, or "" if a is not a recognized algorithm.
type StreamConfiguration ¶
type StreamConfiguration struct {
// StreamID is the "stream_id" the Transmitter assigned.
StreamID string `json:"stream_id"`
// Issuer is the Transmitter's issuer identifier, the "iss" of the
// stream's SETs.
Issuer string `json:"iss"`
// Audience is the "aud" of the stream's SETs.
Audience Audience `json:"aud"`
// EventsSupported are the event types the Transmitter supports.
EventsSupported []EventType `json:"events_supported,omitempty"`
// EventsRequested are the event types the Receiver asked for.
EventsRequested []EventType `json:"events_requested,omitempty"`
// EventsDelivered is always encoded, as an empty array when no
// event types are delivered.
EventsDelivered []EventType `json:"events_delivered"`
// Delivery is how the stream's SETs are delivered.
Delivery Delivery `json:"delivery"`
// MinVerificationInterval is in seconds; zero means none.
MinVerificationInterval int `json:"min_verification_interval,omitempty"`
// Description is the Receiver's free-text description of the stream;
// empty if none.
Description string `json:"description,omitempty"`
// InactivityTimeout is in seconds; zero means none.
InactivityTimeout int `json:"inactivity_timeout,omitempty"`
}
StreamConfiguration is an event stream's configuration (SSF 1.0 §8.1.1), as the Transmitter returns it.
func (StreamConfiguration) LogValue ¶
func (c StreamConfiguration) LogValue() slog.Value
LogValue implements slog.LogValuer: a logged StreamConfiguration withholds its delivery's Authorization header.
func (StreamConfiguration) MarshalJSON ¶
func (c StreamConfiguration) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler, encoding a nil EventsDelivered as an empty array because the member is required.
type StreamState ¶
type StreamState struct {
// StreamID is the stream's "stream_id".
StreamID string `json:"stream_id"`
// Status is the stream's status: enabled, paused or disabled.
Status StreamStatus `json:"status"`
// Reason is free text explaining the status; empty if none given.
Reason string `json:"reason,omitempty"`
}
StreamState is a stream's status as read from, or written to, the Status Endpoint (SSF 1.0 §8.1.2).
type StreamStatus ¶
type StreamStatus string
StreamStatus is the status of an event stream (SSF 1.0 §8.1.2).
const ( // StreamEnabled means the Transmitter transmits events over the // stream. StreamEnabled StreamStatus = "enabled" // StreamPaused means the Transmitter holds events and transmits them // once the stream is enabled again. StreamPaused StreamStatus = "paused" // StreamDisabled means the Transmitter neither transmits nor holds // events. StreamDisabled StreamStatus = "disabled" )
func (StreamStatus) IsValid ¶
func (s StreamStatus) IsValid() bool
IsValid reports whether s is one of the statuses SSF 1.0 §8.1.2 defines.
type StreamUpdated ¶
type StreamUpdated struct {
// Status is the stream's new status. Required.
Status StreamStatus `json:"status"`
// Reason is free text explaining the change; empty if none given.
// Untrusted on receipt: it is the Transmitter's text.
Reason string `json:"reason,omitempty"`
}
StreamUpdated tells the Receiver that the Transmitter changed a stream's status (SSF 1.0 §8.1.5). Its SET's "sub_id" is an OpaqueSubject whose ID is the stream ID.
func (StreamUpdated) EventType ¶
func (StreamUpdated) EventType() EventType
EventType implements Event.
func (StreamUpdated) ValidateSubject ¶
func (StreamUpdated) ValidateSubject(s Subject) error
ValidateSubject implements SubjectConstrainedEvent.
type Subject ¶
type Subject interface {
// Format returns the value of the subject's "format" member.
Format() SubjectFormat
// Validate reports whether every member the format requires is
// present and well formed.
Validate() error
json.Marshaler
// contains filtered or unexported methods
}
Subject is a Subject Member value (SSF 1.0 §3.1.4): either a simple Subject Identifier (RFC 9493) or a ComplexSubject.
Subject is a closed set. Its implementations are exactly the *Subject types in this package, so a type switch over them is exhaustive. A format agreed between two parties out of band (SSF 1.0 §3.4) is carried by ProprietarySubject.
MarshalJSON validates before encoding, so an invalid subject can never be emitted.
func ParseSubject ¶
ParseSubject decodes and validates a Subject Member value.
Members the format does not define are ignored rather than rejected: SSF 1.0 §4.2.3 requires Receivers to ignore fields they do not understand. A format ParseSubject does not recognize is returned as a ProprietarySubject, which the caller may reject.
type SubjectConstrainedEvent ¶
SubjectConstrainedEvent is implemented by events whose definition restricts the SET's "sub_id" — for example SSF's verification event, which requires an opaque stream ID.
type SubjectFormat ¶
type SubjectFormat string
SubjectFormat is the value of a Subject Identifier's "format" member (RFC 9493 §3).
const ( FormatAccount SubjectFormat = "account" FormatEmail SubjectFormat = "email" FormatIssSub SubjectFormat = "iss_sub" FormatOpaque SubjectFormat = "opaque" FormatPhoneNumber SubjectFormat = "phone_number" FormatDID SubjectFormat = "did" FormatURI SubjectFormat = "uri" FormatAliases SubjectFormat = "aliases" )
Subject Identifier formats registered by RFC 9493 §3.2.
const ( FormatJWTID SubjectFormat = "jwt_id" FormatSAMLAssertionID SubjectFormat = "saml_assertion_id" FormatIPAddresses SubjectFormat = "ip-addresses" FormatComplex SubjectFormat = "complex" )
Subject Identifier formats defined by SSF 1.0 §3.5, and the complex subject format of SSF 1.0 §3.3.
const FormatSCIM SubjectFormat = "scim"
FormatSCIM identifies a SCIM resource (RFC 9967 §2.1), the subject of SCIM events.
type TransmitterMetadata ¶
type TransmitterMetadata struct {
// SpecVersion is the version of SSF implemented, such as SpecVersion.
SpecVersion string `json:"spec_version,omitempty"`
// Issuer is the Transmitter's issuer identifier, an https URL. A
// Receiver checks it against the issuer it expected.
Issuer string `json:"issuer"`
// JWKSURI is where the Transmitter publishes the keys that sign its
// SETs. It must be https.
JWKSURI string `json:"jwks_uri,omitempty"`
// DeliveryMethodsSupported are the delivery methods the Transmitter
// supports.
DeliveryMethodsSupported []DeliveryMethod `json:"delivery_methods_supported,omitempty"`
// ConfigurationEndpoint is the stream configuration endpoint
// (SSF 1.0 §8.1.1); empty if not supported.
ConfigurationEndpoint string `json:"configuration_endpoint,omitempty"`
// StatusEndpoint is the stream status endpoint (SSF 1.0 §8.1.2);
// empty if not supported.
StatusEndpoint string `json:"status_endpoint,omitempty"`
// AddSubjectEndpoint is the Add Subject endpoint (SSF 1.0 §8.1.3.2);
// empty if not supported.
AddSubjectEndpoint string `json:"add_subject_endpoint,omitempty"`
// RemoveSubjectEndpoint is the Remove Subject endpoint
// (SSF 1.0 §8.1.3.3); empty if not supported.
RemoveSubjectEndpoint string `json:"remove_subject_endpoint,omitempty"`
// VerificationEndpoint is the Verification endpoint
// (SSF 1.0 §8.1.4.2); empty if not supported.
VerificationEndpoint string `json:"verification_endpoint,omitempty"`
// CriticalSubjectMembers names complex-subject members a Receiver
// must understand: a Receiver rejects a SET whose subject carries
// one it does not process (SSF 1.0 §3.6).
CriticalSubjectMembers []string `json:"critical_subject_members,omitempty"`
// AuthorizationSchemes are the schemes protecting the stream
// management API.
AuthorizationSchemes []AuthorizationScheme `json:"authorization_schemes,omitempty"`
// DefaultSubjects says whether new streams include every subject or
// none; empty if the Transmitter does not say.
DefaultSubjects DefaultSubjects `json:"default_subjects,omitempty"`
}
TransmitterMetadata is the Transmitter Configuration Metadata document (SSF 1.0 §7.1). Array members with no elements are omitted, as §7.2.3 requires.
type URISubject ¶
type URISubject struct {
// URI is the subject's URI. Required.
URI string
}
URISubject identifies a subject by URI (RFC 9493 §3.2.7).
func (URISubject) MarshalJSON ¶
func (s URISubject) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
type Verification ¶
type Verification struct {
// State echoes the value the Receiver supplied when it requested
// verification. It is empty for a verification the Transmitter
// sends unprompted.
State string `json:"state,omitempty"`
}
Verification is sent over a stream to confirm it is configured correctly (SSF 1.0 §8.1.4.1). Its SET's "sub_id" is an OpaqueSubject whose ID is the stream ID.
func (Verification) EventType ¶
func (Verification) EventType() EventType
EventType implements Event.
func (Verification) Validate ¶
func (Verification) Validate() error
Validate implements Event. Every member is optional.
func (Verification) ValidateSubject ¶
func (Verification) ValidateSubject(s Subject) error
ValidateSubject implements SubjectConstrainedEvent.
type VerificationRequest ¶
type VerificationRequest struct {
// StreamID is the stream to verify.
StreamID string `json:"stream_id"`
// State is an opaque value the Transmitter echoes in the verification
// event; empty if none.
State string `json:"state,omitempty"`
}
VerificationRequest is the body of a request to the Verification Endpoint (SSF 1.0 §8.1.4.2).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package caep implements the eight event types of OpenID Continuous Access Evaluation Profile 1.0 (CAEP) on top of the Shared Signals Framework.
|
Package caep implements the eight event types of OpenID Continuous Access Evaluation Profile 1.0 (CAEP) on top of the Shared Signals Framework. |
|
interop
Package interop applies the OpenID CAEP Interoperability Profile 1.0 to an SSFgo Transmitter or Receiver.
|
Package interop applies the OpenID CAEP Interoperability Profile 1.0 to an SSFgo Transmitter or Receiver. |
|
cmd
|
|
|
conformance-receiver
command
Command conformance-receiver drives SSFgo's Receiver through an OIDF SSF Receiver test plan against a running conformance suite.
|
Command conformance-receiver drives SSFgo's Receiver through an OIDF SSF Receiver test plan against a running conformance suite. |
|
conformance-transmitter
command
Command conformance-transmitter runs an SSFgo Transmitter configured for the OpenID Foundation SSF conformance suite's CAEP Interoperability Profile Transmitter plan, with in-memory storage.
|
Command conformance-transmitter runs an SSFgo Transmitter configured for the OpenID Foundation SSF conformance suite's CAEP Interoperability Profile Transmitter plan, with in-memory storage. |
|
internal
|
|
|
assurance
Package assurance applies ssf.AssuranceProduction's requirements, the same for every role.
|
Package assurance applies ssf.AssuranceProduction's requirements, the same for every role. |
|
clientassertion
Package clientassertion builds the signed JWTs a client presents to an OAuth 2.0 token endpoint instead of a client secret (RFC 7523 §2.2, OpenID Connect Core §9: client_secret_jwt and private_key_jwt).
|
Package clientassertion builds the signed JWTs a client presents to an OAuth 2.0 token endpoint instead of a client secret (RFC 7523 §2.2, OpenID Connect Core §9: client_secret_jwt and private_key_jwt). |
|
conformance/txharness
Package txharness runs an SSFgo Transmitter configured for the OpenID Foundation SSF conformance suite's CAEP Interoperability Profile Transmitter plan.
|
Package txharness runs an SSFgo Transmitter configured for the OpenID Foundation SSF conformance suite's CAEP Interoperability Profile Transmitter plan. |
|
critical
Package critical implements the "crit" (Critical) Header Parameter check RFC 7515 §4.1.11 (JWS) and RFC 7516 §4.1.13 (JWE, which inherits the JWS rule) both require: a header must be rejected only if "crit" names a parameter the recipient doesn't actually understand and process — every other unrecognized member is ignored, never rejected (RFC 7515 §4.2/§4.3, RFC 7516 §4.2/§4.3).
|
Package critical implements the "crit" (Critical) Header Parameter check RFC 7515 §4.1.11 (JWS) and RFC 7516 §4.1.13 (JWE, which inherits the JWS rule) both require: a header must be rejected only if "crit" names a parameter the recipient doesn't actually understand and process — every other unrecognized member is ignored, never rejected (RFC 7515 §4.2/§4.3, RFC 7516 §4.2/§4.3). |
|
doccheck
command
Command doccheck builds the Go code in the documentation, so it cannot drift from the API it describes.
|
Command doccheck builds the Go code in the documentation, so it cannot drift from the API it describes. |
|
doclint
command
Command doclint reports exported identifiers of the public packages that have no doc comment: declarations, and the fields of exported structs (design rule 14).
|
Command doclint reports exported identifiers of the public packages that have no doc comment: declarations, and the fields of exported structs (design rule 14). |
|
jose
Package jose implements the JWS and JWK primitives SSFgo needs to sign and verify Security Event Tokens: compact serialization; RSASSA-PKCS1-v1_5 and RSASSA-PSS with SHA-256, -384 and -512, ECDSA on P-256, P-384 and P-521, and EdDSA with Ed25519 — every asymmetric algorithm of RFC 7518 §3.1, and RFC 8037's; and public JWK / JWK Set parsing.
|
Package jose implements the JWS and JWK primitives SSFgo needs to sign and verify Security Event Tokens: compact serialization; RSASSA-PKCS1-v1_5 and RSASSA-PSS with SHA-256, -384 and -512, ECDSA on P-256, P-384 and P-521, and EdDSA with Ed25519 — every asymmetric algorithm of RFC 7518 §3.1, and RFC 8037's; and public JWK / JWK Set parsing. |
|
jsonobj
Package jsonobj decodes a JSON object strictly: a member named twice is an error, not a value the last occurrence silently wins.
|
Package jsonobj decodes a JSON object strictly: a member named twice is an error, not a value the last occurrence silently wins. |
|
peertext
Package peertext makes text from the other party — a Transmitter's error body, a Receiver's rejection, a header member of a SET anyone could push — safe to log, return or report to a hook: cut to a bound the caller names, with anything but printable ASCII replaced, so it can neither flood a log nor forge or disguise a line of one.
|
Package peertext makes text from the other party — a Transmitter's error body, a Receiver's rejection, a header member of a SET anyone could push — safe to log, return or report to a hook: cut to a bound the caller names, with anything but printable ASCII replaced, so it can neither flood a log nor forge or disguise a line of one. |
|
setcodec
Package setcodec signs and verifies Security Event Tokens as profiled by SSF 1.0 §4.
|
Package setcodec signs and verifies Security Event Tokens as profiled by SSF 1.0 §4. |
|
testcert
Package testcert makes throwaway TLS certificates for SSFgo's conformance harnesses.
|
Package testcert makes throwaway TLS certificates for SSFgo's conformance harnesses. |
|
Package receiver is an embeddable SSF Receiver (OpenID Shared Signals Framework 1.0).
|
Package receiver is an embeddable SSF Receiver (OpenID Shared Signals Framework 1.0). |
|
Package revocation turns the security events a Receiver gets into revoked tokens: a session revoked, an account disabled or purged, a SCIM resource deactivated or deleted.
|
Package revocation turns the security events a Receiver gets into revoked tokens: a session revoked, an account disabled or purged, a SCIM resource deactivated or deleted. |
|
Package risc implements the event types of OpenID Risk Incident Sharing and Coordination 1.0 (RISC) on top of the Shared Signals Framework.
|
Package risc implements the event types of OpenID Risk Incident Sharing and Coordination 1.0 (RISC) on top of the Shared Signals Framework. |
|
Package scim implements the SCIM events of RFC 9967 on top of the Shared Signals Framework: provisioning changes of a SCIM service provider — resources created, patched, replaced, deleted, activated and deactivated — feed membership changes, and the completion of asynchronous SCIM requests.
|
Package scim implements the SCIM events of RFC 9967 on top of the Shared Signals Framework: provisioning changes of a SCIM service provider — resources created, patched, replaced, deleted, activated and deactivated — feed membership changes, and the completion of asynchronous SCIM requests. |
|
Package ssftest runs an SSF Transmitter or Receiver in-process, for testing an application that plays the other role.
|
Package ssftest runs an SSF Transmitter or Receiver in-process, for testing an application that plays the other role. |
|
Package storage defines the persistence contracts SSFgo's roles depend on.
|
Package storage defines the persistence contracts SSFgo's roles depend on. |
|
memstore
Package memstore is an in-memory implementation of SSFgo's storage contracts, for tests, examples and conformance runs.
|
Package memstore is an in-memory implementation of SSFgo's storage contracts, for tests, examples and conformance runs. |
|
storagetest
Package storagetest is a contract test suite for implementations of SSFgo's storage interfaces.
|
Package storagetest is a contract test suite for implementations of SSFgo's storage interfaces. |
|
sqlstore
module
|
|
|
Package transmitter is an embeddable SSF Transmitter (OpenID Shared Signals Framework 1.0).
|
Package transmitter is an embeddable SSF Transmitter (OpenID Shared Signals Framework 1.0). |