Merge master

This commit is contained in:
Roland Shoemaker 2015-08-15 16:50:57 -07:00
commit 4fb747ead1
30 changed files with 338 additions and 300 deletions

View File

@ -9,17 +9,7 @@ VERSION ?= 1.0.0
EPOCH ?= 1 EPOCH ?= 1
MAINTAINER ?= "Community" MAINTAINER ?= "Community"
OBJECTS = activity-monitor \ OBJECTS = $(shell find ./cmd -type d -maxdepth 1 -mindepth 1 | xargs basename)
admin-revoker \
boulder-ca \
boulder-ra \
boulder-sa \
boulder-va \
boulder-wfe \
expiration-mailer \
ocsp-updater \
ocsp-responder \
policy-loader
# Build environment variables (referencing core/util.go) # Build environment variables (referencing core/util.go)
COMMIT_ID = $(shell git rev-parse --short HEAD) COMMIT_ID = $(shell git rev-parse --short HEAD)
@ -40,8 +30,6 @@ build: $(OBJECTS)
pre: pre:
@mkdir -p $(OBJDIR) @mkdir -p $(OBJDIR)
@echo [go] lib/github.com/mattn/go-sqlite3
@go install ./Godeps/_workspace/src/github.com/mattn/go-sqlite3
# Compile each of the binaries # Compile each of the binaries
$(OBJECTS): pre $(OBJECTS): pre
@ -49,7 +37,7 @@ $(OBJECTS): pre
@go build -o ./bin/$@ -ldflags \ @go build -o ./bin/$@ -ldflags \
"-X $(BUILD_ID_VAR) '$(BUILD_ID)' -X $(BUILD_TIME_VAR) '$(BUILD_TIME)' \ "-X $(BUILD_ID_VAR) '$(BUILD_ID)' -X $(BUILD_TIME_VAR) '$(BUILD_TIME)' \
-X $(BUILD_HOST_VAR) '$(BUILD_HOST)'" \ -X $(BUILD_HOST_VAR) '$(BUILD_HOST)'" \
cmd/$@/main.go ./cmd/$@/
clean: clean:
rm -f $(OBJDIR)/* rm -f $(OBJDIR)/*

View File

@ -11,7 +11,6 @@ import (
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log" blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/sa"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1" gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
) )
@ -32,14 +31,9 @@ type SerialNumber struct {
// NewCertificateAuthorityDatabaseImpl constructs a Database for the // NewCertificateAuthorityDatabaseImpl constructs a Database for the
// Certificate Authority. // Certificate Authority.
func NewCertificateAuthorityDatabaseImpl(driver string, name string) (cadb core.CertificateAuthorityDatabase, err error) { func NewCertificateAuthorityDatabaseImpl(dbMap *gorp.DbMap) (cadb core.CertificateAuthorityDatabase, err error) {
logger := blog.GetAuditLogger() logger := blog.GetAuditLogger()
dbMap, err := sa.NewDbMap(driver, name)
if err != nil {
return nil, err
}
dbMap.AddTableWithName(SerialNumber{}, "serialNumber").SetKeys(true, "ID") dbMap.AddTableWithName(SerialNumber{}, "serialNumber").SetKeys(true, "ID")
cadb = &CertificateAuthorityDatabaseImpl{ cadb = &CertificateAuthorityDatabaseImpl{

View File

@ -8,39 +8,14 @@ package ca
import ( import (
"testing" "testing"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3" "github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/sa"
"github.com/letsencrypt/boulder/test" "github.com/letsencrypt/boulder/test"
) )
const badDriver = "nothing"
const badFilename = "/doesnotexist/nofile"
const sqliteDriver = "sqlite3"
const sqliteName = ":memory:"
func TestConstruction(t *testing.T) {
// Successful case
_, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
// Covers "sql.Open" error
_, err = NewCertificateAuthorityDatabaseImpl(badDriver, sqliteName)
test.AssertError(t, err, "Should have failed construction")
// Covers "db.Ping" error
_, err = NewCertificateAuthorityDatabaseImpl(sqliteDriver, badFilename)
test.AssertError(t, err, "Should have failed construction")
}
func TestGetSetSequenceOutsideTx(t *testing.T) { func TestGetSetSequenceOutsideTx(t *testing.T) {
cadb, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName) cadb, cleanUp := caDBImpl(t)
test.AssertNotError(t, err, "Could not construct CA DB") defer cleanUp()
err = cadb.CreateTablesIfNotExists()
test.AssertNotError(t, err, "Could not construct tables")
_, err = cadb.IncrementAndGetSerial(nil)
test.AssertError(t, err, "Not permitted")
tx, err := cadb.Begin() tx, err := cadb.Begin()
test.AssertNotError(t, err, "Could not begin") test.AssertNotError(t, err, "Could not begin")
tx.Commit() tx.Commit()
@ -55,12 +30,8 @@ func TestGetSetSequenceOutsideTx(t *testing.T) {
} }
func TestGetSetSequenceNumber(t *testing.T) { func TestGetSetSequenceNumber(t *testing.T) {
cadb, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName) cadb, cleanUp := caDBImpl(t)
test.AssertNotError(t, err, "Could not construct CA DB") defer cleanUp()
err = cadb.CreateTablesIfNotExists()
test.AssertNotError(t, err, "Could not construct tables")
tx, err := cadb.Begin() tx, err := cadb.Begin()
test.AssertNotError(t, err, "Could not begin") test.AssertNotError(t, err, "Could not begin")
@ -74,3 +45,45 @@ func TestGetSetSequenceNumber(t *testing.T) {
err = tx.Commit() err = tx.Commit()
test.AssertNotError(t, err, "Could not commit") test.AssertNotError(t, err, "Could not commit")
} }
func caDBImpl(t *testing.T) (core.CertificateAuthorityDatabase, func()) {
dbMap, err := sa.NewDbMap(dbConnStr)
if err != nil {
t.Fatalf("Could not construct dbMap: %s", err)
}
cadb, err := NewCertificateAuthorityDatabaseImpl(dbMap)
if err != nil {
t.Fatalf("Could not construct CA DB: %s", err)
}
// We intentionally call CreateTablesIfNotExists twice before
// returning because of the weird insert inside it. The
// CADatabaseImpl code expects the existence of a single row in
// its serialIds table or else it errors. CreateTablesIfNotExists
// currently inserts that row and TruncateTables will remove
// it. But we need to make sure the tables exist before
// TruncateTables can be called to reset the table. So, two calls
// to CreateTablesIfNotExists.
err = cadb.CreateTablesIfNotExists()
if err != nil {
t.Fatalf("Could not construct tables: %s", err)
}
err = dbMap.TruncateTables()
if err != nil {
t.Fatalf("Could not truncate tables: %s", err)
}
err = cadb.CreateTablesIfNotExists()
if err != nil {
t.Fatalf("Could not construct tables: %s", err)
}
cleanUp := func() {
if err := dbMap.TruncateTables(); err != nil {
t.Fatalf("Could not truncate tables after the test: %s", err)
}
dbMap.Db.Close()
}
return cadb, cleanUp
}

View File

@ -120,7 +120,7 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
return nil, err return nil, err
} }
pa, err := policy.NewPolicyAuthorityImpl(paConfig.DBDriver, paConfig.DBConnect, paConfig.EnforcePolicyWhitelist) pa, err := policy.NewPolicyAuthorityImpl(paConfig.DBConnect, paConfig.EnforcePolicyWhitelist)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -11,13 +11,11 @@ import (
"encoding/asn1" "encoding/asn1"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"os"
"testing" "testing"
"time" "time"
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config" cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
ocspConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp/config" ocspConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp/config"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/cmd" "github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/mocks" "github.com/letsencrypt/boulder/mocks"
@ -338,30 +336,44 @@ var log = mocks.UseMockLog()
// CFSSL config // CFSSL config
const profileName = "ee" const profileName = "ee"
const caKeyFile = "../test/test-ca.key" const caKeyFile = "../test/test-ca.key"
const caCertFile = "../test/test-ca.pem"
const issuerCert = "../test/test-ca.pem" const issuerCert = "../test/test-ca.pem"
// TODO(jmhodges): change this to boulder_ca_test database
var dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test"
var exPA = cmd.PAConfig{ var exPA = cmd.PAConfig{
DBDriver: "sqlite3", DBConnect: dbConnStr,
DBConnect: ":memory:",
} }
func TestMain(m *testing.M) { func setup(t *testing.T) (core.CertificateAuthorityDatabase, core.StorageAuthority, cmd.CAConfig, func()) {
os.Exit(m.Run())
}
func setup(t *testing.T) (cadb core.CertificateAuthorityDatabase, storageAuthority core.StorageAuthority, caConfig cmd.CAConfig) {
// Create an SA // Create an SA
ssa, err := sa.NewSQLStorageAuthority("sqlite3", ":memory:") dbMap, err := sa.NewDbMap(dbConnStr)
test.AssertNotError(t, err, "Failed to create SA") if err != nil {
ssa.CreateTablesIfNotExists() t.Fatalf("Failed to create dbMap: %s", err)
storageAuthority = ssa }
ssa, err := sa.NewSQLStorageAuthority(dbMap)
if err != nil {
t.Fatalf("Failed to create SA: %s", err)
}
if err = ssa.CreateTablesIfNotExists(); err != nil {
t.Fatalf("Failed to create tables: %s", err)
}
if err = dbMap.TruncateTables(); err != nil {
t.Fatalf("Failed to truncate tables: %s", err)
}
cadb, _ = mocks.NewMockCertificateAuthorityDatabase() cadb, caDBCleanUp := caDBImpl(t)
cleanUp := func() {
if err = dbMap.TruncateTables(); err != nil {
t.Fatalf("Failed to truncate tables after the test: %s", err)
}
dbMap.Db.Close()
caDBCleanUp()
}
// Create a CA // Create a CA
caConfig = cmd.CAConfig{ caConfig := cmd.CAConfig{
Profile: profileName, Profile: profileName,
SerialPrefix: 17, SerialPrefix: 17,
Key: cmd.KeyConfig{ Key: cmd.KeyConfig{
@ -406,19 +418,22 @@ func setup(t *testing.T) (cadb core.CertificateAuthorityDatabase, storageAuthori
}, },
}, },
} }
return cadb, storageAuthority, caConfig return cadb, ssa, caConfig, cleanUp
} }
func TestFailNoSerial(t *testing.T) { func TestFailNoSerial(t *testing.T) {
cadb, _, caConfig := setup(t) cadb, _, caConfig, cleanUp := setup(t)
defer cleanUp()
caConfig.SerialPrefix = 0 caConfig.SerialPrefix = 0
_, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) _, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA)
test.AssertError(t, err, "CA should have failed with no SerialPrefix") test.AssertError(t, err, "CA should have failed with no SerialPrefix")
} }
func TestRevoke(t *testing.T) { func TestRevoke(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
if err != nil { if err != nil {
return return
@ -449,8 +464,9 @@ func TestRevoke(t *testing.T) {
} }
func TestIssueCertificate(t *testing.T) { func TestIssueCertificate(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority ca.SA = storageAuthority
ca.MaxKeySize = 4096 ca.MaxKeySize = 4096
@ -525,8 +541,9 @@ func TestIssueCertificate(t *testing.T) {
} }
func TestRejectNoName(t *testing.T) { func TestRejectNoName(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority ca.SA = storageAuthority
ca.MaxKeySize = 4096 ca.MaxKeySize = 4096
@ -541,8 +558,9 @@ func TestRejectNoName(t *testing.T) {
} }
func TestRejectTooManyNames(t *testing.T) { func TestRejectTooManyNames(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority ca.SA = storageAuthority
@ -554,8 +572,9 @@ func TestRejectTooManyNames(t *testing.T) {
} }
func TestDeduplication(t *testing.T) { func TestDeduplication(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority ca.SA = storageAuthority
ca.MaxKeySize = 4096 ca.MaxKeySize = 4096
@ -583,8 +602,9 @@ func TestDeduplication(t *testing.T) {
} }
func TestRejectValidityTooLong(t *testing.T) { func TestRejectValidityTooLong(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority ca.SA = storageAuthority
ca.MaxKeySize = 4096 ca.MaxKeySize = 4096
@ -604,8 +624,9 @@ func TestRejectValidityTooLong(t *testing.T) {
} }
func TestShortKey(t *testing.T) { func TestShortKey(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
ca.SA = storageAuthority ca.SA = storageAuthority
ca.MaxKeySize = 4096 ca.MaxKeySize = 4096
@ -617,8 +638,9 @@ func TestShortKey(t *testing.T) {
} }
func TestRejectBadAlgorithm(t *testing.T) { func TestRejectBadAlgorithm(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t) cadb, storageAuthority, caConfig, cleanUp := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) defer cleanUp()
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA)
ca.SA = storageAuthority ca.SA = storageAuthority
ca.MaxKeySize = 4096 ca.MaxKeySize = 4096

View File

@ -17,18 +17,12 @@ import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/codegangsta/cli" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/codegangsta/cli"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
// Load both drivers to allow configuring either
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/cmd" "github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log" blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/rpc" "github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/sa" "github.com/letsencrypt/boulder/sa"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
) )
var reasons = map[int]string{ var reasons = map[int]string{
@ -76,7 +70,7 @@ func setupContext(context *cli.Context) (rpc.CertificateAuthorityClient, *blog.A
cac, err := rpc.NewCertificateAuthorityClient(caRPC) cac, err := rpc.NewCertificateAuthorityClient(caRPC)
cmd.FailOnError(err, "Unable to create CA client") cmd.FailOnError(err, "Unable to create CA client")
dbMap, err := sa.NewDbMap(c.Revoker.DBDriver, c.Revoker.DBConnect) dbMap, err := sa.NewDbMap(c.Revoker.DBConnect)
cmd.FailOnError(err, "Couldn't setup database connection") cmd.FailOnError(err, "Couldn't setup database connection")
saRPC, err := rpc.NewAmqpRPCClient("AdminRevoker->SA", c.AMQP.SA.Server, ch) saRPC, err := rpc.NewAmqpRPCClient("AdminRevoker->SA", c.AMQP.SA.Server, ch)

View File

@ -7,11 +7,11 @@ package main
import ( import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/ca" "github.com/letsencrypt/boulder/ca"
"github.com/letsencrypt/boulder/cmd" "github.com/letsencrypt/boulder/cmd"
blog "github.com/letsencrypt/boulder/log" blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/rpc" "github.com/letsencrypt/boulder/rpc"
"github.com/letsencrypt/boulder/sa"
) )
func main() { func main() {
@ -31,8 +31,10 @@ func main() {
go cmd.DebugServer(c.CA.DebugAddr) go cmd.DebugServer(c.CA.DebugAddr)
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(c.CA.DBDriver, c.CA.DBConnect) dbMap, err := sa.NewDbMap(c.CA.DBConnect)
cmd.FailOnError(err, "Couldn't connect to CA database")
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(dbMap)
cmd.FailOnError(err, "Failed to create CA database") cmd.FailOnError(err, "Failed to create CA database")
if c.SQL.CreateTables { if c.SQL.CreateTables {

View File

@ -31,8 +31,10 @@ func main() {
go cmd.DebugServer(c.SA.DebugAddr) go cmd.DebugServer(c.SA.DebugAddr)
sai, err := sa.NewSQLStorageAuthority(c.SA.DBDriver, c.SA.DBConnect) dbMap, err := sa.NewDbMap(c.SA.DBConnect)
cmd.FailOnError(err, "Couldn't connect to SA database")
sai, err := sa.NewSQLStorageAuthority(dbMap)
cmd.FailOnError(err, "Failed to create SA impl") cmd.FailOnError(err, "Failed to create SA impl")
sai.SetSQLDebug(c.SQL.SQLDebug) sai.SetSQLDebug(c.SQL.SQLDebug)

View File

@ -240,7 +240,7 @@ func main() {
go cmd.DebugServer(c.Mailer.DebugAddr) go cmd.DebugServer(c.Mailer.DebugAddr)
// Configure DB // Configure DB
dbMap, err := sa.NewDbMap(c.Mailer.DBDriver, c.Mailer.DBConnect) dbMap, err := sa.NewDbMap(c.Mailer.DBConnect)
cmd.FailOnError(err, "Could not connect to database") cmd.FailOnError(err, "Could not connect to database")
ch, err := rpc.AmqpChannel(c) ch, err := rpc.AmqpChannel(c)

View File

@ -140,11 +140,30 @@ var testKey = rsa.PrivateKey{
Primes: []*big.Int{p, q}, Primes: []*big.Int{p, q},
} }
// TODO(jmhodges): Turn this into boulder_sa_test
var dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test"
func TestFindExpiringCertificates(t *testing.T) { func TestFindExpiringCertificates(t *testing.T) {
dbMap, err := sa.NewDbMap("sqlite3", ":memory:") dbMap, err := sa.NewDbMap(dbConnStr)
test.AssertNotError(t, err, "Couldn't connect to SQLite") if err != nil {
t.Fatalf("Couldn't connect the database: %s", err)
}
err = dbMap.CreateTablesIfNotExists() err = dbMap.CreateTablesIfNotExists()
test.AssertNotError(t, err, "Couldn't create tables") if err != nil {
t.Fatalf("Couldn't create tables: %s", err)
}
err = dbMap.TruncateTables()
if err != nil {
t.Fatalf("Couldn't truncate tables: %s", err)
}
defer func() {
err = dbMap.TruncateTables()
if err != nil {
t.Fatalf("Couldn't truncate tables after the test: %s", err)
}
dbMap.Db.Close()
}()
tmpl, err := template.New("expiry-email").Parse(testTmpl) tmpl, err := template.New("expiry-email").Parse(testTmpl)
test.AssertNotError(t, err, "Couldn't parse test email template") test.AssertNotError(t, err, "Couldn't parse test email template")
stats, _ := statsd.NewNoopClient(nil) stats, _ := statsd.NewNoopClient(nil)

View File

@ -159,7 +159,7 @@ func main() {
blog.SetAuditLogger(auditlogger) blog.SetAuditLogger(auditlogger)
// Configure DB // Configure DB
dbMap, err := sa.NewDbMap(c.PA.DBDriver, c.PA.DBConnect) dbMap, err := sa.NewDbMap(c.PA.DBConnect)
cmd.FailOnError(err, "Could not connect to database") cmd.FailOnError(err, "Could not connect to database")
dbMap.AddTableWithName(core.ExternalCert{}, "externalCerts").SetKeys(false, "SHA1") dbMap.AddTableWithName(core.ExternalCert{}, "externalCerts").SetKeys(false, "SHA1")

View File

@ -134,7 +134,7 @@ func main() {
auditlogger.Info(app.VersionString()) auditlogger.Info(app.VersionString())
// Configure DB // Configure DB
dbMap, err := sa.NewDbMap(c.OCSPResponder.DBDriver, c.OCSPResponder.DBConnect) dbMap, err := sa.NewDbMap(c.OCSPResponder.DBConnect)
cmd.FailOnError(err, "Could not connect to database") cmd.FailOnError(err, "Could not connect to database")
sa.SetSQLDebug(dbMap, c.SQL.SQLDebug) sa.SetSQLDebug(dbMap, c.SQL.SQLDebug)

View File

@ -214,7 +214,7 @@ func main() {
go cmd.DebugServer(c.OCSPUpdater.DebugAddr) go cmd.DebugServer(c.OCSPUpdater.DebugAddr)
// Configure DB // Configure DB
dbMap, err := sa.NewDbMap(c.OCSPUpdater.DBDriver, c.OCSPUpdater.DBConnect) dbMap, err := sa.NewDbMap(c.OCSPUpdater.DBConnect)
cmd.FailOnError(err, "Could not connect to database") cmd.FailOnError(err, "Could not connect to database")
cac, closeChan := setupClients(c) cac, closeChan := setupClients(c)

View File

@ -29,7 +29,7 @@ func setupContext(context *cli.Context) (*policy.PolicyAuthorityDatabaseImpl, st
err = json.Unmarshal(configJSON, &c) err = json.Unmarshal(configJSON, &c)
cmd.FailOnError(err, "Couldn't unmarshal configuration object") cmd.FailOnError(err, "Couldn't unmarshal configuration object")
padb, err := policy.NewPolicyAuthorityDatabaseImpl(c.PA.DBDriver, c.PA.DBConnect) padb, err := policy.NewPolicyAuthorityDatabaseImpl(c.PA.DBConnect)
cmd.FailOnError(err, "Could not connect to PADB") cmd.FailOnError(err, "Could not connect to PADB")
return padb, context.GlobalString("rule-file") return padb, context.GlobalString("rule-file")
} }

View File

@ -90,7 +90,6 @@ type Config struct {
} }
SA struct { SA struct {
DBDriver string
DBConnect string DBConnect string
// DebugAddr is the address to run the /debug handlers on. // DebugAddr is the address to run the /debug handlers on.
@ -121,7 +120,6 @@ type Config struct {
} }
Revoker struct { Revoker struct {
DBDriver string
DBConnect string DBConnect string
} }
@ -131,7 +129,6 @@ type Config struct {
Username string Username string
Password string Password string
DBDriver string
DBConnect string DBConnect string
CertLimit int CertLimit int
@ -144,7 +141,6 @@ type Config struct {
} }
OCSPResponder struct { OCSPResponder struct {
DBDriver string
DBConnect string DBConnect string
Path string Path string
ListenAddress string ListenAddress string
@ -154,7 +150,6 @@ type Config struct {
} }
OCSPUpdater struct { OCSPUpdater struct {
DBDriver string
DBConnect string DBConnect string
MinTimeToExpiry string MinTimeToExpiry string
ResponseLimit int ResponseLimit int
@ -188,7 +183,6 @@ type Config struct {
type CAConfig struct { type CAConfig struct {
Profile string Profile string
TestMode bool TestMode bool
DBDriver string
DBConnect string DBConnect string
SerialPrefix int SerialPrefix int
Key KeyConfig Key KeyConfig
@ -207,7 +201,6 @@ type CAConfig struct {
} }
type PAConfig struct { type PAConfig struct {
DBDriver string
DBConnect string DBConnect string
EnforcePolicyWhitelist bool EnforcePolicyWhitelist bool
} }

View File

@ -6,48 +6,14 @@
package mocks package mocks
import ( import (
"database/sql"
"fmt" "fmt"
"net" "net"
"strings" "strings"
"time" "time"
// Load SQLite3 for test purposes
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
) )
// MockCADatabase is a mock
type MockCADatabase struct {
db *gorp.DbMap
count int64
}
// NewMockCertificateAuthorityDatabase is a mock
func NewMockCertificateAuthorityDatabase() (mock *MockCADatabase, err error) {
db, err := sql.Open("sqlite3", ":memory:")
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
mock = &MockCADatabase{db: dbmap, count: 1}
return mock, err
}
// Begin is a mock
func (cadb *MockCADatabase) Begin() (*gorp.Transaction, error) {
return cadb.db.Begin()
}
// IncrementAndGetSerial is a mock
func (cadb *MockCADatabase) IncrementAndGetSerial(*gorp.Transaction) (int64, error) {
cadb.count = cadb.count + 1
return cadb.count, nil
}
// CreateTablesIfNotExists is a mock
func (cadb *MockCADatabase) CreateTablesIfNotExists() error {
return nil
}
// MockDNS is a mock // MockDNS is a mock
type MockDNS struct { type MockDNS struct {
} }

View File

@ -24,14 +24,14 @@ type PolicyAuthorityImpl struct {
} }
// NewPolicyAuthorityImpl constructs a Policy Authority. // NewPolicyAuthorityImpl constructs a Policy Authority.
func NewPolicyAuthorityImpl(driver, connect string, enforceWhitelist bool) (*PolicyAuthorityImpl, error) { func NewPolicyAuthorityImpl(connect string, enforceWhitelist bool) (*PolicyAuthorityImpl, error) {
logger := blog.GetAuditLogger() logger := blog.GetAuditLogger()
logger.Notice("Policy Authority Starting") logger.Notice("Policy Authority Starting")
pa := PolicyAuthorityImpl{log: logger} pa := PolicyAuthorityImpl{log: logger}
// Setup policy db // Setup policy db
padb, err := NewPolicyAuthorityDatabaseImpl(driver, connect) padb, err := NewPolicyAuthorityDatabaseImpl(connect)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -14,6 +14,7 @@ import (
) )
var log = mocks.UseMockLog() var log = mocks.UseMockLog()
var dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test"
func TestWillingToIssue(t *testing.T) { func TestWillingToIssue(t *testing.T) {
shouldBeSyntaxError := []string{ shouldBeSyntaxError := []string{
@ -91,7 +92,7 @@ func TestWillingToIssue(t *testing.T) {
"www.zombo-.com", "www.zombo-.com",
} }
pa, _ := NewPolicyAuthorityImpl("sqlite3", ":memory:", false) pa, _ := NewPolicyAuthorityImpl(dbConnStr, false)
rules := []DomainRule{} rules := []DomainRule{}
for _, b := range shouldBeBlacklisted { for _, b := range shouldBeBlacklisted {
rules = append(rules, DomainRule{Host: b, Type: blacklisted}) rules = append(rules, DomainRule{Host: b, Type: blacklisted})
@ -147,7 +148,7 @@ func TestWillingToIssue(t *testing.T) {
} }
func TestChallengesFor(t *testing.T) { func TestChallengesFor(t *testing.T) {
pa, _ := NewPolicyAuthorityImpl("sqlite3", ":memory:", true) pa, _ := NewPolicyAuthorityImpl(dbConnStr, true)
challenges, combinations := pa.ChallengesFor(core.AcmeIdentifier{}) challenges, combinations := pa.ChallengesFor(core.AcmeIdentifier{})

View File

@ -41,9 +41,9 @@ type PolicyAuthorityDatabaseImpl struct {
// NewPolicyAuthorityDatabaseImpl constructs a Policy Authority Database (and // NewPolicyAuthorityDatabaseImpl constructs a Policy Authority Database (and
// creates tables if they are non-existent) // creates tables if they are non-existent)
func NewPolicyAuthorityDatabaseImpl(driver, name string) (padb *PolicyAuthorityDatabaseImpl, err error) { func NewPolicyAuthorityDatabaseImpl(name string) (padb *PolicyAuthorityDatabaseImpl, err error) {
logger := blog.GetAuditLogger() logger := blog.GetAuditLogger()
dbMap, err := sa.NewDbMap(driver, name) dbMap, err := sa.NewDbMap(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -23,7 +23,7 @@ var (
) )
func TestLoadAndDump(t *testing.T) { func TestLoadAndDump(t *testing.T) {
p, err := NewPolicyAuthorityDatabaseImpl("sqlite3", ":memory:") p, err := NewPolicyAuthorityDatabaseImpl(dbConnStr)
test.AssertNotError(t, err, "Couldn't create PADB") test.AssertNotError(t, err, "Couldn't create PADB")
err = p.LoadRules([]DomainRule{rA, rB}) err = p.LoadRules([]DomainRule{rA, rB})
@ -36,7 +36,7 @@ func TestLoadAndDump(t *testing.T) {
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
p, err := NewPolicyAuthorityDatabaseImpl("sqlite3", ":memory:") p, err := NewPolicyAuthorityDatabaseImpl(dbConnStr)
test.AssertNotError(t, err, "Couldn't create PADB") test.AssertNotError(t, err, "Couldn't create PADB")
err = p.LoadRules([]DomainRule{rA, rB}) err = p.LoadRules([]DomainRule{rA, rB})

View File

@ -43,7 +43,7 @@ func NewRegistrationAuthorityImpl(paConfig cmd.PAConfig) (ra RegistrationAuthori
logger.Notice("Registration Authority Starting") logger.Notice("Registration Authority Starting")
ra.log = logger ra.log = logger
pa, err := policy.NewPolicyAuthorityImpl(paConfig.DBDriver, paConfig.DBConnect, paConfig.EnforcePolicyWhitelist) pa, err := policy.NewPolicyAuthorityImpl(paConfig.DBConnect, paConfig.EnforcePolicyWhitelist)
if err != nil { if err != nil {
return RegistrationAuthorityImpl{}, err return RegistrationAuthorityImpl{}, err
} }

View File

@ -21,7 +21,6 @@ import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose" jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/ca" "github.com/letsencrypt/boulder/ca"
"github.com/letsencrypt/boulder/cmd" "github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"
@ -125,13 +124,14 @@ var (
log = mocks.UseMockLog() log = mocks.UseMockLog()
// TODO(jmhodges): Turn this into boulder_sa_test
dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test"
common = cmd.PAConfig{ common = cmd.PAConfig{
DBDriver: "sqlite3", DBConnect: dbConnStr,
DBConnect: ":memory:",
} }
) )
func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationAuthority, *sa.SQLStorageAuthority, core.RegistrationAuthority) { func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationAuthority, *sa.SQLStorageAuthority, *RegistrationAuthorityImpl, func()) {
err := json.Unmarshal(AccountKeyJSONA, &AccountKeyA) err := json.Unmarshal(AccountKeyJSONA, &AccountKeyA)
test.AssertNotError(t, err, "Failed to unmarshal public JWK") test.AssertNotError(t, err, "Failed to unmarshal public JWK")
err = json.Unmarshal(AccountKeyJSONB, &AccountKeyB) err = json.Unmarshal(AccountKeyJSONB, &AccountKeyB)
@ -145,11 +145,22 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA
err = json.Unmarshal(ShortKeyJSON, &ShortKey) err = json.Unmarshal(ShortKeyJSON, &ShortKey)
test.AssertNotError(t, err, "Failed to unmarshall JWK") test.AssertNotError(t, err, "Failed to unmarshall JWK")
sa, err := sa.NewSQLStorageAuthority("sqlite3", ":memory:") dbMap, err := sa.NewDbMap(dbConnStr)
test.AssertNotError(t, err, "Failed to create SA")
err = sa.CreateTablesIfNotExists()
if err != nil { if err != nil {
t.Fatalf("unable to create tables: %s", err) t.Fatalf("Failed to create dbMap: %s", err)
}
ssa, err := sa.NewSQLStorageAuthority(dbMap)
if err != nil {
t.Fatalf("Failed to create SA: %s", err)
}
err = ssa.CreateTablesIfNotExists()
if err != nil {
t.Fatalf("Failed to create SA tables: %s", err)
}
if err = dbMap.TruncateTables(); err != nil {
t.Fatalf("Failed to truncate SA tables: %s", err)
} }
va := &DummyValidationAuthority{} va := &DummyValidationAuthority{}
@ -173,26 +184,36 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA
} }
signer, _ := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, basicPolicy) signer, _ := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, basicPolicy)
ocspSigner, _ := ocsp.NewSigner(caCert, caCert, caKey, time.Hour) ocspSigner, _ := ocsp.NewSigner(caCert, caCert, caKey, time.Hour)
pa, _ := policy.NewPolicyAuthorityImpl("sqlite3", ":memory:", false) pa, err := policy.NewPolicyAuthorityImpl(dbConnStr, false)
cadb, _ := mocks.NewMockCertificateAuthorityDatabase() test.AssertNotError(t, err, "Couldn't create PA")
cadb, caDBCleanUp := caDBImpl(t)
ca := ca.CertificateAuthorityImpl{ ca := ca.CertificateAuthorityImpl{
Signer: signer, Signer: signer,
OCSPSigner: ocspSigner, OCSPSigner: ocspSigner,
SA: sa, SA: ssa,
PA: pa, PA: pa,
DB: cadb, DB: cadb,
ValidityPeriod: time.Hour * 2190, ValidityPeriod: time.Hour * 2190,
NotAfter: time.Now().Add(time.Hour * 8761), NotAfter: time.Now().Add(time.Hour * 8761),
MaxKeySize: 4096, MaxKeySize: 4096,
} }
cleanUp := func() {
if err = dbMap.TruncateTables(); err != nil {
t.Fatalf("Failed to truncate tables after the test: %s", err)
}
dbMap.Db.Close()
caDBCleanUp()
}
csrDER, _ := hex.DecodeString(CSRhex) csrDER, _ := hex.DecodeString(CSRhex)
ExampleCSR, _ = x509.ParseCertificateRequest(csrDER) ExampleCSR, _ = x509.ParseCertificateRequest(csrDER)
// This registration implicitly gets ID = 1 // This registration implicitly gets ID = 1
Registration, _ = sa.NewRegistration(core.Registration{Key: AccountKeyA}) Registration, _ = ssa.NewRegistration(core.Registration{Key: AccountKeyA})
ra, err := NewRegistrationAuthorityImpl(common) ra, err := NewRegistrationAuthorityImpl(common)
ra.SA = sa test.AssertNotError(t, err, "Couldn't create RA")
ra.SA = ssa
ra.VA = va ra.VA = va
ra.CA = &ca ra.CA = &ca
ra.PA = pa ra.PA = pa
@ -210,7 +231,55 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA
AuthzFinal.Expires = &exp AuthzFinal.Expires = &exp
AuthzFinal.Challenges[0].Status = "valid" AuthzFinal.Challenges[0].Status = "valid"
return &ca, va, sa, &ra return &ca, va, ssa, &ra, cleanUp
}
// This is an unfortunate bit of tech debt that is being taken on in
// order to get the more important change of using MySQL/MariaDB in
// all of our tests working without SQLite. We already had issues with
// the RA here getting a real CertificateAuthority instead of a
// CertificateAuthorityClient, so this is only marginally worse.
// TODO(Issue #628): use a CAClient fake instead of a CAImpl instance
func caDBImpl(t *testing.T) (core.CertificateAuthorityDatabase, func()) {
dbMap, err := sa.NewDbMap(dbConnStr)
if err != nil {
t.Fatalf("Could not construct dbMap: %s", err)
}
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(dbMap)
if err != nil {
t.Fatalf("Could not construct CA DB: %s", err)
}
// We intentionally call CreateTablesIfNotExists twice before
// returning because of the weird insert inside it. The
// CADatabaseImpl code expects the existence of a single row in
// its serialIds table or else it errors. CreateTablesIfNotExists
// currently inserts that row and TruncateTables will remove
// it. But we need to make sure the tables exist before
// TruncateTables can be called to reset the table. So, two calls
// to CreateTablesIfNotExists.
err = cadb.CreateTablesIfNotExists()
if err != nil {
t.Fatalf("Could not construct tables: %s", err)
}
err = dbMap.TruncateTables()
if err != nil {
t.Fatalf("Could not truncate tables: %s", err)
}
err = cadb.CreateTablesIfNotExists()
if err != nil {
t.Fatalf("Could not construct tables: %s", err)
}
cleanUp := func() {
if err := dbMap.TruncateTables(); err != nil {
t.Fatalf("Could not truncate tables after the test: %s", err)
}
dbMap.Db.Close()
}
return cadb, cleanUp
} }
func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) { func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) {
@ -264,7 +333,8 @@ func TestValidateEmail(t *testing.T) {
} }
func TestNewRegistration(t *testing.T) { func TestNewRegistration(t *testing.T) {
_, _, sa, ra := initAuthorities(t) _, _, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org") mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org")
input := core.Registration{ input := core.Registration{
Contact: []*core.AcmeURL{mailto}, Contact: []*core.AcmeURL{mailto},
@ -288,7 +358,8 @@ func TestNewRegistration(t *testing.T) {
} }
func TestNewRegistrationNoFieldOverwrite(t *testing.T) { func TestNewRegistrationNoFieldOverwrite(t *testing.T) {
_, _, _, ra := initAuthorities(t) _, _, _, ra, cleanUp := initAuthorities(t)
defer cleanUp()
mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org") mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org")
input := core.Registration{ input := core.Registration{
ID: 23, ID: 23,
@ -304,17 +375,19 @@ func TestNewRegistrationNoFieldOverwrite(t *testing.T) {
// TODO: Enable this test case once we validate terms agreement. // TODO: Enable this test case once we validate terms agreement.
//test.Assert(t, result.Agreement != "I agreed", "Agreement shouldn't be set with invalid URL") //test.Assert(t, result.Agreement != "I agreed", "Agreement shouldn't be set with invalid URL")
id := result.ID
result2, err := ra.UpdateRegistration(result, core.Registration{ result2, err := ra.UpdateRegistration(result, core.Registration{
ID: 33, ID: 33,
Key: ShortKey, Key: ShortKey,
}) })
test.AssertNotError(t, err, "Could not update registration") test.AssertNotError(t, err, "Could not update registration")
test.Assert(t, result2.ID != 33, "ID shouldn't be overwritten.") test.Assert(t, result2.ID != 33, fmt.Sprintf("ID shouldn't be overwritten. expected %d, got %d", id, result2.ID))
test.Assert(t, !core.KeyDigestEquals(result2.Key, ShortKey), "Key shouldn't be overwritten") test.Assert(t, !core.KeyDigestEquals(result2.Key, ShortKey), "Key shouldn't be overwritten")
} }
func TestNewRegistrationBadKey(t *testing.T) { func TestNewRegistrationBadKey(t *testing.T) {
_, _, _, ra := initAuthorities(t) _, _, _, ra, cleanUp := initAuthorities(t)
defer cleanUp()
mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org") mailto, _ := core.ParseAcmeURL("mailto:foo@letsencrypt.org")
input := core.Registration{ input := core.Registration{
Contact: []*core.AcmeURL{mailto}, Contact: []*core.AcmeURL{mailto},
@ -326,8 +399,8 @@ func TestNewRegistrationBadKey(t *testing.T) {
} }
func TestNewAuthorization(t *testing.T) { func TestNewAuthorization(t *testing.T) {
_, _, sa, ra := initAuthorities(t) _, _, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
_, err := ra.NewAuthorization(AuthzRequest, 0) _, err := ra.NewAuthorization(AuthzRequest, 0)
test.AssertError(t, err, "Authorization cannot have registrationID == 0") test.AssertError(t, err, "Authorization cannot have registrationID == 0")
@ -354,7 +427,8 @@ func TestNewAuthorization(t *testing.T) {
} }
func TestUpdateAuthorization(t *testing.T) { func TestUpdateAuthorization(t *testing.T) {
_, va, sa, ra := initAuthorities(t) _, va, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
AuthzInitial, _ = sa.NewPendingAuthorization(AuthzInitial) AuthzInitial, _ = sa.NewPendingAuthorization(AuthzInitial)
sa.UpdatePendingAuthorization(AuthzInitial) sa.UpdatePendingAuthorization(AuthzInitial)
@ -377,7 +451,8 @@ func TestUpdateAuthorization(t *testing.T) {
} }
func TestOnValidationUpdate(t *testing.T) { func TestOnValidationUpdate(t *testing.T) {
_, _, sa, ra := initAuthorities(t) _, _, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
AuthzUpdated, _ = sa.NewPendingAuthorization(AuthzUpdated) AuthzUpdated, _ = sa.NewPendingAuthorization(AuthzUpdated)
sa.UpdatePendingAuthorization(AuthzUpdated) sa.UpdatePendingAuthorization(AuthzUpdated)
@ -399,7 +474,8 @@ func TestOnValidationUpdate(t *testing.T) {
} }
func TestCertificateKeyNotEqualAccountKey(t *testing.T) { func TestCertificateKeyNotEqualAccountKey(t *testing.T) {
_, _, sa, ra := initAuthorities(t) _, _, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
authz := core.Authorization{} authz := core.Authorization{}
authz, _ = sa.NewPendingAuthorization(authz) authz, _ = sa.NewPendingAuthorization(authz)
authz.Identifier = core.AcmeIdentifier{ authz.Identifier = core.AcmeIdentifier{
@ -430,7 +506,8 @@ func TestCertificateKeyNotEqualAccountKey(t *testing.T) {
} }
func TestAuthorizationRequired(t *testing.T) { func TestAuthorizationRequired(t *testing.T) {
_, _, sa, ra := initAuthorities(t) _, _, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
AuthzFinal.RegistrationID = 1 AuthzFinal.RegistrationID = 1
AuthzFinal, _ = sa.NewPendingAuthorization(AuthzFinal) AuthzFinal, _ = sa.NewPendingAuthorization(AuthzFinal)
sa.UpdatePendingAuthorization(AuthzFinal) sa.UpdatePendingAuthorization(AuthzFinal)
@ -449,7 +526,8 @@ func TestAuthorizationRequired(t *testing.T) {
} }
func TestNewCertificate(t *testing.T) { func TestNewCertificate(t *testing.T) {
_, _, sa, ra := initAuthorities(t) _, _, sa, ra, cleanUp := initAuthorities(t)
defer cleanUp()
AuthzFinal.RegistrationID = 1 AuthzFinal.RegistrationID = 1
AuthzFinal, _ = sa.NewPendingAuthorization(AuthzFinal) AuthzFinal, _ = sa.NewPendingAuthorization(AuthzFinal)
sa.UpdatePendingAuthorization(AuthzFinal) sa.UpdatePendingAuthorization(AuthzFinal)

View File

@ -11,39 +11,29 @@ import (
"net/url" "net/url"
"strings" "strings"
// Load both drivers to allow configuring either
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/go-sql-driver/mysql" _ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1" gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log" blog "github.com/letsencrypt/boulder/log"
) )
var dialectMap = map[string]interface{}{
"sqlite3": gorp.SqliteDialect{},
"mysql": gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
"postgres": gorp.PostgresDialect{},
}
// NewDbMap creates the root gorp mapping object. Create one of these for each // NewDbMap creates the root gorp mapping object. Create one of these for each
// database schema you wish to map. Each DbMap contains a list of mapped tables. // database schema you wish to map. Each DbMap contains a list of mapped tables.
// It automatically maps the tables for the primary parts of Boulder around the // It automatically maps the tables for the primary parts of Boulder around the
// Storage Authority. This may require some further work when we use a disjoint // Storage Authority. This may require some further work when we use a disjoint
// schema, like that for `certificate-authority-data.go`. // schema, like that for `certificate-authority-data.go`.
func NewDbMap(driver string, dbConnect string) (*gorp.DbMap, error) { func NewDbMap(dbConnect string) (*gorp.DbMap, error) {
logger := blog.GetAuditLogger() logger := blog.GetAuditLogger()
if driver == "mysql" {
var err error var err error
dbConnect, err = recombineURLForDB(dbConnect) dbConnect, err = recombineURLForDB(dbConnect)
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
db, err := sql.Open(driver, dbConnect) logger.Debug("Connecting to database")
db, err := sql.Open("mysql", dbConnect)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,20 +41,13 @@ func NewDbMap(driver string, dbConnect string) (*gorp.DbMap, error) {
return nil, err return nil, err
} }
logger.Debug("Connecting to database") dialect := gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"}
dialect, ok := dialectMap[driver].(gorp.Dialect)
if !ok {
err = fmt.Errorf("Couldn't find dialect for %s", driver)
return nil, err
}
logger.Info("Connected to database")
dbmap := &gorp.DbMap{Db: db, Dialect: dialect, TypeConverter: BoulderTypeConverter{}} dbmap := &gorp.DbMap{Db: db, Dialect: dialect, TypeConverter: BoulderTypeConverter{}}
initTables(dbmap) initTables(dbmap)
logger.Debug("Connected to database")
return dbmap, err return dbmap, err
} }
@ -98,6 +81,10 @@ func recombineURLForDB(dbConnect string) (string, error) {
dsnVals.Set("parseTime", "true") dsnVals.Set("parseTime", "true")
// Required to make UPDATE return the number of rows matched,
// instead of the number of rows changed by the UPDATE.
dsnVals.Set("clientFoundRows", "true")
user := dbURL.User.Username() user := dbURL.User.Username()
passwd, hasPass := dbURL.User.Password() passwd, hasPass := dbURL.User.Password()
dbConn := "" dbConn := ""

View File

@ -11,27 +11,7 @@ import (
"github.com/letsencrypt/boulder/test" "github.com/letsencrypt/boulder/test"
) )
func TestNewDbMap(t *testing.T) {
_, err := NewDbMap("", "")
test.AssertError(t, err, "Nil not permitted.")
_, err = NewDbMap("sqlite3", "/not/a/file")
test.AssertError(t, err, "Shouldn't have found a DB.")
_, err = NewDbMap("sqlite3", ":memory:")
test.AssertNotError(t, err, "Should have constructed a DB.")
}
func TestForgottenDialect(t *testing.T) {
bkup := dialectMap["sqlite3"]
dialectMap["sqlite3"] = ""
defer func() { dialectMap["sqlite3"] = bkup }()
_, err := NewDbMap("sqlite3", ":memory:")
test.AssertError(t, err, "Shouldn't have found the dialect")
}
func TestInvalidDSN(t *testing.T) { func TestInvalidDSN(t *testing.T) {
_, err := NewDbMap("mysql", "invalid") _, err := NewDbMap("invalid")
test.AssertError(t, err, "DB connect string missing the slash separating the database name") test.AssertError(t, err, "DB connect string missing the slash separating the database name")
} }

View File

@ -47,15 +47,12 @@ type authzModel struct {
Sequence int64 `db:"sequence"` Sequence int64 `db:"sequence"`
} }
// NewSQLStorageAuthority provides persistence using a SQL backend for Boulder. // NewSQLStorageAuthority provides persistence using a SQL backend for
func NewSQLStorageAuthority(driver string, dbConnect string) (*SQLStorageAuthority, error) { // Boulder. It will modify the given gorp.DbMap by adding relevent tables.
func NewSQLStorageAuthority(dbMap *gorp.DbMap) (*SQLStorageAuthority, error) {
logger := blog.GetAuditLogger() logger := blog.GetAuditLogger()
logger.Notice("Storage Authority Starting")
dbMap, err := NewDbMap(driver, dbConnect) logger.Notice("Storage Authority Starting")
if err != nil {
return nil, err
}
ssa := &SQLStorageAuthority{ ssa := &SQLStorageAuthority{
dbMap: dbMap, dbMap: dbMap,

View File

@ -17,7 +17,6 @@ import (
"time" "time"
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose" jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/mocks" "github.com/letsencrypt/boulder/mocks"
"github.com/letsencrypt/boulder/test" "github.com/letsencrypt/boulder/test"
@ -25,15 +24,33 @@ import (
var log = mocks.UseMockLog() var log = mocks.UseMockLog()
func initSA(t *testing.T) *SQLStorageAuthority { // TODO(jmhodges): change this to boulder_sa_test database
sa, err := NewSQLStorageAuthority("sqlite3", ":memory:") var dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test"
// initSA constructs a SQLStorageAuthority and a clean up function
// that should be defer'ed to the end of the test.
func initSA(t *testing.T) (*SQLStorageAuthority, func()) {
dbMap, err := NewDbMap(dbConnStr)
if err != nil { if err != nil {
t.Fatalf("Failed to create SA") t.Fatalf("Failed to create dbMap: %s", err)
}
sa, err := NewSQLStorageAuthority(dbMap)
if err != nil {
t.Fatalf("Failed to create SA: %s", err)
} }
if err = sa.CreateTablesIfNotExists(); err != nil { if err = sa.CreateTablesIfNotExists(); err != nil {
t.Fatalf("Failed to create SA") t.Fatalf("Failed to create tables: %s", err)
}
if err = sa.dbMap.TruncateTables(); err != nil {
t.Fatalf("Failed to truncate tables: %s", err)
}
return sa, func() {
if err = sa.dbMap.TruncateTables(); err != nil {
t.Fatalf("Failed to truncate tables after the test: %s", err)
}
sa.dbMap.Db.Close()
} }
return sa
} }
var ( var (
@ -50,7 +67,8 @@ var (
) )
func TestAddRegistration(t *testing.T) { func TestAddRegistration(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
var jwk jose.JsonWebKey var jwk jose.JsonWebKey
err := json.Unmarshal([]byte(theKey), &jwk) err := json.Unmarshal([]byte(theKey), &jwk)
@ -106,7 +124,8 @@ func TestAddRegistration(t *testing.T) {
} }
func TestNoSuchRegistrationErrors(t *testing.T) { func TestNoSuchRegistrationErrors(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
_, err := sa.GetRegistration(100) _, err := sa.GetRegistration(100)
if _, ok := err.(NoSuchRegistrationError); !ok { if _, ok := err.(NoSuchRegistrationError); !ok {
@ -128,7 +147,8 @@ func TestNoSuchRegistrationErrors(t *testing.T) {
} }
func TestAddAuthorization(t *testing.T) { func TestAddAuthorization(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
PA := core.Authorization{} PA := core.Authorization{}
@ -200,7 +220,8 @@ func CreateDomainAuth(t *testing.T, domainName string, sa *SQLStorageAuthority)
// Ensure we get only valid authorization with correct RegID // Ensure we get only valid authorization with correct RegID
func TestGetLatestValidAuthorizationBasic(t *testing.T) { func TestGetLatestValidAuthorizationBasic(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
// attempt to get unauthorized domain // attempt to get unauthorized domain
authz, err := sa.GetLatestValidAuthorization(0, core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "example.org"}) authz, err := sa.GetLatestValidAuthorization(0, core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "example.org"})
@ -229,7 +250,9 @@ func TestGetLatestValidAuthorizationBasic(t *testing.T) {
// Ensure we get the latest valid authorization for an ident // Ensure we get the latest valid authorization for an ident
func TestGetLatestValidAuthorizationMultiple(t *testing.T) { func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
domain := "example.org" domain := "example.org"
ident := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain} ident := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
regID := int64(42) regID := int64(42)
@ -282,7 +305,8 @@ func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
} }
func TestAddCertificate(t *testing.T) { func TestAddCertificate(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
// An example cert taken from EFF's website // An example cert taken from EFF's website
certDER, err := ioutil.ReadFile("www.eff.org.der") certDER, err := ioutil.ReadFile("www.eff.org.der")
@ -334,7 +358,8 @@ func TestAddCertificate(t *testing.T) {
// TestGetCertificateByShortSerial tests some failure conditions for GetCertificate. // TestGetCertificateByShortSerial tests some failure conditions for GetCertificate.
// Success conditions are tested above in TestAddCertificate. // Success conditions are tested above in TestAddCertificate.
func TestGetCertificateByShortSerial(t *testing.T) { func TestGetCertificateByShortSerial(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
_, err := sa.GetCertificateByShortSerial("") _, err := sa.GetCertificateByShortSerial("")
test.AssertError(t, err, "Should've failed on empty serial") test.AssertError(t, err, "Should've failed on empty serial")
@ -352,14 +377,17 @@ func TestDeniedCSR(t *testing.T) {
csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, template, key) csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, template, key)
csr, _ := x509.ParseCertificateRequest(csrBytes) csr, _ := x509.ParseCertificateRequest(csrBytes)
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
exists, err := sa.AlreadyDeniedCSR(append(csr.DNSNames, csr.Subject.CommonName)) exists, err := sa.AlreadyDeniedCSR(append(csr.DNSNames, csr.Subject.CommonName))
test.AssertNotError(t, err, "AlreadyDeniedCSR failed") test.AssertNotError(t, err, "AlreadyDeniedCSR failed")
test.Assert(t, !exists, "Found non-existent CSR") test.Assert(t, !exists, "Found non-existent CSR")
} }
func TestUpdateOCSP(t *testing.T) { func TestUpdateOCSP(t *testing.T) {
sa := initSA(t) sa, cleanUp := initSA(t)
defer cleanUp()
// Add a cert to the DB to test with. // Add a cert to the DB to test with.
certDER, err := ioutil.ReadFile("www.eff.org.der") certDER, err := ioutil.ReadFile("www.eff.org.der")

31
test.sh
View File

@ -7,20 +7,7 @@ fi
FAILURE=0 FAILURE=0
TESTDIRS="analysis \ TESTPATHS=$(go list -f '{{ .ImportPath }}' ./...)
ca \
core \
log \
policy \
ra \
rpc \
sa \
test \
va \
wfe \
cmd/expiration-mailer"
# cmd
# Godeps
# We need to know, for github-pr-status, what the triggering commit is. # We need to know, for github-pr-status, what the triggering commit is.
# Assume first it's the travis commit (for builds of master), unless we're # Assume first it's the travis commit (for builds of master), unless we're
@ -117,8 +104,9 @@ function build_letsencrypt() {
function run_unit_tests() { function run_unit_tests() {
if [ "${TRAVIS}" == "true" ]; then if [ "${TRAVIS}" == "true" ]; then
# Run each test by itself for Travis, so we can get coverage # Run each test by itself for Travis, so we can get coverage
for dir in ${TESTDIRS}; do for path in ${TESTPATHS}; do
run go test -race -cover -coverprofile=${dir}.coverprofile ./${dir}/ dir=$(basename $path)
run go test -race -cover -coverprofile=${dir}.coverprofile ${path}
done done
# Gather all the coverprofiles # Gather all the coverprofiles
@ -180,14 +168,15 @@ check_gofmt() {
run_and_comment check_gofmt run_and_comment check_gofmt
end_context #test/gofmt end_context #test/gofmt
if [ "${TRAVIS}" == "true" ]; then
./test/create_db.sh || die "unable to create the boulder database with test/create_db.sh"
fi
# #
# Unit Tests. These do not receive a context or status updates, # Unit Tests. These do not receive a context or status updates,
# as they are reflected in our eventual exit code. # as they are reflected in our eventual exit code.
# #
# Ensure SQLite is installed so we don't recompile it each time
go install ./Godeps/_workspace/src/github.com/mattn/go-sqlite3
if [ "${SKIP_UNIT_TESTS}" == "1" ]; then if [ "${SKIP_UNIT_TESTS}" == "1" ]; then
echo "Skipping unit tests." echo "Skipping unit tests."
else else
@ -208,10 +197,6 @@ if [ "${SKIP_INTEGRATION_TESTS}" = "1" ]; then
exit ${FAILURE} exit ${FAILURE}
fi fi
if [ "${TRAVIS}" == "true" ]; then
./test/create_db.sh || die "unable to create the boulder database with test/create_db.sh"
fi
# #
# Integration tests # Integration tests
# #

View File

@ -48,7 +48,6 @@
"ca": { "ca": {
"serialPrefix": 255, "serialPrefix": 255,
"profile": "ee", "profile": "ee",
"dbDriver": "mysql",
"dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"debugAddr": "localhost:8001", "debugAddr": "localhost:8001",
"testMode": true, "testMode": true,
@ -120,7 +119,6 @@
}, },
"sa": { "sa": {
"dbDriver": "mysql",
"dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"debugAddr": "localhost:8003" "debugAddr": "localhost:8003"
}, },
@ -136,12 +134,10 @@
}, },
"revoker": { "revoker": {
"dbDriver": "mysql",
"dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test" "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test"
}, },
"ocspResponder": { "ocspResponder": {
"dbDriver": "mysql",
"dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"path": "/", "path": "/",
"listenAddress": "localhost:4001", "listenAddress": "localhost:4001",
@ -149,7 +145,6 @@
}, },
"ocspUpdater": { "ocspUpdater": {
"dbDriver": "mysql",
"dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"minTimeToExpiry": "72h", "minTimeToExpiry": "72h",
"debugAddr": "localhost:8006" "debugAddr": "localhost:8006"
@ -164,7 +159,6 @@
"port": "25", "port": "25",
"username": "cert-master@example.com", "username": "cert-master@example.com",
"password": "password", "password": "password",
"dbDriver": "mysql",
"dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"messageLimit": 0, "messageLimit": 0,
"nagTimes": ["24h", "72h", "168h", "336h"], "nagTimes": ["24h", "72h", "168h", "336h"],

View File

@ -42,8 +42,7 @@
"ca": { "ca": {
"serialPrefix": 255, "serialPrefix": 255,
"profile": "ee", "profile": "ee",
"dbDriver": "sqlite3", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"dbConnect": ":memory:",
"debugAddr": "localhost:8001", "debugAddr": "localhost:8001",
"testMode": true, "testMode": true,
"_comment": "This should only be present in testMode. In prod use an HSM.", "_comment": "This should only be present in testMode. In prod use an HSM.",
@ -105,8 +104,7 @@
}, },
"sa": { "sa": {
"dbDriver": "sqlite3", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"dbConnect": ":memory:",
"debugAddr": "localhost:8003" "debugAddr": "localhost:8003"
}, },
@ -121,21 +119,18 @@
}, },
"revoker": { "revoker": {
"dbDriver": "sqlite3", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test"
"dbConnect": ":memory:"
}, },
"ocspResponder": { "ocspResponder": {
"dbDriver": "sqlite3", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"dbConnect": ":memory:",
"debugAddr": "localhost:8004", "debugAddr": "localhost:8004",
"path": "/", "path": "/",
"listenAddress": "localhost:4001" "listenAddress": "localhost:4001"
}, },
"ocspUpdater": { "ocspUpdater": {
"dbDriver": "sqlite3", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"dbConnect": ":memory:",
"debugAddr": "localhost:8005", "debugAddr": "localhost:8005",
"minTimeToExpiry": "72h" "minTimeToExpiry": "72h"
}, },
@ -149,8 +144,7 @@
"port": "25", "port": "25",
"username": "cert-master@example.com", "username": "cert-master@example.com",
"password": "password", "password": "password",
"dbDriver": "sqlite3", "dbConnect": "mysql+tcp://boulder@localhost:3306/boulder_test",
"dbConnect": ":memory:",
"messageLimit": 0, "messageLimit": 0,
"nagTimes": ["24h", "72h", "168h", "336h"], "nagTimes": ["24h", "72h", "168h", "336h"],
"emailTemplate": "test/example-expiration-template", "emailTemplate": "test/example-expiration-template",

View File

@ -128,6 +128,8 @@ wk6Oiadty3eQqSBJv0HnpmiEdQVffIK5Pg4M8Dd+aOBnEkbopAJOuA==
"d616e2d6578616d706c652e636f6d300b06092a864886f70d01010b0341008cf8" + "d616e2d6578616d706c652e636f6d300b06092a864886f70d01010b0341008cf8" +
"f349efa6d2fadbaf8ed9ba67e5a9b98c3d5a13c06297c4cf36dc76f494e8887e3" + "f349efa6d2fadbaf8ed9ba67e5a9b98c3d5a13c06297c4cf36dc76f494e8887e3" +
"5dd9c885526136d810fc7640f5ba56281e2b75fa3ff7c91a7d23bab7fd4" "5dd9c885526136d810fc7640f5ba56281e2b75fa3ff7c91a7d23bab7fd4"
dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test"
) )
type MockSA struct { type MockSA struct {
@ -514,8 +516,7 @@ func TestIssueCertificate(t *testing.T) {
// TODO: Use a mock RA so we can test various conditions of authorized, not authorized, etc. // TODO: Use a mock RA so we can test various conditions of authorized, not authorized, etc.
common := cmd.PAConfig{ common := cmd.PAConfig{
DBDriver: "sqlite3", DBConnect: dbConnStr,
DBConnect: ":memory:",
} }
ra, _ := ra.NewRegistrationAuthorityImpl(common) ra, _ := ra.NewRegistrationAuthorityImpl(common)
ra.SA = &MockSA{} ra.SA = &MockSA{}