From 6c4bc576901ccf2a94ceb6c48144a57f8f64b400 Mon Sep 17 00:00:00 2001 From: Caleb Doxsey Date: Wed, 19 Jan 2022 11:44:56 -0700 Subject: [PATCH] tests: fix cover make target, fix linting (#26) --- .golangci.yml | 2 +- Makefile | 25 ++++++++----------------- jwks_test.go | 28 +++++++++++++++++++++++++--- middleware.go | 6 +++--- sdk.go | 4 ++++ 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 330f853..fe83d51 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -55,7 +55,6 @@ linters: - errcheck - gofmt - goimports - - golint - goprintffuncname - gosec - gosimple @@ -65,6 +64,7 @@ linters: - misspell - nakedret - nolintlint + - revive - rowserrcheck - staticcheck - structcheck diff --git a/Makefile b/Makefile index a70e654..b2addfd 100644 --- a/Makefile +++ b/Makefile @@ -6,20 +6,17 @@ PKG := github.com/pomerium/$(NAME) BUILDDIR := ${PREFIX}/dist BINDIR := ${PREFIX}/bin -GO111MODULE=on -CGO_ENABLED := 0 -# Set any default go build tags -BUILDTAGS := GOLANGCI_VERSION = v1.43.0 + .PHONY: all -all: clean build-deps cover lint build ## Runs a clean, build, fmt, lint, cover, and vet. +all: clean cover lint build .PHONY: clean clean: ## Cleanup any build binaries or packages. @echo "==> $@" $(RM) -r $(BINDIR) - + $(RM) coverage.txt .PHONY: build-deps build-deps: ## Install build dependencies @@ -29,24 +26,18 @@ build-deps: ## Install build dependencies .PHONY: build build: ## Builds dynamic executables and/or packages. @echo "==> $@" - @CGO_ENABLED=0 GO111MODULE=on go build -tags "$(BUILDTAGS)" ${GO_LDFLAGS} -o $(BINDIR)/$(NAME) + @go build -o $(BINDIR)/$(NAME) .PHONY: lint -lint: ## Verifies `golint` passes. +lint: build-deps ## Verifies `golint` passes. @echo "==> $@" @golangci-lint run ./... - .PHONY: cover cover: ## Runs go test with coverage - @echo "" > coverage.txt - @for d in $(shell go list ./... | grep -v vendor); do \ - go test -race -coverprofile=profile.out -covermode=atomic "$$d"; \ - if [ -f profile.out ]; then \ - cat profile.out >> coverage.txt; \ - rm profile.out; \ - fi; \ - done; + @echo "==> $@" + @go test -race -coverprofile=coverage.txt -tags "$(BUILDTAGS)" ./... + @sort -o coverage.txt coverage.txt .PHONY: help help: diff --git a/jwks_test.go b/jwks_test.go index c3d4c1a..5403922 100644 --- a/jwks_test.go +++ b/jwks_test.go @@ -5,6 +5,7 @@ import ( "crypto/elliptic" "crypto/rsa" "encoding/base64" + "math/big" "math/rand" "testing" @@ -19,8 +20,21 @@ func TestFetchJSONWebKeySet(t *testing.T) { require.NoError(t, err) k2, err := ecdsa.GenerateKey(elliptic.P256(), random) require.NoError(t, err) - k3, err := rsa.GenerateKey(random, 2048) - require.NoError(t, err) + + // rsa key generation is not deterministic, so use the key found in: + // https://cs.opensource.google/go/go/+/refs/tags/go1.17.6:src/crypto/rsa/rsa_test.go;drc=ee3f3a60070ee9edeb3f10fa2e4b90404068cb3a;l=146 + k3 := &rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"), + E: 3, + }, + D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"), + Primes: []*big.Int{ + fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"), + fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"), + }, + } + k3.Precompute() jwks := &jose.JSONWebKeySet{ Keys: []jose.JSONWebKey{ @@ -32,7 +46,15 @@ func TestFetchJSONWebKeySet(t *testing.T) { bs, err := EncodeJSONWebKeySetToPEM(jwks) assert.NoError(t, err) assert.Equal(t, - "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFdloxa3BKandzVW9jWjZlTnhmajZ6cld4bGU3RApYNUcwUDVNYzR2UklLTkdTWFlsOFpKci93dE9VQlhYUWx1Mk5HYkNRaXh4cUlFTEdKMWlRVjFHVGxRPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tCk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXM3L0daNHRJaUgvZFFXVGNxYzYvTjFiZzVMRDIKRlVjN1lTZmJBb0pLYmUyZy9iY0xUNnE3SGRZMjVZS3FTY0FxM2tyR3hoeHNMTENxb2VBTk1CWEJPQT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQotLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLQpNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXRFSGkwMEl2QVRNNXNpTExFT3paCm95NkJTQXlEekxLU3ZrVGxPMjZ0bFdQL0oySkNGSjlSOU1rVkFxK3VPR2dsTGd2dmpNd1BjUzZ6TUlMYUIzNkMKRmV0OUJMTnRqNkFGZ2YybkM2d1ovS0hRSFpWbldFcmU4WmZ4N3dhSFV0QnRsa2E0NVRqcVV6YTE3VnZueDZaNwpyZDBkcnBsN285NHZJR05STkNuWC9SSUQrOUY5Z1hBM1RZeEtrU2dRWnU3eEdrdDRNMHpiMU9EdWtYeWprYVBlCjB3by9tRG1haWMzeFFYV0FsaWFnQnBGcWhiNk5oUUdPYkg5VndLVzVtOHh3Rm43dTU3SkNMMzZUMlVpcE1ob3oKa1hFRnFXVWE0b2lzc1FIYndEeUFOck8rdWdSZHV4cVhGeDJGUXUvRG1QbUlwNHVBU0ZTRFU0ajM5VjNVbnBJbgpjd0lEQVFBQgotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFdloxa3BKandzVW9jWjZlTnhmajZ6cld4bGU3RApYNUcwUDVNYzR2UklLTkdTWFlsOFpKci93dE9VQlhYUWx1Mk5HYkNRaXh4cUlFTEdKMWlRVjFHVGxRPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tCk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXM3L0daNHRJaUgvZFFXVGNxYzYvTjFiZzVMRDIKRlVjN1lTZmJBb0pLYmUyZy9iY0xUNnE3SGRZMjVZS3FTY0FxM2tyR3hoeHNMTENxb2VBTk1CWEJPQT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQotLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLQpNSUlCSHpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVF3QU1JSUJCd0tDQVFCeFk4aENzaGtLaVhDVUt5ZGtydFF0ClFTUmtlMjh3NEpvdG9jRGlWcW91NGs1NURFREpha3ZXYlhYRGNha1Y0SEE4UjJ0T0dnYnh2VGpGbzhFSzQ3MHcKOU85aXBhcFBVU3JSUmFCc1NPbGthYUlzNk9ZaDRGTHdacHFNTkJWVkV0Z3VWVVIvQzM0WTJwUzlrUnJIczZxKwpjR2hEWm9sa1dUN25HeTVlU0V2UERIZzBFQnExMWh1NkhtUG1JM3IwQkluT05xSmcycmNLM1UrK3drMWxuYkQzCnlzQ1pzS09xUlVtczNuL0lXS2VUcVhYbXoyWEtKMnQwTlNYd2lEbUE5cTBHbSt3MGJYaDNsemh0VVA0TWx6UysKbG54OWhLNWJqelNiQ1VCNVJYd01ERy91Tk1RcUM0TW1BNEJQY2VTZk15QUlGamRSTEd5L0s3Z2JiMnZpT1lSdApBZ0VECi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=", base64.StdEncoding.EncodeToString(bs), ) } + +func fromBase10(base10 string) *big.Int { + i, ok := big.NewInt(0).SetString(base10, 10) + if !ok { + panic("bad number: " + base10) + } + return i +} diff --git a/middleware.go b/middleware.go index 30ab721..7912427 100644 --- a/middleware.go +++ b/middleware.go @@ -2,7 +2,6 @@ package sdk import ( "context" - "errors" "net/http" ) @@ -11,8 +10,6 @@ const ( defaultAttestationQueryParam = "jwt" ) -var ErrTokenNotFound = errors.New("attestation token not found") - // AddIdentityToRequest is http middleware handler that -- given an attestation instance -- will // find, parse, verify, and inject a Pomerium identity into the request context. // @@ -75,17 +72,20 @@ func TokenFromQuery(r *http.Request) string { return r.FormValue(defaultAttestationQueryParam) } +// context keys var ( IdentityCtxKey = &contextKey{"Token"} ErrorCtxKey = &contextKey{"Error"} ) +// NewContext creates a new context with the given identity and error stored as values. func NewContext(ctx context.Context, t *Identity, err error) context.Context { ctx = context.WithValue(ctx, IdentityCtxKey, t) ctx = context.WithValue(ctx, ErrorCtxKey, err) return ctx } +// FromContext retrieves the identity and error stored in a context. func FromContext(ctx context.Context) (id *Identity, err error) { id, _ = ctx.Value(IdentityCtxKey).(*Identity) err, _ = ctx.Value(ErrorCtxKey).(error) diff --git a/sdk.go b/sdk.go index 7778e82..7fe36e8 100644 --- a/sdk.go +++ b/sdk.go @@ -1,3 +1,4 @@ +// Package sdk contains code to make verifying the Pomerium attestation token easier. package sdk import ( @@ -15,6 +16,7 @@ import ( "gopkg.in/square/go-jose.v2/jwt" ) +// errors var ( ErrDatastoreRequired = errors.New("must set a datastore") ErrJWKSNotFound = errors.New("empty JSON Web Key Set payload") @@ -22,6 +24,7 @@ var ( ErrJWKSInvalid = errors.New("invalid JSON Web Key") ErrJWKSTypeMismatch = errors.New("priv/pub JSON Web Key mismatch") ErrMultipleHeaders = errors.New("JWT signature must have only one header") + ErrTokenNotFound = errors.New("attestation token not found") ) // JSONWebKeyStore is the interface to for storing JSON Web Keys. @@ -35,6 +38,7 @@ const ( defaultJWKSPath = "/.well-known/pomerium/jwks.json" ) +// A Verifier is used to verify JWT tokens. type Verifier struct { staticJWKSEndpoint string datastore JSONWebKeyStore