Disallow GETs for Registration.
Per the spec, authenticated requests must be signed by an account key, and GET requests can't be signed under the current protocol. If the account holder wishes to fetch their current registration, they can do so by posting a signed, empty update to their registration resource. Also fix a bug in generating registration URLs.
This commit is contained in:
parent
1c251bc19a
commit
8dd4c650bd
|
|
@ -132,12 +132,17 @@ function parseLink(link) {
|
|||
}
|
||||
|
||||
function post(url, body, callback) {
|
||||
var jws = crypto.generateSignature(state.accountPrivateKey, new Buffer(JSON.stringify(body)));
|
||||
var payload = JSON.stringify(jws);
|
||||
var payload = JSON.stringify(body, null, 2);
|
||||
var jws = crypto.generateSignature(state.accountPrivateKey, new Buffer(payload));
|
||||
var signed = JSON.stringify(jws, null, 2);
|
||||
|
||||
var req = request.post(url, callback);
|
||||
console.log('Posting to', url, ':\n', payload);
|
||||
req.write(payload)
|
||||
console.log('Posting to', url, ':\n', signed);
|
||||
console.log('Payload:', payload);
|
||||
req.on('response', function(response) {
|
||||
console.log(response.headers)
|
||||
})
|
||||
req.write(signed)
|
||||
req.end();
|
||||
return req;
|
||||
}
|
||||
|
|
@ -276,13 +281,13 @@ function sendAgreement(answers) {
|
|||
post(state.registrationURL, state.registration,
|
||||
function(err, resp, body) {
|
||||
if (err || Math.floor(resp.statusCode / 100) != 2) {
|
||||
console.log("Couldn't POST agreement back to server, aborting.");
|
||||
console.log("error: " + err);
|
||||
console.log(body);
|
||||
console.log("error: " + err);
|
||||
console.log("Couldn't POST agreement back to server, aborting.");
|
||||
process.exit(1);
|
||||
} else {
|
||||
inquirer.prompt(questions.domain, getChallenges);
|
||||
}
|
||||
|
||||
inquirer.prompt(questions.domain, getChallenges);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
|
|||
return
|
||||
}
|
||||
|
||||
regURL := wfe.RegBase + string(reg.ID)
|
||||
regURL := fmt.Sprintf("%s%d", wfe.RegBase, reg.ID)
|
||||
responseBody, err := json.Marshal(reg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Error marshaling authz", err, http.StatusInternalServerError)
|
||||
|
|
@ -554,6 +554,24 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
|
|||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *http.Request) {
|
||||
if request.Method != "POST" {
|
||||
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, _, currReg, err := wfe.verifyPOST(request, true)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
wfe.sendError(response,
|
||||
"No registration exists matching provided key",
|
||||
err, http.StatusForbidden)
|
||||
} else {
|
||||
wfe.sendError(response,
|
||||
"Unable to read/verify body", err, http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Requests to this handler should have a path that leads to a known
|
||||
// registration
|
||||
idStr := parseIDFromPath(request.URL.Path)
|
||||
|
|
@ -564,66 +582,38 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
|
|||
} else if id <= 0 {
|
||||
wfe.sendError(response, "Registration ID must be a positive non-zero integer", id, http.StatusBadRequest)
|
||||
return
|
||||
} else if id != currReg.ID {
|
||||
wfe.sendError(response, "Request signing key did not match registration key", "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
reg, err := wfe.SA.GetRegistration(id)
|
||||
|
||||
var update core.Registration
|
||||
err = json.Unmarshal(body, &update)
|
||||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
"Unable to find registration", err,
|
||||
http.StatusNotFound)
|
||||
wfe.sendError(response, "Error unmarshaling registration", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
reg.ID = id
|
||||
|
||||
switch request.Method {
|
||||
default:
|
||||
wfe.sendError(response, "Method not allowed", "", http.StatusMethodNotAllowed)
|
||||
// MergeUpdate copies over only the fields that a client is allowed to modify.
|
||||
// Note: The RA will also use MergeUpdate to filter out non-updateable fields,
|
||||
// but we do it here too, so that/ input filtering happens as early in the
|
||||
// request processing as possible.
|
||||
currReg.MergeUpdate(update)
|
||||
// Ask the RA to update this authorization.
|
||||
updatedReg, err := wfe.RA.UpdateRegistration(currReg, currReg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to update registration", err, http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
case "GET":
|
||||
jsonReply, err := json.Marshal(reg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
response.WriteHeader(http.StatusOK)
|
||||
response.Write(jsonReply)
|
||||
|
||||
case "POST":
|
||||
body, _, currReg, err := wfe.verifyPOST(request, true)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
wfe.sendError(response, "No registration exists matching provided key", err, http.StatusForbidden)
|
||||
} else {
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var update core.Registration
|
||||
err = json.Unmarshal(body, &update)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Error unmarshaling registration", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Ask the RA to update this authorization
|
||||
updatedReg, err := wfe.RA.UpdateRegistration(currReg, update)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to update registration", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jsonReply, err := json.Marshal(updatedReg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
response.Write(jsonReply)
|
||||
|
||||
}
|
||||
|
||||
jsonReply, err := json.Marshal(updatedReg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
response.Write(jsonReply)
|
||||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request *http.Request) {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ func (sa *MockSA) GetRegistration(id int64) (core.Registration, error) {
|
|||
var parsedKey jose.JsonWebKey
|
||||
parsedKey.UnmarshalJSON(keyJSON)
|
||||
|
||||
return core.Registration{Key: parsedKey}, nil
|
||||
return core.Registration{ID: id, Key: parsedKey}, nil
|
||||
}
|
||||
|
||||
func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) {
|
||||
|
|
@ -106,7 +106,7 @@ func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration,
|
|||
|
||||
if core.KeyDigestEquals(jwk, test2KeyPublic) {
|
||||
// No key found
|
||||
return core.Registration{}, sql.ErrNoRows
|
||||
return core.Registration{ID: 2}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
// Return a fake registration
|
||||
|
|
@ -602,35 +602,15 @@ func TestRegistration(t *testing.T) {
|
|||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test GET missing entry
|
||||
path, _ = url.Parse("/100")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to find registration\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test GET malformed entry
|
||||
path, _ = url.Parse("/101")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:serverInternal\",\"detail\":\"Failed to marshal authz\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test GET proper entry
|
||||
// Test GET proper entry returns 405
|
||||
path, _ = url.Parse("/1")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: path,
|
||||
})
|
||||
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST invalid JSON
|
||||
|
|
@ -646,7 +626,7 @@ func TestRegistration(t *testing.T) {
|
|||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST valid JSON but key is not registered
|
||||
path, _ = url.Parse("/1")
|
||||
path, _ = url.Parse("/2")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(`{
|
||||
|
|
@ -662,7 +642,7 @@ func TestRegistration(t *testing.T) {
|
|||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST valid JSON with registration up in the mock
|
||||
path, _ = url.Parse("/2")
|
||||
path, _ = url.Parse("/1")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(`{
|
||||
|
|
|
|||
Loading…
Reference in New Issue