Skip to content

Commit

Permalink
WFE returns headers Boulder-Request-ID and Boulder-Requester (letsenc…
Browse files Browse the repository at this point in the history
…rypt#1886)

* WFE returns headers Boulder-Request-ID and Boulder-Requester
* improve test
* add the requestHeader after calls to verifyPOST
* move call of addRequesterHeader in NewRegistration
* move setting of request header to context, improve test
* remove pointless comment
  • Loading branch information
benileo authored and cpu committed Jun 7, 2016
1 parent 19da2be commit 2b99464
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
1 change: 1 addition & 0 deletions wfe/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func (th *topHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
UserAgent: r.Header.Get("User-Agent"),
Extra: make(map[string]interface{}, 0),
}
w.Header().Set("Boulder-Request-ID", logEvent.ID)
if r.URL != nil {
logEvent.Endpoint = r.URL.String()
}
Expand Down
13 changes: 13 additions & 0 deletions wfe/wfe.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,12 @@ func addCacheHeader(w http.ResponseWriter, age float64) {
w.Header().Add("Cache-Control", fmt.Sprintf("public, max-age=%.f", age))
}

func addRequesterHeader(w http.ResponseWriter, requester int64) {
if requester > 0 {
w.Header().Set("Boulder-Requester", fmt.Sprintf("%d", requester))
}
}

// Directory is an HTTP request handler that provides the directory
// object stored in the WFE's DirectoryEndpoints member with paths prefixed
// using the `request.Host` of the HTTP request.
Expand Down Expand Up @@ -537,6 +543,7 @@ func link(url, relation string) string {
func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {

body, key, _, prob := wfe.verifyPOST(ctx, logEvent, request, false, core.ResourceNewReg)
addRequesterHeader(response, logEvent.Requester)
if prob != nil {
// verifyPOST handles its own setting of logEvent.Errors
wfe.sendError(response, logEvent, prob, nil)
Expand Down Expand Up @@ -581,6 +588,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *reque
return
}
logEvent.Requester = reg.ID
addRequesterHeader(response, reg.ID)
logEvent.Contacts = reg.Contact

// Use an explicitly typed variable. Otherwise `go vet' incorrectly complains
Expand Down Expand Up @@ -609,6 +617,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *reque
// NewAuthorization is used by clients to submit a new ID Authorization
func (wfe *WebFrontEndImpl) NewAuthorization(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
body, _, currReg, prob := wfe.verifyPOST(ctx, logEvent, request, true, core.ResourceNewAuthz)
addRequesterHeader(response, logEvent.Requester)
if prob != nil {
// verifyPOST handles its own setting of logEvent.Errors
wfe.sendError(response, logEvent, prob, nil)
Expand Down Expand Up @@ -665,6 +674,7 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(ctx context.Context, logEvent *req
// We don't ask verifyPOST to verify there is a corresponding registration,
// because anyone with the right private key can revoke a certificate.
body, requestKey, registration, prob := wfe.verifyPOST(ctx, logEvent, request, false, core.ResourceRevokeCert)
addRequesterHeader(response, logEvent.Requester)
if prob != nil {
// verifyPOST handles its own setting of logEvent.Errors
wfe.sendError(response, logEvent, prob, nil)
Expand Down Expand Up @@ -758,6 +768,7 @@ func (wfe *WebFrontEndImpl) logCsr(request *http.Request, cr core.CertificateReq
// authorized identifier.
func (wfe *WebFrontEndImpl) NewCertificate(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
body, _, reg, prob := wfe.verifyPOST(ctx, logEvent, request, true, core.ResourceNewCert)
addRequesterHeader(response, logEvent.Requester)
if prob != nil {
// verifyPOST handles its own setting of logEvent.Errors
wfe.sendError(response, logEvent, prob, nil)
Expand Down Expand Up @@ -959,6 +970,7 @@ func (wfe *WebFrontEndImpl) postChallenge(
challengeIndex int,
logEvent *requestEvent) {
body, _, currReg, prob := wfe.verifyPOST(ctx, logEvent, request, true, core.ResourceChallenge)
addRequesterHeader(response, logEvent.Requester)
if prob != nil {
// verifyPOST handles its own setting of logEvent.Errors
wfe.sendError(response, logEvent, prob, nil)
Expand Down Expand Up @@ -1026,6 +1038,7 @@ func (wfe *WebFrontEndImpl) postChallenge(
func (wfe *WebFrontEndImpl) Registration(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {

body, _, currReg, prob := wfe.verifyPOST(ctx, logEvent, request, true, core.ResourceRegistration)
addRequesterHeader(response, logEvent.Requester)
if prob != nil {
// verifyPOST handles its own setting of logEvent.Errors
wfe.sendError(response, logEvent, prob, nil)
Expand Down
44 changes: 44 additions & 0 deletions wfe/wfe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1592,3 +1592,47 @@ func TestVerifyPOSTInvalidJWK(t *testing.T) {
test.AssertEquals(t, probs.MalformedProblem, prob.Type)
test.AssertEquals(t, http.StatusBadRequest, prob.HTTPStatus)
}

func TestHeaderBoulderRequestId(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
responseWriter := httptest.NewRecorder()

mux.ServeHTTP(responseWriter, &http.Request{
Method: "GET",
URL: mustParseURL(directoryPath),
})

requestID := responseWriter.Header().Get("Boulder-Request-ID")
test.Assert(t, len(requestID) > 0, "Boulder-Request-ID header is empty")
}

func TestHeaderBoulderRequester(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
responseWriter := httptest.NewRecorder()

// create a signed request
key, err := jose.LoadPrivateKey([]byte(test1KeyPrivatePEM))
test.AssertNotError(t, err, "Failed to load key")
rsaKey, ok := key.(*rsa.PrivateKey)
test.Assert(t, ok, "Couldn't load RSA key")
signer, err := jose.NewSigner("RS256", rsaKey)
test.AssertNotError(t, err, "Failed to make signer")

// requests that do not call sendError() have the requester header
signer.SetNonceSource(wfe.nonceService)
result, err := signer.Sign([]byte(`{"resource":"reg","agreement":"` + agreementURL + `"}`))
request := makePostRequestWithPath(regPath+"1", result.FullSerialize())
mux.ServeHTTP(responseWriter, request)
test.AssertEquals(t, responseWriter.Header().Get("Boulder-Requester"), "1")

// requests that do call sendError() also should have the requester header
signer.SetNonceSource(wfe.nonceService)
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"https://letsencrypt.org/im-bad"}`))
request = makePostRequestWithPath(regPath+"1", result.FullSerialize())
mux.ServeHTTP(responseWriter, request)
test.AssertEquals(t, responseWriter.Header().Get("Boulder-Requester"), "1")
}

0 comments on commit 2b99464

Please sign in to comment.