jcp

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Dec 23, 2022 License: Apache-2.0 Imports: 13 Imported by: 0

README

jcp

This is a JWK Set client proxy, JCP for short. It is used to validate JWTs that were signed by a key that lives in a remote JWK Set. JCP caches the JWK Set in memory and automatically refreshes the JWK Set as configured.

This project serves a few primary use cases:

  1. The language or shell a program is written in does not have an adequate JWK Set client. Validate JWTs with curl? Why not?
  2. Restrictive networking policies prevent a program from accessing the remote JWK Set directly.
  3. Many co-located services need to validate JWTs that were signed by a key that lives in a remote JWK Set.

It is recommended that JCP is hosted in the same environment (data center) as the program verifying JWTs to reduce latency.

flowchart LR
    subgraph Public Internet
    J[Remote JWK Set]
    end
    subgraph Your Datacenter
    Y[Your code]
    JCP
    end
    Y-->JCP
    JCP-->Y
    JCP-->J
    J-->JCP

API Specifications

This proxy server implements a Swagger 2.0 and OpenAPI 3 specification. Please see swagger.yml for the Swagger 2.0 specification and openapi.yml for the OpenAPI 3 specification.

These specification files can be used to generate client code for your favorite language. However, there is only one small endpoint for JWT validation so hand-coding a client is reasonable.

Installation

This project can be installed via a Docker or using the Go toolchain.

Docker

Pull the image:

docker pull micahparks/jcp

See docker-compose.yml for a working Docker Compose example.

Go

Confirm you have Go installed. The minimum required version can be found in go.mod.

go install github.com/MicahParks/jcp/cmd/proxy@latest

Or you can compile the by downloading this repository, making it your current working directory and running the below commands:

cd cmd/proxy/
go build

After these commands have been run, the proxy executable will be in the cmd/proxy/ directory.

Validation features

Below is a table of JWT registered claims and the validation behavior of JCP.

JWT Validation Type Behavior
Cryptographic signature automatic
alg header automatic
exp claim automatic
iat claim automatic
nbf claim automatic
aud claim per request
iss claim per request
sub claim per request

Configuration

This project is configured via JSON. This program will check three places for this configuration JSON on startup in this order:

  1. The CONFIG_JSON environment variable's raw contents.
  2. The CONFIG_PATH environment variable will be read. If non-empty, it will attempt to parse the file at that path.
  3. The config.json file in the current working directory.

Configuration JSON structure

{
  "jwks": {
    "https://example.com/jwks.json": {
      "refreshInterval": "1h",
      "refreshTimeout": "10s"
    }
  },
  "listenAddress": ":8080",
  "logFormat": "json",
  "requestMaxBytes": 1048576
}
JSON Attribute Description Example Default Value Required
jwks An object mapping remote JWK Set URLs to their options. see above none required
refreshInterval The amount of time to wait before automatically refreshing the remote JWK Set resource. It uses Go syntax for time.ParseDuration. 1h30m5s 1h optional
refreshTimeout The amount of time to wait failing a remote JWK Set refresh due to a timeout. It uses Go syntax for time.ParseDuration. 5s 10s optional
listenAddress The address to listen on. It uses Go syntax for net.Listen. :3000 :8080 optional
logFormat The format to log in. This determines which zap output logging is used. Valid values are human and json. human json optional
requestMaxBytes The maximum number of bytes to read from the request body. 10000 1048576 optional

For most use cases, ensure all JWK Set URLs are HTTPS to prevent MITM attacks.

Test coverage

This project currently has greater than 90% test coverage:

$ go test -cover -race
PASS
coverage: 91.1% of statements
ok      github.com/MicahParks/jcp   0.043s

Local debug setup

Run these commands in the listed order in separate terminals.

Start a local JWK Set server:

go run cmd/local_jwkset/main.go

Start the JCP server (debugger instructions not shown):

CONFIG_PATH=config.local.json go run cmd/proxy/main.go

References

This project was built on the following JSON Object Signing and Encryption (JOSE) related libraries:

Documentation

Index

Constants

View Source
const (
	// DefaultRefreshInterval is the default time between refreshes of the JWKS.
	DefaultRefreshInterval = time.Hour
	// DefaultRefreshTimeout is the default time to wait for a refresh of the JWKS before cancelling and logging an
	// error.
	DefaultRefreshTimeout = 10 * time.Second
	// DefaultListenAddress is the default address to listen on.
	DefaultListenAddress = ":8080"
	// DefaultLogFormat is the default log format.
	DefaultLogFormat = LogFormatJSON
	// DefaultRequestMaxBytes is the default maximum number of bytes to read from a request.
	DefaultRequestMaxBytes = 1 << 20 // 1 MB as defined by http.DefaultMaxHeaderBytes.
)
View Source
const (
	// LogFormatJSON is the JSON log format.
	LogFormatJSON = "json"
	// LogFormatHuman is the human-readable log format.
	LogFormatHuman = "human"
)
View Source
const (
	// ContentTypeJSON is the HTTP header value for Content-Type for JSON.
	ContentTypeJSON = "application/json"
	// HeaderContentType is the HTTP header for Content-Type.
	HeaderContentType = "Content-Type"
)

Variables

View Source
var (
	// ErrClaimCheck is returned when a registered claims check fails.
	ErrClaimCheck = errors.New("registered claims check failed")
	// ErrNoConfiguration is returned when no configuration is given.
	ErrNoConfiguration = errors.New("no configuration provided")
)
View Source
var ErrInvalidConfig = errors.New("invalid configuration")

ErrInvalidConfig is returned when the configuration is invalid.

Functions

This section is empty.

Types

type Config

type Config struct {
	JWKS            map[string]JWKSConfig `json:"jwks"`
	ListenAddress   string                `json:"listenAddress"`
	LogFormat       string                `json:"logFormat"`
	RequestMaxBytes int64                 `json:"requestMaxBytes"`
}

Config contains the configuration for the JWKS client proxy.

func (Config) DefaultsAndValidate

func (c Config) DefaultsAndValidate() (Config, error)

DefaultsAndValidate helps implement the jsontype.Config interface.

type ErrorResponse

type ErrorResponse struct {
	Code int         `json:"code"`
	Meta RequestMeta `json:"meta"`
	Msg  string      `json:"msg"`
}

ErrorResponse is the response for an error.

type HTTPHandler

type HTTPHandler struct {
	Logger          *zap.Logger
	Proxy           Proxy
	RequestMaxBytes int64
}

HTTPHandler is the HTTP handler for the Proxy.

func (HTTPHandler) Validate

func (h HTTPHandler) Validate() http.Handler

Validate creates an HTTP handler for the associated Proxy method.

If more HTTP handlers are added: * Use a middleware for HTTP request metadata method, content type, body limiting, etc.

type JWKSConfig

type JWKSConfig struct {
	RefreshInterval *jsontype.JSONType[time.Duration] `json:"refreshInterval"`
	RefreshTimeout  *jsontype.JSONType[time.Duration] `json:"refreshTimeout"`
}

JWKSConfig contains the configuration for a JWKS.

type LogFormat

type LogFormat string

LogFormat is the set of enums for the format of logs.

type Proxy

type Proxy interface {
	Validate(ctx context.Context, args ValidateArgs) (ValidateResults, error)
}

Proxy is the interface for the JWKS client proxy.

func NewProxy

func NewProxy(multiple map[string]keyfunc.Options, options keyfunc.MultipleOptions) (Proxy, error)

NewProxy creates a new JWKS client proxy.

type RequestMeta

type RequestMeta struct {
	UUID uuid.UUID `json:"uuid"`
}

RequestMeta is the metadata for a request.

type ValidateArgs

type ValidateArgs struct {
	Aud   []string `json:"aud"`
	Iss   []string `json:"iss"`
	Sub   []string `json:"sub"`
	Token string   `json:"token"`
}

ValidateArgs are the arguments for a verification request.

type ValidateRequest

type ValidateRequest struct {
	Args ValidateArgs `json:"args"`
}

ValidateRequest is the request for a verification.

type ValidateResponse

type ValidateResponse struct {
	Results ValidateResults `json:"results"`
	Meta    RequestMeta     `json:"meta"`
}

ValidateResponse is the response for a verification.

type ValidateResults

type ValidateResults struct {
	Success bool `json:"success"`
}

ValidateResults are the results of a verification.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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