Add a Certificate Authority Database stub
* A few tests, but they don't all pass * needs actual DB code
This commit is contained in:
parent
ea4b0be56c
commit
97b356fcd4
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2015 ISRG. All rights reserved
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package ca
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
type CertificateAuthorityDatabaseImpl struct {
|
||||
log *blog.AuditLogger
|
||||
db *sql.DB
|
||||
activeTx *sql.Tx
|
||||
}
|
||||
|
||||
func NewCertificateAuthorityDatabaseImpl(logger *blog.AuditLogger, driver string, name string) (cadb core.CertificateAuthorityDatabase, err error) {
|
||||
if logger == nil {
|
||||
err = errors.New("Nil logger not permitted")
|
||||
return
|
||||
}
|
||||
|
||||
db, err := sql.Open(driver, name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = db.Ping(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cadb = &CertificateAuthorityDatabaseImpl{
|
||||
db: db,
|
||||
log: logger,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cadb *CertificateAuthorityDatabaseImpl) Begin() (err error) {
|
||||
if cadb.activeTx != nil {
|
||||
err = errors.New("Transaction already open")
|
||||
return
|
||||
}
|
||||
cadb.activeTx, err = cadb.db.Begin()
|
||||
return
|
||||
}
|
||||
|
||||
func (cadb *CertificateAuthorityDatabaseImpl) Commit() (err error) {
|
||||
if cadb.activeTx == nil {
|
||||
err = errors.New("Transaction already closed")
|
||||
return
|
||||
}
|
||||
err = cadb.activeTx.Commit()
|
||||
cadb.activeTx = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (cadb *CertificateAuthorityDatabaseImpl) GetNextNumber() (val int, err error) {
|
||||
if cadb.activeTx == nil {
|
||||
err = errors.New("No transaction open")
|
||||
return
|
||||
}
|
||||
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (cadb *CertificateAuthorityDatabaseImpl) IncrementNumber() (err error) {
|
||||
if cadb.activeTx == nil {
|
||||
err = errors.New("No transaction open")
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2015 ISRG. All rights reserved
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package ca
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
const badDriver = "nothing"
|
||||
const badFilename = "/doesnotexist/nofile"
|
||||
const sqliteDriver = "sqlite3"
|
||||
const sqliteName = ":memory:"
|
||||
|
||||
func TestConstruction(t *testing.T) {
|
||||
log, err := blog.Dial("", "", "tag")
|
||||
test.AssertNotError(t, err, "Could not construct audit logger")
|
||||
|
||||
// Successful case
|
||||
_, err = NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
|
||||
test.AssertNotError(t, err, "Could not construct CA DB")
|
||||
|
||||
// Covers "sql.Open" error
|
||||
_, err = NewCertificateAuthorityDatabaseImpl(log, badDriver, sqliteName)
|
||||
test.AssertError(t, err, "Should have failed construction")
|
||||
|
||||
// Covers "db.Ping" error
|
||||
_, err = NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, badFilename)
|
||||
test.AssertError(t, err, "Should have failed construction")
|
||||
|
||||
// Ensures no nil pointer exception in logging
|
||||
_, err = NewCertificateAuthorityDatabaseImpl(nil, sqliteDriver, sqliteName)
|
||||
test.AssertError(t, err, "Should have failed construction")
|
||||
}
|
||||
|
||||
func TestBeginCommit(t *testing.T) {
|
||||
log, err := blog.Dial("", "", "tag")
|
||||
test.AssertNotError(t, err, "Could not construct audit logger")
|
||||
|
||||
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
|
||||
test.AssertNotError(t, err, "Could not construct CA DB")
|
||||
|
||||
err = cadb.Begin()
|
||||
test.AssertNotError(t, err, "Could not begin")
|
||||
|
||||
err = cadb.Begin()
|
||||
test.AssertError(t, err, "Should have already begun")
|
||||
|
||||
err = cadb.Commit()
|
||||
test.AssertNotError(t, err, "Could not commit")
|
||||
|
||||
err = cadb.Commit()
|
||||
test.AssertError(t, err, "Should have already committed")
|
||||
|
||||
}
|
||||
|
||||
func TestGetSetSequenceOutsideTx(t *testing.T) {
|
||||
log, err := blog.Dial("", "", "tag")
|
||||
test.AssertNotError(t, err, "Could not construct audit logger")
|
||||
|
||||
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
|
||||
test.AssertNotError(t, err, "Could not construct CA DB")
|
||||
|
||||
_, err = cadb.GetNextNumber()
|
||||
test.AssertError(t, err, "Not permitted")
|
||||
|
||||
err = cadb.IncrementNumber()
|
||||
test.AssertError(t, err, "Not permitted")
|
||||
}
|
||||
|
||||
func TestGetSetSequenceNumber(t *testing.T) {
|
||||
log, err := blog.Dial("", "", "tag")
|
||||
test.AssertNotError(t, err, "Could not construct audit logger")
|
||||
|
||||
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
|
||||
test.AssertNotError(t, err, "Could not construct CA DB")
|
||||
|
||||
err = cadb.Begin()
|
||||
test.AssertNotError(t, err, "Could not begin")
|
||||
|
||||
num, err := cadb.GetNextNumber()
|
||||
test.AssertNotError(t, err, "Could not get number")
|
||||
|
||||
num2, err := cadb.GetNextNumber()
|
||||
test.AssertNotError(t, err, "Could not get number")
|
||||
test.Assert(t, num == num2, "Numbers should be the same")
|
||||
|
||||
err = cadb.IncrementNumber()
|
||||
test.AssertNotError(t, err, "Could not get number")
|
||||
|
||||
num3, err := cadb.GetNextNumber()
|
||||
test.AssertNotError(t, err, "Could not get number")
|
||||
test.Assert(t, num3 != num2, "Numbers should not be the same")
|
||||
|
||||
num4, err := cadb.GetNextNumber()
|
||||
test.AssertNotError(t, err, "Could not get number")
|
||||
test.Assert(t, num4 == num3, "Numbers should be the same")
|
||||
|
||||
err = cadb.Commit()
|
||||
test.AssertNotError(t, err, "Could not commit")
|
||||
}
|
|
@ -26,6 +26,7 @@ type CertificateAuthorityImpl struct {
|
|||
Signer signer.Signer
|
||||
SA core.StorageAuthority
|
||||
PA core.PolicyAuthority
|
||||
DB core.CertificateAuthorityDatabase
|
||||
log *blog.AuditLogger
|
||||
}
|
||||
|
||||
|
@ -35,7 +36,7 @@ type CertificateAuthorityImpl struct {
|
|||
// using CFSSL's authenticated signature scheme. A CA created in this way
|
||||
// issues for a single profile on the remote signer, which is indicated
|
||||
// by name in this constructor.
|
||||
func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, authKey string, profile string) (ca *CertificateAuthorityImpl, err error) {
|
||||
func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, authKey string, profile string, cadb core.CertificateAuthorityDatabase) (ca *CertificateAuthorityImpl, err error) {
|
||||
logger.Notice("Certificate Authority Starting")
|
||||
|
||||
// Create the remote signer
|
||||
|
@ -57,7 +58,13 @@ func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, auth
|
|||
|
||||
pa := policy.NewPolicyAuthorityImpl(logger)
|
||||
|
||||
ca = &CertificateAuthorityImpl{Signer: signer, profile: profile, PA: pa, log: logger}
|
||||
ca = &CertificateAuthorityImpl{
|
||||
Signer: signer,
|
||||
profile: profile,
|
||||
PA: pa,
|
||||
DB: cadb,
|
||||
log: logger,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
|
||||
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/sa"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
|
@ -218,6 +219,33 @@ var NO_NAME_CSR_HEX = "308202523082013a020100300d310b300906035504061302555330820
|
|||
"58c004d9e1e55af59ea517dfbd2bccca58216d8130b9f77c90328b2aa54b" +
|
||||
"1778a629b584f2bc059489a236131de9b444adca90218c31a499a485"
|
||||
|
||||
type MockCADatabase struct {
|
||||
// empty
|
||||
}
|
||||
|
||||
func NewMockCertificateAuthorityDatabase() (core.CertificateAuthorityDatabase, error) {
|
||||
return &MockCADatabase{}, nil
|
||||
}
|
||||
|
||||
|
||||
func (cadb *MockCADatabase) Begin() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cadb *MockCADatabase) Commit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cadb *MockCADatabase) GetNextNumber() (int, error) {
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (cadb *MockCADatabase) IncrementNumber() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
func TestIssueCertificate(t *testing.T) {
|
||||
// Audit logger
|
||||
audit, _ := blog.Dial("", "", "tag")
|
||||
|
@ -274,9 +302,11 @@ func TestIssueCertificate(t *testing.T) {
|
|||
// This goroutine should get killed when main() return
|
||||
go (func() { http.ListenAndServe(hostPort, nil) })()
|
||||
|
||||
cadb, err := NewMockCertificateAuthorityDatabase()
|
||||
|
||||
// Create a CA
|
||||
// Uncomment to test with a remote signer
|
||||
ca, err := NewCertificateAuthorityImpl(audit, hostPort, authKey, profileName)
|
||||
ca, err := NewCertificateAuthorityImpl(audit, hostPort, authKey, profileName, cadb)
|
||||
test.AssertNotError(t, err, "Failed to create CA")
|
||||
ca.SA = sa
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ package main
|
|||
|
||||
import (
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
|
||||
// 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/ca"
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
|
@ -21,7 +24,10 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
cai, err := ca.NewCertificateAuthorityImpl(auditlogger, c.CA.Server, c.CA.AuthKey, c.CA.Profile)
|
||||
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(auditlogger, c.CA.DBDriver, c.CA.DBName)
|
||||
cmd.FailOnError(err, "Failed to create CA database")
|
||||
|
||||
cai, err := ca.NewCertificateAuthorityImpl(auditlogger, c.CA.Server, c.CA.AuthKey, c.CA.Profile, cadb)
|
||||
cmd.FailOnError(err, "Failed to create CA impl")
|
||||
|
||||
for {
|
||||
|
|
|
@ -62,6 +62,8 @@ type Config struct {
|
|||
AuthKey string
|
||||
Profile string
|
||||
TestMode bool
|
||||
DBDriver string
|
||||
DBName string
|
||||
}
|
||||
|
||||
SA struct {
|
||||
|
|
|
@ -110,3 +110,12 @@ type StorageAuthority interface {
|
|||
StorageGetter
|
||||
StorageAdder
|
||||
}
|
||||
|
||||
// The CA Database represents an atomic sequence source
|
||||
type CertificateAuthorityDatabase interface {
|
||||
Begin() error
|
||||
Commit() error
|
||||
|
||||
GetNextNumber() (int, error)
|
||||
IncrementNumber() error
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
"server": "localhost:9000",
|
||||
"authKey": "79999d86250c367a2b517a1ae7d409c1",
|
||||
"profile": "ee",
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:",
|
||||
"testMode": true
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue