asap

package module
v0.0.0-...-aef5c55 Latest Latest
Warning

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

Go to latest
Published: Feb 19, 2024 License: Apache-2.0 Imports: 21 Imported by: 5

README

go-asap

A library that creates and verifies JSON Web Tokens (JWT) for service to service authentication purposes using the Atlassian Service Authentication Protocol (ASAP).

Atlassian S2S Authentication Protocol (ASAP) - Specification

Getting Started

Installing
    go get bitbucket.org/atlassian/go-asap/v2
Generating key pairs

Use OpenSSL from the command line to generate the key pairs.

    openssl genrsa -out private-key.pem 2048
    openssl rsa -in private-key.pem -pubout > public-key.pem

Usage

Generate a token for an outgoing request
privateKey, _ := asap.NewPrivateKey([]byte(os.Getenv("ASAP_PRIVATE_KEY")))
p := asap.NewMicrosProvisioner([]string{"target_service1", "target_service1"}, time.Minute)
token, _ := p.Provision()
headerValue, _ := token.Serialize(privateKey)
bearer := fmt.Sprintf("Bearer %s", string(headerValue))
Validate incoming requests

To validate a token we need to two things: a way of fetching public keys for signature verification and a set of validation rules to apply. Every service should define its own custom validation rules and combine them with the DefaultValidator which enforces the minimum ASAP requirements.

v := asap.NewValidatorChain(
  asap.DefaultValidator,
  asap.NewSignatureValidator(asap.NewHTTPKeyFetcher(os.Getenv("ASAP_PUBLIC_KEY_REPOSITORY_URL"), http.DefaultClient)),
  asap.NewAllowedAudienceValidator("myserviceid"),
)
token, _ := asap.ParseToken(valueFromAuthorizationHeader)
err := v.Validate(token)
if err != nil {
  // Invalid token
}

If using an http mux that supports middleware you can add your validation rules to all incoming requests via:

v := asap.NewValidatorChain(
  asap.DefaultValidator,
  asap.NewSignatureValidator(asap.NewHTTPKeyFetcher(os.Getenv("ASAP_PUBLIC_KEY_REPOSITORY_URL"), http.DefaultClient)),
  asap.NewAllowedAudienceValidator("myserviceid"),
)

m := asap.NewMiddleware(v, nil) // func(http.Handler) http.Handler

Documentation

Index

Constants

View Source
const (
	// ClaimAlgorithm is the JWT specific encryption algorithm claim.
	ClaimAlgorithm = "alg"
	// ClaimKeyID is the JWT specified key identifier claim.
	ClaimKeyID = "kid"
	// ClaimIssuer is the JWT specified token issuer claim.
	ClaimIssuer = "iss"
	// ClaimExpiration is the JWT specified token expiration claim.
	ClaimExpiration = "exp"
	// ClaimIssuedAt is the JWT specified issued at claim.
	ClaimIssuedAt = "iat"
	// ClaimAudience is the JWT specified audience claim.
	ClaimAudience = "aud"
	// ClaimTokenID is the JWT specified JWT ID claim.
	ClaimTokenID = "jti"
	// ClaimSubject is the JWT specified subject claim.
	ClaimSubject = "sub"
	// ClaimNotBefore is the JWT specified not before claim.
	ClaimNotBefore = "nbf"
)

Variables

View Source
var AlgorithmValidator = validatorFunc(algorithmValidator)

AlgorithmValidator enforces the ASAP rules around allowed crypto algorithms.

DefaultValidator applies the basic ASAP validation for a JWT by validating the kid and ensuring that all required ASAP claims are present. This should be combined with your own validation rules using NewValidatorChain.

View Source
var ExpirationValidator = validatorFunc(expirationValidator)

ExpirationValidator enforces the ASAP rules around token lifetime. Specifically, it rejects all tokens that are provisioned for greater than one hour.

View Source
var KidValidator = validatorFunc(kidValidator)

KidValidator enforces the ASAP formatting rules for the kid header.

Functions

func NewMicrosPrivateKey

func NewMicrosPrivateKey() (interface{}, error)

NewMicrosPrivateKey plucks the key from the contracted ENV vars documented here: https://extranet.atlassian.com/pages/viewpage.action?pageId=2763562051

func NewMiddleware

func NewMiddleware(validator Validator, callback func(http.ResponseWriter, *http.Request, error)) func(http.Handler) http.Handler

NewMiddleware generates a func(http.Handler) http.Handler that validates all incoming requests. An optional callback can be provided to handle validation failure. If nil, the middleware will respond with a 401.

func NewPrivateKey

func NewPrivateKey(privateKeyData []byte) (interface{}, error)

NewPrivateKey attempts to decode the given bytes into a valid private key of some type and return something suitable for signing a token.

func NewPublicKey

func NewPublicKey(publicKeyData []byte) (interface{}, error)

NewPublicKey attempts to decode the given bytes into a valid public key of some type and return something suitable for verifying a token signature.

func NewTransportDecorator

func NewTransportDecorator(provisioner Provisioner, pk interface{}) func(http.RoundTripper) http.RoundTripper

NewTransportDecorator wraps a transport in order to include the asap token header in outgoing requests.

func ToContext

func ToContext(parentCtx context.Context, token Token) context.Context

ToContext adds an ASAP token to a context. This is exposed externally to help consumers writing unit tests that depend on this middleware.

Types

type CacheableKeyer

type CacheableKeyer interface {
	CacheKey() string
}

CacheableKeyer is a trait for cacheable entities

type CachingChainedASAPValidatorCallBack

type CachingChainedASAPValidatorCallBack func(CachingChainedASAPValidatorEvent)

CachingChainedASAPValidatorCallBack defines type for a callback function to get notified on various cache events

type CachingChainedASAPValidatorEvent

type CachingChainedASAPValidatorEvent int

CachingChainedASAPValidatorEvent defines a type to represent different events from the cache

const (
	// CachingChainedASAPValidatorEventNone is default uninitialized state
	CachingChainedASAPValidatorEventNone CachingChainedASAPValidatorEvent = iota

	// CachingChainedASAPValidatorEventHit denotes a cache hit event
	CachingChainedASAPValidatorEventHit

	// CachingChainedASAPValidatorEventMiss denotes a cache miss
	CachingChainedASAPValidatorEventMiss

	// CachingChainedASAPValidatorEventPurge denotes a cache purge
	CachingChainedASAPValidatorEventPurge
)

type CachingTokenCallBack

type CachingTokenCallBack func(CachingTokenEvent)

CachingTokenCallBack defines type for a callback function to get notified on various cache events

type CachingTokenEvent

type CachingTokenEvent int

CachingTokenEvent defines a type to represent different events from the cache

const (
	// CachingTokenEventNone is default uninitialized state
	CachingTokenEventNone CachingTokenEvent = iota

	// CachingTokenEventHit denotes a cache hit event
	CachingTokenEventHit

	// CachingTokenEventMiss denotes a cache miss
	CachingTokenEventMiss

	// CachingTokenEventPurge denotes a cache purge
	CachingTokenEventPurge
)

type FailedValidationError

type FailedValidationError struct {
	Reason error
	Token  Token
}

FailedValidationError is used to signal that a given token was parsed correctly but failed the validation rules

func (*FailedValidationError) Error

func (e *FailedValidationError) Error() string

type KeyFetcher

type KeyFetcher interface {
	Fetch(keyID string) (interface{}, error)
}

KeyFetcher takes in an ASAP compliant kid and returns the public key associated with it for use in verifying tokens.

func NewCachingFetcher

func NewCachingFetcher(wrapped KeyFetcher) KeyFetcher

NewCachingFetcher wraps a given KeyFetcher implementation with an in-memory cache for returned keys.

func NewExpiringCacheFetcher

func NewExpiringCacheFetcher(baseURL string, client *http.Client, _ time.Duration) (KeyFetcher, error)

NewExpiringCacheFetcher wraps a given KeyFetcher implementation that returns a keyExpirationPair with an in-memory cache for returned keys.

func NewExpiringCacheFetcherWithStats

func NewExpiringCacheFetcherWithStats(baseURL string, client *http.Client, stats func(stat string, count float64, tags ...string)) (KeyFetcher, error)

func NewHTTPKeyFetcher

func NewHTTPKeyFetcher(baseURL string, client *http.Client) KeyFetcher

NewHTTPKeyFetcher pulls public keys from an HTTP accessible source.

func NewMicrosKeyFetcher

func NewMicrosKeyFetcher(client *http.Client) KeyFetcher

NewMicrosKeyFetcher pulls public keys from the shared s3 bucket given as part of the ASAP env var contract in Micros. Documentation for contract: https://extranet.atlassian.com/pages/viewpage.action?pageId=2763562051

func NewMultiFetcher

func NewMultiFetcher(fetchers ...KeyFetcher) KeyFetcher

NewMultiFetcher will return the first non error fetch result

type MultiKeyFetcher

type MultiKeyFetcher []KeyFetcher

MultiKeyFetcher returns the first non error result from its list of fetchers

func (MultiKeyFetcher) Fetch

func (f MultiKeyFetcher) Fetch(key string) (interface{}, error)

Fetch iterates through the list of fetchers returning first fetch result that succeeds

type Provisioner

type Provisioner interface {
	Provision() (Token, error)
}

Provisioner is a component used to generate new ASAP tokens for outgoing requests.

func NewCachingProvisioner

func NewCachingProvisioner(wrapped Provisioner) Provisioner

NewCachingProvisioner wraps any given provisioner in a time-based cache. It will only call the underlying provisioner when the cached token is expired.

func NewMicrosProvisioner

func NewMicrosProvisioner(audience []string, ttl time.Duration) Provisioner

NewMicrosProvisioner uses the contracted ASAP env var to populate the provisioner. Contract documentation: https://extranet.atlassian.com/pages/viewpage.action?pageId=2763562051

func NewProvisioner

func NewProvisioner(kid string, ttl time.Duration, issuer string, audience []string, signingMethod crypto.SigningMethod) Provisioner

NewProvisioner generates a Provisioner implementation that sets all the required claims and headers for ASAP.

type SignatureValidatorOption

type SignatureValidatorOption func(*signatureValidator)

SignatureValidatorOption is a functional option type for setting custom values for fields on SignatureValidators

func WithLeeway

WithLeeway is a SignatureValidatorOption that takes in a time.Duration between 1s and 30s which can be used to set the leeway for NBF and EXP to account for server clock skew

type Token

type Token interface {
	jwt.JWT
}

Token is an interface that abstracts an underlying JWT implementation. It can be decomposed to a byte slice for transmission and provides access to the JWT claims.

func FromContext

func FromContext(ctx context.Context) Token

FromContext returns the ASAP token for the current request.

func FromContextSafe

func FromContextSafe(ctx context.Context) (Token, error)

FromContextSafe returns the ASAP token for the current request. It returns an error instead of panicking when the token is not present in the context.

func ParseToken

func ParseToken(raw string) (Token, error)

ParseToken converts a string header value, minus the "Bearer " bit, into a Token.

type TokenCache

type TokenCache interface {
	Get(string) Token
	Store(string, Token)
}

TokenCache is a higher level ASAP token cache

func NewTokenCache

func NewTokenCache(ctx context.Context, maxTokenCacheSize int64,
	callbackFunc CachingTokenCallBack) TokenCache

NewTokenCache returns a token cache

type Validator

type Validator interface {
	Validate(token Token) error
}

Validator is a component used to validate incoming ASAP tokens. Example implementations would include one that ensure all required claims are present for ASAP and one that verifies individual claims required by a service.

func NewAllowedAudienceValidator

func NewAllowedAudienceValidator(values ...string) Validator

NewAllowedAudienceValidator takes a set of allowed audience values. If a at least one of the given audience values matches on of the approved then the validator will return no error.

func NewAllowedStringsValidator

func NewAllowedStringsValidator(name string, values ...string) Validator

NewAllowedStringsValidator takes a claim name and set of allowed string values. If a value is given for the claim that is not in the list then the Validator will return an error.

func NewCachingChainedASAPValidator

func NewCachingChainedASAPValidator(ctx context.Context, maxTokenCacheSize int64,
	callbackFunc CachingChainedASAPValidatorCallBack, vs ...Validator) Validator

NewCachingChainedASAPValidator returns an instance of caching chained validators

func NewRequiredClaimsValidator

func NewRequiredClaimsValidator(names ...string) Validator

NewRequiredClaimsValidator takes a set of names and returns a Validator that fails if any of the given claims are not present.

func NewSignatureValidator

func NewSignatureValidator(fetcher KeyFetcher, options ...SignatureValidatorOption) Validator

NewSignatureValidator enforces that tokens are signed by the key they claim to be.

func NewValidatorChain

func NewValidatorChain(vs ...Validator) Validator

NewValidatorChain composes all given validators into one.

Jump to

Keyboard shortcuts

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