Merge branch 'master' into clean_up_new_reg_test

This commit is contained in:
Jeff Hodges 2015-09-10 14:48:59 -07:00
commit 845e1261a4
11 changed files with 218 additions and 144 deletions

View File

@ -18,7 +18,6 @@ import (
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/ra"
"github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/wfe"
)
func main() {
@ -44,7 +43,6 @@ func main() {
cmd.FailOnError(err, "Couldn't create PA")
rai := ra.NewRegistrationAuthorityImpl(clock.Default(), auditlogger)
rai.AuthzBase = c.Common.BaseURL + wfe.AuthzPath
rai.PA = pa
raDNSTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
cmd.FailOnError(err, "Couldn't parse RA DNS timeout")

View File

@ -241,6 +241,8 @@ type ValidationRecord struct {
// challenge, we just throw all the elements into one bucket,
// together with the common metadata elements.
type Challenge struct {
ID int64 `json:"id,omitempty"`
// The type of challenge
Type string `json:"type"`
@ -255,7 +257,7 @@ type Challenge struct {
Validated *time.Time `json:"validated,omitempty"`
// A URI to which a response can be POSTed
URI *AcmeURL `json:"uri"`
URI string `json:"uri"`
// Used by simpleHttp, dvsni, and dns challenges
Token string `json:"token,omitempty"`
@ -431,6 +433,18 @@ type Authorization struct {
Combinations [][]int `json:"combinations,omitempty" db:"combinations"`
}
// FindChallenge will look for the given challenge inside this authorization. If
// found, it will return the index of that challenge within the Authorization's
// Challenges array. Otherwise it will return -1.
func (authz *Authorization) FindChallenge(challengeID int64) int {
for i, c := range authz.Challenges {
if c.ID == challengeID {
return i
}
}
return -1
}
// JSONBuffer fields get encoded and decoded JOSE-style, in base64url encoding
// with stripped padding.
type JSONBuffer []byte

View File

@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"net/mail"
"strconv"
"strings"
"time"
@ -31,8 +30,6 @@ type RegistrationAuthorityImpl struct {
DNSResolver core.DNSResolver
clk clock.Clock
log *blog.AuditLogger
AuthzBase string
}
// NewRegistrationAuthorityImpl constructs a new RA object.
@ -150,6 +147,11 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
// Create validations, but we have to update them with URIs later
challenges, combinations := ra.PA.ChallengesFor(identifier)
for i, _ := range challenges {
// Add the account key used to generate the challenge
challenges[i].AccountKey = &reg.Key
}
// Partially-filled object
authz = core.Authorization{
Identifier: identifier,
@ -165,33 +167,19 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
// InternalServerError since the user-data was validated before being
// passed to the SA.
err = core.InternalServerError(fmt.Sprintf("Invalid authorization request: %s", err))
return authz, err
return core.Authorization{}, err
}
// Construct all the challenge URIs
for i := range authz.Challenges {
// Ignoring these errors because we construct the URLs to be correct
challengeURI, _ := core.ParseAcmeURL(ra.AuthzBase + authz.ID + "?challenge=" + strconv.Itoa(i))
authz.Challenges[i].URI = challengeURI
// Add the account key used to generate the challenge
authz.Challenges[i].AccountKey = &reg.Key
if !authz.Challenges[i].IsSane(false) {
// Check each challenge for sanity.
for _, challenge := range authz.Challenges {
if !challenge.IsSane(false) {
// InternalServerError because we generated these challenges, they should
// be OK.
err = core.InternalServerError(fmt.Sprintf("Challenge didn't pass sanity check: %+v", authz.Challenges[i]))
return authz, err
err = core.InternalServerError(fmt.Sprintf("Challenge didn't pass sanity check: %+v", challenge))
return core.Authorization{}, err
}
}
// Store the authorization object, then return it
err = ra.SA.UpdatePendingAuthorization(authz)
if err != nil {
// InternalServerError because we created the authorization just above,
// and adding Sane challenges should not break it.
err = core.InternalServerError(err.Error())
}
return authz, err
}

View File

@ -214,7 +214,6 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
ra.VA = va
ra.CA = &ca
ra.PA = pa
ra.AuthzBase = "http://acme.invalid/authz/"
ra.DNSResolver = &mocks.MockDNS{}
AuthzInitial.RegistrationID = Registration.ID

View File

@ -366,6 +366,7 @@ func (rpc *AmqpRPCServer) processMessage(msg amqp.Delivery) {
CorrelationId: msg.CorrelationId,
Type: msg.Type,
Body: jsonResponse, // XXX-JWS: jws.Sign(privKey, body)
Expiration: "30000",
})
}
@ -486,7 +487,12 @@ func NewAmqpRPCClient(clientQueuePrefix, serverQueue string, channel *amqp.Chann
return nil, err
}
clientQueue := fmt.Sprintf("%s.%s", clientQueuePrefix, hostname)
randID := make([]byte, 3)
_, err = rand.Read(randID)
if err != nil {
return nil, err
}
clientQueue := fmt.Sprintf("%s.%s.%x", clientQueuePrefix, hostname, randID)
rpc = &AmqpRPCCLient{
serverQueue: serverQueue,
@ -558,6 +564,7 @@ func (rpc *AmqpRPCCLient) Dispatch(method string, body []byte) chan []byte {
ReplyTo: rpc.clientQueue,
Type: method,
Body: body, // XXX-JWS: jws.Sign(privKey, body)
Expiration: "30000",
})
return responseChan

View File

@ -0,0 +1,13 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `challenges` DROP COLUMN `uri`;
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back
ALTER TABLE `challenges` ADD COLUMN (
`uri` varchar(255)
);

View File

@ -36,7 +36,6 @@ type challModel struct {
Status core.AcmeStatus `db:"status"`
Error []byte `db:"error"`
Validated *time.Time `db:"validated"`
URI string `db:"uri"`
Token string `db:"token"`
TLS *bool `db:"tls"`
Validation []byte `db:"validation"`
@ -85,6 +84,7 @@ func modelToRegistration(rm *regModel) (core.Registration, error) {
func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
cm := challModel{
ID: c.ID,
AuthorizationID: authID,
Type: c.Type,
Status: c.Status,
@ -108,12 +108,6 @@ func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
}
cm.Error = errJSON
}
if c.URI != nil {
if len(c.URI.String()) > 255 {
return nil, fmt.Errorf("URI is too long to store in the database")
}
cm.URI = c.URI.String()
}
if len(c.ValidationRecord) > 0 {
vrJSON, err := json.Marshal(c.ValidationRecord)
if err != nil {
@ -139,19 +133,13 @@ func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
func modelToChallenge(cm *challModel) (core.Challenge, error) {
c := core.Challenge{
ID: cm.ID,
Type: cm.Type,
Status: cm.Status,
Validated: cm.Validated,
Token: cm.Token,
TLS: cm.TLS,
}
if len(cm.URI) > 0 {
uri, err := core.ParseAcmeURL(cm.URI)
if err != nil {
return core.Challenge{}, err
}
c.URI = uri
}
if len(cm.Validation) > 0 {
val, err := jose.ParseSigned(string(cm.Validation))
if err != nil {

View File

@ -440,17 +440,28 @@ func (ssa *SQLStorageAuthority) NewPendingAuthorization(authz core.Authorization
return
}
for _, c := range authz.Challenges {
chall, err := challengeToModel(&c, pendingAuthz.ID)
for i, c := range authz.Challenges {
challModel, err := challengeToModel(&c, pendingAuthz.ID)
if err != nil {
tx.Rollback()
return core.Authorization{}, err
}
err = tx.Insert(chall)
// Magic happens here: Gorp will modify challModel, setting challModel.ID
// to the auto-increment primary key. This is important because we want
// the challenge objects inside the Authorization we return to know their
// IDs, so they can have proper URLs.
// See https://godoc.org/github.com/coopernurse/gorp#DbMap.Insert
err = tx.Insert(challModel)
if err != nil {
tx.Rollback()
return core.Authorization{}, err
}
challenge, err := modelToChallenge(challModel)
if err != nil {
tx.Rollback()
return core.Authorization{}, err
}
authz.Challenges[i] = challenge
}
err = tx.Commit()

View File

@ -177,9 +177,7 @@ func CreateDomainAuthWithRegId(t *testing.T, domainName string, sa *SQLStorageAu
test.Assert(t, authz.ID != "", "ID shouldn't be blank")
// prepare challenge for auth
u, err := core.ParseAcmeURL(domainName)
test.AssertNotError(t, err, "Couldn't parse domainName "+domainName)
chall := core.Challenge{Type: "simpleHttp", Status: core.StatusValid, URI: u, Token: "THISWOULDNTBEAGOODTOKEN"}
chall := core.Challenge{Type: "simpleHttp", Status: core.StatusValid, URI: domainName, Token: "THISWOULDNTBEAGOODTOKEN"}
combos := make([][]int, 1)
combos[0] = []int{0, 1}
exp := time.Now().AddDate(0, 0, 1) // expire in 1 day

View File

@ -11,7 +11,6 @@ import (
"database/sql"
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"net/http"
"regexp"
@ -32,6 +31,7 @@ const (
RegPath = "/acme/reg/"
NewAuthzPath = "/acme/new-authz"
AuthzPath = "/acme/authz/"
ChallengePath = "/acme/challenge/"
NewCertPath = "/acme/new-cert"
CertPath = "/acme/cert/"
RevokeCertPath = "/acme/revoke-cert"
@ -47,13 +47,14 @@ type WebFrontEndImpl struct {
log *blog.AuditLogger
// URL configuration parameters
BaseURL string
NewReg string
RegBase string
NewAuthz string
AuthzBase string
NewCert string
CertBase string
BaseURL string
NewReg string
RegBase string
NewAuthz string
AuthzBase string
ChallengeBase string
NewCert string
CertBase string
// JSON encoded endpoint directory
DirectoryJSON []byte
@ -195,6 +196,7 @@ func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {
wfe.RegBase = wfe.BaseURL + RegPath
wfe.NewAuthz = wfe.BaseURL + NewAuthzPath
wfe.AuthzBase = wfe.BaseURL + AuthzPath
wfe.ChallengeBase = wfe.BaseURL + ChallengePath
wfe.NewCert = wfe.BaseURL + NewCertPath
wfe.CertBase = wfe.BaseURL + CertPath
@ -212,18 +214,22 @@ func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {
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")
wfe.HandleFunc(m, RegPath, wfe.Registration, "POST")
wfe.HandleFunc(m, AuthzPath, wfe.Authorization, "GET", "POST")
wfe.HandleFunc(m, AuthzPath, wfe.Authorization, "GET")
wfe.HandleFunc(m, ChallengePath, wfe.Challenge, "GET", "POST")
wfe.HandleFunc(m, CertPath, wfe.Certificate, "GET")
wfe.HandleFunc(m, RevokeCertPath, wfe.RevokeCertificate, "POST")
wfe.HandleFunc(m, TermsPath, wfe.Terms, "GET")
wfe.HandleFunc(m, IssuerPath, wfe.Issuer, "GET")
wfe.HandleFunc(m, BuildIDPath, wfe.BuildID, "GET")
// 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
// https://github.com/letsencrypt/boulder/issues/717
m.HandleFunc("/", wfe.Index)
return m, nil
}
@ -243,16 +249,22 @@ func (wfe *WebFrontEndImpl) Index(response http.ResponseWriter, request *http.Re
return
}
tmpl := template.Must(template.New("body").Parse(`<html>
<body>
This is an <a href="https://github.com/letsencrypt/acme-spec/">ACME</a>
Certificate Authority running <a href="https://github.com/letsencrypt/boulder">Boulder</a>,
New registration is available at <a href="{{.NewReg}}">{{.NewReg}}</a>.
</body>
</html>
`))
tmpl.Execute(response, wfe)
if request.Method != "GET" {
logEvent.Error = "Bad method"
response.Header().Set("Allow", "GET")
response.WriteHeader(http.StatusMethodNotAllowed)
return
}
response.Header().Set("Content-Type", "text/html")
response.Write([]byte(fmt.Sprintf(`<html>
<body>
This is an <a href="https://github.com/letsencrypt/acme-spec/">ACME</a>
Certificate Authority running <a href="https://github.com/letsencrypt/boulder">Boulder</a>.
JSON directory is available at <a href="%s">%s</a>.
</body>
</html>
`, DirectoryPath, DirectoryPath)))
addCacheHeader(response, wfe.IndexCacheDuration.Seconds())
}
@ -265,6 +277,7 @@ func addCacheHeader(w http.ResponseWriter, age float64) {
}
func (wfe *WebFrontEndImpl) Directory(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "application/json")
response.Write(wfe.DirectoryJSON)
}
@ -554,8 +567,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
// Make a URL for this authz, then blow away the ID and RegID before serializing
authzURL := wfe.AuthzBase + string(authz.ID)
authz.ID = ""
authz.RegistrationID = 0
wfe.prepAuthorizationForDisplay(&authz)
responseBody, err := json.Marshal(authz)
if err != nil {
logEvent.Error = err.Error()
@ -773,46 +785,93 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
wfe.Stats.Inc("Certificates", 1, 1.0)
}
func (wfe *WebFrontEndImpl) challenge(
func (wfe *WebFrontEndImpl) Challenge(
response http.ResponseWriter,
request *http.Request,
authz core.Authorization,
logEvent *requestEvent) {
request *http.Request) {
logEvent := wfe.populateRequestEvent(request)
defer wfe.logRequestDetails(&logEvent)
// Check that the requested challenge exists within the authorization
found := false
var challengeIndex int
var challenge core.Challenge
for i, challenge := range authz.Challenges {
tempURL := challenge.URI
if tempURL.Path == request.URL.Path && tempURL.RawQuery == request.URL.RawQuery {
found = true
challengeIndex = i
break
}
notFound := func() {
wfe.sendError(response, "No such registration", request.URL.Path, http.StatusNotFound)
}
if !found {
logEvent.Error = "Unable to find challenge"
wfe.sendError(response, logEvent.Error, request.URL.RawQuery, http.StatusNotFound)
// Challenge URIs are of the form /acme/challenge/<auth id>/<challenge id>.
// Here we parse out the id components. TODO: Use a better tool to parse out
// URL structure: https://github.com/letsencrypt/boulder/issues/437
slug := strings.Split(request.URL.Path[len(ChallengePath):], "/")
if len(slug) != 2 {
notFound()
return
}
authorizationID := slug[0]
challengeID, err := strconv.ParseInt(slug[1], 10, 64)
if err != nil {
notFound()
return
}
logEvent.Extra["AuthorizationID"] = authorizationID
logEvent.Extra["ChallengeID"] = challengeID
authz, err := wfe.SA.GetAuthorization(authorizationID)
if err != nil {
notFound()
return
}
// Check that the requested challenge exists within the authorization
challengeIndex := authz.FindChallenge(challengeID)
if challengeIndex == -1 {
notFound()
return
}
challenge := authz.Challenges[challengeIndex]
logEvent.Extra["ChallengeType"] = challenge.Type
logEvent.Extra["AuthorizationRegistrationID"] = authz.RegistrationID
logEvent.Extra["AuthorizationIdentifier"] = authz.Identifier
logEvent.Extra["AuthorizationStatus"] = authz.Status
logEvent.Extra["AuthorizationExpires"] = authz.Expires
switch request.Method {
case "GET":
wfe.getChallenge(response, request, authz, challenge, logEvent)
wfe.getChallenge(response, request, authz, &challenge, &logEvent)
case "POST":
wfe.postChallenge(response, request, authz, challengeIndex, logEvent)
wfe.postChallenge(response, request, authz, challengeIndex, &logEvent)
}
}
// prepChallengeForDisplay takes a core.Challenge and prepares it for display to
// the client by filling in its URI field and clearing its AccountKey and ID
// fields.
// TODO: Come up with a cleaner way to do this.
// https://github.com/letsencrypt/boulder/issues/761
func (wfe *WebFrontEndImpl) prepChallengeForDisplay(authz core.Authorization, challenge *core.Challenge) {
challenge.URI = fmt.Sprintf("%s%s/%d", wfe.ChallengeBase, authz.ID, challenge.ID)
challenge.AccountKey = nil
// 0 is considered "empty" for the purpose of the JSON omitempty tag.
challenge.ID = 0
}
// prepAuthorizationForDisplay takes a core.Authorization and prepares it for
// display to the client by clearing its ID and RegistrationID fields, and
// preparing all its challenges.
func (wfe *WebFrontEndImpl) prepAuthorizationForDisplay(authz *core.Authorization) {
for i, _ := range authz.Challenges {
wfe.prepChallengeForDisplay(*authz, &authz.Challenges[i])
}
authz.ID = ""
authz.RegistrationID = 0
}
func (wfe *WebFrontEndImpl) getChallenge(
response http.ResponseWriter,
request *http.Request,
authz core.Authorization,
challenge core.Challenge,
challenge *core.Challenge,
logEvent *requestEvent) {
wfe.prepChallengeForDisplay(authz, challenge)
jsonReply, err := json.Marshal(challenge)
if err != nil {
logEvent.Error = err.Error()
@ -823,7 +882,7 @@ func (wfe *WebFrontEndImpl) getChallenge(
}
authzURL := wfe.AuthzBase + string(authz.ID)
response.Header().Add("Location", challenge.URI.String())
response.Header().Add("Location", challenge.URI)
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(authzURL, "up"))
response.WriteHeader(http.StatusAccepted)
@ -890,6 +949,7 @@ func (wfe *WebFrontEndImpl) postChallenge(
// assumption: UpdateAuthorization does not modify order of challenges
challenge := updatedAuthorization.Challenges[challengeIndex]
wfe.prepChallengeForDisplay(authz, &challenge)
jsonReply, err := json.Marshal(challenge)
if err != nil {
logEvent.Error = err.Error()
@ -899,7 +959,7 @@ func (wfe *WebFrontEndImpl) postChallenge(
}
authzURL := wfe.AuthzBase + string(authz.ID)
response.Header().Add("Location", challenge.URI.String())
response.Header().Add("Location", challenge.URI)
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(authzURL, "up"))
response.WriteHeader(http.StatusAccepted)
@ -1013,31 +1073,8 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
logEvent.Extra["AuthorizationStatus"] = authz.Status
logEvent.Extra["AuthorizationExpires"] = authz.Expires
// If there is a fragment, then this is actually a request to a challenge URI
if len(request.URL.RawQuery) != 0 {
wfe.challenge(response, request, authz, &logEvent)
} else if request.Method == "GET" {
wfe.GetAuthorization(response, request, authz, &logEvent)
} else {
// For challenges, POST and GET are allowed. For authorizations only GET is
// allowed.
// TODO(jsha): Split challenge updates into a different path so we can use
// the HandleFunc functionality for declaring allowed methods.
// https://github.com/letsencrypt/boulder/issues/638
logEvent.Error = "Method not allowed"
response.Header().Set("Allow", "GET")
wfe.sendError(response, logEvent.Error, request.Method, http.StatusMethodNotAllowed)
}
}
wfe.prepAuthorizationForDisplay(&authz)
func (wfe *WebFrontEndImpl) GetAuthorization(
response http.ResponseWriter,
request *http.Request,
authz core.Authorization,
logEvent *requestEvent) {
// Blank out ID and regID
authz.ID = ""
authz.RegistrationID = 0
jsonReply, err := json.Marshal(authz)
if err != nil {
logEvent.Error = err.Error()

View File

@ -156,7 +156,20 @@ func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration,
func (sa *MockSA) GetAuthorization(id string) (core.Authorization, error) {
if id == "valid" {
exp := time.Now().AddDate(100, 0, 0)
return core.Authorization{Status: core.StatusValid, RegistrationID: 1, Expires: &exp, Identifier: core.AcmeIdentifier{Type: "dns", Value: "not-an-example.com"}}, nil
return core.Authorization{
ID: "valid",
Status: core.StatusValid,
RegistrationID: 1,
Expires: &exp,
Identifier: core.AcmeIdentifier{Type: "dns", Value: "not-an-example.com"},
Challenges: []core.Challenge{
core.Challenge{
ID: 23,
Type: "dns",
URI: "http://localhost:4300/acme/challenge/valid/23",
},
},
}, nil
}
return core.Authorization{}, nil
}
@ -343,6 +356,7 @@ func setupWFE(t *testing.T) WebFrontEndImpl {
wfe.RegBase = wfe.BaseURL + RegPath
wfe.NewAuthz = wfe.BaseURL + NewAuthzPath
wfe.AuthzBase = wfe.BaseURL + AuthzPath
wfe.ChallengeBase = wfe.BaseURL + ChallengePath
wfe.NewCert = wfe.BaseURL + NewCertPath
wfe.CertBase = wfe.BaseURL + CertPath
wfe.SubscriberAgreementURL = agreementURL
@ -458,11 +472,11 @@ func TestStandardHeaders(t *testing.T) {
path string
allowed []string
}{
{"/", []string{"GET"}},
{wfe.NewReg, []string{"POST"}},
{wfe.RegBase, []string{"POST"}},
{wfe.NewAuthz, []string{"POST"}},
{wfe.AuthzBase, []string{"GET", "POST"}},
{wfe.AuthzBase, []string{"GET"}},
{wfe.ChallengeBase, []string{"GET", "POST"}},
{wfe.NewCert, []string{"POST"}},
{wfe.CertBase, []string{"GET"}},
{wfe.SubscriberAgreementURL, []string{"GET"}},
@ -484,6 +498,28 @@ func TestStandardHeaders(t *testing.T) {
}
}
func TestIndexPOST(t *testing.T) {
wfe := setupWFE(t)
responseWriter := httptest.NewRecorder()
url, _ := url.Parse("/")
wfe.Index(responseWriter, &http.Request{
Method: "POST",
URL: url,
})
test.AssertEquals(t, responseWriter.Code, http.StatusMethodNotAllowed)
}
func TestPOST404(t *testing.T) {
wfe := setupWFE(t)
responseWriter := httptest.NewRecorder()
url, _ := url.Parse("/foobar")
wfe.Index(responseWriter, &http.Request{
Method: "POST",
URL: url,
})
test.AssertEquals(t, responseWriter.Code, http.StatusNotFound)
}
func TestIndex(t *testing.T) {
wfe := setupWFE(t)
wfe.IndexCacheDuration = time.Second * 10
@ -497,8 +533,8 @@ func TestIndex(t *testing.T) {
})
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
test.AssertNotEquals(t, responseWriter.Body.String(), "404 page not found\n")
test.Assert(t, strings.Contains(responseWriter.Body.String(), wfe.NewReg),
"new-reg not found")
test.Assert(t, strings.Contains(responseWriter.Body.String(), DirectoryPath),
"directory path not found")
test.AssertEquals(t, responseWriter.Header().Get("Cache-Control"), "public, max-age=10")
responseWriter.Body.Reset()
@ -525,6 +561,7 @@ func TestDirectory(t *testing.T) {
Method: "GET",
URL: url,
})
test.AssertEquals(t, responseWriter.Header().Get("Content-Type"), "application/json")
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"}`)
}
@ -675,37 +712,21 @@ func TestChallenge(t *testing.T) {
`), &key)
test.AssertNotError(t, err, "Could not unmarshal testing key")
challengeURL := "/acme/authz/asdf?challenge=foo"
challengeAcme := (*core.AcmeURL)(mustParseURL(challengeURL))
authz := core.Authorization{
ID: "asdf",
Identifier: core.AcmeIdentifier{
Type: "dns",
Value: "letsencrypt.org",
},
Challenges: []core.Challenge{
core.Challenge{
Type: "dns",
URI: challengeAcme,
},
},
RegistrationID: 1,
}
wfe.challenge(responseWriter,
challengeURL := "/acme/challenge/valid/23"
wfe.Challenge(responseWriter,
makePostRequestWithPath(challengeURL,
signRequest(t, `{"resource":"challenge"}`, &wfe.nonceService)),
authz, &requestEvent{})
signRequest(t, `{"resource":"challenge"}`, &wfe.nonceService)))
test.AssertEquals(t, responseWriter.Code, 202)
test.AssertEquals(
t, responseWriter.Header().Get("Location"),
"/acme/authz/asdf?challenge=foo")
challengeURL)
test.AssertEquals(
t, responseWriter.Header().Get("Link"),
`</acme/authz/asdf>;rel="up"`)
`</acme/authz/valid>;rel="up"`)
test.AssertEquals(
t, responseWriter.Body.String(),
`{"type":"dns","uri":"/acme/authz/asdf?challenge=foo"}`)
`{"type":"dns","uri":"/acme/challenge/valid/23"}`)
}
func TestNewRegistration(t *testing.T) {