187 lines
5.3 KiB
Go
187 lines
5.3 KiB
Go
package acme
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/letsencrypt/boulder/test"
|
|
)
|
|
|
|
// Path constants for test cases and mockDirectoryServer handlers.
|
|
const (
|
|
wrongStatusCodePath = "/dir-wrong-status"
|
|
invalidJSONPath = "/dir-bad-json"
|
|
missingEndpointPath = "/dir-missing-endpoint"
|
|
invalidEndpointURLPath = "/dir-invalid-endpoint"
|
|
validDirectoryPath = "/dir-valid"
|
|
invalidMetaDirectoryPath = "/dir-valid-meta-invalid"
|
|
invalidMetaDirectoryToSPath = "/dir-valid-meta-valid-tos-invalid"
|
|
)
|
|
|
|
// mockDirectoryServer is an httptest.Server that returns mock data for ACME
|
|
// directory GET requests based on the requested path.
|
|
type mockDirectoryServer struct {
|
|
*httptest.Server
|
|
}
|
|
|
|
// newMockDirectoryServer creates a mockDirectoryServer that returns mock data
|
|
// based on the requested path. The returned server will not be started
|
|
// automatically.
|
|
func newMockDirectoryServer() *mockDirectoryServer {
|
|
m := http.NewServeMux()
|
|
|
|
m.HandleFunc(wrongStatusCodePath, func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnavailableForLegalReasons)
|
|
})
|
|
|
|
m.HandleFunc(invalidJSONPath, func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprint(w, `{`)
|
|
})
|
|
|
|
m.HandleFunc(missingEndpointPath, func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprint(w, `{}`)
|
|
})
|
|
|
|
m.HandleFunc(invalidEndpointURLPath, func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprint(w, `{
|
|
"newAccount": "",
|
|
"newNonce": "ht\ntp://bad-scheme",
|
|
"newOrder": "",
|
|
"revokeCert": ""
|
|
}`)
|
|
})
|
|
|
|
m.HandleFunc(invalidMetaDirectoryPath, func(w http.ResponseWriter, r *http.Request) {
|
|
noMetaDir := `{
|
|
"keyChange": "https://localhost:14000/rollover-account-key",
|
|
"newAccount": "https://localhost:14000/sign-me-up",
|
|
"newNonce": "https://localhost:14000/nonce-plz",
|
|
"newOrder": "https://localhost:14000/order-plz",
|
|
"revokeCert": "https://localhost:14000/revoke-cert"
|
|
}`
|
|
fmt.Fprint(w, noMetaDir)
|
|
})
|
|
|
|
m.HandleFunc(invalidMetaDirectoryToSPath, func(w http.ResponseWriter, r *http.Request) {
|
|
noToSDir := `{
|
|
"keyChange": "https://localhost:14000/rollover-account-key",
|
|
"meta": {
|
|
"chaos": "reigns"
|
|
},
|
|
"newAccount": "https://localhost:14000/sign-me-up",
|
|
"newNonce": "https://localhost:14000/nonce-plz",
|
|
"newOrder": "https://localhost:14000/order-plz",
|
|
"revokeCert": "https://localhost:14000/revoke-cert"
|
|
}`
|
|
fmt.Fprint(w, noToSDir)
|
|
})
|
|
|
|
m.HandleFunc(validDirectoryPath, func(w http.ResponseWriter, r *http.Request) {
|
|
validDir := `{
|
|
"keyChange": "https://localhost:14000/rollover-account-key",
|
|
"meta": {
|
|
"termsOfService": "data:text/plain,Do%20what%20thou%20wilt"
|
|
},
|
|
"newAccount": "https://localhost:14000/sign-me-up",
|
|
"newNonce": "https://localhost:14000/nonce-plz",
|
|
"newOrder": "https://localhost:14000/order-plz",
|
|
"revokeCert": "https://localhost:14000/revoke-cert"
|
|
}`
|
|
fmt.Fprint(w, validDir)
|
|
})
|
|
|
|
srv := &mockDirectoryServer{
|
|
Server: httptest.NewUnstartedServer(m),
|
|
}
|
|
|
|
return srv
|
|
}
|
|
|
|
// TestNew tests that creating a new Client and populating the endpoint map
|
|
// works correctly.
|
|
func TestNew(t *testing.T) {
|
|
srv := newMockDirectoryServer()
|
|
srv.Start()
|
|
defer srv.Close()
|
|
|
|
srvUrl, _ := url.Parse(srv.URL)
|
|
_, port, _ := net.SplitHostPort(srvUrl.Host)
|
|
|
|
testURL := func(path string) string {
|
|
return fmt.Sprintf("http://localhost:%s%s", port, path)
|
|
}
|
|
|
|
testCases := []struct {
|
|
Name string
|
|
DirectoryURL string
|
|
ExpectedError string
|
|
}{
|
|
{
|
|
Name: "empty directory URL",
|
|
ExpectedError: ErrEmptyDirectory.Error(),
|
|
},
|
|
{
|
|
Name: "invalid directory URL",
|
|
DirectoryURL: "http://" + string([]byte{0x1, 0x7F}),
|
|
ExpectedError: ErrInvalidDirectoryURL.Error(),
|
|
},
|
|
{
|
|
Name: "unreachable directory URL",
|
|
DirectoryURL: "http://localhost:1987",
|
|
ExpectedError: "connect: connection refused",
|
|
},
|
|
{
|
|
Name: "wrong directory HTTP status code",
|
|
DirectoryURL: testURL(wrongStatusCodePath),
|
|
ExpectedError: ErrInvalidDirectoryHTTPCode.Error(),
|
|
},
|
|
{
|
|
Name: "invalid directory JSON",
|
|
DirectoryURL: testURL(invalidJSONPath),
|
|
ExpectedError: ErrInvalidDirectoryJSON.Error(),
|
|
},
|
|
{
|
|
Name: "directory JSON missing required endpoint",
|
|
DirectoryURL: testURL(missingEndpointPath),
|
|
ExpectedError: ErrMissingEndpoint{endpoint: NewNonceEndpoint}.Error(),
|
|
},
|
|
{
|
|
Name: "directory JSON with invalid endpoint URL",
|
|
DirectoryURL: testURL(invalidEndpointURLPath),
|
|
ExpectedError: ErrInvalidEndpointURL{
|
|
endpoint: NewNonceEndpoint,
|
|
value: "ht\ntp://bad-scheme",
|
|
}.Error(),
|
|
},
|
|
{
|
|
Name: "directory JSON missing meta key",
|
|
DirectoryURL: testURL(invalidMetaDirectoryPath),
|
|
ExpectedError: ErrInvalidDirectoryMeta.Error(),
|
|
},
|
|
{
|
|
Name: "directory JSON missing meta TermsOfService key",
|
|
DirectoryURL: testURL(invalidMetaDirectoryToSPath),
|
|
ExpectedError: ErrInvalidTermsOfService.Error(),
|
|
},
|
|
{
|
|
Name: "valid directory",
|
|
DirectoryURL: testURL(validDirectoryPath),
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
_, err := NewDirectory(tc.DirectoryURL)
|
|
if err == nil && tc.ExpectedError != "" {
|
|
t.Errorf("expected error %q got nil", tc.ExpectedError)
|
|
} else if err != nil {
|
|
test.AssertContains(t, err.Error(), tc.ExpectedError)
|
|
}
|
|
})
|
|
}
|
|
}
|