switch authz and pending_authz to store registration ID instead of key (and update all the random stuff they touched)

This commit is contained in:
Roland Shoemaker 2015-05-14 14:14:36 -07:00
parent 672f0b1fbe
commit e233fdaa61
9 changed files with 75 additions and 41 deletions

View File

@ -53,7 +53,7 @@ type RegistrationAuthority interface {
NewRegistration(Registration, jose.JsonWebKey) (Registration, error)
// [WebFrontEnd]
NewAuthorization(Authorization, jose.JsonWebKey) (Authorization, error)
NewAuthorization(Authorization, int) (Authorization, error)
// [WebFrontEnd]
NewCertificate(CertificateRequest, jose.JsonWebKey) (Certificate, error)
@ -88,7 +88,7 @@ type PolicyAuthority interface {
}
type StorageGetter interface {
GetRegistration(string) (Registration, error)
GetRegistration(int) (Registration, error)
GetRegistrationByKey(jose.JsonWebKey) (Registration, error)
GetAuthorization(string) (Authorization, error)
GetCertificate(string) ([]byte, error)

View File

@ -100,7 +100,7 @@ func (cr CertificateRequest) MarshalJSON() ([]byte, error) {
// to account keys.
type Registration struct {
// Unique identifier
ID string `json:"-" db:"id"`
ID int `json:"-" db:"id"`
// Account key to which the details are attached
Key jose.JsonWebKey `json:"key" db:"key"`
@ -261,7 +261,9 @@ type Authorization struct {
Identifier AcmeIdentifier `json:"identifier,omitempty" db:"identifier"`
// The account key that is authorized for the identifier
Key jose.JsonWebKey `json:"key,omitempty" db:"key"`
// Key jose.JsonWebKey `json:"key,omitempty" db:"key"`
// The registration ID associated with the authorization
RegID int `json:"regID,omitempty" db:"regID"`
// The status of the validation of this authorization
Status AcmeStatus `json:"status,omitempty" db:"status"`

View File

@ -58,7 +58,7 @@ func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration, key
return
}
func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, key jose.JsonWebKey) (authz core.Authorization, err error) {
func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int) (authz core.Authorization, err error) {
identifier := request.Identifier
// Check that the identifier is present and appropriate
@ -88,7 +88,7 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
authz = core.Authorization{
ID: authID,
Identifier: identifier,
Key: key,
RegID: regID,
Status: core.StatusPending,
Challenges: challenges,
Combinations: combinations,
@ -120,6 +120,11 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
return emptyCert, err
}
registration, err := ra.SA.GetRegistrationByKey(requestKey)
if err != nil {
return emptyCert, err
}
// Gather authorized domains from the referenced authorizations
authorizedDomains := map[string]bool{}
now := time.Now()
@ -127,7 +132,7 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
id := lastPathSegment(url)
authz, err := ra.SA.GetAuthorization(id)
if err != nil || // Couldn't find authorization
!core.KeyDigestEquals(authz.Key, requestKey) ||
authz.RegID != registration.ID || // Key doesn't match
authz.Status != core.StatusValid || // Not finalized or not successful
authz.Expires.Before(now) || // Expired
authz.Identifier.Type != core.IdentifierDNS {

View File

@ -127,14 +127,14 @@ func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) {
test.Assert(t, a1.ID == a2.ID, "ret != DB: ID")
test.Assert(t, a1.Identifier == a2.Identifier, "ret != DB: Identifier")
test.Assert(t, a1.Status == a2.Status, "ret != DB: Status")
test.Assert(t, core.KeyDigestEquals(a1.Key, a2.Key), "ret != DB: Key")
test.Assert(t, a1.RegID == a2.RegID, "ret != DB: Key")
// Not testing: Contact, Challenges
}
func TestNewAuthorization(t *testing.T) {
_, _, sa, ra := initAuthorities(t)
authz, err := ra.NewAuthorization(AuthzRequest, AccountKey)
authz, err := ra.NewAuthorization(AuthzRequest, 1)
test.AssertNotError(t, err, "NewAuthorization failed")
// Verify that returned authz same as DB
@ -143,7 +143,7 @@ func TestNewAuthorization(t *testing.T) {
assertAuthzEqual(t, authz, dbAuthz)
// Verify that the returned authz has the right information
test.Assert(t, core.KeyDigestEquals(authz.Key, AccountKey), "Initial authz did not get the right key")
test.Assert(t, authz.RegID == 1, "Initial authz did not get the right key")
test.Assert(t, authz.Identifier == AuthzRequest.Identifier, "Initial authz had wrong identifier")
test.Assert(t, authz.Status == core.StatusPending, "Initial authz not pending")
@ -216,6 +216,8 @@ func TestOnValidationUpdate(t *testing.T) {
func TestNewCertificate(t *testing.T) {
_, _, sa, ra := initAuthorities(t)
sa.NewRegistration(core.Registration{Key: AccountKey})
AuthzFinal.RegID = 1
AuthzFinal.ID, _ = sa.NewPendingAuthorization()
sa.UpdatePendingAuthorization(AuthzFinal)
sa.FinalizeAuthorization(AuthzFinal)
@ -225,6 +227,7 @@ func TestNewCertificate(t *testing.T) {
AuthzFinalWWW.Identifier.Value = "www.example.com"
AuthzFinalWWW.ID, _ = sa.NewPendingAuthorization()
sa.FinalizeAuthorization(AuthzFinalWWW)
sa.DumpTables()
// Construct a cert request referencing the two authorizations
url1, _ := url.Parse("http://doesnt.matter/" + AuthzFinal.ID)

View File

@ -70,7 +70,7 @@ type registrationRequest struct {
type authorizationRequest struct {
Authz core.Authorization
Key jose.JsonWebKey
RegID int
}
type certificateRequest struct {
@ -106,7 +106,7 @@ func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, i
return nil
}
authz, err := impl.NewAuthorization(ar.Authz, ar.Key)
authz, err := impl.NewAuthorization(ar.Authz, ar.RegID)
if err != nil {
return nil
}
@ -239,8 +239,8 @@ func (rac RegistrationAuthorityClient) NewRegistration(reg core.Registration, ke
return
}
func (rac RegistrationAuthorityClient) NewAuthorization(authz core.Authorization, key jose.JsonWebKey) (newAuthz core.Authorization, err error) {
data, err := json.Marshal(authorizationRequest{authz, key})
func (rac RegistrationAuthorityClient) NewAuthorization(authz core.Authorization, regID int) (newAuthz core.Authorization, err error) {
data, err := json.Marshal(authorizationRequest{authz, regID})
if err != nil {
return
}
@ -436,7 +436,15 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
rpc := NewAmqpRPCServer(serverQueue, channel)
rpc.Handle(MethodGetRegistration, func(req []byte) (response []byte) {
reg, err := impl.GetRegistration(string(req))
var intReq struct {
ID int
}
err := json.Unmarshal(req, &intReq)
if err != nil {
return nil
}
reg, err := impl.GetRegistration(intReq.ID)
if err != nil {
return nil
}
@ -635,8 +643,18 @@ func NewStorageAuthorityClient(clientQueue, serverQueue string, channel *amqp.Ch
return
}
func (cac StorageAuthorityClient) GetRegistration(id string) (reg core.Registration, err error) {
jsonReg, err := cac.rpc.DispatchSync(MethodGetRegistration, []byte(id))
func (cac StorageAuthorityClient) GetRegistration(id int) (reg core.Registration, err error) {
var intReq struct {
ID int
}
intReq.ID = id
data, err := json.Marshal(intReq)
if err != nil {
return
}
jsonReg, err := cac.rpc.DispatchSync(MethodGetRegistration, data)
if err != nil {
return
}

View File

@ -175,7 +175,7 @@ func NewSQLStorageAuthority(driver string, name string) (ssa *SQLStorageAuthorit
}
func (ssa *SQLStorageAuthority) InitTables() (err error) {
ssa.dbMap.AddTableWithName(core.Registration{}, "registrations").SetKeys(false, "ID").SetVersionCol("LockCol")
ssa.dbMap.AddTableWithName(core.Registration{}, "registrations").SetKeys(true, "ID").SetVersionCol("LockCol")
ssa.dbMap.AddTableWithName(pendingauthzModel{}, "pending_authz").SetKeys(false, "ID").SetVersionCol("LockCol")
ssa.dbMap.AddTableWithName(authzModel{}, "authz").SetKeys(false, "ID")
ssa.dbMap.AddTableWithName(core.Certificate{}, "certificates").SetKeys(false, "Serial")
@ -305,19 +305,19 @@ func existingFinal(tx *gorp.Transaction, id string) (bool) {
return count > 0
}
func existingRegistration(tx *gorp.Transaction, id string) (bool) {
func existingRegistration(tx *gorp.Transaction, id int) (bool) {
var count int64
_ = tx.SelectOne(&count, "SELECT count(*) FROM registrations WHERE id = :id", map[string]interface{} {"id": id})
return count > 0
}
func (ssa *SQLStorageAuthority) GetRegistration(id string) (reg core.Registration, err error) {
func (ssa *SQLStorageAuthority) GetRegistration(id int) (reg core.Registration, err error) {
regObj, err := ssa.dbMap.Get(core.Registration{}, id)
if err != nil {
return
}
if regObj == nil {
err = fmt.Errorf("No registrations with ID %s", id)
err = fmt.Errorf("No registrations with ID %d", id)
return
}
reg = *regObj.(*core.Registration)
@ -432,11 +432,11 @@ func (ssa *SQLStorageAuthority) NewRegistration(reg core.Registration) (output c
}
// Check that it doesn't exist already
id := core.NewToken()
/*id := core.NewToken()
for existingRegistration(tx, id) {
id = core.NewToken()
}
reg.ID = id
reg.ID = id*/
err = tx.Insert(&reg)
if err != nil {
@ -506,7 +506,7 @@ func (ssa *SQLStorageAuthority) UpdateRegistration(reg core.Registration) (err e
}
if !existingRegistration(tx, reg.ID) {
err = errors.New("Requested registration not found " + reg.ID)
err = fmt.Errorf("Requested registration not found %v", reg.ID)
tx.Rollback()
return
}

View File

@ -11,6 +11,7 @@ import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"fmt"
"net/url"
"time"
@ -53,10 +54,10 @@ func TestAddRegistration(t *testing.T) {
Key: jwk,
})
test.AssertNotError(t, err, "Couldn't create new registration")
test.Assert(t, reg.ID != "", "ID shouldn't be blank")
// test.Assert(t, reg.ID != "", "ID shouldn't be blank")
dbReg, err := sa.GetRegistration(reg.ID)
test.AssertNotError(t, err, "Couldn't get registration with ID "+reg.ID)
test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.ID))
expectedReg := core.Registration{
ID: reg.ID,
@ -70,7 +71,7 @@ func TestAddRegistration(t *testing.T) {
newReg := core.Registration{ID: reg.ID, Key: jwk, RecoveryToken: "RBNvo1WzZ4oRRq0W9", Contact: []core.AcmeURL{u}, Agreement: "yes"}
err = sa.UpdateRegistration(newReg)
test.AssertNotError(t, err, "Couldn't update registration with ID "+reg.ID)
test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.ID))
dbReg, err = sa.GetRegistrationByKey(jwk)
test.AssertNotError(t, err, "Couldn't update registration by key")
@ -109,7 +110,7 @@ func TestAddAuthorization(t *testing.T) {
combos[0] = []int{0,1}
newPa := core.Authorization{ID: paID, Identifier: core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "wut.com"}, Key: jwk, Status: core.StatusPending, Expires: time.Now().AddDate(0, 0, 1), Challenges: []core.Challenge{chall}, Combinations: combos, Contact: []core.AcmeURL{u}}
newPa := core.Authorization{ID: paID, Identifier: core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "wut.com"}, RegID: 0, Status: core.StatusPending, Expires: time.Now().AddDate(0, 0, 1), Challenges: []core.Challenge{chall}, Combinations: combos, Contact: []core.AcmeURL{u}}
err = sa.UpdatePendingAuthorization(newPa)
test.AssertNotError(t, err, "Couldn't update pending authorization with ID "+paID)

View File

@ -15,6 +15,7 @@ import (
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
@ -248,7 +249,6 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
}
regURL := wfe.RegBase + string(reg.ID)
reg.ID = ""
responseBody, err := json.Marshal(reg)
if err != nil {
wfe.sendError(response, "Error marshaling authz", http.StatusInternalServerError)
@ -275,7 +275,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
return
}
body, key, _, err := wfe.verifyPOST(request, true)
body, _, currReg, err := wfe.verifyPOST(request, true)
if err != nil {
if err == sql.ErrNoRows {
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
@ -293,7 +293,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
}
// Create new authz and return
authz, err := wfe.RA.NewAuthorization(init, *key)
authz, err := wfe.RA.NewAuthorization(init, currReg.ID)
if err != nil {
wfe.sendError(response,
fmt.Sprintf("Error creating new authz: %+v", err),
@ -408,7 +408,7 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
return
case "POST":
body, key, _, err := wfe.verifyPOST(request, true)
body, _, currReg, err := wfe.verifyPOST(request, true)
if err != nil {
if err == sql.ErrNoRows {
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
@ -426,7 +426,7 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
}
// Check that the signing key is the right key
if !core.KeyDigestEquals(key, authz.Key) {
if currReg.ID != authz.RegID {
wfe.sendError(response, "Signing key does not match key in authorization", http.StatusForbidden)
return
}
@ -462,7 +462,12 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *http.Request) {
// Requests to this handler should have a path that leads to a known
// registration
id := parseIDFromPath(request.URL.Path)
idStr := parseIDFromPath(request.URL.Path)
id, err := strconv.Atoi(idStr)
if err != nil {
wfe.sendError(response, "Registration ID must be an integer", http.StatusBadRequest)
return
}
reg, err := wfe.SA.GetRegistration(id)
if err != nil {
wfe.sendError(response,
@ -488,7 +493,7 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
response.Write(jsonReply)
case "POST":
body, _, _, err := wfe.verifyPOST(request, true)
body, _, currReg, err := wfe.verifyPOST(request, true)
if err != nil {
if err == sql.ErrNoRows {
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
@ -506,7 +511,7 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
}
// Ask the RA to update this authorization
updatedReg, err := wfe.RA.UpdateRegistration(reg, update)
updatedReg, err := wfe.RA.UpdateRegistration(currReg, update)
if err != nil {
wfe.sendError(response, "Unable to update registration", http.StatusInternalServerError)
return

View File

@ -29,7 +29,7 @@ type MockSA struct {
// empty
}
func (sa *MockSA) GetRegistration(string) (core.Registration, error) {
func (sa *MockSA) GetRegistration(int) (core.Registration, error) {
return core.Registration{}, nil
}
@ -244,8 +244,8 @@ func (ra *MockRegistrationAuthority) NewRegistration(reg core.Registration, jwk
return reg, nil
}
func (ra *MockRegistrationAuthority) NewAuthorization(authz core.Authorization, jwk jose.JsonWebKey) (core.Authorization, error) {
authz.Key = jwk
func (ra *MockRegistrationAuthority) NewAuthorization(authz core.Authorization, regID int) (core.Authorization, error) {
authz.RegID = regID
return authz, nil
}
@ -296,7 +296,7 @@ func TestChallenge(t *testing.T) {
URI: core.AcmeURL(*challengeURL),
},
},
Key: key,
RegID: 0,
}
wfe.Challenge(authz, responseWriter, &http.Request{
@ -500,7 +500,7 @@ func TestAuthorization(t *testing.T) {
Body: makeBody(signRequest(t, "{\"identifier\":{\"type\":\"dns\",\"value\":\"test.com\"}}")),
})
test.AssertEquals(t, responseWriter.Body.String(), "{\"identifier\":{\"type\":\"dns\",\"value\":\"test.com\"},\"key\":{\"kty\":\"RSA\",\"n\":\"z2NsNdHeqAiGdPP8KuxfQXat_uatOK9y12SyGpfKw1sfkizBIsNxERjNDke6Wp9MugN9srN3sr2TDkmQ-gK8lfWo0v1uG_QgzJb1vBdf_hH7aejgETRGLNJZOdaKDsyFnWq1WGJq36zsHcd0qhggTk6zVwqczSxdiWIAZzEakIUZ13KxXvoepYLY0Q-rEEQiuX71e4hvhfeJ4l7m_B-awn22UUVvo3kCqmaRlZT-36vmQhDGoBsoUo1KBEU44jfeK5PbNRk7vDJuH0B7qinr_jczHcvyD-2TtPzKaCioMtNh_VZbPNDaG67sYkQlC15-Ff3HPzKKJW2XvkVG91qMvQ\",\"e\":\"AAEAAQ\"},\"expires\":\"0001-01-01T00:00:00Z\"}")
test.AssertEquals(t, responseWriter.Body.String(), "{\"identifier\":{\"type\":\"dns\",\"value\":\"test.com\"},\"expires\":\"0001-01-01T00:00:00Z\"}")
var authz core.Authorization
err := json.Unmarshal([]byte(responseWriter.Body.String()), &authz)