Switch to real model vs. view

This commit is contained in:
Roland Shoemaker 2015-08-18 16:38:06 -07:00
parent 015e089b7d
commit 69edf779b5
6 changed files with 115 additions and 88 deletions

View File

@ -21,7 +21,7 @@ CREATE TABLE `registrations` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `authz` (
`id` varchar(255) NOT NULL,
`id` varchar(43) NOT NULL,
`identifier` varchar(255) DEFAULT NULL,
`registrationID` bigint(20) DEFAULT NULL,
`status` varchar(255) DEFAULT NULL,
@ -59,11 +59,11 @@ CREATE TABLE `certificateStatus` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `challenges` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`authorizationID` char(43) NOT NULL,
`LockCol` bigint(20) DEFAULT NULL,
`type` varchar(255) NOT NULL,
`status` varchar(255) DEFAULT NULL,
`status` varchar(255) NOT NULL,
`error` varchar(255) DEFAULT NULL,
`validated` datetime DEFAULT NULL,
`uri` varchar(255) DEFAULT NULL,
@ -96,7 +96,7 @@ CREATE TABLE `ocspResponses` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `pending_authz` (
`id` varchar(255) NOT NULL,
`id` varchar(43) NOT NULL,
`identifier` varchar(255) DEFAULT NULL,
`registrationID` bigint(20) DEFAULT NULL,
`status` varchar(255) DEFAULT NULL,

View File

@ -129,7 +129,7 @@ func initTables(dbMap *gorp.DbMap) {
pendingAuthzTable := dbMap.AddTableWithName(pendingauthzModel{}, "pending_authz").SetKeys(false, "ID")
pendingAuthzTable.SetVersionCol("LockCol")
dbMap.AddTableWithName(authzModel{}, "authz").SetKeys(false, "ID")
dbMap.AddTableWithName(challengeModel{}, "challenges").SetKeys(true, "ID").SetVersionCol("LockCol")
dbMap.AddTableWithName(challModel{}, "challenges").SetKeys(true, "ID").SetVersionCol("LockCol")
dbMap.AddTableWithName(core.Certificate{}, "certificates").SetKeys(false, "Serial")
dbMap.AddTableWithName(core.CertificateStatus{}, "certificateStatus").SetKeys(false, "Serial").SetVersionCol("LockCol")
dbMap.AddTableWithName(core.OCSPResponse{}, "ocspResponses").SetKeys(true, "ID")

View File

@ -3,6 +3,8 @@ package sa
import (
"encoding/json"
"fmt"
"math"
"time"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/core"
@ -18,6 +20,23 @@ type regModel struct {
LockCol int64
}
// challModel is the description of a core.Challenge in the database
type challModel struct {
ID int64 `db:"id"`
AuthorizationID string `db:"authorizationID"`
Type string `db:"type"`
Status core.AcmeStatus `db:"status"`
Error []byte `db:"error"`
Validated *time.Time `db:"validated"`
URI *core.AcmeURL `db:"uri"`
Token string `db:"token"`
TLS *bool `db:"tls"`
Validation []byte `db:"validation"`
LockCol int64
}
// newReg creates a reg model object from a core.Registration
func registrationToModel(r *core.Registration) (*regModel, error) {
key, err := json.Marshal(r.Key)
@ -54,3 +73,61 @@ func modelToRegistration(rm *regModel) (core.Registration, error) {
}
return r, nil
}
func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
cm := challModel{
AuthorizationID: authID,
Type: c.Type,
Status: c.Status,
Validated: c.Validated,
URI: c.URI,
Token: c.Token,
TLS: c.TLS,
// Validation: []byte(c.Validation.FullSerialize()),
}
if c.Validation != nil {
cm.Validation = []byte(c.Validation.FullSerialize())
if len(cm.Validation) > int(math.Pow(2, 24)) {
return nil, fmt.Errorf("Validation object is too large to store in the database")
}
}
if c.Error != nil {
errJSON, err := json.Marshal(c.Error)
if err != nil {
return nil, err
}
cm.Error = errJSON
}
if cm.URI != nil && len(cm.URI.String()) > 255 {
return nil, fmt.Errorf("URI is too long")
}
return &cm, nil
}
func modelToChallenge(cm *challModel) (core.Challenge, error) {
var val *jose.JsonWebSignature
var problem core.ProblemDetails
var err error
if len(cm.Validation) > 0 {
val, err = jose.ParseSigned(string(cm.Validation))
if err != nil {
return core.Challenge{}, err
}
}
if len(cm.Error) > 0 {
err := json.Unmarshal(cm.Error, &problem)
if err != nil {
return core.Challenge{}, err
}
}
return core.Challenge{
Type: cm.Type,
Status: cm.Status,
Error: &problem,
Validated: cm.Validated,
URI: cm.URI,
Token: cm.Token,
TLS: cm.TLS,
Validation: val,
}, nil
}

View File

@ -47,14 +47,6 @@ type authzModel struct {
Sequence int64 `db:"sequence"`
}
type challengeModel struct {
ID int `json:"id,omitempty" db:"id"`
AuthorizationID string `json:"authorizationID,omitempty" db:"authorizationID"`
LockCol int64
core.Challenge
}
// NewSQLStorageAuthority provides persistence using a SQL backend for
// Boulder. It will modify the given gorp.DbMap by adding relevent tables.
func NewSQLStorageAuthority(dbMap *gorp.DbMap) (*SQLStorageAuthority, error) {
@ -178,7 +170,7 @@ func (ssa *SQLStorageAuthority) GetAuthorization(id string) (authz core.Authoriz
authz = authD.Authorization
}
var challObjs []challengeModel
var challObjs []challModel
_, err = tx.Select(&challObjs, "SELECT * FROM challenges WHERE authorizationID = :authID", map[string]interface{}{"authID": authz.ID})
if err != nil {
tx.Rollback()
@ -186,7 +178,12 @@ func (ssa *SQLStorageAuthority) GetAuthorization(id string) (authz core.Authoriz
}
var challs []core.Challenge
for _, c := range challObjs {
challs = append(challs, c.Challenge)
chall, err := modelToChallenge(&c)
if err != nil {
tx.Rollback()
return core.Authorization{}, err
}
challs = append(challs, chall)
}
authz.Challenges = challs
@ -209,13 +206,17 @@ func (ssa *SQLStorageAuthority) GetLatestValidAuthorization(registrationId int64
return
}
var challObjs []challengeModel
var challObjs []challModel
_, err = ssa.dbMap.Select(&challObjs, "SELECT * FROM challenges WHERE authorizationID = :authID", map[string]interface{}{"authID": authz.ID})
if err != nil {
return
}
for _, c := range challObjs {
authz.Challenges = append(authz.Challenges, c.Challenge)
chall, err := modelToChallenge(&c)
if err != nil {
return core.Authorization{}, err
}
authz.Challenges = append(authz.Challenges, chall)
}
return
@ -418,14 +419,15 @@ func (ssa *SQLStorageAuthority) NewPendingAuthorization(authz core.Authorization
}
for _, c := range authz.Challenges {
chall := challengeModel{
AuthorizationID: pendingAuthz.ID,
Challenge: c,
}
err = tx.Insert(&chall)
chall, err := challengeToModel(&c, pendingAuthz.ID)
if err != nil {
tx.Rollback()
return
return core.Authorization{}, err
}
err = tx.Insert(chall)
if err != nil {
tx.Rollback()
return core.Authorization{}, err
}
}
@ -473,7 +475,7 @@ func (ssa *SQLStorageAuthority) UpdatePendingAuthorization(authz core.Authorizat
return
}
var challs []challengeModel
var challs []challModel
_, err = tx.Select(
&challs,
"SELECT * FROM challenges WHERE authorizationID = :authID",
@ -487,15 +489,13 @@ func (ssa *SQLStorageAuthority) UpdatePendingAuthorization(authz core.Authorizat
return fmt.Errorf("Invalid number of challenges provided")
}
for i, authChall := range authz.Challenges {
chall := challengeModel{
ID: challs[i].ID,
Challenge: authChall,
AuthorizationID: challs[i].AuthorizationID,
chall, err := challengeToModel(&authChall, challs[i].AuthorizationID)
if err != nil {
tx.Rollback()
return err
}
chall.Challenge = authChall
chall.ID = challs[i].ID
chall.AuthorizationID = challs[i].AuthorizationID
_, err = tx.Update(&chall)
_, err = tx.Update(chall)
if err != nil {
tx.Rollback()
return err
@ -557,7 +557,7 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization(authz core.Authorization)
return
}
var challs []challengeModel
var challs []challModel
_, err = tx.Select(
&challs,
"SELECT * FROM challenges WHERE authorizationID = :authID",
@ -571,12 +571,13 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization(authz core.Authorization)
return fmt.Errorf("Invalid number of challenges provided")
}
for i, authChall := range authz.Challenges {
chall := challengeModel{
Challenge: authChall,
ID: challs[i].ID,
AuthorizationID: challs[i].AuthorizationID,
chall, err := challengeToModel(&authChall, challs[i].AuthorizationID)
if err != nil {
tx.Rollback()
return err
}
_, err = tx.Update(&chall)
chall.ID = challs[i].ID
_, err = tx.Update(chall)
if err != nil {
tx.Rollback()
return err

View File

@ -43,11 +43,6 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
return t.String(), nil
}
return "", nil
case *jose.JsonWebSignature:
if t != nil {
return []byte(t.FullSerialize()), nil
}
return []byte{}, nil
default:
return val, nil
}
@ -84,26 +79,6 @@ func (tc BoulderTypeConverter) FromDb(target interface{}) (gorp.CustomScanner, b
return nil
}
return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
case **jose.JsonWebSignature:
binder := func(holder, target interface{}) error {
s, ok := holder.(*[]byte)
if !ok {
return errors.New("FromDb: Unable to convert *string")
}
st, ok := target.(**jose.JsonWebSignature)
if !ok {
return fmt.Errorf("FromDb: Unable to convert %T to **jose.JsonWebSignature", target)
}
if len(*s) != 0 {
sig, err := jose.ParseSigned(string(*s))
if err != nil {
return err
}
*st = &(*sig)
}
return nil
}
return gorp.CustomScanner{Holder: new([]byte), Target: target, Binder: binder}, true
case *jose.JsonWebKey:
binder := func(holder, target interface{}) error {
s, ok := holder.(*string)

View File

@ -185,29 +185,3 @@ func TestAcmeURL(t *testing.T) {
err = scanner.Binder(&marshaled, &out)
test.AssertMarshaledEquals(t, au, out)
}
func TestJsonWebSignature(t *testing.T) {
tc := BoulderTypeConverter{}
var out *jose.JsonWebSignature
validationPayload, _ := json.Marshal(map[string]interface{}{
"type": "type",
"token": "token",
})
signer, _ := jose.NewSigner(jose.RS256, &TheKey)
jws, _ := signer.Sign(validationPayload, "")
marshaledI, err := tc.ToDb(jws)
test.AssertNotError(t, err, "Could not ToDb")
scanner, ok := tc.FromDb(&out)
test.Assert(t, ok, "FromDb failed")
if !ok {
t.FailNow()
return
}
marshaled := marshaledI.([]byte)
err = scanner.Binder(&marshaled, &out)
test.AssertMarshaledEquals(t, jws, out)
}