Allow account IDs in authz and challenge URLs (#7768)
This adds new handlers under `/acme/authz/` and `/acme/chall/` that expect to be followed by `{regID}/{authzID}` and `{regID}/{authzID}/{challengeID}`, respectively. For deployability, the old handlers continue to work, and the URLs returned for newly created objects will still point to the paths used by the old handlers (`/acme/authz-v3/` and `/acme/chall-v3/`). There are some self-referential URLs in authz and challenge responses, like the Location header, and the URL of challenges embedded in an authorization object. This PR updates `prepAuthorizationForDisplay` and `prepChallengeForDisplay` so those URLs can be generated consistently with the path that was requested. For the WFE tests, in most cases I duplicated an entire test and then updated it to test the `WithAccount` handler. The idea is that once we're fully switched over to the new format we can delete the tests for the non-`WithAccount` variants. Part of #7683
This commit is contained in:
parent
2603aa45a8
commit
2058d985cc
147
wfe2/wfe.go
147
wfe2/wfe.go
|
@ -57,16 +57,18 @@ const (
|
|||
acctPath = "/acme/acct/"
|
||||
// When we moved to authzv2, we used a "-v3" suffix to avoid confusion
|
||||
// regarding ACMEv2.
|
||||
authzPath = "/acme/authz-v3/"
|
||||
challengePath = "/acme/chall-v3/"
|
||||
certPath = "/acme/cert/"
|
||||
revokeCertPath = "/acme/revoke-cert"
|
||||
buildIDPath = "/build"
|
||||
rolloverPath = "/acme/key-change"
|
||||
newNoncePath = "/acme/new-nonce"
|
||||
newOrderPath = "/acme/new-order"
|
||||
orderPath = "/acme/order/"
|
||||
finalizeOrderPath = "/acme/finalize/"
|
||||
authzPath = "/acme/authz-v3/"
|
||||
authzPathWithAcct = "/acme/authz/"
|
||||
challengePath = "/acme/chall-v3/"
|
||||
challengePathWithAcct = "/acme/chall/"
|
||||
certPath = "/acme/cert/"
|
||||
revokeCertPath = "/acme/revoke-cert"
|
||||
buildIDPath = "/build"
|
||||
rolloverPath = "/acme/key-change"
|
||||
newNoncePath = "/acme/new-nonce"
|
||||
newOrderPath = "/acme/new-order"
|
||||
orderPath = "/acme/order/"
|
||||
finalizeOrderPath = "/acme/finalize/"
|
||||
|
||||
getAPIPrefix = "/get/"
|
||||
getOrderPath = getAPIPrefix + "order/"
|
||||
|
@ -432,13 +434,15 @@ func (wfe *WebFrontEndImpl) Handler(stats prometheus.Registerer, oTelHTTPOptions
|
|||
// TODO(@cpu): After November 1st, 2020 support for "GET" to the following
|
||||
// endpoints will be removed, leaving only POST-as-GET support.
|
||||
wfe.HandleFunc(m, orderPath, wfe.GetOrder, "GET", "POST")
|
||||
wfe.HandleFunc(m, authzPath, wfe.Authorization, "GET", "POST")
|
||||
wfe.HandleFunc(m, challengePath, wfe.Challenge, "GET", "POST")
|
||||
wfe.HandleFunc(m, authzPath, wfe.AuthorizationHandler, "GET", "POST")
|
||||
wfe.HandleFunc(m, authzPathWithAcct, wfe.AuthorizationHandlerWithAccount, "GET", "POST")
|
||||
wfe.HandleFunc(m, challengePath, wfe.ChallengeHandler, "GET", "POST")
|
||||
wfe.HandleFunc(m, challengePathWithAcct, wfe.ChallengeHandlerWithAccount, "GET", "POST")
|
||||
wfe.HandleFunc(m, certPath, wfe.Certificate, "GET", "POST")
|
||||
// Boulder-specific GET-able resource endpoints
|
||||
wfe.HandleFunc(m, getOrderPath, wfe.GetOrder, "GET")
|
||||
wfe.HandleFunc(m, getAuthzPath, wfe.Authorization, "GET")
|
||||
wfe.HandleFunc(m, getChallengePath, wfe.Challenge, "GET")
|
||||
wfe.HandleFunc(m, getAuthzPath, wfe.AuthorizationHandler, "GET")
|
||||
wfe.HandleFunc(m, getChallengePath, wfe.ChallengeHandler, "GET")
|
||||
wfe.HandleFunc(m, getCertPath, wfe.Certificate, "GET")
|
||||
|
||||
// Endpoint for draft-ietf-acme-ari
|
||||
|
@ -1088,31 +1092,55 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(
|
|||
response.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
// Challenge handles POST requests to challenge URLs.
|
||||
// ChallengeHandler handles POST requests to challenge URLs of the form /acme/chall-v3/<authorizationID>/<challengeID>.
|
||||
// Such requests are clients' responses to the server's challenges.
|
||||
func (wfe *WebFrontEndImpl) Challenge(
|
||||
func (wfe *WebFrontEndImpl) ChallengeHandler(
|
||||
ctx context.Context,
|
||||
logEvent *web.RequestEvent,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request) {
|
||||
notFound := func() {
|
||||
wfe.sendError(response, logEvent, probs.NotFound("No such challenge"), nil)
|
||||
}
|
||||
slug := strings.Split(request.URL.Path, "/")
|
||||
if len(slug) != 2 {
|
||||
notFound()
|
||||
wfe.sendError(response, logEvent, probs.NotFound("No such challenge"), nil)
|
||||
return
|
||||
}
|
||||
authorizationID, err := strconv.ParseInt(slug[0], 10, 64)
|
||||
|
||||
wfe.Challenge(ctx, logEvent, challengePath, response, request, slug[0], slug[1])
|
||||
}
|
||||
|
||||
// ChallengeHandlerWithAccount handles POST requests to challenge URLs of the form /acme/chall/{regID}/{authzID}/{challID}.
|
||||
func (wfe *WebFrontEndImpl) ChallengeHandlerWithAccount(
|
||||
ctx context.Context,
|
||||
logEvent *web.RequestEvent,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request) {
|
||||
slug := strings.Split(request.URL.Path, "/")
|
||||
if len(slug) != 3 {
|
||||
wfe.sendError(response, logEvent, probs.NotFound("No such challenge"), nil)
|
||||
return
|
||||
}
|
||||
// TODO(#7683): the regID is currently ignored.
|
||||
wfe.Challenge(ctx, logEvent, challengePathWithAcct, response, request, slug[1], slug[2])
|
||||
}
|
||||
|
||||
// Challenge handles POSTS to both formats of challenge URLs.
|
||||
func (wfe *WebFrontEndImpl) Challenge(
|
||||
ctx context.Context,
|
||||
logEvent *web.RequestEvent,
|
||||
handlerPath string,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request,
|
||||
authorizationIDStr string,
|
||||
challengeID string) {
|
||||
authorizationID, err := strconv.ParseInt(authorizationIDStr, 10, 64)
|
||||
if err != nil {
|
||||
wfe.sendError(response, logEvent, probs.Malformed("Invalid authorization ID"), nil)
|
||||
return
|
||||
}
|
||||
challengeID := slug[1]
|
||||
authzPB, err := wfe.ra.GetAuthorization(ctx, &rapb.GetAuthorizationRequest{Id: authorizationID})
|
||||
if err != nil {
|
||||
if errors.Is(err, berrors.NotFound) {
|
||||
notFound()
|
||||
wfe.sendError(response, logEvent, probs.NotFound("No such challenge"), nil)
|
||||
} else {
|
||||
wfe.sendError(response, logEvent, web.ProblemDetailsForError(err, "Problem getting authorization"), err)
|
||||
}
|
||||
|
@ -1133,7 +1161,7 @@ func (wfe *WebFrontEndImpl) Challenge(
|
|||
}
|
||||
challengeIndex := authz.FindChallengeByStringID(challengeID)
|
||||
if challengeIndex == -1 {
|
||||
notFound()
|
||||
wfe.sendError(response, logEvent, probs.NotFound("No such challenge"), nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1157,11 +1185,11 @@ func (wfe *WebFrontEndImpl) Challenge(
|
|||
challenge := authz.Challenges[challengeIndex]
|
||||
switch request.Method {
|
||||
case "GET", "HEAD":
|
||||
wfe.getChallenge(response, request, authz, &challenge, logEvent)
|
||||
wfe.getChallenge(handlerPath, response, request, authz, &challenge, logEvent)
|
||||
|
||||
case "POST":
|
||||
logEvent.ChallengeType = string(challenge.Type)
|
||||
wfe.postChallenge(ctx, response, request, authz, challengeIndex, logEvent)
|
||||
wfe.postChallenge(ctx, handlerPath, response, request, authz, challengeIndex, logEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1186,9 +1214,17 @@ func prepAccountForDisplay(acct *core.Registration) {
|
|||
// prepChallengeForDisplay takes a core.Challenge and prepares it for display to
|
||||
// the client by filling in its URL field and clearing several unnecessary
|
||||
// fields.
|
||||
func (wfe *WebFrontEndImpl) prepChallengeForDisplay(request *http.Request, authz core.Authorization, challenge *core.Challenge) {
|
||||
func (wfe *WebFrontEndImpl) prepChallengeForDisplay(
|
||||
handlerPath string,
|
||||
request *http.Request,
|
||||
authz core.Authorization,
|
||||
challenge *core.Challenge,
|
||||
) {
|
||||
// Update the challenge URL to be relative to the HTTP request Host
|
||||
challenge.URL = web.RelativeEndpoint(request, fmt.Sprintf("%s%s/%s", challengePath, authz.ID, challenge.StringID()))
|
||||
if handlerPath == challengePathWithAcct || handlerPath == authzPathWithAcct {
|
||||
challenge.URL = web.RelativeEndpoint(request, fmt.Sprintf("%s%d/%s/%s", challengePathWithAcct, authz.RegistrationID, authz.ID, challenge.StringID()))
|
||||
}
|
||||
|
||||
// Internally, we store challenge error problems with just the short form
|
||||
// (e.g. "CAA") of the problem type. But for external display, we need to
|
||||
|
@ -1211,9 +1247,9 @@ func (wfe *WebFrontEndImpl) prepChallengeForDisplay(request *http.Request, authz
|
|||
|
||||
// prepAuthorizationForDisplay takes a core.Authorization and prepares it for
|
||||
// display to the client by preparing all its challenges.
|
||||
func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(request *http.Request, authz *core.Authorization) {
|
||||
func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(handlerPath string, request *http.Request, authz *core.Authorization) {
|
||||
for i := range authz.Challenges {
|
||||
wfe.prepChallengeForDisplay(request, *authz, &authz.Challenges[i])
|
||||
wfe.prepChallengeForDisplay(handlerPath, request, *authz, &authz.Challenges[i])
|
||||
}
|
||||
|
||||
// Shuffle the challenges so no one relies on their order.
|
||||
|
@ -1235,15 +1271,15 @@ func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(request *http.Request, a
|
|||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) getChallenge(
|
||||
handlerPath string,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request,
|
||||
authz core.Authorization,
|
||||
challenge *core.Challenge,
|
||||
logEvent *web.RequestEvent) {
|
||||
wfe.prepChallengeForDisplay(handlerPath, request, authz, challenge)
|
||||
|
||||
wfe.prepChallengeForDisplay(request, authz, challenge)
|
||||
|
||||
authzURL := urlForAuthz(authz, request)
|
||||
authzURL := urlForAuthz(handlerPath, authz, request)
|
||||
response.Header().Add("Location", challenge.URL)
|
||||
response.Header().Add("Link", link(authzURL, "up"))
|
||||
|
||||
|
@ -1258,6 +1294,7 @@ func (wfe *WebFrontEndImpl) getChallenge(
|
|||
|
||||
func (wfe *WebFrontEndImpl) postChallenge(
|
||||
ctx context.Context,
|
||||
handlerPath string,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request,
|
||||
authz core.Authorization,
|
||||
|
@ -1286,7 +1323,7 @@ func (wfe *WebFrontEndImpl) postChallenge(
|
|||
// challenge details, not a POST to initiate a challenge
|
||||
if string(body) == "" {
|
||||
challenge := authz.Challenges[challengeIndex]
|
||||
wfe.getChallenge(response, request, authz, &challenge, logEvent)
|
||||
wfe.getChallenge(handlerPath, response, request, authz, &challenge, logEvent)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1336,9 +1373,9 @@ func (wfe *WebFrontEndImpl) postChallenge(
|
|||
|
||||
// assumption: PerformValidation does not modify order of challenges
|
||||
challenge := returnAuthz.Challenges[challengeIndex]
|
||||
wfe.prepChallengeForDisplay(request, authz, &challenge)
|
||||
wfe.prepChallengeForDisplay(handlerPath, request, authz, &challenge)
|
||||
|
||||
authzURL := urlForAuthz(authz, request)
|
||||
authzURL := urlForAuthz(handlerPath, authz, request)
|
||||
response.Header().Add("Location", challenge.URL)
|
||||
response.Header().Add("Link", link(authzURL, "up"))
|
||||
|
||||
|
@ -1524,11 +1561,39 @@ func (wfe *WebFrontEndImpl) deactivateAuthorization(
|
|||
return true
|
||||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) Authorization(
|
||||
// AuthorizationHandler handles requests to authorization URLs of the form /acme/authz/{authzID}.
|
||||
func (wfe *WebFrontEndImpl) AuthorizationHandler(
|
||||
ctx context.Context,
|
||||
logEvent *web.RequestEvent,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request) {
|
||||
wfe.Authorization(ctx, authzPath, logEvent, response, request, request.URL.Path)
|
||||
}
|
||||
|
||||
// AuthorizationHandlerWithAccount handles requests to authorization URLs of the form /acme/authz/{regID}/{authzID}.
|
||||
func (wfe *WebFrontEndImpl) AuthorizationHandlerWithAccount(
|
||||
ctx context.Context,
|
||||
logEvent *web.RequestEvent,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request) {
|
||||
slug := strings.Split(request.URL.Path, "/")
|
||||
if len(slug) != 2 {
|
||||
wfe.sendError(response, logEvent, probs.NotFound("No such authorization"), nil)
|
||||
return
|
||||
}
|
||||
// TODO(#7683): The regID is currently ignored.
|
||||
wfe.Authorization(ctx, authzPathWithAcct, logEvent, response, request, slug[1])
|
||||
}
|
||||
|
||||
// Authorization handles both `/acme/authz/{authzID}` and `/acme/authz/{regID}/{authzID}` requests,
|
||||
// after the calling function has parsed out the authzID.
|
||||
func (wfe *WebFrontEndImpl) Authorization(
|
||||
ctx context.Context,
|
||||
handlerPath string,
|
||||
logEvent *web.RequestEvent,
|
||||
response http.ResponseWriter,
|
||||
request *http.Request,
|
||||
authzIDStr string) {
|
||||
var requestAccount *core.Registration
|
||||
var requestBody []byte
|
||||
// If the request is a POST it is either:
|
||||
|
@ -1546,7 +1611,7 @@ func (wfe *WebFrontEndImpl) Authorization(
|
|||
requestBody = body
|
||||
}
|
||||
|
||||
authzID, err := strconv.ParseInt(request.URL.Path, 10, 64)
|
||||
authzID, err := strconv.ParseInt(authzIDStr, 10, 64)
|
||||
if err != nil {
|
||||
wfe.sendError(response, logEvent, probs.Malformed("Invalid authorization ID"), nil)
|
||||
return
|
||||
|
@ -1615,7 +1680,7 @@ func (wfe *WebFrontEndImpl) Authorization(
|
|||
return
|
||||
}
|
||||
|
||||
wfe.prepAuthorizationForDisplay(request, &authz)
|
||||
wfe.prepAuthorizationForDisplay(handlerPath, request, &authz)
|
||||
|
||||
err = wfe.writeJsonResponse(response, logEvent, http.StatusOK, authz)
|
||||
if err != nil {
|
||||
|
@ -2731,6 +2796,10 @@ func extractRequesterIP(req *http.Request) (net.IP, error) {
|
|||
return net.ParseIP(host), nil
|
||||
}
|
||||
|
||||
func urlForAuthz(authz core.Authorization, request *http.Request) string {
|
||||
func urlForAuthz(handlerPath string, authz core.Authorization, request *http.Request) string {
|
||||
if handlerPath == challengePathWithAcct || handlerPath == authzPathWithAcct {
|
||||
return web.RelativeEndpoint(request, fmt.Sprintf("%s%d/%s", authzPathWithAcct, authz.RegistrationID, authz.ID))
|
||||
}
|
||||
|
||||
return web.RelativeEndpoint(request, authzPath+authz.ID)
|
||||
}
|
||||
|
|
463
wfe2/wfe_test.go
463
wfe2/wfe_test.go
|
@ -1164,7 +1164,7 @@ func TestHTTPMethods(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetChallenge(t *testing.T) {
|
||||
func TestGetChallengeHandler(t *testing.T) {
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
// The slug "7TyhFQ" is the StringID of a challenge with type "http-01" and
|
||||
|
@ -1181,7 +1181,7 @@ func TestGetChallenge(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Could not make NewRequest")
|
||||
req.URL.Path = fmt.Sprintf("1/%s", challSlug)
|
||||
|
||||
wfe.Challenge(ctx, newRequestEvent(), resp, req)
|
||||
wfe.ChallengeHandler(ctx, newRequestEvent(), resp, req)
|
||||
test.AssertEquals(t, resp.Code, http.StatusOK)
|
||||
test.AssertEquals(t, resp.Header().Get("Location"), challengeURL)
|
||||
test.AssertEquals(t, resp.Header().Get("Content-Type"), "application/json")
|
||||
|
@ -1198,7 +1198,41 @@ func TestGetChallenge(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestChallenge(t *testing.T) {
|
||||
func TestGetChallengeHandlerWithAccount(t *testing.T) {
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
// The slug "7TyhFQ" is the StringID of a challenge with type "http-01" and
|
||||
// token "token".
|
||||
challSlug := "7TyhFQ"
|
||||
|
||||
for _, method := range []string{"GET", "HEAD"} {
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
// We set req.URL.Path separately to emulate the path-stripping that
|
||||
// Boulder's request handler does.
|
||||
challengeURL := fmt.Sprintf("http://localhost/acme/chall/1/1/%s", challSlug)
|
||||
req, err := http.NewRequest(method, challengeURL, nil)
|
||||
test.AssertNotError(t, err, "Could not make NewRequest")
|
||||
req.URL.Path = fmt.Sprintf("1/1/%s", challSlug)
|
||||
|
||||
wfe.ChallengeHandlerWithAccount(ctx, newRequestEvent(), resp, req)
|
||||
test.AssertEquals(t, resp.Code, http.StatusOK)
|
||||
test.AssertEquals(t, resp.Header().Get("Location"), challengeURL)
|
||||
test.AssertEquals(t, resp.Header().Get("Content-Type"), "application/json")
|
||||
test.AssertEquals(t, resp.Header().Get("Link"), `<http://localhost/acme/authz/1/1>;rel="up"`)
|
||||
|
||||
// Body is only relevant for GET. For HEAD, body will
|
||||
// be discarded by HandleFunc() anyway, so it doesn't
|
||||
// matter what Challenge() writes to it.
|
||||
if method == "GET" {
|
||||
test.AssertUnmarshaledEquals(
|
||||
t, resp.Body.String(),
|
||||
`{"status": "valid", "type":"http-01","token":"token","url":"http://localhost/acme/chall/1/1/7TyhFQ"}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChallengeHandler(t *testing.T) {
|
||||
wfe, _, signer := setupWFE(t)
|
||||
|
||||
post := func(path string) *http.Request {
|
||||
|
@ -1264,7 +1298,86 @@ func TestChallenge(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.Challenge(ctx, newRequestEvent(), responseWriter, tc.Request)
|
||||
wfe.ChallengeHandler(ctx, newRequestEvent(), responseWriter, tc.Request)
|
||||
// Check the response code, headers and body match expected
|
||||
headers := responseWriter.Header()
|
||||
body := responseWriter.Body.String()
|
||||
test.AssertEquals(t, responseWriter.Code, tc.ExpectedStatus)
|
||||
for h, v := range tc.ExpectedHeaders {
|
||||
test.AssertEquals(t, headers.Get(h), v)
|
||||
}
|
||||
test.AssertUnmarshaledEquals(t, body, tc.ExpectedBody)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChallengeHandlerWithAccount(t *testing.T) {
|
||||
wfe, _, signer := setupWFE(t)
|
||||
|
||||
post := func(path string) *http.Request {
|
||||
signedURL := fmt.Sprintf("http://localhost/%s", path)
|
||||
_, _, jwsBody := signer.byKeyID(1, nil, signedURL, `{}`)
|
||||
return makePostRequestWithPath(path, jwsBody)
|
||||
}
|
||||
postAsGet := func(keyID int64, path, body string) *http.Request {
|
||||
_, _, jwsBody := signer.byKeyID(keyID, nil, fmt.Sprintf("http://localhost/%s", path), body)
|
||||
return makePostRequestWithPath(path, jwsBody)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Request *http.Request
|
||||
ExpectedStatus int
|
||||
ExpectedHeaders map[string]string
|
||||
ExpectedBody string
|
||||
}{
|
||||
{
|
||||
Name: "Valid challenge",
|
||||
Request: post("1/1/7TyhFQ"),
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"Location": "http://localhost/acme/chall/1/1/7TyhFQ",
|
||||
"Link": `<http://localhost/acme/authz/1/1>;rel="up"`,
|
||||
},
|
||||
ExpectedBody: `{"status": "valid", "type":"http-01","token":"token","url":"http://localhost/acme/chall/1/1/7TyhFQ"}`,
|
||||
},
|
||||
{
|
||||
Name: "Expired challenge",
|
||||
Request: post("1/3/7TyhFQ"),
|
||||
ExpectedStatus: http.StatusNotFound,
|
||||
ExpectedBody: `{"type":"` + probs.ErrorNS + `malformed","detail":"Expired authorization","status":404}`,
|
||||
},
|
||||
{
|
||||
Name: "Missing challenge",
|
||||
Request: post("1/1/"),
|
||||
ExpectedStatus: http.StatusNotFound,
|
||||
ExpectedBody: `{"type":"` + probs.ErrorNS + `malformed","detail":"No such challenge","status":404}`,
|
||||
},
|
||||
{
|
||||
Name: "Unspecified database error",
|
||||
Request: post("1/4/7TyhFQ"),
|
||||
ExpectedStatus: http.StatusInternalServerError,
|
||||
ExpectedBody: `{"type":"` + probs.ErrorNS + `serverInternal","detail":"Problem getting authorization","status":500}`,
|
||||
},
|
||||
{
|
||||
Name: "POST-as-GET, wrong owner",
|
||||
Request: postAsGet(1, "1/5/7TyhFQ", ""),
|
||||
ExpectedStatus: http.StatusForbidden,
|
||||
ExpectedBody: `{"type":"` + probs.ErrorNS + `unauthorized","detail":"User account ID doesn't match account ID in authorization","status":403}`,
|
||||
},
|
||||
{
|
||||
Name: "Valid POST-as-GET",
|
||||
Request: postAsGet(1, "1/1/7TyhFQ", ""),
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedBody: `{"status": "valid", "type":"http-01", "token":"token", "url": "http://localhost/acme/chall/1/1/7TyhFQ"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.ChallengeHandlerWithAccount(ctx, newRequestEvent(), responseWriter, tc.Request)
|
||||
// Check the response code, headers and body match expected
|
||||
headers := responseWriter.Header()
|
||||
body := responseWriter.Body.String()
|
||||
|
@ -1287,10 +1400,10 @@ func (ra *MockRAPerformValidationError) PerformValidation(context.Context, *rapb
|
|||
return nil, errors.New("broken on purpose")
|
||||
}
|
||||
|
||||
// TestUpdateChallengeFinalizedAuthz tests that POSTing a challenge associated
|
||||
// TestUpdateChallengeHandlerFinalizedAuthz tests that POSTing a challenge associated
|
||||
// with an already valid authorization just returns the challenge without calling
|
||||
// the RA.
|
||||
func TestUpdateChallengeFinalizedAuthz(t *testing.T) {
|
||||
func TestUpdateChallengeHandlerFinalizedAuthz(t *testing.T) {
|
||||
wfe, fc, signer := setupWFE(t)
|
||||
wfe.ra = &MockRAPerformValidationError{MockRegistrationAuthority{clk: fc}}
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
@ -1298,7 +1411,7 @@ func TestUpdateChallengeFinalizedAuthz(t *testing.T) {
|
|||
signedURL := "http://localhost/1/7TyhFQ"
|
||||
_, _, jwsBody := signer.byKeyID(1, nil, signedURL, `{}`)
|
||||
request := makePostRequestWithPath("1/7TyhFQ", jwsBody)
|
||||
wfe.Challenge(ctx, newRequestEvent(), responseWriter, request)
|
||||
wfe.ChallengeHandler(ctx, newRequestEvent(), responseWriter, request)
|
||||
|
||||
body := responseWriter.Body.String()
|
||||
test.AssertUnmarshaledEquals(t, body, `{
|
||||
|
@ -1309,10 +1422,32 @@ func TestUpdateChallengeFinalizedAuthz(t *testing.T) {
|
|||
}`)
|
||||
}
|
||||
|
||||
// TestUpdateChallengeRAError tests that when the RA returns an error from
|
||||
// TestUpdateChallengeHandlerWithAccountFinalizedAuthz tests that POSTing a challenge associated
|
||||
// with an already valid authorization just returns the challenge without calling
|
||||
// the RA.
|
||||
func TestUpdateChallengeHandlerWithAccountFinalizedAuthz(t *testing.T) {
|
||||
wfe, fc, signer := setupWFE(t)
|
||||
wfe.ra = &MockRAPerformValidationError{MockRegistrationAuthority{clk: fc}}
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
signedURL := "http://localhost/1/1/7TyhFQ"
|
||||
_, _, jwsBody := signer.byKeyID(1, nil, signedURL, `{}`)
|
||||
request := makePostRequestWithPath("1/1/7TyhFQ", jwsBody)
|
||||
wfe.ChallengeHandlerWithAccount(ctx, newRequestEvent(), responseWriter, request)
|
||||
|
||||
body := responseWriter.Body.String()
|
||||
test.AssertUnmarshaledEquals(t, body, `{
|
||||
"status": "valid",
|
||||
"type": "http-01",
|
||||
"token": "token",
|
||||
"url": "http://localhost/acme/chall/1/1/7TyhFQ"
|
||||
}`)
|
||||
}
|
||||
|
||||
// TestUpdateChallengeHandlerRAError tests that when the RA returns an error from
|
||||
// PerformValidation that the WFE returns an internal server error as expected
|
||||
// and does not panic or otherwise bug out.
|
||||
func TestUpdateChallengeRAError(t *testing.T) {
|
||||
func TestUpdateChallengeHandlerRAError(t *testing.T) {
|
||||
wfe, fc, signer := setupWFE(t)
|
||||
// Mock the RA to always fail PerformValidation
|
||||
wfe.ra = &MockRAPerformValidationError{MockRegistrationAuthority{clk: fc}}
|
||||
|
@ -1323,7 +1458,32 @@ func TestUpdateChallengeRAError(t *testing.T) {
|
|||
responseWriter := httptest.NewRecorder()
|
||||
request := makePostRequestWithPath("2/7TyhFQ", jwsBody)
|
||||
|
||||
wfe.Challenge(ctx, newRequestEvent(), responseWriter, request)
|
||||
wfe.ChallengeHandler(ctx, newRequestEvent(), responseWriter, request)
|
||||
|
||||
// The result should be an internal server error problem.
|
||||
body := responseWriter.Body.String()
|
||||
test.AssertUnmarshaledEquals(t, body, `{
|
||||
"type": "urn:ietf:params:acme:error:serverInternal",
|
||||
"detail": "Unable to update challenge",
|
||||
"status": 500
|
||||
}`)
|
||||
}
|
||||
|
||||
// TestUpdateChallengeHandlerWithAccountRAError tests that when the RA returns an error from
|
||||
// PerformValidation that the WFE returns an internal server error as expected
|
||||
// and does not panic or otherwise bug out.
|
||||
func TestUpdateChallengeHandlerWithAccountRAError(t *testing.T) {
|
||||
wfe, fc, signer := setupWFE(t)
|
||||
// Mock the RA to always fail PerformValidation
|
||||
wfe.ra = &MockRAPerformValidationError{MockRegistrationAuthority{clk: fc}}
|
||||
|
||||
// Update a pending challenge
|
||||
signedURL := "http://localhost/1/2/7TyhFQ"
|
||||
_, _, jwsBody := signer.byKeyID(1, nil, signedURL, `{}`)
|
||||
responseWriter := httptest.NewRecorder()
|
||||
request := makePostRequestWithPath("1/2/7TyhFQ", jwsBody)
|
||||
|
||||
wfe.ChallengeHandlerWithAccount(ctx, newRequestEvent(), responseWriter, request)
|
||||
|
||||
// The result should be an internal server error problem.
|
||||
body := responseWriter.Body.String()
|
||||
|
@ -1640,13 +1800,13 @@ func TestNewAccountNoID(t *testing.T) {
|
|||
}`)
|
||||
}
|
||||
|
||||
func TestGetAuthorization(t *testing.T) {
|
||||
func TestGetAuthorizationHandler(t *testing.T) {
|
||||
wfe, _, signer := setupWFE(t)
|
||||
|
||||
// Expired authorizations should be inaccessible
|
||||
authzURL := "3"
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: mustParseURL(authzURL),
|
||||
})
|
||||
|
@ -1656,7 +1816,7 @@ func TestGetAuthorization(t *testing.T) {
|
|||
responseWriter.Body.Reset()
|
||||
|
||||
// Ensure that a valid authorization can't be reached with an invalid URL
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
URL: mustParseURL("1d"),
|
||||
Method: "GET",
|
||||
})
|
||||
|
@ -1668,7 +1828,7 @@ func TestGetAuthorization(t *testing.T) {
|
|||
|
||||
responseWriter = httptest.NewRecorder()
|
||||
// Ensure that a POST-as-GET to an authorization works
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, postAsGet)
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, postAsGet)
|
||||
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
|
||||
body := responseWriter.Body.String()
|
||||
test.AssertUnmarshaledEquals(t, body, `
|
||||
|
@ -1690,13 +1850,63 @@ func TestGetAuthorization(t *testing.T) {
|
|||
}`)
|
||||
}
|
||||
|
||||
// TestAuthorization500 tests that internal errors on GetAuthorization result in
|
||||
func TestGetAuthorizationHandlerWithAccount(t *testing.T) {
|
||||
wfe, _, signer := setupWFE(t)
|
||||
|
||||
// Expired authorizations should be inaccessible
|
||||
authzURL := "1/3"
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.AuthorizationHandlerWithAccount(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: mustParseURL(authzURL),
|
||||
})
|
||||
test.AssertEquals(t, responseWriter.Code, http.StatusNotFound)
|
||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(),
|
||||
`{"type":"`+probs.ErrorNS+`malformed","detail":"Expired authorization","status":404}`)
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Ensure that a valid authorization can't be reached with an invalid URL
|
||||
wfe.AuthorizationHandlerWithAccount(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
URL: mustParseURL("1/1d"),
|
||||
Method: "GET",
|
||||
})
|
||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(),
|
||||
`{"type":"`+probs.ErrorNS+`malformed","detail":"Invalid authorization ID","status":400}`)
|
||||
|
||||
_, _, jwsBody := signer.byKeyID(1, nil, "http://localhost/1/1", "")
|
||||
postAsGet := makePostRequestWithPath("1/1", jwsBody)
|
||||
|
||||
responseWriter = httptest.NewRecorder()
|
||||
// Ensure that a POST-as-GET to an authorization works
|
||||
wfe.AuthorizationHandlerWithAccount(ctx, newRequestEvent(), responseWriter, postAsGet)
|
||||
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
|
||||
body := responseWriter.Body.String()
|
||||
test.AssertUnmarshaledEquals(t, body, `
|
||||
{
|
||||
"identifier": {
|
||||
"type": "dns",
|
||||
"value": "not-an-example.com"
|
||||
},
|
||||
"status": "valid",
|
||||
"expires": "2070-01-01T00:00:00Z",
|
||||
"challenges": [
|
||||
{
|
||||
"status": "valid",
|
||||
"type": "http-01",
|
||||
"token":"token",
|
||||
"url": "http://localhost/acme/chall/1/1/7TyhFQ"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
}
|
||||
|
||||
// TestAuthorizationHandler500 tests that internal errors on GetAuthorization result in
|
||||
// a 500.
|
||||
func TestAuthorization500(t *testing.T) {
|
||||
func TestAuthorizationHandler500(t *testing.T) {
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: mustParseURL("4"),
|
||||
})
|
||||
|
@ -1708,6 +1918,24 @@ func TestAuthorization500(t *testing.T) {
|
|||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), expected)
|
||||
}
|
||||
|
||||
// TestAuthorizationHandlerWithAccount500 tests that internal errors on GetAuthorization result in
|
||||
// a 500.
|
||||
func TestAuthorizationHandlerWithAccount500(t *testing.T) {
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.AuthorizationHandlerWithAccount(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: mustParseURL("1/4"),
|
||||
})
|
||||
expected := `{
|
||||
"type": "urn:ietf:params:acme:error:serverInternal",
|
||||
"detail": "Problem getting authorization",
|
||||
"status": 500
|
||||
}`
|
||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), expected)
|
||||
}
|
||||
|
||||
// RAWithFailedChallenges is a fake RA whose GetAuthorization method returns
|
||||
// an authz with a failed challenge.
|
||||
type RAWithFailedChallenge struct {
|
||||
|
@ -1738,14 +1966,35 @@ func (ra *RAWithFailedChallenge) GetAuthorization(ctx context.Context, id *rapb.
|
|||
}, nil
|
||||
}
|
||||
|
||||
// TestAuthorizationChallengeNamespace tests that the runtime prefixing of
|
||||
// TestAuthorizationChallengeHandlerNamespace tests that the runtime prefixing of
|
||||
// Challenge Problem Types works as expected
|
||||
func TestAuthorizationChallengeNamespace(t *testing.T) {
|
||||
func TestAuthorizationChallengeHandlerNamespace(t *testing.T) {
|
||||
wfe, clk, _ := setupWFE(t)
|
||||
wfe.ra = &RAWithFailedChallenge{clk: clk}
|
||||
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: mustParseURL("6"),
|
||||
})
|
||||
|
||||
var authz core.Authorization
|
||||
err := json.Unmarshal(responseWriter.Body.Bytes(), &authz)
|
||||
test.AssertNotError(t, err, "Couldn't unmarshal returned authorization object")
|
||||
test.AssertEquals(t, len(authz.Challenges), 1)
|
||||
// The Challenge Error Type should have had the probs.ErrorNS prefix added
|
||||
test.AssertEquals(t, string(authz.Challenges[0].Error.Type), probs.ErrorNS+"things:are:whack")
|
||||
responseWriter.Body.Reset()
|
||||
}
|
||||
|
||||
// TestAuthorizationChallengeHandlerWithAccountNamespace tests that the runtime prefixing of
|
||||
// Challenge Problem Types works as expected
|
||||
func TestAuthorizationChallengeHandlerWithAccountNamespace(t *testing.T) {
|
||||
wfe, clk, _ := setupWFE(t)
|
||||
wfe.ra = &RAWithFailedChallenge{clk: clk}
|
||||
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: mustParseURL("6"),
|
||||
})
|
||||
|
@ -2392,7 +2641,7 @@ func TestHeaderBoulderRequester(t *testing.T) {
|
|||
test.AssertEquals(t, responseWriter.Header().Get("Boulder-Requester"), "1")
|
||||
}
|
||||
|
||||
func TestDeactivateAuthorization(t *testing.T) {
|
||||
func TestDeactivateAuthorizationHandler(t *testing.T) {
|
||||
wfe, _, signer := setupWFE(t)
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
|
@ -2402,7 +2651,7 @@ func TestDeactivateAuthorization(t *testing.T) {
|
|||
_, _, body := signer.byKeyID(1, nil, "http://localhost/1", payload)
|
||||
request := makePostRequestWithPath("1", body)
|
||||
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, request)
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, request)
|
||||
test.AssertUnmarshaledEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
`{"type": "`+probs.ErrorNS+`malformed","detail": "Invalid status value","status": 400}`)
|
||||
|
@ -2412,7 +2661,48 @@ func TestDeactivateAuthorization(t *testing.T) {
|
|||
_, _, body = signer.byKeyID(1, nil, "http://localhost/1", payload)
|
||||
request = makePostRequestWithPath("1", body)
|
||||
|
||||
wfe.Authorization(ctx, newRequestEvent(), responseWriter, request)
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, request)
|
||||
test.AssertUnmarshaledEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
`{
|
||||
"identifier": {
|
||||
"type": "dns",
|
||||
"value": "not-an-example.com"
|
||||
},
|
||||
"status": "deactivated",
|
||||
"expires": "2070-01-01T00:00:00Z",
|
||||
"challenges": [
|
||||
{
|
||||
"status": "valid",
|
||||
"type": "http-01",
|
||||
"token": "token",
|
||||
"url": "http://localhost/acme/chall-v3/1/7TyhFQ"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
}
|
||||
|
||||
func TestDeactivateAuthorizationHandlerWithAccount(t *testing.T) {
|
||||
wfe, _, signer := setupWFE(t)
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
payload := `{"status":""}`
|
||||
_, _, body := signer.byKeyID(1, nil, "http://localhost/1", payload)
|
||||
request := makePostRequestWithPath("1", body)
|
||||
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, request)
|
||||
test.AssertUnmarshaledEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
`{"type": "`+probs.ErrorNS+`malformed","detail": "Invalid status value","status": 400}`)
|
||||
|
||||
responseWriter.Body.Reset()
|
||||
payload = `{"status":"deactivated"}`
|
||||
_, _, body = signer.byKeyID(1, nil, "http://localhost/1", payload)
|
||||
request = makePostRequestWithPath("1", body)
|
||||
|
||||
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, request)
|
||||
test.AssertUnmarshaledEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
`{
|
||||
|
@ -3399,7 +3689,33 @@ func TestPrepAuthzForDisplay(t *testing.T) {
|
|||
}
|
||||
|
||||
// This modifies the authz in-place.
|
||||
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
|
||||
wfe.prepAuthorizationForDisplay(authzPath, &http.Request{Host: "localhost"}, authz)
|
||||
|
||||
// Ensure ID and RegID are omitted.
|
||||
authzJSON, err := json.Marshal(authz)
|
||||
test.AssertNotError(t, err, "Failed to marshal authz")
|
||||
test.AssertNotContains(t, string(authzJSON), "\"id\":\"12345\"")
|
||||
test.AssertNotContains(t, string(authzJSON), "\"registrationID\":\"1\"")
|
||||
}
|
||||
|
||||
func TestPrepAuthzWithAccountForDisplay(t *testing.T) {
|
||||
t.Parallel()
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
authz := &core.Authorization{
|
||||
ID: "12345",
|
||||
Status: core.StatusPending,
|
||||
RegistrationID: 1,
|
||||
Identifier: identifier.NewDNS("example.com"),
|
||||
Challenges: []core.Challenge{
|
||||
{Type: core.ChallengeTypeDNS01, Status: core.StatusPending, Token: "token"},
|
||||
{Type: core.ChallengeTypeHTTP01, Status: core.StatusPending, Token: "token"},
|
||||
{Type: core.ChallengeTypeTLSALPN01, Status: core.StatusPending, Token: "token"},
|
||||
},
|
||||
}
|
||||
|
||||
// This modifies the authz in-place.
|
||||
wfe.prepAuthorizationForDisplay(authzPathWithAcct, &http.Request{Host: "localhost"}, authz)
|
||||
|
||||
// Ensure ID and RegID are omitted.
|
||||
authzJSON, err := json.Marshal(authz)
|
||||
|
@ -3425,7 +3741,32 @@ func TestPrepRevokedAuthzForDisplay(t *testing.T) {
|
|||
}
|
||||
|
||||
// This modifies the authz in-place.
|
||||
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
|
||||
wfe.prepAuthorizationForDisplay(authzPath, &http.Request{Host: "localhost"}, authz)
|
||||
|
||||
// All of the challenges should be revoked as well.
|
||||
for _, chall := range authz.Challenges {
|
||||
test.AssertEquals(t, chall.Status, core.StatusInvalid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepRevokedAuthzWithAccountForDisplay(t *testing.T) {
|
||||
t.Parallel()
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
authz := &core.Authorization{
|
||||
ID: "12345",
|
||||
Status: core.StatusInvalid,
|
||||
RegistrationID: 1,
|
||||
Identifier: identifier.NewDNS("example.com"),
|
||||
Challenges: []core.Challenge{
|
||||
{Type: core.ChallengeTypeDNS01, Status: core.StatusPending, Token: "token"},
|
||||
{Type: core.ChallengeTypeHTTP01, Status: core.StatusPending, Token: "token"},
|
||||
{Type: core.ChallengeTypeTLSALPN01, Status: core.StatusPending, Token: "token"},
|
||||
},
|
||||
}
|
||||
|
||||
// This modifies the authz in-place.
|
||||
wfe.prepAuthorizationForDisplay(authzPathWithAcct, &http.Request{Host: "localhost"}, authz)
|
||||
|
||||
// All of the challenges should be revoked as well.
|
||||
for _, chall := range authz.Challenges {
|
||||
|
@ -3448,7 +3789,30 @@ func TestPrepWildcardAuthzForDisplay(t *testing.T) {
|
|||
}
|
||||
|
||||
// This modifies the authz in-place.
|
||||
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
|
||||
wfe.prepAuthorizationForDisplay(authzPath, &http.Request{Host: "localhost"}, authz)
|
||||
|
||||
// The identifier should not start with a star, but the authz should be marked
|
||||
// as a wildcard.
|
||||
test.AssertEquals(t, strings.HasPrefix(authz.Identifier.Value, "*."), false)
|
||||
test.AssertEquals(t, authz.Wildcard, true)
|
||||
}
|
||||
|
||||
func TestPrepWildcardAuthzWithAcountForDisplay(t *testing.T) {
|
||||
t.Parallel()
|
||||
wfe, _, _ := setupWFE(t)
|
||||
|
||||
authz := &core.Authorization{
|
||||
ID: "12345",
|
||||
Status: core.StatusPending,
|
||||
RegistrationID: 1,
|
||||
Identifier: identifier.NewDNS("*.example.com"),
|
||||
Challenges: []core.Challenge{
|
||||
{Type: core.ChallengeTypeDNS01, Status: core.StatusPending, Token: "token"},
|
||||
},
|
||||
}
|
||||
|
||||
// This modifies the authz in-place.
|
||||
wfe.prepAuthorizationForDisplay(authzPathWithAcct, &http.Request{Host: "localhost"}, authz)
|
||||
|
||||
// The identifier should not start with a star, but the authz should be marked
|
||||
// as a wildcard.
|
||||
|
@ -3484,7 +3848,7 @@ func TestPrepAuthzForDisplayShuffle(t *testing.T) {
|
|||
// Prep the authz 100 times, and count where each challenge ended up each time.
|
||||
for range 100 {
|
||||
// This modifies the authz in place
|
||||
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
|
||||
wfe.prepAuthorizationForDisplay(challengePath, &http.Request{Host: "localhost"}, authz)
|
||||
for i, chall := range authz.Challenges {
|
||||
counts[chall.Type][i] += 1
|
||||
}
|
||||
|
@ -3567,7 +3931,7 @@ func TestPrepAccountForDisplay(t *testing.T) {
|
|||
test.AssertEquals(t, acct.ID, int64(0))
|
||||
}
|
||||
|
||||
func TestGETAPIAuthz(t *testing.T) {
|
||||
func TestGETAPIAuthorizationHandler(t *testing.T) {
|
||||
wfe, _, _ := setupWFE(t)
|
||||
makeGet := func(path, endpoint string) (*http.Request, *web.RequestEvent) {
|
||||
return &http.Request{URL: &url.URL{Path: path}, Method: "GET"},
|
||||
|
@ -3595,7 +3959,46 @@ func TestGETAPIAuthz(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
responseWriter := httptest.NewRecorder()
|
||||
req, logEvent := makeGet(tc.path, getAuthzPath)
|
||||
wfe.Authorization(context.Background(), logEvent, responseWriter, req)
|
||||
wfe.AuthorizationHandler(context.Background(), logEvent, responseWriter, req)
|
||||
|
||||
if responseWriter.Code == http.StatusOK && tc.expectTooFreshErr {
|
||||
t.Errorf("expected too fresh error, got http.StatusOK")
|
||||
} else {
|
||||
test.AssertEquals(t, responseWriter.Code, http.StatusForbidden)
|
||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), tooFreshErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGETAPIAuthorizationHandlerWitAccount(t *testing.T) {
|
||||
wfe, _, _ := setupWFE(t)
|
||||
makeGet := func(path, endpoint string) (*http.Request, *web.RequestEvent) {
|
||||
return &http.Request{URL: &url.URL{Path: path}, Method: "GET"},
|
||||
&web.RequestEvent{Endpoint: endpoint}
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
path string
|
||||
expectTooFreshErr bool
|
||||
}{
|
||||
{
|
||||
name: "fresh authz",
|
||||
path: "1/1",
|
||||
expectTooFreshErr: true,
|
||||
},
|
||||
{
|
||||
name: "old authz",
|
||||
path: "1/2",
|
||||
expectTooFreshErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
tooFreshErr := `{"type":"` + probs.ErrorNS + `unauthorized","detail":"Authorization is too new for GET API. You should only use this non-standard API to access resources created more than 10s ago","status":403}`
|
||||
for _, tc := range testCases {
|
||||
responseWriter := httptest.NewRecorder()
|
||||
req, logEvent := makeGet(tc.path, getAuthzPath)
|
||||
wfe.AuthorizationHandlerWithAccount(context.Background(), logEvent, responseWriter, req)
|
||||
|
||||
if responseWriter.Code == http.StatusOK && tc.expectTooFreshErr {
|
||||
t.Errorf("expected too fresh error, got http.StatusOK")
|
||||
|
@ -3634,7 +4037,7 @@ func TestGETAPIChallenge(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
responseWriter := httptest.NewRecorder()
|
||||
req, logEvent := makeGet(tc.path, getAuthzPath)
|
||||
wfe.Challenge(context.Background(), logEvent, responseWriter, req)
|
||||
wfe.ChallengeHandler(context.Background(), logEvent, responseWriter, req)
|
||||
|
||||
if responseWriter.Code == http.StatusOK && tc.expectTooFreshErr {
|
||||
t.Errorf("expected too fresh error, got http.StatusOK")
|
||||
|
|
Loading…
Reference in New Issue