wfe: remove authz-v3 and chall-v3 paths (#7904)

This removes the `handlerPath` parameter to various calls, which was
used solely to distinguish the `-v3`-style paths from the `WithAccount`
paths.

Also, this removes `WithAccount` from all names that had it. The fact
that these URLS include an account ID is now implicit.
This commit is contained in:
Jacob Hoffman-Andrews 2024-12-19 11:19:49 -08:00 committed by GitHub
parent d42865c187
commit e8a49c5a02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 466 deletions

View File

@ -50,31 +50,24 @@ import (
// lowercase plus hyphens. If you violate that assumption you should update
// measured_http.
const (
directoryPath = "/directory"
newAcctPath = "/acme/new-acct"
acctPath = "/acme/acct/"
// When we moved to authzv2, we used a "-v3" suffix to avoid confusion
// regarding ACMEv2. More recently we moved back to using plain `/acme/authz/`
// and `/acme/chall/`, so the `-v3` paths are deprecated.
// TODO(#7683): Remove authz-v3 and chall-v3 once the new paths have been
// the default in prod for 30 days.
deprecatedAuthzPath = "/acme/authz-v3/"
authzPathWithAcct = "/acme/authz/"
deprecatedChallengePath = "/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/"
directoryPath = "/directory"
newAcctPath = "/acme/new-acct"
acctPath = "/acme/acct/"
authzPath = "/acme/authz/"
challengePath = "/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/"
getAuthzPath = getAPIPrefix + "authz-v3/"
getChallengePath = getAPIPrefix + "chall-v3/"
getAuthzPath = getAPIPrefix + "authz/"
getChallengePath = getAPIPrefix + "chall/"
getCertPath = getAPIPrefix + "cert/"
// Draft or likely-to-change paths
@ -435,15 +428,13 @@ 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, deprecatedAuthzPath, wfe.DeprecatedAuthorizationHandler, "GET", "POST")
wfe.HandleFunc(m, authzPathWithAcct, wfe.AuthorizationHandler, "GET", "POST")
wfe.HandleFunc(m, deprecatedChallengePath, wfe.DeprecatedChallengeHandler, "GET", "POST")
wfe.HandleFunc(m, challengePathWithAcct, wfe.ChallengeHandler, "GET", "POST")
wfe.HandleFunc(m, authzPath, wfe.AuthorizationHandler, "GET", "POST")
wfe.HandleFunc(m, challengePath, wfe.ChallengeHandler, "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.DeprecatedAuthorizationHandler, "GET")
wfe.HandleFunc(m, getChallengePath, wfe.DeprecatedChallengeHandler, "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
@ -1089,22 +1080,6 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(
response.WriteHeader(http.StatusOK)
}
// DeprecatedChallengeHandler 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) DeprecatedChallengeHandler(
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 challenge"), nil)
return
}
wfe.Challenge(ctx, logEvent, deprecatedChallengePath, response, request, slug[0], slug[1])
}
// ChallengeHandler handles POST requests to challenge URLs of the form /acme/chall/{regID}/{authzID}/{challID}.
func (wfe *WebFrontEndImpl) ChallengeHandler(
ctx context.Context,
@ -1117,14 +1092,13 @@ func (wfe *WebFrontEndImpl) ChallengeHandler(
return
}
// TODO(#7683): the regID is currently ignored.
wfe.Challenge(ctx, logEvent, challengePathWithAcct, response, request, slug[1], slug[2])
wfe.Challenge(ctx, logEvent, 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,
@ -1182,11 +1156,11 @@ func (wfe *WebFrontEndImpl) Challenge(
challenge := authz.Challenges[challengeIndex]
switch request.Method {
case "GET", "HEAD":
wfe.getChallenge(handlerPath, response, request, authz, &challenge, logEvent)
wfe.getChallenge(response, request, authz, &challenge, logEvent)
case "POST":
logEvent.ChallengeType = string(challenge.Type)
wfe.postChallenge(ctx, handlerPath, response, request, authz, challengeIndex, logEvent)
wfe.postChallenge(ctx, response, request, authz, challengeIndex, logEvent)
}
}
@ -1212,16 +1186,12 @@ func prepAccountForDisplay(acct *core.Registration) {
// the client by filling in its URL field and clearing several unnecessary
// fields.
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", deprecatedChallengePath, 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()))
}
challenge.URL = web.RelativeEndpoint(request, fmt.Sprintf("%s%d/%s/%s", challengePath, 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
@ -1244,9 +1214,9 @@ func (wfe *WebFrontEndImpl) prepChallengeForDisplay(
// prepAuthorizationForDisplay takes a core.Authorization and prepares it for
// display to the client by preparing all its challenges.
func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(handlerPath string, request *http.Request, authz *core.Authorization) {
func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(request *http.Request, authz *core.Authorization) {
for i := range authz.Challenges {
wfe.prepChallengeForDisplay(handlerPath, request, *authz, &authz.Challenges[i])
wfe.prepChallengeForDisplay(request, *authz, &authz.Challenges[i])
}
// Shuffle the challenges so no one relies on their order.
@ -1268,15 +1238,14 @@ func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(handlerPath string, requ
}
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(handlerPath, authz, request)
authzURL := urlForAuthz(authz, request)
response.Header().Add("Location", challenge.URL)
response.Header().Add("Link", link(authzURL, "up"))
@ -1291,7 +1260,6 @@ func (wfe *WebFrontEndImpl) getChallenge(
func (wfe *WebFrontEndImpl) postChallenge(
ctx context.Context,
handlerPath string,
response http.ResponseWriter,
request *http.Request,
authz core.Authorization,
@ -1320,7 +1288,7 @@ func (wfe *WebFrontEndImpl) postChallenge(
// challenge details, not a POST to initiate a challenge
if string(body) == "" {
challenge := authz.Challenges[challengeIndex]
wfe.getChallenge(handlerPath, response, request, authz, &challenge, logEvent)
wfe.getChallenge(response, request, authz, &challenge, logEvent)
return
}
@ -1370,9 +1338,9 @@ func (wfe *WebFrontEndImpl) postChallenge(
// assumption: PerformValidation does not modify order of challenges
challenge := returnAuthz.Challenges[challengeIndex]
wfe.prepChallengeForDisplay(handlerPath, request, authz, &challenge)
wfe.prepChallengeForDisplay(request, authz, &challenge)
authzURL := urlForAuthz(handlerPath, authz, request)
authzURL := urlForAuthz(authz, request)
response.Header().Add("Location", challenge.URL)
response.Header().Add("Link", link(authzURL, "up"))
@ -1538,15 +1506,6 @@ func (wfe *WebFrontEndImpl) deactivateAuthorization(
return true
}
// DeprecatedAuthorizationHandler handles requests to authorization URLs of the form /acme/authz/{authzID}.
func (wfe *WebFrontEndImpl) DeprecatedAuthorizationHandler(
ctx context.Context,
logEvent *web.RequestEvent,
response http.ResponseWriter,
request *http.Request) {
wfe.Authorization(ctx, deprecatedAuthzPath, logEvent, response, request, request.URL.Path)
}
// AuthorizationHandler handles requests to authorization URLs of the form /acme/authz/{regID}/{authzID}.
func (wfe *WebFrontEndImpl) AuthorizationHandler(
ctx context.Context,
@ -1559,14 +1518,13 @@ func (wfe *WebFrontEndImpl) AuthorizationHandler(
return
}
// TODO(#7683): The regID is currently ignored.
wfe.Authorization(ctx, authzPathWithAcct, logEvent, response, request, slug[1])
wfe.Authorization(ctx, 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,
@ -1657,7 +1615,7 @@ func (wfe *WebFrontEndImpl) Authorization(
return
}
wfe.prepAuthorizationForDisplay(handlerPath, request, &authz)
wfe.prepAuthorizationForDisplay(request, &authz)
err = wfe.writeJsonResponse(response, logEvent, http.StatusOK, authz)
if err != nil {
@ -2050,7 +2008,7 @@ func (wfe *WebFrontEndImpl) orderToOrderJSON(request *http.Request, order *corep
respObj.Error.Type = probs.ErrorNS + respObj.Error.Type
}
for _, v2ID := range order.V2Authorizations {
respObj.Authorizations = append(respObj.Authorizations, web.RelativeEndpoint(request, fmt.Sprintf("%s%d/%d", authzPathWithAcct, order.RegistrationID, v2ID)))
respObj.Authorizations = append(respObj.Authorizations, web.RelativeEndpoint(request, fmt.Sprintf("%s%d/%d", authzPath, order.RegistrationID, v2ID)))
}
if respObj.Status == core.StatusValid {
certURL := web.RelativeEndpoint(request,
@ -2766,10 +2724,6 @@ func extractRequesterIP(req *http.Request) (net.IP, error) {
return net.ParseIP(host), nil
}
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, deprecatedAuthzPath+authz.ID)
func urlForAuthz(authz core.Authorization, request *http.Request) string {
return web.RelativeEndpoint(request, fmt.Sprintf("%s%d/%s", authzPath, authz.RegistrationID, authz.ID))
}

View File

@ -1041,13 +1041,13 @@ func TestHTTPMethods(t *testing.T) {
// TODO(@cpu): Remove GET authz support, support only POST-as-GET
{
Name: "Authz path should be GET or POST only",
Path: deprecatedAuthzPath,
Path: authzPath,
Allowed: getOrPost,
},
// TODO(@cpu): Remove GET challenge support, support only POST-as-GET
{
Name: "Challenge path should be GET or POST only",
Path: deprecatedChallengePath,
Path: challengePath,
Allowed: getOrPost,
},
// TODO(@cpu): Remove GET certificate support, support only POST-as-GET
@ -1146,40 +1146,6 @@ func TestGetChallengeHandler(t *testing.T) {
// 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-v3/1/%s", challSlug)
req, err := http.NewRequest(method, challengeURL, nil)
test.AssertNotError(t, err, "Could not make NewRequest")
req.URL.Path = fmt.Sprintf("1/%s", challSlug)
wfe.DeprecatedChallengeHandler(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-v3/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-v3/1/7TyhFQ"}`)
}
}
}
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()
@ -1220,85 +1186,6 @@ func TestChallengeHandler(t *testing.T) {
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/7TyhFQ"),
ExpectedStatus: http.StatusOK,
ExpectedHeaders: map[string]string{
"Content-Type": "application/json",
"Location": "http://localhost/acme/chall-v3/1/7TyhFQ",
"Link": `<http://localhost/acme/authz-v3/1>;rel="up"`,
},
ExpectedBody: `{"status": "valid", "type":"http-01","token":"token","url":"http://localhost/acme/chall-v3/1/7TyhFQ"}`,
},
{
Name: "Expired challenge",
Request: post("3/7TyhFQ"),
ExpectedStatus: http.StatusNotFound,
ExpectedBody: `{"type":"` + probs.ErrorNS + `malformed","detail":"Expired authorization","status":404}`,
},
{
Name: "Missing challenge",
Request: post("1/"),
ExpectedStatus: http.StatusNotFound,
ExpectedBody: `{"type":"` + probs.ErrorNS + `malformed","detail":"No such challenge","status":404}`,
},
{
Name: "Unspecified database error",
Request: post("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, "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/7TyhFQ", ""),
ExpectedStatus: http.StatusOK,
ExpectedBody: `{"status": "valid", "type":"http-01", "token":"token", "url": "http://localhost/acme/chall-v3/1/7TyhFQ"}`,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
responseWriter := httptest.NewRecorder()
wfe.DeprecatedChallengeHandler(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
@ -1383,28 +1270,6 @@ func TestUpdateChallengeHandlerFinalizedAuthz(t *testing.T) {
wfe.ra = &MockRAPerformValidationError{MockRegistrationAuthority{clk: fc}}
responseWriter := httptest.NewRecorder()
signedURL := "http://localhost/1/7TyhFQ"
_, _, jwsBody := signer.byKeyID(1, nil, signedURL, `{}`)
request := makePostRequestWithPath("1/7TyhFQ", jwsBody)
wfe.DeprecatedChallengeHandler(ctx, newRequestEvent(), responseWriter, request)
body := responseWriter.Body.String()
test.AssertUnmarshaledEquals(t, body, `{
"status": "valid",
"type": "http-01",
"token": "token",
"url": "http://localhost/acme/chall-v3/1/7TyhFQ"
}`)
}
// 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)
@ -1427,31 +1292,6 @@ func TestUpdateChallengeHandlerRAError(t *testing.T) {
// Mock the RA to always fail PerformValidation
wfe.ra = &MockRAPerformValidationError{MockRegistrationAuthority{clk: fc}}
// Update a pending challenge
signedURL := "http://localhost/2/7TyhFQ"
_, _, jwsBody := signer.byKeyID(1, nil, signedURL, `{}`)
responseWriter := httptest.NewRecorder()
request := makePostRequestWithPath("2/7TyhFQ", jwsBody)
wfe.DeprecatedChallengeHandler(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, `{}`)
@ -1807,56 +1647,6 @@ func TestNewAccountNoID(t *testing.T) {
func TestGetAuthorizationHandler(t *testing.T) {
wfe, _, signer := setupWFE(t)
// Expired authorizations should be inaccessible
authzURL := "3"
responseWriter := httptest.NewRecorder()
wfe.DeprecatedAuthorizationHandler(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.DeprecatedAuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
URL: mustParseURL("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", "")
postAsGet := makePostRequestWithPath("1", jwsBody)
responseWriter = httptest.NewRecorder()
// Ensure that a POST-as-GET to an authorization works
wfe.DeprecatedAuthorizationHandler(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-v3/1/7TyhFQ"
}
]
}`)
}
func TestGetAuthorizationHandlerWithAccount(t *testing.T) {
wfe, _, signer := setupWFE(t)
// Expired authorizations should be inaccessible
authzURL := "1/3"
responseWriter := httptest.NewRecorder()
@ -1909,24 +1699,6 @@ func TestGetAuthorizationHandlerWithAccount(t *testing.T) {
func TestAuthorizationHandler500(t *testing.T) {
wfe, _, _ := setupWFE(t)
responseWriter := httptest.NewRecorder()
wfe.DeprecatedAuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
URL: mustParseURL("4"),
})
expected := `{
"type": "urn:ietf:params:acme:error:serverInternal",
"detail": "Problem getting authorization",
"status": 500
}`
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.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
@ -1977,30 +1749,9 @@ func TestAuthorizationChallengeHandlerNamespace(t *testing.T) {
wfe.ra = &RAWithFailedChallenge{clk: clk}
responseWriter := httptest.NewRecorder()
wfe.DeprecatedAuthorizationHandler(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.DeprecatedAuthorizationHandler(ctx, newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
URL: mustParseURL("6"),
URL: mustParseURL("1/6"),
})
var authz core.Authorization
@ -2652,20 +2403,20 @@ func TestDeactivateAuthorizationHandler(t *testing.T) {
responseWriter.Body.Reset()
payload := `{"status":""}`
_, _, body := signer.byKeyID(1, nil, "http://localhost/1", payload)
request := makePostRequestWithPath("1", body)
_, _, body := signer.byKeyID(1, nil, "http://localhost/1/1", payload)
request := makePostRequestWithPath("1/1", body)
wfe.DeprecatedAuthorizationHandler(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}`)
responseWriter.Body.Reset()
payload = `{"status":"deactivated"}`
_, _, body = signer.byKeyID(1, nil, "http://localhost/1", payload)
request = makePostRequestWithPath("1", body)
_, _, body = signer.byKeyID(1, nil, "http://localhost/1/1", payload)
request = makePostRequestWithPath("1/1", body)
wfe.DeprecatedAuthorizationHandler(ctx, newRequestEvent(), responseWriter, request)
wfe.AuthorizationHandler(ctx, newRequestEvent(), responseWriter, request)
test.AssertUnmarshaledEquals(t,
responseWriter.Body.String(),
`{
@ -2680,48 +2431,7 @@ func TestDeactivateAuthorizationHandler(t *testing.T) {
"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.DeprecatedAuthorizationHandler(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.DeprecatedAuthorizationHandler(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"
"url": "http://localhost/acme/chall/1/1/7TyhFQ"
}
]
}`)
@ -3681,33 +3391,7 @@ func TestPrepAuthzForDisplay(t *testing.T) {
}
// This modifies the authz in-place.
wfe.prepAuthorizationForDisplay(deprecatedAuthzPath, &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)
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
// Ensure ID and RegID are omitted.
authzJSON, err := json.Marshal(authz)
@ -3733,32 +3417,7 @@ func TestPrepRevokedAuthzForDisplay(t *testing.T) {
}
// This modifies the authz in-place.
wfe.prepAuthorizationForDisplay(deprecatedAuthzPath, &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)
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
// All of the challenges should be revoked as well.
for _, chall := range authz.Challenges {
@ -3781,30 +3440,7 @@ func TestPrepWildcardAuthzForDisplay(t *testing.T) {
}
// This modifies the authz in-place.
wfe.prepAuthorizationForDisplay(deprecatedAuthzPath, &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)
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
// The identifier should not start with a star, but the authz should be marked
// as a wildcard.
@ -3840,7 +3476,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(deprecatedChallengePath, &http.Request{Host: "localhost"}, authz)
wfe.prepAuthorizationForDisplay(&http.Request{Host: "localhost"}, authz)
for i, chall := range authz.Challenges {
counts[chall.Type][i] += 1
}
@ -3937,12 +3573,12 @@ func TestGETAPIAuthorizationHandler(t *testing.T) {
}{
{
name: "fresh authz",
path: "1",
path: "1/1",
expectTooFreshErr: true,
},
{
name: "old authz",
path: "2",
path: "1/2",
expectTooFreshErr: false,
},
}
@ -3951,7 +3587,7 @@ func TestGETAPIAuthorizationHandler(t *testing.T) {
for _, tc := range testCases {
responseWriter := httptest.NewRecorder()
req, logEvent := makeGet(tc.path, getAuthzPath)
wfe.DeprecatedAuthorizationHandler(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")
@ -4015,12 +3651,12 @@ func TestGETAPIChallenge(t *testing.T) {
}{
{
name: "fresh authz challenge",
path: "1/7TyhFQ",
path: "1/1/7TyhFQ",
expectTooFreshErr: true,
},
{
name: "old authz challenge",
path: "2/7TyhFQ",
path: "1/2/7TyhFQ",
expectTooFreshErr: false,
},
}
@ -4029,7 +3665,7 @@ func TestGETAPIChallenge(t *testing.T) {
for _, tc := range testCases {
responseWriter := httptest.NewRecorder()
req, logEvent := makeGet(tc.path, getAuthzPath)
wfe.DeprecatedChallengeHandler(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")