Support POST-as-GET. (#695)

This commit is contained in:
Ludovic Fernandez 2018-11-04 01:51:53 +01:00 committed by GitHub
parent 5992cc0ece
commit 4f36f4354b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 26 deletions

View file

@ -665,7 +665,7 @@ func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, error)
go func(authzURL string) {
var authz authorization
_, err := getJSON(authzURL, &authz)
_, err := postAsGet(c.jws, authzURL, &authz)
if err != nil {
errc <- domainError{Domain: authz.Identifier.Value, Error: err}
return
@ -789,7 +789,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
case <-stopTimer.C:
return nil, errors.New("certificate polling timed out")
case <-retryTick.C:
_, err := getJSON(order.URL, &retOrder)
_, err := postAsGet(c.jws, order.URL, &retOrder)
if err != nil {
return nil, err
}
@ -813,7 +813,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResource, bundle bool) (bool, error) {
switch order.Status {
case statusValid:
resp, err := httpGet(order.Certificate)
resp, err := postAsGet(c.jws, order.Certificate, nil)
if err != nil {
return false, err
}
@ -871,7 +871,7 @@ func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResou
// getIssuerCertificate requests the issuer certificate
func (c *Client) getIssuerCertificate(url string) ([]byte, error) {
log.Infof("acme: Requesting issuer cert from %s", url)
resp, err := httpGet(url)
resp, err := postAsGet(c.jws, url, nil)
if err != nil {
return nil, err
}
@ -943,11 +943,15 @@ func validate(j *jws, domain, uri string, c challenge) error {
// If it doesn't, we'll just poll hard.
ra = 5
}
time.Sleep(time.Duration(ra) * time.Second)
hdr, err = getJSON(uri, &chlng)
resp, err := postAsGet(j, uri, &chlng)
if err != nil {
return err
}
if resp != nil {
hdr = resp.Header
}
}
}

View file

@ -155,10 +155,10 @@ func TestValidate(t *testing.T) {
privKey, err := rsa.GenerateKey(rand.Reader, 512)
require.NoError(t, err)
// validateNoBody reads the http.Request POST body, parses the JWS and
// validates it to read the body. If there is an error doing this, or if the
// JWS body is not the empty JSON payload "{}" an error is returned. We use
// this to verify challenge POSTs to the ts below do not send a JWS body.
// validateNoBody reads the http.Request POST body, parses the JWS and validates it to read the body.
// If there is an error doing this,
// or if the JWS body is not the empty JSON payload "{}" or a POST-as-GET payload "" an error is returned.
// We use this to verify challenge POSTs to the ts below do not send a JWS body.
validateNoBody := func(r *http.Request) error {
reqBody, err := ioutil.ReadAll(r.Body)
if err != nil {
@ -178,8 +178,8 @@ func TestValidate(t *testing.T) {
return err
}
if bodyStr := string(body); bodyStr != "{}" {
return fmt.Errorf(`expected JWS POST body "{}", got %q`, bodyStr)
if bodyStr := string(body); bodyStr != "{}" && bodyStr != "" {
return fmt.Errorf(`expected JWS POST body "{}" or "", got %q`, bodyStr)
}
return nil
}

View file

@ -151,48 +151,56 @@ func postJSON(j *jws, uri string, reqBody, respBody interface{}) (http.Header, e
return nil, errors.New("failed to marshal network message")
}
resp, err := j.post(uri, jsonBytes)
if err != nil {
return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
resp, err := post(j, uri, jsonBytes, respBody)
if resp == nil {
return nil, err
}
defer resp.Body.Close()
return resp.Header, err
}
func postAsGet(j *jws, uri string, respBody interface{}) (*http.Response, error) {
return post(j, uri, []byte{}, respBody)
}
func post(j *jws, uri string, reqBody []byte, respBody interface{}) (*http.Response, error) {
resp, err := j.post(uri, reqBody)
if err != nil {
return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
}
if resp.StatusCode >= http.StatusBadRequest {
err = handleHTTPError(resp)
switch err.(type) {
case NonceError:
// Retry once if the nonce was invalidated
retryResp, errP := j.post(uri, jsonBytes)
retryResp, errP := j.post(uri, reqBody)
if errP != nil {
return nil, fmt.Errorf("failed to post JWS message. -> %v", errP)
}
defer retryResp.Body.Close()
if retryResp.StatusCode >= http.StatusBadRequest {
return retryResp.Header, handleHTTPError(retryResp)
return retryResp, handleHTTPError(retryResp)
}
if respBody == nil {
return retryResp.Header, nil
return retryResp, nil
}
return retryResp.Header, json.NewDecoder(retryResp.Body).Decode(respBody)
return retryResp, json.NewDecoder(retryResp.Body).Decode(respBody)
default:
return resp.Header, err
return resp, err
}
}
if respBody == nil {
return resp.Header, nil
return resp, nil
}
return resp.Header, json.NewDecoder(resp.Body).Decode(respBody)
return resp, json.NewDecoder(resp.Body).Decode(respBody)
}
// userAgent builds and returns the User-Agent string to use in requests.