kerbexchange

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: Apache-2.0 Imports: 32 Imported by: 0

README

go-oauth2-kerberos-exchange

Exchange a validated OAuth 2.0 access token for Kerberos credentials for the end user — a service ticket (as a krb5 ccache) or a ready-made GSSAPI/SPNEGO initial-context token — so a gateway can authenticate to Kerberos/GSSAPI-only backends (IMAP/SMTP SASL GSSAPI, SPNEGO-fronted HTTP) as that user, with no master-user and no stored passwords.

The HTTP surface is a profile of RFC 8693 (OAuth 2.0 Token Exchange): subject_token in, a krb5 token type requested, a credential issued. The library is also embeddable directly (net/http handler) and ships a standalone server.

Status: pre-publication. The first tagged release will be v0.1.0. The API is unstable until then.

Install

go get github.com/hstern/go-oauth2-kerberos-exchange

Requires Go 1.26+.

How it works

OAuth2 access token
        │  validate (JWKS / introspection / delegated)
        ▼  Identity{subject, claims, exp}
   resolve → client principal + target SPN
        ▼
   mint a Kerberos service ticket (held service keys), carrying a signed PAC
   whose group authorization = (identity groups ∩ scope-admitted) — least privilege
        ▼
   krb5 ccache  (holder-of-key: caller drives GSSAPI with the session key)
   or AP-REQ    (bearer-style GSSAPI token the caller presents verbatim)

The ticket lifetime is capped to the token's exp. The issuer holds the realm's service keys (a keytab per SPN); target services validate minted tickets offline with their own keytab — they never talk to this service on the wire.

Quickstart — embed the handler

Mount the RFC 8693 endpoint in your own mux. Here the gateway validated the token at its edge and passes the claims through with a DelegatedValidator:

package main

import (
	"context"
	"encoding/json"
	"net/http"
	"time"

	kerb "github.com/hstern/go-oauth2-kerberos-exchange"
	"github.com/hstern/go-oauth2-kerberos-exchange/httpexchange"
)

func main() {
	ks, err := kerb.LoadKeytabSource("/etc/krb5.keytab", "EXAMPLE.COM")
	if err != nil {
		panic(err)
	}
	pac, err := kerb.NewSyntheticPACBuilder("S-1-5-21-1111111111-2222222222-3333333333")
	if err != nil {
		panic(err)
	}

	svc := &kerb.Service{
		// The gateway already validated the token; decode its claims into an Identity.
		Validator: kerb.DelegatedValidator{ValidateFunc: func(_ context.Context, tok string) (kerb.Identity, error) {
			return decodeTrustedClaims(tok) // your edge logic → kerb.Identity{Subject, Claims, Expiry}
		}},
		Resolver:    kerb.StaticResolver{DefaultRealm: "EXAMPLE.COM"},
		Minter:      kerb.NewDirectMinter(ks, "EXAMPLE.COM").WithPACBuilder(pac),
		Cache:       kerb.NewMemoryCache(), // optional
		MaxLifetime: 5 * time.Minute,
	}

	mux := http.NewServeMux()
	mux.Handle("/token", httpexchange.NewHandler(svc))
	_ = http.ListenAndServe(":8080", mux)
}

func decodeTrustedClaims(tok string) (kerb.Identity, error) {
	// e.g. decode the already-verified JWT body without re-verifying the signature
	return kerb.Identity{Subject: "alice", Claims: json.RawMessage(`{"groups":["mail-users"]}`), Expiry: time.Now().Add(time.Hour)}, nil
}

To validate tokens here instead, swap the validator for a JWKS validator:

v, err := kerb.NewJWKSValidator(context.Background(), "https://idp.example.com/.well-known/jwks.json",
	kerb.WithIssuer("https://idp.example.com"), kerb.WithAudience("kerberos-exchange"))
// svc.Validator = v

or RFC 7662 introspection:

svc.Validator = &kerb.IntrospectionValidator{
	Endpoint: "https://idp.example.com/introspect", ClientID: "gw", ClientSecret: "…",
}

Quickstart — standalone server

go run ./cmd/kerbexchanged \
  -addr :8080 -token-path /token \
  -keytab /etc/krb5.keytab -realm EXAMPLE.COM \
  -jwks-url https://idp.example.com/.well-known/jwks.json \
  -domain-sid S-1-5-21-1111111111-2222222222-3333333333 \
  -max-lifetime 5m

Calling it (client SDK)

c := httpexchange.NewClient("https://exchange.example.com/token", nil)
cred, err := c.Exchange(ctx, accessToken,
	kerb.ServicePrincipal{Service: "imap", Host: "mail.example.com", Realm: "EXAMPLE.COM"},
	kerb.OutputCCache)
ccache, _ := cred.CCache() // feed into github.com/go-krb5/krb5's credentials.CCache

Output shapes

OutputType Issued Use it when
OutputCCache MIT credential cache (ticket + session key) The caller has a krb5 stack and needs full GSSAPI: mutual auth, the SASL security layer, channel binding, or reuse across connections. Holder-of-key (RFC 7800).
OutputAPReq GSSAPI/SPNEGO initial-context token The caller has no krb5 library and just drops the token into one AUTHENTICATE GSSAPI / HTTP Negotiate exchange. Bearer-style, single-target.

Token validators

Validator Notes
DelegatedValidator The gateway validated at its edge; supply a func returning the Identity. No JWT dependency.
JWKSValidator Verifies JWT access tokens against a JWKS endpoint (RS256/ES256 allowlist; alg:none/HMAC rejected).
IntrospectionValidator RFC 7662 token introspection.

The PAC's group authorization is the intersection of the identity's groups and those the granted scope admits (configure a ScopeFilter) — exchanging a narrowly-scoped token yields a correspondingly narrowed Kerberos credential.

License

Apache-2.0 — see LICENSE.

Documentation

Overview

Package kerbexchange exchanges a validated OAuth 2.0 access token for Kerberos credentials (a service ticket as a krb5 ccache, or a ready-made GSSAPI/SPNEGO initial-context token) for the end user.

Index

Constants

View Source
const (
	KrbCCacheTokenType = "https://github.com/hstern/go-oauth2-kerberos-exchange/token-type/krb5-ccache"
	KrbAPReqTokenType  = "https://github.com/hstern/go-oauth2-kerberos-exchange/token-type/krb5-apreq"
)

krb5 token-type identifiers for the RFC 8693 profile. Provisional, project-defined absolute URIs (not IANA-registered).

View Source
const SpecVersion = "v0 (OAuth2-to-Kerberos exchange; RFC 8693 profile)"

SpecVersion is the OAuth2-to-Kerberos credential-exchange profile this build implements (composes RFC 8693 + RFC 4752 + RFC 4559 + IAKERB + MS-KKDCP).

Variables

View Source
var (
	ErrNoCCache = errors.New("kerbexchange: credential has no ccache")
	ErrNoAPReq  = errors.New("kerbexchange: credential has no AP-REQ")
)

Sentinel errors for a representation the credential does not carry.

View Source
var (
	ErrWrongGrantType      = errors.New("kerbexchange: grant_type is not token-exchange")
	ErrMissingSubjectToken = errors.New("kerbexchange: missing subject_token")
	ErrNoTarget            = errors.New("kerbexchange: no resource or audience names a target SPN")
)

Translation sentinels for an unprocessable token-exchange request.

View Source
var ErrMalformedSPN = errors.New("kerbexchange: malformed service principal name")

ErrMalformedSPN is returned when a string is not a valid "service/host" (optionally "@REALM") service principal name.

View Source
var ErrNoServiceKey = errors.New("kerbexchange: no service key for principal")

ErrNoServiceKey is returned when the KeySource holds no key for an SPN/etype.

View Source
var ErrTokenInvalid = errors.New("kerbexchange: invalid access token")

ErrTokenInvalid is the sentinel for a rejected access token.

View Source
var ErrUnknownTokenType = errors.New("kerbexchange: unknown requested token type")

ErrUnknownTokenType is returned for a non-empty requested_token_type that is not one of this library's krb5 token types.

Functions

func CacheKey

func CacheKey(subject string, spn ServicePrincipal, output OutputType) string

CacheKey builds a cache lookup key from a subject, a ServicePrincipal, and the requested output type. The output type is part of the key because a cached Credential carries only the representation it was minted for (ccache or AP-REQ); omitting it would let a ccache request return an AP-REQ-only entry, or vice versa. The NUL separators ensure that no two distinct (subject, spn, output) triples collide.

func MarshalAPReqToken

func MarshalAPReqToken(mt MintedTicket) ([]byte, error)

MarshalAPReqToken builds a GSSAPI initial-context token (RFC 2743 §3.1) wrapping a KRB_AP_REQ constructed from mt. No live KDC is required; the session key carried in mt is used directly to encrypt the authenticator.

Token layout:

0x60 ‖ DER-length ‖ krb5-mech-OID ‖ 01 00 ‖ AP-REQ DER

func MarshalCCache

func MarshalCCache(mt MintedTicket) ([]byte, error)

MarshalCCache builds a single-credential MIT credential cache from the minted ticket and serializes it via hstern/krb5's CCache.Marshal.

func TokenExchangeErrorCode

func TokenExchangeErrorCode(err error) string

TokenExchangeErrorCode maps a library error to the RFC 8693 token-exchange "error" code the HTTP layer returns. Unrecognized errors map to the safe default "invalid_request".

Types

type Cache

type Cache interface {
	Get(key string) (*Credential, bool)
	Put(key string, cred *Credential)
}

Cache is an opt-in credential store keyed by an arbitrary string.

type ClaimsMapper

type ClaimsMapper interface {
	Map(id Identity) (subject string, groupNames []string, grantedScopes []string, err error)
}

ClaimsMapper extracts the identity facts a PAC needs from a validated token's claims: the subject, its group names, and the granted scopes.

type ConfigMapFilter

type ConfigMapFilter struct {
	ScopeGroups map[string][]string
}

ConfigMapFilter admits a candidate group iff some granted scope lists it in ScopeGroups (scope -> admitted group names). Deployment policy supplies the map.

func (ConfigMapFilter) Admit

func (f ConfigMapFilter) Admit(grantedScopes, candidateGroups []string) []string

Admit implements ScopeFilter. The result preserves candidateGroups order and contains each admitted group at most once.

type Credential

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

Credential is an issued Kerberos credential for one subject and target SPN. It may carry a ccache, an AP-REQ, or both, depending on the requested output.

func NewCredential

func NewCredential(subject string, target ServicePrincipal, expiry time.Time, ccache, apreq []byte) *Credential

NewCredential builds a Credential. Either ccache or apreq (or both) may be nil.

func (*Credential) APReq

func (c *Credential) APReq() ([]byte, error)

APReq returns the GSSAPI/SPNEGO initial-context token, or ErrNoAPReq if absent.

func (*Credential) CCache

func (c *Credential) CCache() ([]byte, error)

CCache returns the MIT ccache bytes, or ErrNoCCache if absent.

func (*Credential) Expiry

func (c *Credential) Expiry() time.Time

Expiry returns the credential's expiry.

func (*Credential) Subject

func (c *Credential) Subject() string

Subject returns the credential's subject.

func (*Credential) Target

func (c *Credential) Target() ServicePrincipal

Target returns the service principal the credential authenticates to.

type DefaultClaimsMapper

type DefaultClaimsMapper struct {
	GroupsClaim string
}

DefaultClaimsMapper reads group names from GroupsClaim (default "groups") and scopes from the RFC 6749 space-delimited "scope" claim. Both claims may be a JSON array of strings or a single space/comma-delimited string (lenient).

func (DefaultClaimsMapper) Map

Map implements ClaimsMapper.

type DelegatedValidator

type DelegatedValidator struct {
	ValidateFunc func(ctx context.Context, accessToken string) (Identity, error)
}

DelegatedValidator delegates validation to a caller-supplied function — used when the gateway already validated the token at its edge and constructs the Identity itself (e.g. decoding a trusted JWT's claims without re-verifying).

func (DelegatedValidator) Validate

func (v DelegatedValidator) Validate(ctx context.Context, accessToken string) (Identity, error)

Validate implements TokenValidator.

type DirectMinter

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

DirectMinter implements Minter by building an EncTicketPart in-process, marshalling it with the go-krb5 ASN.1 codec, and encrypting it under the long-term service key fetched from a KeySource.

It prefers AES-256-CTS-HMAC-SHA1-96. When a PACBuilder is configured via WithPACBuilder, a signed MS-PAC is embedded in the ticket's AuthorizationData.

func NewDirectMinter

func NewDirectMinter(keys KeySource, defaultRealm string) *DirectMinter

NewDirectMinter returns a DirectMinter backed by the given KeySource.

func (*DirectMinter) Mint

Mint builds and encrypts a service ticket for spn according to opts.

func (*DirectMinter) WithPACBuilder

func (m *DirectMinter) WithPACBuilder(b PACBuilder) *DirectMinter

WithPACBuilder configures a PACBuilder whose output is embedded as a signed MS-PAC in the AuthorizationData of every ticket Mint produces. Returns the receiver to allow method chaining.

type ExchangeRequest

type ExchangeRequest struct {
	AccessToken string
	Target      ServicePrincipal
	Output      OutputType
}

ExchangeRequest is the library's internal exchange request: a validated access token, the target service principal, and the desired output shape.

func ExchangeRequestFromWire

func ExchangeRequestFromWire(w *tokenexchange.TokenExchangeRequest) (ExchangeRequest, error)

ExchangeRequestFromWire translates a parsed RFC 8693 token-exchange request into an ExchangeRequest. It is liberal: it rejects only what makes the request unprocessable (wrong grant type, no subject token, no target, or an unknown requested token type). The target SPN comes from the first resource, falling back to the first audience.

type Exchanger

type Exchanger interface {
	Exchange(ctx context.Context, req ExchangeRequest) (*Credential, error)
}

Exchanger exchanges a validated OAuth token for a Kerberos credential.

type Identity

type Identity struct {
	// Subject is the authenticated subject (e.g. the token "sub" claim).
	Subject string
	// Claims is the raw claims JSON, kept byte-stable for downstream mapping.
	Claims json.RawMessage
	// Expiry is the access token's expiry; the issued ticket never outlives it.
	Expiry time.Time
}

Identity is the validated subject of an OAuth 2.0 access token: the principal subject, the raw token claims, and the token's expiry. The Resolver maps Subject to a Kerberos client principal; Expiry caps the issued ticket's life.

type IntrospectionValidator

type IntrospectionValidator struct {
	// Endpoint is the URL of the token introspection endpoint (RFC 7662 §2).
	Endpoint string
	// ClientID is the client identifier for HTTP Basic auth. When empty, no
	// Authorization header is sent.
	ClientID string
	// ClientSecret is the client secret paired with ClientID.
	ClientSecret string
	// HTTPClient is the HTTP client used for introspection requests. When nil,
	// http.DefaultClient is used.
	HTTPClient *http.Client
}

IntrospectionValidator implements TokenValidator using the OAuth 2.0 Token Introspection endpoint defined in RFC 7662. It POSTs the access token to the configured endpoint and interprets the "active" field to determine validity.

When ClientID is non-empty, HTTP Basic authentication is added to the request using ClientID and ClientSecret. If HTTPClient is nil, http.DefaultClient is used.

Lifetime note: RFC 7662 responses commonly omit the "exp" field; when absent, the returned Identity.Expiry is the zero time, so operators SHOULD set Service.MaxLifetime to bound the issued Kerberos ticket — otherwise ticket minting fails closed on a zero EndTime.

func (*IntrospectionValidator) Validate

func (v *IntrospectionValidator) Validate(ctx context.Context, accessToken string) (Identity, error)

Validate implements TokenValidator. It sends the access token to the introspection endpoint and returns an Identity when the token is active.

A non-200 HTTP response or transport error is returned as a plain error (not wrapped with ErrTokenInvalid) because those conditions indicate a server or network failure rather than a definitively invalid token. An active=false response wraps ErrTokenInvalid.

type JWKSOption

type JWKSOption func(*jwksValidatorConfig)

JWKSOption is a functional option for NewJWKSValidator.

func WithAudience

func WithAudience(aud string) JWKSOption

WithAudience configures the expected audience ("aud") claim. When set, tokens that do not include this audience are rejected.

func WithClockSkew

func WithClockSkew(d time.Duration) JWKSOption

WithClockSkew configures the acceptable clock skew for exp/iat/nbf checks.

func WithIssuer

func WithIssuer(iss string) JWKSOption

WithIssuer configures the expected issuer ("iss") claim. When set, tokens with a different issuer are rejected.

type JWKSValidator

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

JWKSValidator is a TokenValidator that verifies JWTs using a remote JWKS endpoint. Keys are fetched and cached automatically via jwk.Cache.

Algorithm security: verification is driven entirely by the algorithm field on each jwk.Key in the cached key set (set at JWKS-fetch time). The library never trusts the alg header from the token itself, which prevents algorithm substitution attacks including "alg:none" and HMAC confusion. Only keys whose alg field is RS256 or ES256 will ever match; tokens that would require any other algorithm are rejected.

Allowlist trust boundary: the RS256/ES256 allowlist is enforced as "the key set must contain at least one key with an allowed algorithm." It does NOT independently reject a JWKS that also publishes keys with disallowed algorithms — a JWKS containing both an RS256 key and an unexpected key type will still pass. This is intentional: the security model trusts the JWKS endpoint itself, and a hostile issuer that controls that endpoint could equally publish a malicious RS256 key. Operators MUST ensure the JWKS URL is obtained from a trustworthy discovery document over HTTPS and is not attacker-controlled.

func NewJWKSValidator

func NewJWKSValidator(ctx context.Context, jwksURL string, opts ...JWKSOption) (*JWKSValidator, error)

NewJWKSValidator constructs a JWKSValidator that fetches and caches the JWKS document at jwksURL. The context controls the lifetime of the background refresh goroutine started by jwk.Cache; cancel it when the validator is no longer needed.

func (*JWKSValidator) Validate

func (v *JWKSValidator) Validate(ctx context.Context, accessToken string) (Identity, error)

Validate implements TokenValidator. It parses and verifies the JWT, enforces the RS256/ES256 algorithm allowlist, validates standard claims (exp, nbf, iat, iss, aud), and returns an Identity on success. Any failure is wrapped with ErrTokenInvalid.

type KeySource

type KeySource interface {
	ServiceKey(spn ServicePrincipal, etype int32) (key types.EncryptionKey, kvno int, err error)
	KDCSigningKey(etype int32) (key types.EncryptionKey, kvno int, err error)
}

KeySource provides the long-term key for a service principal, used to encrypt the minted service ticket, and the KDC signing key used for PAC checksums.

type KeytabSource

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

KeytabSource is a KeySource backed by a Kerberos keytab.

func LoadKeytabSource

func LoadKeytabSource(path, defaultRealm string) (*KeytabSource, error)

LoadKeytabSource loads a keytab from disk.

func NewKeytabSource

func NewKeytabSource(kt *keytab.Keytab, defaultRealm string) *KeytabSource

NewKeytabSource wraps an in-memory keytab.

func (*KeytabSource) KDCSigningKey

func (s *KeytabSource) KDCSigningKey(etype int32) (types.EncryptionKey, int, error)

KDCSigningKey returns the key used to sign the PAC's KDC checksum. This is a designated KDC-signing principal (default krbtgt/<realm>); v0 issues no TGT, so this key is used ONLY for the PAC KDC/ticket checksums, never to encrypt a TGT.

func (*KeytabSource) ServiceKey

func (s *KeytabSource) ServiceKey(spn ServicePrincipal, etype int32) (types.EncryptionKey, int, error)

ServiceKey returns the long-term key for spn at the given etype.

type MemoryCache

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

MemoryCache is a concurrency-safe in-memory Cache backed by a plain map. Expired entries are evicted lazily on Get.

func NewMemoryCache

func NewMemoryCache() *MemoryCache

NewMemoryCache returns an initialised, empty MemoryCache.

func (*MemoryCache) Get

func (m *MemoryCache) Get(key string) (*Credential, bool)

Get returns the credential for key if it exists and has not expired. An expired entry is removed from the cache before returning a miss.

func (*MemoryCache) Put

func (m *MemoryCache) Put(key string, cred *Credential)

Put stores cred under key, replacing any previous entry.

type MintOptions

type MintOptions struct {
	// ClientName is the Kerberos principal name of the subject.
	ClientName types.PrincipalName
	// ClientRealm is the realm of the subject.
	ClientRealm string
	// Identity is the authenticated identity for which the ticket is minted.
	// Required when a PACBuilder is configured on the DirectMinter; ignored
	// otherwise.
	Identity Identity
	// AuthTime is the time at which the client was authenticated (maps to
	// EncTicketPart.AuthTime).
	AuthTime time.Time
	// StartTime, if non-zero, is the ticket's earliest valid time. Defaults
	// to AuthTime when zero.
	StartTime time.Time
	// EndTime is when the ticket expires.
	EndTime time.Time
	// RenewTill, if non-zero, sets the renewable-until time.
	RenewTill time.Time
}

MintOptions carries the per-ticket parameters set by the caller (typically derived from the validated OAuth2 token and the exchange request).

type MintedTicket

type MintedTicket struct {
	// Ticket is the fully populated Kerberos Ticket ready for wire encoding.
	Ticket messages.Ticket
	// SessionKey is the session key embedded in EncTicketPart.Key.
	SessionKey types.EncryptionKey
	// ClientName is the Kerberos principal name of the subject.
	ClientName types.PrincipalName
	// ClientRealm is the realm of the subject.
	ClientRealm string
	// Target is the service principal for which the ticket was issued, with
	// the resolved realm populated.
	Target ServicePrincipal
	// AuthTime mirrors EncTicketPart.AuthTime.
	AuthTime time.Time
	// EndTime mirrors EncTicketPart.EndTime for convenient expiry checks.
	EndTime time.Time
}

MintedTicket is returned by Minter.Mint. It carries both the wire-form Ticket and the metadata needed by callers that build a ccache or AP-REQ.

func (MintedTicket) Credential

func (mt MintedTicket) Credential(output OutputType) (*Credential, error)

Credential assembles a Phase-2 Credential from the minted ticket, carrying the representation named by output.

type Minter

type Minter interface {
	Mint(spn ServicePrincipal, opts MintOptions) (MintedTicket, error)
}

Minter issues service tickets directly without a live KDC.

type OutputType

type OutputType int

OutputType selects the representation of the issued Kerberos credential.

const (
	// OutputCCache returns the service ticket as an MIT krb5 ccache.
	OutputCCache OutputType = iota
	// OutputAPReq returns a ready-made GSSAPI/SPNEGO initial-context token.
	OutputAPReq
)

func OutputTypeFromTokenType

func OutputTypeFromTokenType(uri string) (OutputType, error)

OutputTypeFromTokenType maps a requested_token_type URI to an OutputType. An empty URI defaults to OutputCCache (the library's primary output).

func (OutputType) String

func (o OutputType) String() string

String implements fmt.Stringer.

func (OutputType) TokenType

func (o OutputType) TokenType() string

TokenType returns the krb5 token-type URI for this output.

type PACBuilder

type PACBuilder interface {
	Build(id Identity, authTime time.Time) (*pac.KerbValidationInfo, *pac.ClientInfo, error)
}

PACBuilder constructs the PAC payloads for a given identity at authentication time. Implementations are free to derive group membership from the Claims field or from an external directory.

type Resolver

type Resolver interface {
	Resolve(ctx context.Context, id Identity, requested ServicePrincipal) (clientName types.PrincipalName, clientRealm string, target ServicePrincipal, err error)
}

Resolver maps a validated Identity and a requested SPN to the concrete Kerberos client principal, its realm, and the resolved target SPN.

type ScopeFilter

type ScopeFilter interface {
	Admit(grantedScopes, candidateGroups []string) []string
}

ScopeFilter narrows candidate group names to those the granted scopes admit. It is how the exchanged OAuth scope downscopes the issued Kerberos authorization: a group lands in the PAC only if some granted scope admits it.

type Service

type Service struct {
	Validator   TokenValidator
	Resolver    Resolver
	Minter      Minter
	Cache       Cache         // optional; nil => no caching
	MaxLifetime time.Duration // EndTime = min(now+MaxLifetime, token exp); 0 => only token exp
}

Service is the default Exchanger: validate → resolve → (cache) → mint → output.

func (*Service) Exchange

func (s *Service) Exchange(ctx context.Context, req ExchangeRequest) (*Credential, error)

Exchange implements Exchanger.

type ServicePrincipal

type ServicePrincipal struct {
	Service string
	Host    string
	Realm   string
}

ServicePrincipal is a Kerberos service principal: service/host[@REALM].

func ParseServicePrincipal

func ParseServicePrincipal(s string) (ServicePrincipal, error)

ParseServicePrincipal parses "service/host" or "service/host@REALM".

func (ServicePrincipal) Empty

func (p ServicePrincipal) Empty() bool

Empty reports whether the principal has no service and host.

func (ServicePrincipal) String

func (p ServicePrincipal) String() string

String renders the principal as "service/host" or "service/host@REALM".

type StaticResolver

type StaticResolver struct {
	DefaultRealm string
}

StaticResolver maps the token subject directly to a single-component client principal and fills empty realms with DefaultRealm.

func (StaticResolver) Resolve

Resolve implements Resolver.

type SyntheticPACBuilder

type SyntheticPACBuilder struct {
	// DomainSID is the authority SID of the synthetic Kerberos domain
	// (e.g. S-1-5-21-a-b-c).
	DomainSID mstypes.RPCSID

	// DefaultPrimaryGroupRID is the RID of the primary group assigned to
	// every synthesized identity.  Domain Users (513) is the conventional
	// default.
	DefaultPrimaryGroupRID uint32

	// GroupsClaim is the JWT claim name that lists group membership
	// (default "groups").  Forwarded to DefaultClaimsMapper when Mapper is nil.
	GroupsClaim string

	// GroupOverrides maps a group name to an explicit RID, bypassing the
	// deterministic FNV-32a synthesis.  Useful when the PAC consumer has a
	// fixed SID/RID expectation for a well-known group.
	GroupOverrides map[string]uint32

	// ScopeFilter, when non-nil, restricts which claim groups land in the PAC
	// to those admitted by the token's granted scopes.  When nil, all claim
	// groups are included.
	ScopeFilter ScopeFilter

	// Mapper overrides the claim extraction logic.  When nil, DefaultClaimsMapper
	// with GroupsClaim is used.
	Mapper ClaimsMapper
}

SyntheticPACBuilder builds a minimal, self-contained PAC from the identity's Subject claim alone. No directory lookup is performed. Group membership is derived from identity claims and optionally downscoped by a ScopeFilter; ExtraSIDs and ResourceGroup fields are left empty. This is suitable for environments where the downstream Kerberos service only needs a verifiable identity principal with claim-derived group membership.

func NewSyntheticPACBuilder

func NewSyntheticPACBuilder(domainSID string) (*SyntheticPACBuilder, error)

NewSyntheticPACBuilder parses domainSID (format "S-1-5-21-a-b-c") and returns a SyntheticPACBuilder ready to use.

func (*SyntheticPACBuilder) Build

Build constructs a minimal KerbValidationInfo and ClientInfo for id. authTime is stored in the ClientInfo ClientID field per the MS-PAC spec. Group membership is derived from identity claims; a ScopeFilter, if set, restricts groups to those admitted by the token's granted scopes.

type TokenValidator

type TokenValidator interface {
	Validate(ctx context.Context, accessToken string) (Identity, error)
}

TokenValidator validates an OAuth 2.0 access token and returns the Identity.

Directories

Path Synopsis
cmd
kerbexchanged command
Package main implements kerbexchanged, a standalone HTTP server that exchanges OAuth2 access tokens for Kerberos credentials via the RFC 8693 token-exchange protocol.
Package main implements kerbexchanged, a standalone HTTP server that exchanges OAuth2 access tokens for Kerberos credentials via the RFC 8693 token-exchange protocol.
Package httpexchange provides an HTTP handler that implements the RFC 8693 token-exchange profile for the go-oauth2-kerberos-exchange library.
Package httpexchange provides an HTTP handler that implements the RFC 8693 token-exchange profile for the go-oauth2-kerberos-exchange library.
test
ad-demo/mint command
Command admint is the AD-deployment-demo minter: it loads a service keytab exported from a real Active Directory domain (Samba AD DC) and mints a Kerberos service ticket for the end user with this library's DirectMinter, writing both an MIT ccache and a GSSAPI AP-REQ token.
Command admint is the AD-deployment-demo minter: it loads a service keytab exported from a real Active Directory domain (Samba AD DC) and mints a Kerberos service ticket for the end user with this library's DirectMinter, writing both an MIT ccache and a GSSAPI AP-REQ token.
interop/mint command
Command mint is an interop fixture: it generates a service keytab, mints a Kerberos service ticket (carrying a signed synthetic PAC) for that service using this library's DirectMinter, and writes the resulting GSSAPI initial-context (AP-REQ) token plus a PAC-verify bundle (the PAC bytes and the two signing keys).
Command mint is an interop fixture: it generates a service keytab, mints a Kerberos service ticket (carrying a signed synthetic PAC) for that service using this library's DirectMinter, and writes the resulting GSSAPI initial-context (AP-REQ) token plus a PAC-verify bundle (the PAC bytes and the two signing keys).

Jump to

Keyboard shortcuts

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