Remove features checks from wfe2 (#2982)
This commit is contained in:
parent
e670e6e6b5
commit
c560fa4fc5
10
core/util.go
10
core/util.go
|
|
@ -95,10 +95,18 @@ func (e BadNonceError) Error() string { return string(e) }
|
||||||
|
|
||||||
// Random stuff
|
// Random stuff
|
||||||
|
|
||||||
|
type randSource interface {
|
||||||
|
Read(p []byte) (n int, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandReader is used so that it can be replaced in tests that require
|
||||||
|
// deterministic output
|
||||||
|
var RandReader randSource = rand.Reader
|
||||||
|
|
||||||
// RandomString returns a randomly generated string of the requested length.
|
// RandomString returns a randomly generated string of the requested length.
|
||||||
func RandomString(byteLength int) string {
|
func RandomString(byteLength int) string {
|
||||||
b := make([]byte, byteLength)
|
b := make([]byte, byteLength)
|
||||||
_, err := io.ReadFull(rand.Reader, b)
|
_, err := io.ReadFull(RandReader, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Error reading random bytes: %s", err))
|
panic(fmt.Sprintf("Error reading random bytes: %s", err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
80
wfe2/wfe.go
80
wfe2/wfe.go
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/letsencrypt/boulder/core"
|
"github.com/letsencrypt/boulder/core"
|
||||||
"github.com/letsencrypt/boulder/features"
|
|
||||||
"github.com/letsencrypt/boulder/goodkey"
|
"github.com/letsencrypt/boulder/goodkey"
|
||||||
blog "github.com/letsencrypt/boulder/log"
|
blog "github.com/letsencrypt/boulder/log"
|
||||||
"github.com/letsencrypt/boulder/metrics"
|
"github.com/letsencrypt/boulder/metrics"
|
||||||
|
|
@ -269,7 +268,7 @@ func (wfe *WebFrontEndImpl) relativeDirectory(request *http.Request, directory m
|
||||||
// the `BaseURL`. Otherwise, prefix each endpoint using the request protocol
|
// the `BaseURL`. Otherwise, prefix each endpoint using the request protocol
|
||||||
// & host.
|
// & host.
|
||||||
for k, v := range directory {
|
for k, v := range directory {
|
||||||
if features.Enabled(features.RandomDirectoryEntry) && v == randomDirKeyExplanationLink {
|
if v == randomDirKeyExplanationLink {
|
||||||
relativeDir[k] = v
|
relativeDir[k] = v
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -308,9 +307,7 @@ func (wfe *WebFrontEndImpl) Handler() http.Handler {
|
||||||
wfe.HandleFunc(m, termsPath, wfe.Terms, "GET")
|
wfe.HandleFunc(m, termsPath, wfe.Terms, "GET")
|
||||||
wfe.HandleFunc(m, issuerPath, wfe.Issuer, "GET")
|
wfe.HandleFunc(m, issuerPath, wfe.Issuer, "GET")
|
||||||
wfe.HandleFunc(m, buildIDPath, wfe.BuildID, "GET")
|
wfe.HandleFunc(m, buildIDPath, wfe.BuildID, "GET")
|
||||||
if features.Enabled(features.AllowKeyRollover) {
|
wfe.HandleFunc(m, rolloverPath, wfe.KeyRollover, "POST")
|
||||||
wfe.HandleFunc(m, rolloverPath, wfe.KeyRollover, "POST")
|
|
||||||
}
|
|
||||||
// We don't use our special HandleFunc for "/" because it matches everything,
|
// We don't use our special HandleFunc for "/" because it matches everything,
|
||||||
// meaning we can wind up returning 405 when we mean to return 404. See
|
// meaning we can wind up returning 405 when we mean to return 404. See
|
||||||
// https://github.com/letsencrypt/boulder/issues/717
|
// https://github.com/letsencrypt/boulder/issues/717
|
||||||
|
|
@ -376,26 +373,18 @@ func (wfe *WebFrontEndImpl) Directory(ctx context.Context, logEvent *requestEven
|
||||||
"revoke-cert": revokeCertPath,
|
"revoke-cert": revokeCertPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Versions of Certbot pre-0.6.0 (named LetsEncryptPythonClient at the time) break when they
|
directoryEndpoints["key-change"] = rolloverPath
|
||||||
// encounter a directory containing elements they don't expect so we gate
|
|
||||||
// adding new directory fields for clients matching this UA.
|
// Add a random key to the directory in order to make sure that clients don't hardcode an
|
||||||
clientDirChangeIntolerant := strings.HasPrefix(request.UserAgent(), "LetsEncryptPythonClient")
|
// expected set of keys. This ensures that we can properly extend the directory when we
|
||||||
if features.Enabled(features.AllowKeyRollover) && !clientDirChangeIntolerant {
|
// need to add a new endpoint or meta element.
|
||||||
directoryEndpoints["key-change"] = rolloverPath
|
directoryEndpoints[core.RandomString(8)] = randomDirKeyExplanationLink
|
||||||
}
|
|
||||||
if features.Enabled(features.RandomDirectoryEntry) && !clientDirChangeIntolerant {
|
// ACME since draft-02 describes an optional "meta" directory entry. The
|
||||||
// Add a random key to the directory in order to make sure that clients don't hardcode an
|
// meta entry may optionally contain a "terms-of-service" URI for the
|
||||||
// expected set of keys. This ensures that we can properly extend the directory when we
|
// current ToS.
|
||||||
// need to add a new endpoint or meta element.
|
directoryEndpoints["meta"] = map[string]string{
|
||||||
directoryEndpoints[core.RandomString(8)] = randomDirKeyExplanationLink
|
"terms-of-service": wfe.SubscriberAgreementURL,
|
||||||
}
|
|
||||||
if features.Enabled(features.DirectoryMeta) && !clientDirChangeIntolerant {
|
|
||||||
// ACME since draft-02 describes an optional "meta" directory entry. The
|
|
||||||
// meta entry may optionally contain a "terms-of-service" URI for the
|
|
||||||
// current ToS.
|
|
||||||
directoryEndpoints["meta"] = map[string]string{
|
|
||||||
"terms-of-service": wfe.SubscriberAgreementURL,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Header().Set("Content-Type", "application/json")
|
response.Header().Set("Content-Type", "application/json")
|
||||||
|
|
@ -707,15 +696,10 @@ func (wfe *WebFrontEndImpl) NewCertificate(ctx context.Context, logEvent *reques
|
||||||
|
|
||||||
// TODO Content negotiation
|
// TODO Content negotiation
|
||||||
response.Header().Add("Location", certURL)
|
response.Header().Add("Location", certURL)
|
||||||
if features.Enabled(features.UseAIAIssuerURL) {
|
if err = wfe.addIssuingCertificateURLs(response, parsedCertificate.IssuingCertificateURL); err != nil {
|
||||||
if err = wfe.addIssuingCertificateURLs(response, parsedCertificate.IssuingCertificateURL); err != nil {
|
logEvent.AddError("unable to parse IssuingCertificateURL: %s", err)
|
||||||
logEvent.AddError("unable to parse IssuingCertificateURL: %s", err)
|
wfe.sendError(response, logEvent, probs.ServerInternal("unable to parse IssuingCertificateURL"), err)
|
||||||
wfe.sendError(response, logEvent, probs.ServerInternal("unable to parse IssuingCertificateURL"), err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
relativeIssuerPath := wfe.relativeEndpoint(request, issuerPath)
|
|
||||||
response.Header().Add("Link", link(relativeIssuerPath, "up"))
|
|
||||||
}
|
}
|
||||||
response.Header().Set("Content-Type", "application/pkix-cert")
|
response.Header().Set("Content-Type", "application/pkix-cert")
|
||||||
response.WriteHeader(http.StatusCreated)
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
|
@ -953,7 +937,7 @@ func (wfe *WebFrontEndImpl) Registration(
|
||||||
// If a user tries to send both a deactivation request and an update to their
|
// If a user tries to send both a deactivation request and an update to their
|
||||||
// contacts or subscriber agreement URL the deactivation will take place and
|
// contacts or subscriber agreement URL the deactivation will take place and
|
||||||
// return before an update would be performed.
|
// return before an update would be performed.
|
||||||
if features.Enabled(features.AllowAccountDeactivation) && (update.Status != "" && update.Status != currReg.Status) {
|
if update.Status != "" && update.Status != currReg.Status {
|
||||||
if update.Status != core.StatusDeactivated {
|
if update.Status != core.StatusDeactivated {
|
||||||
wfe.sendError(response, logEvent, probs.Malformed("Invalid value provided for status field"), nil)
|
wfe.sendError(response, logEvent, probs.Malformed("Invalid value provided for status field"), nil)
|
||||||
return
|
return
|
||||||
|
|
@ -1127,22 +1111,18 @@ func (wfe *WebFrontEndImpl) Certificate(ctx context.Context, logEvent *requestEv
|
||||||
|
|
||||||
// TODO Content negotiation
|
// TODO Content negotiation
|
||||||
response.Header().Set("Content-Type", "application/pkix-cert")
|
response.Header().Set("Content-Type", "application/pkix-cert")
|
||||||
if features.Enabled(features.UseAIAIssuerURL) {
|
parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER))
|
||||||
parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER))
|
if err != nil {
|
||||||
if err != nil {
|
logEvent.AddError("unable to parse certificate: %s", err)
|
||||||
logEvent.AddError("unable to parse certificate: %s", err)
|
wfe.sendError(response, logEvent, probs.ServerInternal("Unable to parse certificate"), err)
|
||||||
wfe.sendError(response, logEvent, probs.ServerInternal("Unable to parse certificate"), err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = wfe.addIssuingCertificateURLs(response, parsedCertificate.IssuingCertificateURL); err != nil {
|
|
||||||
logEvent.AddError("unable to parse IssuingCertificateURL: %s", err)
|
|
||||||
wfe.sendError(response, logEvent, probs.ServerInternal("unable to parse IssuingCertificateURL"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
relativeIssuerPath := wfe.relativeEndpoint(request, issuerPath)
|
|
||||||
response.Header().Add("Link", link(relativeIssuerPath, "up"))
|
|
||||||
}
|
}
|
||||||
|
if err = wfe.addIssuingCertificateURLs(response, parsedCertificate.IssuingCertificateURL); err != nil {
|
||||||
|
logEvent.AddError("unable to parse IssuingCertificateURL: %s", err)
|
||||||
|
wfe.sendError(response, logEvent, probs.ServerInternal("unable to parse IssuingCertificateURL"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteHeader(http.StatusOK)
|
response.WriteHeader(http.StatusOK)
|
||||||
if _, err = response.Write(cert.DER); err != nil {
|
if _, err = response.Write(cert.DER); err != nil {
|
||||||
logEvent.AddError(err.Error())
|
logEvent.AddError(err.Error())
|
||||||
|
|
|
||||||
217
wfe2/wfe_test.go
217
wfe2/wfe_test.go
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -26,7 +27,6 @@ import (
|
||||||
|
|
||||||
"github.com/letsencrypt/boulder/core"
|
"github.com/letsencrypt/boulder/core"
|
||||||
corepb "github.com/letsencrypt/boulder/core/proto"
|
corepb "github.com/letsencrypt/boulder/core/proto"
|
||||||
"github.com/letsencrypt/boulder/features"
|
|
||||||
"github.com/letsencrypt/boulder/goodkey"
|
"github.com/letsencrypt/boulder/goodkey"
|
||||||
blog "github.com/letsencrypt/boulder/log"
|
blog "github.com/letsencrypt/boulder/log"
|
||||||
"github.com/letsencrypt/boulder/metrics"
|
"github.com/letsencrypt/boulder/metrics"
|
||||||
|
|
@ -625,6 +625,12 @@ func randomDirectoryKeyPresent(t *testing.T, buf []byte) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeRand struct{}
|
||||||
|
|
||||||
|
func (fr fakeRand) Read(p []byte) (int, error) {
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestDirectory(t *testing.T) {
|
func TestDirectory(t *testing.T) {
|
||||||
// Note: `TestDirectory` sets the `wfe.BaseURL` specifically to test the
|
// Note: `TestDirectory` sets the `wfe.BaseURL` specifically to test the
|
||||||
// that it overrides the relative /directory behaviour.
|
// that it overrides the relative /directory behaviour.
|
||||||
|
|
@ -634,27 +640,8 @@ func TestDirectory(t *testing.T) {
|
||||||
wfe, _ := setupWFE(t)
|
wfe, _ := setupWFE(t)
|
||||||
wfe.BaseURL = "http://localhost:4300"
|
wfe.BaseURL = "http://localhost:4300"
|
||||||
mux := wfe.Handler()
|
mux := wfe.Handler()
|
||||||
|
core.RandReader = fakeRand{}
|
||||||
const (
|
defer func() { core.RandReader = rand.Reader }()
|
||||||
oldUA = "LetsEncryptPythonClient"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Directory with a key change endpoint but no meta endpoint or random entry
|
|
||||||
noMetaJSONWithKeyChange := `{
|
|
||||||
"key-change": "http://localhost:4300/acme/key-change",
|
|
||||||
"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"
|
|
||||||
}`
|
|
||||||
|
|
||||||
// Directory without a key change endpoint or a random entry
|
|
||||||
noMetaJSONWithoutKeyChange := `{
|
|
||||||
"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"
|
|
||||||
}`
|
|
||||||
|
|
||||||
// Directory with a key change endpoint and a meta entry
|
// Directory with a key change endpoint and a meta entry
|
||||||
metaJSON := `{
|
metaJSON := `{
|
||||||
|
|
@ -665,115 +652,37 @@ func TestDirectory(t *testing.T) {
|
||||||
"new-authz": "http://localhost:4300/acme/new-authz",
|
"new-authz": "http://localhost:4300/acme/new-authz",
|
||||||
"new-cert": "http://localhost:4300/acme/new-cert",
|
"new-cert": "http://localhost:4300/acme/new-cert",
|
||||||
"new-reg": "http://localhost:4300/acme/new-reg",
|
"new-reg": "http://localhost:4300/acme/new-reg",
|
||||||
"revoke-cert": "http://localhost:4300/acme/revoke-cert"
|
"revoke-cert": "http://localhost:4300/acme/revoke-cert",
|
||||||
|
"AAAAAAAAAAA": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417"
|
||||||
}`
|
}`
|
||||||
|
|
||||||
// Directory with a meta entry but no key change endpoint
|
// NOTE: the req.URL will be modified and must be constructed per
|
||||||
metaNoKeyChangeJSON := `{
|
// testcase or things will break and you will be confused and sad.
|
||||||
"meta": {
|
url, _ := url.Parse("/directory")
|
||||||
"terms-of-service": "http://example.invalid/terms"
|
req := &http.Request{
|
||||||
},
|
Method: "GET",
|
||||||
"new-authz": "http://localhost:4300/acme/new-authz",
|
URL: url,
|
||||||
"new-cert": "http://localhost:4300/acme/new-cert",
|
Host: "127.0.0.1:4300",
|
||||||
"new-reg": "http://localhost:4300/acme/new-reg",
|
|
||||||
"revoke-cert": "http://localhost:4300/acme/revoke-cert"
|
|
||||||
}`
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
Name string
|
|
||||||
UserAgent string
|
|
||||||
SetFeatures []string
|
|
||||||
ExpectedJSON string
|
|
||||||
RandomEntry bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Name: "No meta feature enabled, no explicit user-agent",
|
|
||||||
ExpectedJSON: noMetaJSONWithoutKeyChange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Key change feature enabled, no explicit user-agent",
|
|
||||||
SetFeatures: []string{"AllowKeyRollover"},
|
|
||||||
ExpectedJSON: noMetaJSONWithKeyChange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "DirectoryMeta feature enabled, no explicit user-agent",
|
|
||||||
SetFeatures: []string{"DirectoryMeta"},
|
|
||||||
ExpectedJSON: metaNoKeyChangeJSON,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "DirectoryMeta feature enabled, no key change enabled, explicit old Let's Encrypt user-agent",
|
|
||||||
SetFeatures: []string{"DirectoryMeta"},
|
|
||||||
UserAgent: oldUA,
|
|
||||||
ExpectedJSON: noMetaJSONWithoutKeyChange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "DirectoryMeta feature enabled, key change enabled, explicit old Let's Encrypt user-agent",
|
|
||||||
SetFeatures: []string{"DirectoryMeta", "AllowKeyRollover"},
|
|
||||||
UserAgent: oldUA,
|
|
||||||
ExpectedJSON: noMetaJSONWithoutKeyChange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "DirectoryMeta feature enabled, key change enabled, no explicit user-agent",
|
|
||||||
SetFeatures: []string{"DirectoryMeta", "AllowKeyRollover"},
|
|
||||||
ExpectedJSON: metaJSON,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "RandomDirectoryEntry feature enabled, no explicit user-agent",
|
|
||||||
SetFeatures: []string{"RandomDirectoryEntry"},
|
|
||||||
RandomEntry: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "RandomDirectoryEntry feature enabled, explicit old Let's Encrypt user-agent",
|
|
||||||
UserAgent: oldUA,
|
|
||||||
SetFeatures: []string{"RandomDirectoryEntry"},
|
|
||||||
RandomEntry: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
// Each test case will set zero or more feature flags
|
|
||||||
for _, feature := range tc.SetFeatures {
|
|
||||||
_ = features.Set(map[string]bool{feature: true})
|
|
||||||
}
|
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
|
||||||
// NOTE: the req.URL will be modified and must be constructed per
|
|
||||||
// testcase or things will break and you will be confused and sad.
|
|
||||||
url, _ := url.Parse("/directory")
|
|
||||||
req := &http.Request{
|
|
||||||
Method: "GET",
|
|
||||||
URL: url,
|
|
||||||
Host: "127.0.0.1:4300",
|
|
||||||
}
|
|
||||||
// Set an explicit User-Agent header as directed by the test case
|
|
||||||
if tc.UserAgent != "" {
|
|
||||||
req.Header = map[string][]string{"User-Agent": []string{tc.UserAgent}}
|
|
||||||
}
|
|
||||||
// Serve the /directory response for this request into a recorder
|
|
||||||
responseWriter := httptest.NewRecorder()
|
|
||||||
mux.ServeHTTP(responseWriter, req)
|
|
||||||
// We expect all directory requests to return a json object with a good HTTP status
|
|
||||||
test.AssertEquals(t, responseWriter.Header().Get("Content-Type"), "application/json")
|
|
||||||
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
|
|
||||||
// If the test case specifies exact JSON it expects, test that it matches
|
|
||||||
if tc.ExpectedJSON != "" {
|
|
||||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), tc.ExpectedJSON)
|
|
||||||
}
|
|
||||||
// Check if there is a random directory key present and if so, that it is
|
|
||||||
// expected to be present
|
|
||||||
test.AssertEquals(t,
|
|
||||||
randomDirectoryKeyPresent(t, responseWriter.Body.Bytes()),
|
|
||||||
tc.RandomEntry)
|
|
||||||
})
|
|
||||||
// Reset the feature flags between test cases to get a blank slate
|
|
||||||
features.Reset()
|
|
||||||
}
|
}
|
||||||
|
// Serve the /directory response for this request into a recorder
|
||||||
|
responseWriter := httptest.NewRecorder()
|
||||||
|
mux.ServeHTTP(responseWriter, req)
|
||||||
|
// We expect all directory requests to return a json object with a good HTTP status
|
||||||
|
test.AssertEquals(t, responseWriter.Header().Get("Content-Type"), "application/json")
|
||||||
|
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
|
||||||
|
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), metaJSON)
|
||||||
|
// Check if there is a random directory key present and if so, that it is
|
||||||
|
// expected to be present
|
||||||
|
test.AssertEquals(t,
|
||||||
|
randomDirectoryKeyPresent(t, responseWriter.Body.Bytes()),
|
||||||
|
true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRelativeDirectory(t *testing.T) {
|
func TestRelativeDirectory(t *testing.T) {
|
||||||
_ = features.Set(map[string]bool{"AllowKeyRollover": true})
|
|
||||||
defer features.Reset()
|
|
||||||
wfe, _ := setupWFE(t)
|
wfe, _ := setupWFE(t)
|
||||||
mux := wfe.Handler()
|
mux := wfe.Handler()
|
||||||
|
core.RandReader = fakeRand{}
|
||||||
|
defer func() { core.RandReader = rand.Reader }()
|
||||||
|
|
||||||
dirTests := []struct {
|
dirTests := []struct {
|
||||||
host string
|
host string
|
||||||
|
|
@ -781,15 +690,15 @@ func TestRelativeDirectory(t *testing.T) {
|
||||||
result string
|
result string
|
||||||
}{
|
}{
|
||||||
// Test '' (No host header) with no proto header
|
// Test '' (No host header) with no proto header
|
||||||
{"", "", `{"key-change":"http://localhost/acme/key-change","new-authz":"http://localhost/acme/new-authz","new-cert":"http://localhost/acme/new-cert","new-reg":"http://localhost/acme/new-reg","revoke-cert":"http://localhost/acme/revoke-cert"}`},
|
{"", "", `{"key-change":"http://localhost/acme/key-change","new-authz":"http://localhost/acme/new-authz","new-cert":"http://localhost/acme/new-cert","new-reg":"http://localhost/acme/new-reg","revoke-cert":"http://localhost/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||||
// Test localhost:4300 with no proto header
|
// Test localhost:4300 with no proto header
|
||||||
{"localhost:4300", "", `{"key-change":"http://localhost:4300/acme/key-change","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"}`},
|
{"localhost:4300", "", `{"key-change":"http://localhost:4300/acme/key-change","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","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||||
// Test 127.0.0.1:4300 with no proto header
|
// Test 127.0.0.1:4300 with no proto header
|
||||||
{"127.0.0.1:4300", "", `{"key-change":"http://127.0.0.1:4300/acme/key-change","new-authz":"http://127.0.0.1:4300/acme/new-authz","new-cert":"http://127.0.0.1:4300/acme/new-cert","new-reg":"http://127.0.0.1:4300/acme/new-reg","revoke-cert":"http://127.0.0.1:4300/acme/revoke-cert"}`},
|
{"127.0.0.1:4300", "", `{"key-change":"http://127.0.0.1:4300/acme/key-change","new-authz":"http://127.0.0.1:4300/acme/new-authz","new-cert":"http://127.0.0.1:4300/acme/new-cert","new-reg":"http://127.0.0.1:4300/acme/new-reg","revoke-cert":"http://127.0.0.1:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||||
// Test localhost:4300 with HTTP proto header
|
// Test localhost:4300 with HTTP proto header
|
||||||
{"localhost:4300", "http", `{"key-change":"http://localhost:4300/acme/key-change","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"}`},
|
{"localhost:4300", "http", `{"key-change":"http://localhost:4300/acme/key-change","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","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||||
// Test localhost:4300 with HTTPS proto header
|
// Test localhost:4300 with HTTPS proto header
|
||||||
{"localhost:4300", "https", `{"key-change":"https://localhost:4300/acme/key-change","new-authz":"https://localhost:4300/acme/new-authz","new-cert":"https://localhost:4300/acme/new-cert","new-reg":"https://localhost:4300/acme/new-reg","revoke-cert":"https://localhost:4300/acme/revoke-cert"}`},
|
{"localhost:4300", "https", `{"key-change":"https://localhost:4300/acme/key-change","new-authz":"https://localhost:4300/acme/new-authz","new-cert":"https://localhost:4300/acme/new-cert","new-reg":"https://localhost:4300/acme/new-reg","revoke-cert":"https://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range dirTests {
|
for _, tt := range dirTests {
|
||||||
|
|
@ -815,10 +724,6 @@ func TestRelativeDirectory(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPMethods(t *testing.T) {
|
func TestHTTPMethods(t *testing.T) {
|
||||||
// Always allow key rollover to test the rolloverPath
|
|
||||||
_ = features.Set(map[string]bool{"AllowKeyRollover": true})
|
|
||||||
defer features.Reset()
|
|
||||||
|
|
||||||
wfe, _ := setupWFE(t)
|
wfe, _ := setupWFE(t)
|
||||||
mux := wfe.Handler()
|
mux := wfe.Handler()
|
||||||
|
|
||||||
|
|
@ -1031,14 +936,6 @@ func TestIssueCertificate(t *testing.T) {
|
||||||
cert, err := core.LoadCert("test/not-an-example.com.crt")
|
cert, err := core.LoadCert("test/not-an-example.com.crt")
|
||||||
test.AssertNotError(t, err, "Could not load cert")
|
test.AssertNotError(t, err, "Could not load cert")
|
||||||
|
|
||||||
goodCertHeaders := map[string]string{
|
|
||||||
"Location": "http://localhost/acme/cert/0000ff0000000000000e4b4f67d86e818c46",
|
|
||||||
"Link": `<http://localhost/acme/issuer-cert>;rel="up"`,
|
|
||||||
"Content-Type": "application/pkix-cert",
|
|
||||||
}
|
|
||||||
// NOTE(@cpu): Unlike the test case above this case expects
|
|
||||||
// `localhost:4000` in the Link header value since the AIAIssuer flag
|
|
||||||
// will have been true. The WFE will also promote it from HTTP to HTTPS.
|
|
||||||
goodCertAIAHeaders := map[string]string{
|
goodCertAIAHeaders := map[string]string{
|
||||||
"Location": "http://localhost/acme/cert/0000ff0000000000000e4b4f67d86e818c46",
|
"Location": "http://localhost/acme/cert/0000ff0000000000000e4b4f67d86e818c46",
|
||||||
"Link": `<https://localhost:4000/acme/issuer-cert>;rel="up"`,
|
"Link": `<https://localhost:4000/acme/issuer-cert>;rel="up"`,
|
||||||
|
|
@ -1058,7 +955,6 @@ func TestIssueCertificate(t *testing.T) {
|
||||||
AssertCSRLogged bool
|
AssertCSRLogged bool
|
||||||
ExpectedHeaders map[string]string
|
ExpectedHeaders map[string]string
|
||||||
ExpectedLogParts []string
|
ExpectedLogParts []string
|
||||||
UseAIAIssuer bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "POST, but no body",
|
Name: "POST, but no body",
|
||||||
|
|
@ -1101,20 +997,11 @@ func TestIssueCertificate(t *testing.T) {
|
||||||
ExpectedProblem: `{"type":"urn:acme:error:unauthorized","detail":"Error creating new cert :: authorizations for these names not found or expired: meep.com","status":403}`,
|
ExpectedProblem: `{"type":"urn:acme:error:unauthorized","detail":"Error creating new cert :: authorizations for these names not found or expired: meep.com","status":403}`,
|
||||||
AssertCSRLogged: true,
|
AssertCSRLogged: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "POST, properly signed JWS, authorizations for all names in CSR",
|
|
||||||
Request: signAndPost(t, targetPath, signedURL, goodCertCSRPayload, 1, wfe.nonceService),
|
|
||||||
ExpectedCert: string(cert.Raw),
|
|
||||||
AssertCSRLogged: true,
|
|
||||||
ExpectedHeaders: goodCertHeaders,
|
|
||||||
ExpectedLogParts: goodCertLogParts,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "POST, properly signed JWS, authorizations for all names in CSR, using AIAIssuer",
|
Name: "POST, properly signed JWS, authorizations for all names in CSR, using AIAIssuer",
|
||||||
Request: signAndPost(t, targetPath, signedURL, goodCertCSRPayload, 1, wfe.nonceService),
|
Request: signAndPost(t, targetPath, signedURL, goodCertCSRPayload, 1, wfe.nonceService),
|
||||||
ExpectedCert: string(cert.Raw),
|
ExpectedCert: string(cert.Raw),
|
||||||
AssertCSRLogged: true,
|
AssertCSRLogged: true,
|
||||||
UseAIAIssuer: true,
|
|
||||||
ExpectedHeaders: goodCertAIAHeaders,
|
ExpectedHeaders: goodCertAIAHeaders,
|
||||||
ExpectedLogParts: goodCertLogParts,
|
ExpectedLogParts: goodCertLogParts,
|
||||||
},
|
},
|
||||||
|
|
@ -1128,10 +1015,6 @@ func TestIssueCertificate(t *testing.T) {
|
||||||
responseWriter.HeaderMap = http.Header{}
|
responseWriter.HeaderMap = http.Header{}
|
||||||
mockLog.Clear()
|
mockLog.Clear()
|
||||||
|
|
||||||
if tc.UseAIAIssuer {
|
|
||||||
_ = features.Set(map[string]bool{"UseAIAIssuerURL": true})
|
|
||||||
}
|
|
||||||
|
|
||||||
wfe.NewCertificate(ctx, newRequestEvent(), responseWriter, tc.Request)
|
wfe.NewCertificate(ctx, newRequestEvent(), responseWriter, tc.Request)
|
||||||
if len(tc.ExpectedProblem) > 0 {
|
if len(tc.ExpectedProblem) > 0 {
|
||||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), tc.ExpectedProblem)
|
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), tc.ExpectedProblem)
|
||||||
|
|
@ -1155,7 +1038,6 @@ func TestIssueCertificate(t *testing.T) {
|
||||||
test.AssertContains(t, reqlogs[0], msg)
|
test.AssertContains(t, reqlogs[0], msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
features.Reset()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1618,8 +1500,6 @@ func contains(s []string, e string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegistration(t *testing.T) {
|
func TestRegistration(t *testing.T) {
|
||||||
_ = features.Set(map[string]bool{"AllowKeyRollover": true})
|
|
||||||
defer features.Reset()
|
|
||||||
wfe, _ := setupWFE(t)
|
wfe, _ := setupWFE(t)
|
||||||
mux := wfe.Handler()
|
mux := wfe.Handler()
|
||||||
responseWriter := httptest.NewRecorder()
|
responseWriter := httptest.NewRecorder()
|
||||||
|
|
@ -1768,26 +1648,13 @@ func TestGetCertificate(t *testing.T) {
|
||||||
ExpectedBody string
|
ExpectedBody string
|
||||||
ExpectedCert []byte
|
ExpectedCert []byte
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
Name: "Valid serial, cached",
|
|
||||||
Path: goodSerial,
|
|
||||||
ExpectedStatus: http.StatusOK,
|
|
||||||
ExpectedHeaders: map[string]string{
|
|
||||||
"Content-Type": pkixContent,
|
|
||||||
"Link": `<http://localhost/acme/issuer-cert>;rel="up"`,
|
|
||||||
},
|
|
||||||
ExpectedCert: certBlock.Bytes,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "Valid serial, UseAIAIssuer feature enabled",
|
Name: "Valid serial, UseAIAIssuer feature enabled",
|
||||||
Path: goodSerial,
|
Path: goodSerial,
|
||||||
Features: []string{"UseAIAIssuerURL"},
|
|
||||||
ExpectedStatus: http.StatusOK,
|
ExpectedStatus: http.StatusOK,
|
||||||
ExpectedHeaders: map[string]string{
|
ExpectedHeaders: map[string]string{
|
||||||
"Content-Type": pkixContent,
|
"Content-Type": pkixContent,
|
||||||
// NOTE(@cpu): Unlike the test case above we expect the AIA Issuer
|
"Link": `<https://localhost:4000/acme/issuer-cert>;rel="up"`,
|
||||||
// feature to result in a Link header value with the port included.
|
|
||||||
"Link": `<https://localhost:4000/acme/issuer-cert>;rel="up"`,
|
|
||||||
},
|
},
|
||||||
ExpectedCert: certBlock.Bytes,
|
ExpectedCert: certBlock.Bytes,
|
||||||
},
|
},
|
||||||
|
|
@ -1813,9 +1680,6 @@ func TestGetCertificate(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
for _, feature := range tc.Features {
|
|
||||||
_ = features.Set(map[string]bool{feature: true})
|
|
||||||
}
|
|
||||||
responseWriter := httptest.NewRecorder()
|
responseWriter := httptest.NewRecorder()
|
||||||
mockLog := wfe.log.(*blog.Mock)
|
mockLog := wfe.log.(*blog.Mock)
|
||||||
mockLog.Clear()
|
mockLog.Clear()
|
||||||
|
|
@ -1856,9 +1720,6 @@ func TestGetCertificate(t *testing.T) {
|
||||||
test.AssertEquals(t, len(reqlogs), 1)
|
test.AssertEquals(t, len(reqlogs), 1)
|
||||||
test.AssertContains(t, reqlogs[0], `INFO: `)
|
test.AssertContains(t, reqlogs[0], `INFO: `)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset any features that were set
|
|
||||||
features.Reset()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2040,8 +1901,6 @@ func TestDeactivateAuthorization(t *testing.T) {
|
||||||
func TestDeactivateRegistration(t *testing.T) {
|
func TestDeactivateRegistration(t *testing.T) {
|
||||||
responseWriter := httptest.NewRecorder()
|
responseWriter := httptest.NewRecorder()
|
||||||
wfe, _ := setupWFE(t)
|
wfe, _ := setupWFE(t)
|
||||||
_ = features.Set(map[string]bool{"AllowAccountDeactivation": true})
|
|
||||||
defer features.Reset()
|
|
||||||
|
|
||||||
responseWriter.Body.Reset()
|
responseWriter.Body.Reset()
|
||||||
payload := `{"status":"asd"}`
|
payload := `{"status":"asd"}`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue