[acme db interface] continuing unit test work

This commit is contained in:
max furman 2021-03-11 13:10:14 -08:00
parent 291fd5d45a
commit 20b9785d20
6 changed files with 226 additions and 153 deletions

View file

@ -105,7 +105,7 @@ func (h *Handler) NewAccount(w http.ResponseWriter, r *http.Request) {
return return
} }
acc := &acme.Account{ acc = &acme.Account{
Key: jwk, Key: jwk,
Contact: nar.Contact, Contact: nar.Contact,
Status: acme.StatusValid, Status: acme.StatusValid,

View file

@ -278,18 +278,13 @@ func TestHandler_GetOrdersByAccountID(t *testing.T) {
} }
func TestHandler_NewAccount(t *testing.T) { func TestHandler_NewAccount(t *testing.T) {
accID := "accountID"
acc := acme.Account{
ID: accID,
Status: "valid",
Orders: fmt.Sprintf("https://ca.smallstep.com/acme/account/%s/orders", accID),
}
prov := newProv() prov := newProv()
provName := url.PathEscape(prov.GetName()) provName := url.PathEscape(prov.GetName())
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"} baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
type test struct { type test struct {
db acme.DB db acme.DB
acc *acme.Account
ctx context.Context ctx context.Context
statusCode int statusCode int
err *acme.Error err *acme.Error
@ -372,7 +367,7 @@ func TestHandler_NewAccount(t *testing.T) {
err: acme.NewErrorISE("jwk expected in request context"), err: acme.NewErrorISE("jwk expected in request context"),
} }
}, },
"fail/NewAccount-error": func(t *testing.T) test { "fail/db.CreateAccount-error": func(t *testing.T) test {
nar := &NewAccountRequest{ nar := &NewAccountRequest{
Contact: []string{"foo", "bar"}, Contact: []string{"foo", "bar"},
} }
@ -410,20 +405,18 @@ func TestHandler_NewAccount(t *testing.T) {
return test{ return test{
db: &acme.MockDB{ db: &acme.MockDB{
MockCreateAccount: func(ctx context.Context, acc *acme.Account) error { MockCreateAccount: func(ctx context.Context, acc *acme.Account) error {
acc.ID = "accountID"
assert.Equals(t, acc.Contact, nar.Contact) assert.Equals(t, acc.Contact, nar.Contact)
assert.Equals(t, acc.Key, jwk) assert.Equals(t, acc.Key, jwk)
return nil return nil
}, },
/* },
getLink: func(ctx context.Context, typ acme.Link, abs bool, in ...string) string { acc: &acme.Account{
assert.Equals(t, typ, acme.AccountLink) ID: "accountID",
assert.True(t, abs) Key: jwk,
assert.True(t, abs) Status: acme.StatusValid,
assert.Equals(t, baseURL, acme.BaseURLFromContext(ctx)) Contact: []string{"foo", "bar"},
return fmt.Sprintf("%s/acme/%s/account/%s", Orders: "https://test.ca.smallstep.com/acme/test@acme-provisioner.com/account/accountID/orders",
baseURL.String(), provName, accID)
},
*/
}, },
ctx: ctx, ctx: ctx,
statusCode: 201, statusCode: 201,
@ -435,12 +428,21 @@ func TestHandler_NewAccount(t *testing.T) {
} }
b, err := json.Marshal(nar) b, err := json.Marshal(nar)
assert.FatalError(t, err) assert.FatalError(t, err)
jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
assert.FatalError(t, err)
acc := &acme.Account{
ID: "accountID",
Key: jwk,
Status: acme.StatusValid,
Contact: []string{"foo", "bar"},
}
ctx := context.WithValue(context.Background(), provisionerContextKey, prov) ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: b}) ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: b})
ctx = context.WithValue(ctx, accContextKey, &acc) ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, baseURLContextKey, baseURL) ctx = context.WithValue(ctx, baseURLContextKey, baseURL)
return test{ return test{
ctx: ctx, ctx: ctx,
acc: acc,
statusCode: 200, statusCode: 200,
} }
}, },
@ -448,7 +450,7 @@ func TestHandler_NewAccount(t *testing.T) {
for name, run := range tests { for name, run := range tests {
tc := run(t) tc := run(t)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
h := &Handler{db: tc.db} h := &Handler{db: tc.db, linker: NewLinker("dns", "acme")}
req := httptest.NewRequest("GET", "/foo/bar", nil) req := httptest.NewRequest("GET", "/foo/bar", nil)
req = req.WithContext(tc.ctx) req = req.WithContext(tc.ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -471,19 +473,19 @@ func TestHandler_NewAccount(t *testing.T) {
assert.Equals(t, ae.Subproblems, tc.err.Subproblems) assert.Equals(t, ae.Subproblems, tc.err.Subproblems)
assert.Equals(t, res.Header["Content-Type"], []string{"application/problem+json"}) assert.Equals(t, res.Header["Content-Type"], []string{"application/problem+json"})
} else { } else {
expB, err := json.Marshal(acc) expB, err := json.Marshal(tc.acc)
assert.FatalError(t, err) assert.FatalError(t, err)
assert.Equals(t, bytes.TrimSpace(body), expB) assert.Equals(t, bytes.TrimSpace(body), expB)
assert.Equals(t, res.Header["Location"], assert.Equals(t, res.Header["Location"],
[]string{fmt.Sprintf("%s/acme/%s/account/%s", baseURL.String(), []string{fmt.Sprintf("%s/acme/%s/account/%s", baseURL.String(),
provName, accID)}) provName, "accountID")})
assert.Equals(t, res.Header["Content-Type"], []string{"application/json"}) assert.Equals(t, res.Header["Content-Type"], []string{"application/json"})
} }
}) })
} }
} }
func TestHandlerGetUpdateAccount(t *testing.T) { func TestHandler_GetUpdateAccount(t *testing.T) {
accID := "accountID" accID := "accountID"
acc := acme.Account{ acc := acme.Account{
ID: accID, ID: accID,
@ -594,16 +596,6 @@ func TestHandlerGetUpdateAccount(t *testing.T) {
assert.Equals(t, upd.ID, acc.ID) assert.Equals(t, upd.ID, acc.ID)
return nil return nil
}, },
/*
getLink: func(ctx context.Context, typ acme.Link, abs bool, ins ...string) string {
assert.Equals(t, typ, acme.AccountLink)
assert.True(t, abs)
assert.Equals(t, acme.BaseURLFromContext(ctx), baseURL)
assert.Equals(t, ins, []string{accID})
return fmt.Sprintf("%s/acme/%s/account/%s",
baseURL.String(), provName, accID)
},
*/
}, },
ctx: ctx, ctx: ctx,
statusCode: 200, statusCode: 200,
@ -639,16 +631,6 @@ func TestHandlerGetUpdateAccount(t *testing.T) {
assert.Equals(t, upd.ID, acc.ID) assert.Equals(t, upd.ID, acc.ID)
return nil return nil
}, },
/*
getLink: func(ctx context.Context, typ acme.Link, abs bool, ins ...string) string {
assert.Equals(t, typ, acme.AccountLink)
assert.True(t, abs)
assert.Equals(t, acme.BaseURLFromContext(ctx), baseURL)
assert.Equals(t, ins, []string{accID})
return fmt.Sprintf("%s/acme/%s/account/%s",
baseURL.String(), provName, accID)
},
*/
}, },
ctx: ctx, ctx: ctx,
statusCode: 200, statusCode: 200,
@ -660,18 +642,6 @@ func TestHandlerGetUpdateAccount(t *testing.T) {
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isPostAsGet: true}) ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isPostAsGet: true})
ctx = context.WithValue(ctx, baseURLContextKey, baseURL) ctx = context.WithValue(ctx, baseURLContextKey, baseURL)
return test{ return test{
/*
auth: &mockAcmeAuthority{
getLink: func(ctx context.Context, typ acme.Link, abs bool, ins ...string) string {
assert.Equals(t, typ, acme.AccountLink)
assert.True(t, abs)
assert.Equals(t, acme.BaseURLFromContext(ctx), baseURL)
assert.Equals(t, ins, []string{accID})
return fmt.Sprintf("%s/acme/%s/account/%s",
baseURL, provName, accID)
},
},
*/
ctx: ctx, ctx: ctx,
statusCode: 200, statusCode: 200,
} }
@ -680,7 +650,7 @@ func TestHandlerGetUpdateAccount(t *testing.T) {
for name, run := range tests { for name, run := range tests {
tc := run(t) tc := run(t)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
h := &Handler{db: tc.db} h := &Handler{db: tc.db, linker: NewLinker("dns", "acme")}
req := httptest.NewRequest("GET", "/foo/bar", nil) req := httptest.NewRequest("GET", "/foo/bar", nil)
req = req.WithContext(tc.ctx) req = req.WithContext(tc.ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()

View file

@ -38,10 +38,11 @@ type payloadInfo struct {
// Handler is the ACME API request handler. // Handler is the ACME API request handler.
type Handler struct { type Handler struct {
db acme.DB db acme.DB
backdate provisioner.Duration backdate provisioner.Duration
ca acme.CertificateAuthority ca acme.CertificateAuthority
linker Linker linker Linker
validateChallengeOptions *acme.ValidateChallengeOptions
} }
// HandlerOptions required to create a new ACME API request handler. // HandlerOptions required to create a new ACME API request handler.
@ -63,11 +64,24 @@ type HandlerOptions struct {
// NewHandler returns a new ACME API handler. // NewHandler returns a new ACME API handler.
func NewHandler(ops HandlerOptions) api.RouterHandler { func NewHandler(ops HandlerOptions) api.RouterHandler {
client := http.Client{
Timeout: time.Duration(30 * time.Second),
}
dialer := &net.Dialer{
Timeout: 30 * time.Second,
}
return &Handler{ return &Handler{
ca: ops.CA, ca: ops.CA,
db: ops.DB, db: ops.DB,
backdate: ops.Backdate, backdate: ops.Backdate,
linker: NewLinker(ops.DNS, ops.Prefix), linker: NewLinker(ops.DNS, ops.Prefix),
validateChallengeOptions: &acme.ValidateChallengeOptions{
HTTPGet: client.Get,
LookupTxt: net.LookupTXT,
TLSDial: func(network, addr string, config *tls.Config) (*tls.Conn, error) {
return tls.DialWithDialer(dialer, network, addr, config)
},
},
} }
} }
@ -212,24 +226,12 @@ func (h *Handler) GetChallenge(w http.ResponseWriter, r *http.Request) {
"account '%s' does not own challenge '%s'", acc.ID, ch.ID)) "account '%s' does not own challenge '%s'", acc.ID, ch.ID))
return return
} }
client := http.Client{
Timeout: time.Duration(30 * time.Second),
}
dialer := &net.Dialer{
Timeout: 30 * time.Second,
}
jwk, err := jwkFromContext(ctx) jwk, err := jwkFromContext(ctx)
if err != nil { if err != nil {
api.WriteError(w, err) api.WriteError(w, err)
return return
} }
if err = ch.Validate(ctx, h.db, jwk, acme.ValidateOptions{ if err = ch.Validate(ctx, h.db, jwk, h.validateChallengeOptions); err != nil {
HTTPGet: client.Get,
LookupTxt: net.LookupTXT,
TLSDial: func(network, addr string, config *tls.Config) (*tls.Conn, error) {
return tls.DialWithDialer(dialer, network, addr, config)
},
}); err != nil {
api.WriteError(w, acme.WrapErrorISE(err, "error validating challenge")) api.WriteError(w, acme.WrapErrorISE(err, "error validating challenge"))
return return
} }

View file

@ -8,14 +8,17 @@ import (
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"testing" "testing"
"time" "time"
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/smallstep/assert" "github.com/smallstep/assert"
"github.com/smallstep/certificates/acme" "github.com/smallstep/certificates/acme"
"go.step.sm/crypto/jose"
"go.step.sm/crypto/pemutil" "go.step.sm/crypto/pemutil"
) )
@ -438,16 +441,21 @@ func ch() acme.Challenge {
func TestHandler_GetChallenge(t *testing.T) { func TestHandler_GetChallenge(t *testing.T) {
chiCtx := chi.NewRouteContext() chiCtx := chi.NewRouteContext()
chiCtx.URLParams.Add("chID", "chID") chiCtx.URLParams.Add("chID", "chID")
chiCtx.URLParams.Add("authzID", "authzID")
prov := newProv() prov := newProv()
provName := url.PathEscape(prov.GetName()) provName := url.PathEscape(prov.GetName())
baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"} baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"}
url := fmt.Sprintf("%s/acme/challenge/%s", baseURL, "chID")
url := fmt.Sprintf("%s/acme/%s/challenge/%s/%s",
baseURL.String(), provName, "authzID", "chID")
type test struct { type test struct {
db acme.DB db acme.DB
vco *acme.ValidateChallengeOptions
ctx context.Context ctx context.Context
statusCode int statusCode int
ch acme.Challenge ch *acme.Challenge
err *acme.Error err *acme.Error
} }
var tests = map[string]func(t *testing.T) test{ var tests = map[string]func(t *testing.T) test{
@ -485,84 +493,177 @@ func TestHandler_GetChallenge(t *testing.T) {
err: acme.NewError(acme.ErrorMalformedType, "payload expected in request context"), err: acme.NewError(acme.ErrorMalformedType, "payload expected in request context"),
} }
}, },
/* "fail/db.GetChallenge-error": func(t *testing.T) test {
"fail/validate-challenge-error": func(t *testing.T) test { acc := &acme.Account{ID: "accID"}
acc := &acme.Account{ID: "accID"} ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx := context.WithValue(context.Background(), provisionerContextKey, prov) ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, accContextKey, acc) ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true})
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true}) ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx)
ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) return test{
return test{ db: &acme.MockDB{
db: &acme.MockDB{ MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
MockError: acme.NewError(acme.ErrorUnauthorizedType, "unauthorized"), assert.Equals(t, chID, "chID")
assert.Equals(t, azID, "authzID")
return nil, acme.NewErrorISE("force")
}, },
ctx: ctx, },
statusCode: 401, ctx: ctx,
err: acme.NewError(acme.ErrorUnauthorizedType, "unauthorized"), statusCode: 500,
} err: acme.NewErrorISE("force"),
}, }
"fail/get-challenge-error": func(t *testing.T) test { },
acc := &acme.Account{ID: "accID"} "fail/account-id-mismatch": func(t *testing.T) test {
ctx := context.WithValue(context.Background(), provisionerContextKey, prov) acc := &acme.Account{ID: "accID"}
ctx = context.WithValue(ctx, accContextKey, acc) ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isPostAsGet: true}) ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true})
return test{ ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx)
db: &acme.MockDB{ return test{
MockError: acme.NewError(acme.ErrorUnauthorizedType, "unauthorized"), db: &acme.MockDB{
MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
assert.Equals(t, chID, "chID")
assert.Equals(t, azID, "authzID")
return &acme.Challenge{AccountID: "foo"}, nil
}, },
ctx: ctx, },
statusCode: 401, ctx: ctx,
err: acme.NewError(acme.ErrorUnauthorizedType, "unauthorized"), statusCode: 401,
} err: acme.NewError(acme.ErrorUnauthorizedType, "accout id mismatch"),
}, }
"ok/validate-challenge": func(t *testing.T) test { },
key, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) "fail/no-jwk": func(t *testing.T) test {
assert.FatalError(t, err) acc := &acme.Account{ID: "accID"}
acc := &acme.Account{ID: "accID", Key: key} ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx := context.WithValue(context.Background(), provisionerContextKey, prov) ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, accContextKey, acc) ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true})
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true}) ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx)
ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) return test{
ctx = context.WithValue(ctx, baseURLContextKey, baseURL) db: &acme.MockDB{
ch := ch() MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
ch.Status = "valid" assert.Equals(t, chID, "chID")
ch.Validated = time.Now().UTC().Format(time.RFC3339) assert.Equals(t, azID, "authzID")
return test{ return &acme.Challenge{AccountID: "accID"}, nil
db: &acme.MockDB{
MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
assert.Equals(t, chID, ch.ID)
return &ch, nil
},
getLink: func(ctx context.Context, typ acme.Link, abs bool, in ...string) string {
var ret string
switch count {
case 0:
assert.Equals(t, typ, acme.AuthzLink)
assert.True(t, abs)
assert.Equals(t, in, []string{ch.AuthzID})
ret = fmt.Sprintf("%s/acme/%s/authz/%s", baseURL.String(), provName, ch.AuthzID)
case 1:
assert.Equals(t, typ, acme.ChallengeLink)
assert.True(t, abs)
assert.Equals(t, in, []string{ch.ID})
ret = url
}
count++
return ret
},
}, },
ctx: ctx, },
statusCode: 200, ctx: ctx,
ch: ch, statusCode: 500,
} err: acme.NewErrorISE("missing jwk"),
}, }
*/ },
"fail/nil-jwk": func(t *testing.T) test {
acc := &acme.Account{ID: "accID"}
ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true})
ctx = context.WithValue(ctx, jwkContextKey, nil)
ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx)
return test{
db: &acme.MockDB{
MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
assert.Equals(t, chID, "chID")
assert.Equals(t, azID, "authzID")
return &acme.Challenge{AccountID: "accID"}, nil
},
},
ctx: ctx,
statusCode: 500,
err: acme.NewErrorISE("nil jwk"),
}
},
"fail/validate-challenge-error": func(t *testing.T) test {
acc := &acme.Account{ID: "accID"}
ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true})
_jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
assert.FatalError(t, err)
_pub := _jwk.Public()
ctx = context.WithValue(ctx, jwkContextKey, &_pub)
ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx)
return test{
db: &acme.MockDB{
MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
assert.Equals(t, chID, "chID")
assert.Equals(t, azID, "authzID")
return &acme.Challenge{
Status: acme.StatusPending,
Type: "http-01",
AccountID: "accID",
}, nil
},
MockUpdateChallenge: func(ctx context.Context, ch *acme.Challenge) error {
assert.Equals(t, ch.Status, acme.StatusPending)
assert.Equals(t, ch.Type, "http-01")
assert.Equals(t, ch.AccountID, "accID")
assert.HasSuffix(t, ch.Error.Type, acme.ErrorConnectionType.String())
return acme.NewErrorISE("force")
},
},
vco: &acme.ValidateChallengeOptions{
HTTPGet: func(string) (*http.Response, error) {
return nil, errors.New("force")
},
},
ctx: ctx,
statusCode: 500,
err: acme.NewErrorISE("force"),
}
},
"ok": func(t *testing.T) test {
acc := &acme.Account{ID: "accID"}
ctx := context.WithValue(context.Background(), provisionerContextKey, prov)
ctx = context.WithValue(ctx, accContextKey, acc)
ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{isEmptyJSON: true})
_jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
assert.FatalError(t, err)
_pub := _jwk.Public()
ctx = context.WithValue(ctx, jwkContextKey, &_pub)
ctx = context.WithValue(ctx, baseURLContextKey, baseURL)
ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx)
return test{
db: &acme.MockDB{
MockGetChallenge: func(ctx context.Context, chID, azID string) (*acme.Challenge, error) {
assert.Equals(t, chID, "chID")
assert.Equals(t, azID, "authzID")
return &acme.Challenge{
ID: "chID",
AuthzID: "authzID",
Status: acme.StatusPending,
Type: "http-01",
AccountID: "accID",
}, nil
},
MockUpdateChallenge: func(ctx context.Context, ch *acme.Challenge) error {
assert.Equals(t, ch.Status, acme.StatusPending)
assert.Equals(t, ch.Type, "http-01")
assert.Equals(t, ch.AccountID, "accID")
assert.HasSuffix(t, ch.Error.Type, acme.ErrorConnectionType.String())
return nil
},
},
ch: &acme.Challenge{
ID: "chID",
AuthzID: "authzID",
Status: acme.StatusPending,
Type: "http-01",
AccountID: "accID",
URL: url,
Error: acme.NewError(acme.ErrorConnectionType, "force"),
},
vco: &acme.ValidateChallengeOptions{
HTTPGet: func(string) (*http.Response, error) {
return nil, errors.New("force")
},
},
ctx: ctx,
statusCode: 200,
}
},
} }
for name, run := range tests { for name, run := range tests {
tc := run(t) tc := run(t)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
h := &Handler{db: tc.db, linker: NewLinker("dns", "acme")} h := &Handler{db: tc.db, linker: NewLinker("dns", "acme"), validateChallengeOptions: tc.vco}
req := httptest.NewRequest("GET", url, nil) req := httptest.NewRequest("GET", url, nil)
req = req.WithContext(tc.ctx) req = req.WithContext(tc.ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()

View file

@ -462,7 +462,7 @@ func provisionerFromContext(ctx context.Context) (acme.Provisioner, error) {
func payloadFromContext(ctx context.Context) (*payloadInfo, error) { func payloadFromContext(ctx context.Context) (*payloadInfo, error) {
val, ok := ctx.Value(payloadContextKey).(*payloadInfo) val, ok := ctx.Value(payloadContextKey).(*payloadInfo)
if !ok || val == nil { if !ok || val == nil {
return nil, acme.NewError(acme.ErrorMalformedType, "payload expected in request context") return nil, acme.NewErrorISE("payload expected in request context")
} }
return val, nil return val, nil
} }

View file

@ -47,7 +47,7 @@ func (ch *Challenge) ToLog() (interface{}, error) {
// type using the DB interface. // type using the DB interface.
// satisfactorily validated, the 'status' and 'validated' attributes are // satisfactorily validated, the 'status' and 'validated' attributes are
// updated. // updated.
func (ch *Challenge) Validate(ctx context.Context, db DB, jwk *jose.JSONWebKey, vo ValidateOptions) error { func (ch *Challenge) Validate(ctx context.Context, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
// If already valid or invalid then return without performing validation. // If already valid or invalid then return without performing validation.
if ch.Status == StatusValid || ch.Status == StatusInvalid { if ch.Status == StatusValid || ch.Status == StatusInvalid {
return nil return nil
@ -64,7 +64,7 @@ func (ch *Challenge) Validate(ctx context.Context, db DB, jwk *jose.JSONWebKey,
} }
} }
func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo ValidateOptions) error { func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
url := fmt.Sprintf("http://%s/.well-known/acme-challenge/%s", ch.Value, ch.Token) url := fmt.Sprintf("http://%s/.well-known/acme-challenge/%s", ch.Value, ch.Token)
resp, err := vo.HTTPGet(url) resp, err := vo.HTTPGet(url)
@ -105,7 +105,7 @@ func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWeb
return nil return nil
} }
func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo ValidateOptions) error { func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
config := &tls.Config{ config := &tls.Config{
NextProtos: []string{"acme-tls/1"}, NextProtos: []string{"acme-tls/1"},
ServerName: ch.Value, ServerName: ch.Value,
@ -197,7 +197,7 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON
"incorrect certificate for tls-alpn-01 challenge: missing acmeValidationV1 extension")) "incorrect certificate for tls-alpn-01 challenge: missing acmeValidationV1 extension"))
} }
func dns01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo ValidateOptions) error { func dns01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
// Normalize domain for wildcard DNS names // Normalize domain for wildcard DNS names
// This is done to avoid making TXT lookups for domains like // This is done to avoid making TXT lookups for domains like
// _acme-challenge.*.example.com // _acme-challenge.*.example.com
@ -263,8 +263,8 @@ type httpGetter func(string) (*http.Response, error)
type lookupTxt func(string) ([]string, error) type lookupTxt func(string) ([]string, error)
type tlsDialer func(network, addr string, config *tls.Config) (*tls.Conn, error) type tlsDialer func(network, addr string, config *tls.Config) (*tls.Conn, error)
// ValidateOptions are ACME challenge validator functions. // ValidateChallengeOptions are ACME challenge validator functions.
type ValidateOptions struct { type ValidateChallengeOptions struct {
HTTPGet httpGetter HTTPGet httpGetter
LookupTxt lookupTxt LookupTxt lookupTxt
TLSDial tlsDialer TLSDial tlsDialer