Basic ACME directory endpoint

This commit is contained in:
Roland Shoemaker 2015-07-21 16:55:57 -07:00
parent 31f8a3083c
commit 2d758a7ab6
4 changed files with 58 additions and 11 deletions

View File

@ -120,7 +120,8 @@ func main() {
// Set up paths
wfe.BaseURL = c.Common.BaseURL
h := wfe.Handler()
h, err := wfe.Handler()
cmd.FailOnError(err, "Failed to marshal directory to JSON")
auditlogger.Info(app.VersionString())

View File

@ -122,7 +122,8 @@ func main() {
// Set up paths
ra.AuthzBase = c.Common.BaseURL + wfe.AuthzPath
wfei.BaseURL = c.Common.BaseURL
h := wfei.Handler()
h, err := wfei.Handler()
cmd.FailOnError(err, "Failed to marshal directory to JSON")
ra.MaxKeySize = c.Common.MaxKeySize
ca.MaxKeySize = c.Common.MaxKeySize

View File

@ -30,6 +30,7 @@ import (
// Paths are the ACME-spec identified URL path-segments for various methods
const (
DirectoryPath = "/directory"
NewRegPath = "/acme/new-reg"
RegPath = "/acme/reg/"
NewAuthzPath = "/acme/new-authz"
@ -58,6 +59,9 @@ type WebFrontEndImpl struct {
NewCert string
CertBase string
// JSON encoded endpoint directory
DirectoryJSON []byte
// Issuer certificate (DER) for /acme/issuer-cert
IssuerCert []byte
@ -182,7 +186,7 @@ func (wfe *WebFrontEndImpl) HandleFunc(mux *http.ServeMux, pattern string, h fun
// Handler returns an http.Handler that uses various functions for
// various ACME-specified paths.
func (wfe *WebFrontEndImpl) Handler() http.Handler {
func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {
wfe.NewReg = wfe.BaseURL + NewRegPath
wfe.RegBase = wfe.BaseURL + RegPath
wfe.NewAuthz = wfe.BaseURL + NewAuthzPath
@ -190,8 +194,23 @@ func (wfe *WebFrontEndImpl) Handler() http.Handler {
wfe.NewCert = wfe.BaseURL + NewCertPath
wfe.CertBase = wfe.BaseURL + CertPath
// Only generate directory once
directory := map[string]string{
"new-reg": wfe.NewReg,
// "recover-reg": wfe.
"new-authz": wfe.NewAuthz,
"new-cert": wfe.NewCert,
"revoke-cert": wfe.BaseURL + RevokeCertPath,
}
directoryJSON, err := json.Marshal(directory)
if err != nil {
return nil, err
}
wfe.DirectoryJSON = directoryJSON
m := http.NewServeMux()
wfe.HandleFunc(m, "/", wfe.Index, "GET")
wfe.HandleFunc(m, DirectoryPath, wfe.Directory, "GET")
wfe.HandleFunc(m, NewRegPath, wfe.NewRegistration, "POST")
wfe.HandleFunc(m, NewAuthzPath, wfe.NewAuthorization, "POST")
wfe.HandleFunc(m, NewCertPath, wfe.NewCertificate, "POST")
@ -202,7 +221,7 @@ func (wfe *WebFrontEndImpl) Handler() http.Handler {
wfe.HandleFunc(m, TermsPath, wfe.Terms, "GET")
wfe.HandleFunc(m, IssuerPath, wfe.Issuer, "GET")
wfe.HandleFunc(m, BuildIDPath, wfe.BuildID, "GET")
return m
return m, nil
}
// Method implementations
@ -233,6 +252,10 @@ func (wfe *WebFrontEndImpl) Index(response http.ResponseWriter, request *http.Re
response.Header().Set("Content-Type", "text/html")
}
func (wfe *WebFrontEndImpl) Directory(response http.ResponseWriter, request *http.Request) {
response.Write(wfe.DirectoryJSON)
}
// The ID is always the last slash-separated token in the path
func parseIDFromPath(path string) string {
re := regexp.MustCompile("^.*/")

View File

@ -374,7 +374,7 @@ func TestHandleFunc(t *testing.T) {
{[]string{"GET", "POST"}, "POST", true},
{[]string{"GET"}, "", false},
{[]string{"GET"}, "POST", false},
{[]string{"GET"}, "OPTIONS", false}, // TODO, #469
{[]string{"GET"}, "OPTIONS", false}, // TODO, #469
{[]string{"GET"}, "MAKE-COFFEE", false}, // 405, or 418?
} {
runWrappedHandler(&http.Request{Method: c.reqMethod}, c.allowed...)
@ -408,7 +408,8 @@ func TestHandleFunc(t *testing.T) {
func TestStandardHeaders(t *testing.T) {
wfe := setupWFE(t)
mux := wfe.Handler()
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
cases := []struct {
path string
@ -464,11 +465,29 @@ func TestIndex(t *testing.T) {
test.AssertEquals(t, responseWriter.Body.String(), "404 page not found\n")
}
func TestDirectory(t *testing.T) {
wfe := setupWFE(t)
wfe.BaseURL = "http://localhost:4300"
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
responseWriter := httptest.NewRecorder()
url, _ := url.Parse("/directory")
mux.ServeHTTP(responseWriter, &http.Request{
Method: "GET",
URL: url,
})
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
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"}`)
}
// TODO: Write additional test cases for:
// - RA returns with a failure
func TestIssueCertificate(t *testing.T) {
wfe := setupWFE(t)
mux := wfe.Handler()
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
// TODO: Use a mock RA so we can test various conditions of authorized, not authorized, etc.
ra := ra.NewRegistrationAuthorityImpl()
@ -649,7 +668,8 @@ func TestChallenge(t *testing.T) {
func TestNewRegistration(t *testing.T) {
wfe := setupWFE(t)
mux := wfe.Handler()
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &MockSA{}
@ -893,7 +913,8 @@ func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
func TestAuthorization(t *testing.T) {
wfe := setupWFE(t)
mux := wfe.Handler()
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &MockSA{}
@ -972,13 +993,14 @@ func TestAuthorization(t *testing.T) {
test.AssertEquals(t, responseWriter.Body.String(), "{\"identifier\":{\"type\":\"dns\",\"value\":\"test.com\"}}")
var authz core.Authorization
err := json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
err = json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
test.AssertNotError(t, err, "Couldn't unmarshal returned authorization object")
}
func TestRegistration(t *testing.T) {
wfe := setupWFE(t)
mux := wfe.Handler()
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Failed to marshal directory to JSON")
wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &MockSA{}