Skip to content

Commit 2d758a7

Browse files
Basic ACME directory endpoint
1 parent 31f8a30 commit 2d758a7

File tree

4 files changed

+58
-11
lines changed

4 files changed

+58
-11
lines changed

cmd/boulder-wfe/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ func main() {
120120

121121
// Set up paths
122122
wfe.BaseURL = c.Common.BaseURL
123-
h := wfe.Handler()
123+
h, err := wfe.Handler()
124+
cmd.FailOnError(err, "Failed to marshal directory to JSON")
124125

125126
auditlogger.Info(app.VersionString())
126127

cmd/boulder/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ func main() {
122122
// Set up paths
123123
ra.AuthzBase = c.Common.BaseURL + wfe.AuthzPath
124124
wfei.BaseURL = c.Common.BaseURL
125-
h := wfei.Handler()
125+
h, err := wfei.Handler()
126+
cmd.FailOnError(err, "Failed to marshal directory to JSON")
126127

127128
ra.MaxKeySize = c.Common.MaxKeySize
128129
ca.MaxKeySize = c.Common.MaxKeySize

wfe/web-front-end.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
// Paths are the ACME-spec identified URL path-segments for various methods
3232
const (
33+
DirectoryPath = "/directory"
3334
NewRegPath = "/acme/new-reg"
3435
RegPath = "/acme/reg/"
3536
NewAuthzPath = "/acme/new-authz"
@@ -58,6 +59,9 @@ type WebFrontEndImpl struct {
5859
NewCert string
5960
CertBase string
6061

62+
// JSON encoded endpoint directory
63+
DirectoryJSON []byte
64+
6165
// Issuer certificate (DER) for /acme/issuer-cert
6266
IssuerCert []byte
6367

@@ -182,16 +186,31 @@ func (wfe *WebFrontEndImpl) HandleFunc(mux *http.ServeMux, pattern string, h fun
182186

183187
// Handler returns an http.Handler that uses various functions for
184188
// various ACME-specified paths.
185-
func (wfe *WebFrontEndImpl) Handler() http.Handler {
189+
func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {
186190
wfe.NewReg = wfe.BaseURL + NewRegPath
187191
wfe.RegBase = wfe.BaseURL + RegPath
188192
wfe.NewAuthz = wfe.BaseURL + NewAuthzPath
189193
wfe.AuthzBase = wfe.BaseURL + AuthzPath
190194
wfe.NewCert = wfe.BaseURL + NewCertPath
191195
wfe.CertBase = wfe.BaseURL + CertPath
192196

197+
// Only generate directory once
198+
directory := map[string]string{
199+
"new-reg": wfe.NewReg,
200+
// "recover-reg": wfe.
201+
"new-authz": wfe.NewAuthz,
202+
"new-cert": wfe.NewCert,
203+
"revoke-cert": wfe.BaseURL + RevokeCertPath,
204+
}
205+
directoryJSON, err := json.Marshal(directory)
206+
if err != nil {
207+
return nil, err
208+
}
209+
wfe.DirectoryJSON = directoryJSON
210+
193211
m := http.NewServeMux()
194212
wfe.HandleFunc(m, "/", wfe.Index, "GET")
213+
wfe.HandleFunc(m, DirectoryPath, wfe.Directory, "GET")
195214
wfe.HandleFunc(m, NewRegPath, wfe.NewRegistration, "POST")
196215
wfe.HandleFunc(m, NewAuthzPath, wfe.NewAuthorization, "POST")
197216
wfe.HandleFunc(m, NewCertPath, wfe.NewCertificate, "POST")
@@ -202,7 +221,7 @@ func (wfe *WebFrontEndImpl) Handler() http.Handler {
202221
wfe.HandleFunc(m, TermsPath, wfe.Terms, "GET")
203222
wfe.HandleFunc(m, IssuerPath, wfe.Issuer, "GET")
204223
wfe.HandleFunc(m, BuildIDPath, wfe.BuildID, "GET")
205-
return m
224+
return m, nil
206225
}
207226

208227
// Method implementations
@@ -233,6 +252,10 @@ func (wfe *WebFrontEndImpl) Index(response http.ResponseWriter, request *http.Re
233252
response.Header().Set("Content-Type", "text/html")
234253
}
235254

255+
func (wfe *WebFrontEndImpl) Directory(response http.ResponseWriter, request *http.Request) {
256+
response.Write(wfe.DirectoryJSON)
257+
}
258+
236259
// The ID is always the last slash-separated token in the path
237260
func parseIDFromPath(path string) string {
238261
re := regexp.MustCompile("^.*/")

wfe/web-front-end_test.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ func TestHandleFunc(t *testing.T) {
374374
{[]string{"GET", "POST"}, "POST", true},
375375
{[]string{"GET"}, "", false},
376376
{[]string{"GET"}, "POST", false},
377-
{[]string{"GET"}, "OPTIONS", false}, // TODO, #469
377+
{[]string{"GET"}, "OPTIONS", false}, // TODO, #469
378378
{[]string{"GET"}, "MAKE-COFFEE", false}, // 405, or 418?
379379
} {
380380
runWrappedHandler(&http.Request{Method: c.reqMethod}, c.allowed...)
@@ -408,7 +408,8 @@ func TestHandleFunc(t *testing.T) {
408408

409409
func TestStandardHeaders(t *testing.T) {
410410
wfe := setupWFE(t)
411-
mux := wfe.Handler()
411+
mux, err := wfe.Handler()
412+
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
412413

413414
cases := []struct {
414415
path string
@@ -464,11 +465,29 @@ func TestIndex(t *testing.T) {
464465
test.AssertEquals(t, responseWriter.Body.String(), "404 page not found\n")
465466
}
466467

468+
func TestDirectory(t *testing.T) {
469+
wfe := setupWFE(t)
470+
wfe.BaseURL = "http://localhost:4300"
471+
mux, err := wfe.Handler()
472+
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
473+
474+
responseWriter := httptest.NewRecorder()
475+
476+
url, _ := url.Parse("/directory")
477+
mux.ServeHTTP(responseWriter, &http.Request{
478+
Method: "GET",
479+
URL: url,
480+
})
481+
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
482+
test.AssertEquals(t, responseWriter.Body.String(), `{"new-authz":"http://localhost:4300/acme/new-authz","new-cert":"http://localhost:4300/acme/new-cert","new-reg":"http://localhost:4300/acme/new-reg","revoke-cert":"http://localhost:4300/acme/revoke-cert"}`)
483+
}
484+
467485
// TODO: Write additional test cases for:
468486
// - RA returns with a failure
469487
func TestIssueCertificate(t *testing.T) {
470488
wfe := setupWFE(t)
471-
mux := wfe.Handler()
489+
mux, err := wfe.Handler()
490+
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
472491

473492
// TODO: Use a mock RA so we can test various conditions of authorized, not authorized, etc.
474493
ra := ra.NewRegistrationAuthorityImpl()
@@ -649,7 +668,8 @@ func TestChallenge(t *testing.T) {
649668

650669
func TestNewRegistration(t *testing.T) {
651670
wfe := setupWFE(t)
652-
mux := wfe.Handler()
671+
mux, err := wfe.Handler()
672+
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
653673

654674
wfe.RA = &MockRegistrationAuthority{}
655675
wfe.SA = &MockSA{}
@@ -893,7 +913,8 @@ func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
893913

894914
func TestAuthorization(t *testing.T) {
895915
wfe := setupWFE(t)
896-
mux := wfe.Handler()
916+
mux, err := wfe.Handler()
917+
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
897918

898919
wfe.RA = &MockRegistrationAuthority{}
899920
wfe.SA = &MockSA{}
@@ -972,13 +993,14 @@ func TestAuthorization(t *testing.T) {
972993
test.AssertEquals(t, responseWriter.Body.String(), "{\"identifier\":{\"type\":\"dns\",\"value\":\"test.com\"}}")
973994

974995
var authz core.Authorization
975-
err := json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
996+
err = json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
976997
test.AssertNotError(t, err, "Couldn't unmarshal returned authorization object")
977998
}
978999

9791000
func TestRegistration(t *testing.T) {
9801001
wfe := setupWFE(t)
981-
mux := wfe.Handler()
1002+
mux, err := wfe.Handler()
1003+
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
9821004

9831005
wfe.RA = &MockRegistrationAuthority{}
9841006
wfe.SA = &MockSA{}

0 commit comments

Comments
 (0)