Merge pull request #138 from letsencrypt/135-auditlogger_singletons

Issue #135: Convert the AuditLogger object to have Singleton pattern semantics
This commit is contained in:
James 'J.C.' Jones 2015-05-01 22:03:27 -07:00
commit 3ce61478ee
25 changed files with 206 additions and 168 deletions

View File

@ -39,7 +39,8 @@ func (eng *LoggingAnalysisEngine) ProcessMessage(delivery amqp.Delivery) (err er
}
// Construct a new Analysis Engine.
func NewLoggingAnalysisEngine(logger *blog.AuditLogger) AnalysisEngine {
func NewLoggingAnalysisEngine() AnalysisEngine {
logger := blog.GetAuditLogger()
logger.Notice("Analysis Engine Starting")
return &LoggingAnalysisEngine{log: logger}

View File

@ -6,19 +6,13 @@
package analysisengine
import (
"log/syslog"
"testing"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
"github.com/letsencrypt/boulder/log"
)
func TestNewLoggingAnalysisEngine(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
writer, _ := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
log, _ := log.NewAuditLogger(writer, stats)
ae := NewLoggingAnalysisEngine(log)
ae := NewLoggingAnalysisEngine()
// Trivially check an empty mock message
d := &amqp.Delivery{}
@ -45,10 +39,7 @@ func (m *MockAck) Reject(tag uint64, requeue bool) error {
}
func TestAnalysisEngineBadMessage(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
writer, _ := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
log, _ := log.NewAuditLogger(writer, stats)
ae := NewLoggingAnalysisEngine(log)
ae := NewLoggingAnalysisEngine()
// Trivially check an empty mock message
d := &amqp.Delivery{Acknowledger: &MockAck{}}

View File

@ -24,11 +24,8 @@ type CertificateAuthorityDatabaseImpl struct {
// NewCertificateAuthorityDatabaseImpl constructs a Database for the
// Certificate Authority.
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
}
func NewCertificateAuthorityDatabaseImpl(driver string, name string) (cadb core.CertificateAuthorityDatabase, err error) {
logger := blog.GetAuditLogger()
db, err := sql.Open(driver, name)
if err != nil {

View File

@ -8,9 +8,7 @@ package ca
import (
"testing"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/test"
)
@ -20,33 +18,21 @@ const sqliteDriver = "sqlite3"
const sqliteName = ":memory:"
func TestConstruction(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
log, err := blog.Dial("", "", "tag", stats)
test.AssertNotError(t, err, "Could not construct audit logger")
// Successful case
_, err = NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
_, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
// Covers "sql.Open" error
_, err = NewCertificateAuthorityDatabaseImpl(log, badDriver, sqliteName)
_, err = NewCertificateAuthorityDatabaseImpl(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)
_, err = NewCertificateAuthorityDatabaseImpl(sqliteDriver, badFilename)
test.AssertError(t, err, "Should have failed construction")
}
func TestBeginCommit(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
log, err := blog.Dial("", "", "tag", stats)
test.AssertNotError(t, err, "Could not construct audit logger")
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
cadb, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
err = cadb.Begin()
@ -64,11 +50,7 @@ func TestBeginCommit(t *testing.T) {
}
func TestGetSetSequenceOutsideTx(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
log, err := blog.Dial("", "", "tag", stats)
test.AssertNotError(t, err, "Could not construct audit logger")
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
cadb, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
_, err = cadb.IncrementAndGetSerial()
@ -76,11 +58,7 @@ func TestGetSetSequenceOutsideTx(t *testing.T) {
}
func TestGetSetSequenceNumber(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
log, err := blog.Dial("", "", "tag", stats)
test.AssertNotError(t, err, "Could not construct audit logger")
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
cadb, err := NewCertificateAuthorityDatabaseImpl(sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
err = cadb.Begin()

View File

@ -40,7 +40,8 @@ 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, serialPrefix int, cadb core.CertificateAuthorityDatabase) (ca *CertificateAuthorityImpl, err error) {
func NewCertificateAuthorityImpl(hostport string, authKey string, profile string, serialPrefix int, cadb core.CertificateAuthorityDatabase) (ca *CertificateAuthorityImpl, err error) {
logger := blog.GetAuditLogger()
logger.Notice("Certificate Authority Starting")
// Create the remote signer
@ -61,7 +62,7 @@ func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, auth
return
}
pa := policy.NewPolicyAuthorityImpl(logger)
pa := policy.NewPolicyAuthorityImpl()
ca = &CertificateAuthorityImpl{
Signer: signer,

View File

@ -20,7 +20,6 @@ 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"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/sa"
"github.com/letsencrypt/boulder/test"
@ -260,7 +259,7 @@ func TestIssueCertificate(t *testing.T) {
profileName := "ee"
// Create an SA
sa, err := sa.NewSQLStorageAuthority(blog.TestLogger(), "sqlite3", ":memory:")
sa, err := sa.NewSQLStorageAuthority("sqlite3", ":memory:")
test.AssertNotError(t, err, "Failed to create SA")
sa.InitTables()
@ -285,7 +284,7 @@ func TestIssueCertificate(t *testing.T) {
Provider: authHandler,
CSRWhitelist: &config.CSRWhitelist{
PublicKeyAlgorithm: true,
PublicKey: true,
PublicKey: true,
SignatureAlgorithm: true,
},
},
@ -306,7 +305,7 @@ func TestIssueCertificate(t *testing.T) {
// Create a CA
// Uncomment to test with a remote signer
ca, err := NewCertificateAuthorityImpl(blog.TestLogger(), hostPort, authKey, profileName, 17, cadb)
ca, err := NewCertificateAuthorityImpl(hostPort, authKey, profileName, 17, cadb)
test.AssertNotError(t, err, "Failed to create CA")
ca.SA = sa

View File

@ -61,7 +61,7 @@ func timeDelivery(d amqp.Delivery, stats statsd.Statter, deliveryTimings map[str
}
func startMonitor(rpcCh *amqp.Channel, logger *blog.AuditLogger, stats statsd.Statter) {
ae := analysisengine.NewLoggingAnalysisEngine(logger)
ae := analysisengine.NewLoggingAnalysisEngine()
// For convenience at the broker, identifiy ourselves by hostname
consumerTag, err := os.Hostname()
@ -144,6 +144,8 @@ func main() {
cmd.FailOnError(err, "Could not connect to Syslog")
blog.SetAuditLogger(auditlogger)
ch := cmd.AmqpChannel(c.AMQP.Server)
go cmd.ProfileCmd("AM", stats)
@ -153,4 +155,3 @@ func main() {
app.Run()
}

View File

@ -28,15 +28,16 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
cmd.FailOnError(err, "Could not connect to Syslog")
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(auditlogger, c.CA.DBDriver, c.CA.DBName)
blog.SetAuditLogger(auditlogger)
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(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, c.CA.SerialPrefix, cadb)
cai, err := ca.NewCertificateAuthorityImpl(c.CA.Server, c.CA.AuthKey, c.CA.Profile, c.CA.SerialPrefix, cadb)
cmd.FailOnError(err, "Failed to create CA impl")
go cmd.ProfileCmd("CA", stats)
for {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))

View File

@ -25,11 +25,12 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
cmd.FailOnError(err, "Could not connect to Syslog")
rai := ra.NewRegistrationAuthorityImpl(auditlogger)
blog.SetAuditLogger(auditlogger)
rai := ra.NewRegistrationAuthorityImpl()
go cmd.ProfileCmd("RA", stats)
for {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))

View File

@ -28,12 +28,13 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
cmd.FailOnError(err, "Could not connect to Syslog")
sai, err := sa.NewSQLStorageAuthority(auditlogger, c.SA.DBDriver, c.SA.DBName)
blog.SetAuditLogger(auditlogger)
sai, err := sa.NewSQLStorageAuthority(c.SA.DBDriver, c.SA.DBName)
cmd.FailOnError(err, "Failed to create SA impl")
go cmd.ProfileCmd("SA", stats)
for {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))

View File

@ -25,9 +25,11 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
cmd.FailOnError(err, "Could not connect to Syslog")
blog.SetAuditLogger(auditlogger)
go cmd.ProfileCmd("VA", stats)
vai := va.NewValidationAuthorityImpl(auditlogger, c.CA.TestMode)
vai := va.NewValidationAuthorityImpl(c.CA.TestMode)
for {
ch := cmd.AmqpChannel(c.AMQP.Server)

View File

@ -19,7 +19,7 @@ import (
"github.com/letsencrypt/boulder/wfe"
)
func setupWFE(c cmd.Config, auditlogger *blog.AuditLogger) (rpc.RegistrationAuthorityClient, rpc.StorageAuthorityClient, chan *amqp.Error) {
func setupWFE(c cmd.Config) (rpc.RegistrationAuthorityClient, rpc.StorageAuthorityClient, chan *amqp.Error) {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))
@ -73,8 +73,10 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
cmd.FailOnError(err, "Could not connect to Syslog")
wfe := wfe.NewWebFrontEndImpl(auditlogger)
rac, sac, closeChan := setupWFE(c, auditlogger)
blog.SetAuditLogger(auditlogger)
wfe := wfe.NewWebFrontEndImpl()
rac, sac, closeChan := setupWFE(c)
wfe.RA = &rac
wfe.SA = &sac
wfe.Stats = stats
@ -89,7 +91,7 @@ func main() {
for err := range closeChan {
auditlogger.Warning(fmt.Sprintf("AMQP Channel closed, will reconnect in 5 seconds: [%s]", err))
time.Sleep(time.Second * 5)
rac, sac, closeChan = setupWFE(c, auditlogger)
rac, sac, closeChan = setupWFE(c)
wfe.RA = &rac
wfe.SA = &sac
auditlogger.Warning("Reconnected to AMQP")

View File

@ -65,21 +65,23 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
cmd.FailOnError(err, "Could not connect to Syslog")
blog.SetAuditLogger(auditlogger)
// Run StatsD profiling
go cmd.ProfileCmd("Monolith", stats)
// Create the components
wfe := wfe.NewWebFrontEndImpl(auditlogger)
sa, err := sa.NewSQLStorageAuthority(auditlogger, c.SA.DBDriver, c.SA.DBName)
wfe := wfe.NewWebFrontEndImpl()
sa, err := sa.NewSQLStorageAuthority(c.SA.DBDriver, c.SA.DBName)
cmd.FailOnError(err, "Unable to create SA")
ra := ra.NewRegistrationAuthorityImpl(auditlogger)
va := va.NewValidationAuthorityImpl(auditlogger, c.CA.TestMode)
ra := ra.NewRegistrationAuthorityImpl()
va := va.NewValidationAuthorityImpl(c.CA.TestMode)
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(auditlogger, c.CA.DBDriver, c.CA.DBName)
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(c.CA.DBDriver, c.CA.DBName)
cmd.FailOnError(err, "Failed to create CA database")
ca, err := ca.NewCertificateAuthorityImpl(auditlogger, c.CA.Server, c.CA.AuthKey, c.CA.Profile, c.CA.SerialPrefix, cadb)
ca, err := ca.NewCertificateAuthorityImpl(c.CA.Server, c.CA.AuthKey, c.CA.Profile, c.CA.SerialPrefix, cadb)
cmd.FailOnError(err, "Unable to create CA")
// Wire them up

View File

@ -9,10 +9,20 @@ import (
"errors"
"fmt"
"log/syslog"
"sync"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
)
// singleton defines the object of a Singleton pattern
type singleton struct {
once sync.Once
log *AuditLogger
}
// _Singleton is the single AuditLogger entity in memory
var _Singleton singleton
// The constant used to identify audit-specific messages
const auditTag = "[AUDIT]"
@ -26,14 +36,6 @@ type AuditLogger struct {
Stats statsd.Statter
}
// TestLogger returns an AuditLogger, required to initialize many components
func TestLogger() (logger *AuditLogger) {
stats, _ := statsd.NewNoopClient(nil)
// Audit logger
logger, _ = Dial("", "", "tag", stats)
return
}
// Dial establishes a connection to the log daemon by passing through
// the parameters to the syslog.Dial method.
// See http://golang.org/pkg/log/syslog/#Dial
@ -54,6 +56,45 @@ func NewAuditLogger(log *syslog.Writer, stats statsd.Statter) (*AuditLogger, err
return &AuditLogger{log, stats}, nil
}
// initializeAuditLogger should only be used in unit tests. Failures in this
// method are unlikely as the defaults are safe, and they are also
// of minimal consequence during unit testing -- logs get printed to stdout
// even if syslog is missing.
func initializeAuditLogger() {
stats, _ := statsd.NewNoopClient(nil)
audit, _ := Dial("", "", "default", stats)
audit.Notice("Using default logging configuration.")
SetAuditLogger(audit)
}
// SetAuditLogger configures the singleton audit logger. This method
// must only be called once, and before calling GetAuditLogger the
// first time.
func SetAuditLogger(logger *AuditLogger) (err error) {
if _Singleton.log != nil {
err = errors.New("You may not call SetAuditLogger after it has already been implicitly or explicitly set.")
_Singleton.log.WarningErr(err)
} else {
_Singleton.log = logger
}
return
}
// GetAuditLogger obtains the singleton audit logger. If SetAuditLogger
// has not been called first, this method initializes with basic defaults.
// The basic defaults cannot error, and subequent access to an already-set
// AuditLogger also cannot error, so this method is error-safe.
func GetAuditLogger() *AuditLogger {
_Singleton.once.Do(func() {
if _Singleton.log == nil {
initializeAuditLogger()
}
})
return _Singleton.log
}
// Audit sends a NOTICE-severity message that is prefixed with the
// audit tag, for special handling at the upstream system logger.
func (log *AuditLogger) Audit(msg string) (err error) {

View File

@ -14,7 +14,6 @@ import (
"github.com/letsencrypt/boulder/test"
)
func TestConstruction(t *testing.T) {
writer, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
test.AssertNotError(t, err, "Could not construct syslog object")
@ -24,6 +23,35 @@ func TestConstruction(t *testing.T) {
test.AssertNotError(t, err, "Could not construct audit logger")
}
func TestSingleton(t *testing.T) {
log1 := GetAuditLogger()
test.AssertNotNil(t, log1, "Logger shouldn't be nil")
log2 := GetAuditLogger()
test.AssertEquals(t, log1, log2)
writer, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
test.AssertNotError(t, err, "Could not construct syslog object")
stats, _ := statsd.NewNoopClient(nil)
log3, err := NewAuditLogger(writer, stats)
test.AssertNotError(t, err, "Could not construct audit logger")
// Should not work
err = SetAuditLogger(log3)
test.AssertError(t, err, "Can't re-set")
// Verify no change
log4 := GetAuditLogger()
// Verify that log4 != log3
test.AssertNotEquals(t, log4, log3)
// Verify that log4 == log2 == log1
test.AssertEquals(t, log4, log2)
test.AssertEquals(t, log4, log1)
}
func TestDial(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
_, err := Dial("", "", "tag", stats)
@ -73,7 +101,9 @@ func TestEmitErrors(t *testing.T) {
}
func TestSyslogMethods(t *testing.T) {
writer, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
// Write all logs to UDP on a high port so as to not bother the system
// which is running the test, particularly for Emerg()
writer, err := syslog.Dial("udp", "127.0.0.1:65530", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
test.AssertNotError(t, err, "Could not construct syslog object")
stats, _ := statsd.NewNoopClient(nil)
@ -83,10 +113,10 @@ func TestSyslogMethods(t *testing.T) {
audit.Audit("audit-logger_test.go: audit-notice")
audit.Crit("audit-logger_test.go: critical")
audit.Debug("audit-logger_test.go: debug")
// Don't test Emerg... it sends a wall to the host OS.
// audit.Emerg("audit-logger_test.go: emerg")
audit.Emerg("audit-logger_test.go: emerg")
audit.Err("audit-logger_test.go: err")
audit.Info("audit-logger_test.go: info")
audit.Notice("audit-logger_test.go: notice")
audit.Warning("audit-logger_test.go: warning")
audit.Alert("audit-logger_test.go: alert")
}

View File

@ -22,7 +22,8 @@ type PolicyAuthorityImpl struct {
Blacklist map[string]bool // A blacklist of denied names
}
func NewPolicyAuthorityImpl(logger *blog.AuditLogger) *PolicyAuthorityImpl {
func NewPolicyAuthorityImpl() *PolicyAuthorityImpl {
logger := blog.GetAuditLogger()
logger.Notice("Registration Authority Starting")
pa := PolicyAuthorityImpl{log: logger}

View File

@ -8,9 +8,7 @@ package policy
import (
"testing"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
)
func TestWillingToIssue(t *testing.T) {
@ -89,11 +87,7 @@ func TestWillingToIssue(t *testing.T) {
"www.zombo-.com",
}
stats, _ := statsd.NewNoopClient(nil)
// Audit logger
audit, _ := blog.Dial("", "", "tag", stats)
pa := NewPolicyAuthorityImpl(audit)
pa := NewPolicyAuthorityImpl()
// Test for invalid identifier type
identifier := core.AcmeIdentifier{Type: "ip", Value: "example.com"}
@ -136,11 +130,7 @@ func TestWillingToIssue(t *testing.T) {
}
func TestChallengesFor(t *testing.T) {
stats, _ := statsd.NewNoopClient(nil)
// Audit logger
audit, _ := blog.Dial("", "", "tag", stats)
pa := NewPolicyAuthorityImpl(audit)
pa := NewPolicyAuthorityImpl()
challenges, combinations := pa.ChallengesFor(core.AcmeIdentifier{})

View File

@ -31,11 +31,12 @@ type RegistrationAuthorityImpl struct {
AuthzBase string
}
func NewRegistrationAuthorityImpl(logger *blog.AuditLogger) RegistrationAuthorityImpl {
func NewRegistrationAuthorityImpl() RegistrationAuthorityImpl {
logger := blog.GetAuditLogger()
logger.Notice("Registration Authority Starting")
ra := RegistrationAuthorityImpl{log: logger}
ra.PA = policy.NewPolicyAuthorityImpl(logger)
ra.PA = policy.NewPolicyAuthorityImpl()
return ra
}

View File

@ -15,13 +15,11 @@ import (
"net/url"
"testing"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"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/ca"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/jose"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/policy"
"github.com/letsencrypt/boulder/sa"
"github.com/letsencrypt/boulder/test"
@ -95,14 +93,10 @@ var (
)
func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationAuthority, *sa.SQLStorageAuthority, core.RegistrationAuthority) {
stats, _ := statsd.NewNoopClient(nil)
// Audit logger
audit, _ := blog.Dial("", "", "tag", stats)
err := json.Unmarshal(AccountKeyJSON, &AccountKey)
test.AssertNotError(t, err, "Failed to unmarshall JWK")
sa, err := sa.NewSQLStorageAuthority(audit, "sqlite3", ":memory:")
sa, err := sa.NewSQLStorageAuthority("sqlite3", ":memory:")
test.AssertNotError(t, err, "Failed to create SA")
sa.InitTables()
@ -114,13 +108,13 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA
caCertPEM, _ := pem.Decode([]byte(CA_CERT_PEM))
caCert, _ := x509.ParseCertificate(caCertPEM.Bytes)
signer, _ := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, nil)
pa := policy.NewPolicyAuthorityImpl(audit)
pa := policy.NewPolicyAuthorityImpl()
cadb := &MockCADatabase{}
ca := ca.CertificateAuthorityImpl{Signer: signer, SA: sa, PA: pa, DB: cadb}
csrDER, _ := hex.DecodeString(CSR_HEX)
ExampleCSR, _ = x509.ParseCertificateRequest(csrDER)
ra := NewRegistrationAuthorityImpl(audit)
ra := NewRegistrationAuthorityImpl()
ra.SA = sa
ra.VA = va
ra.CA = &ca

View File

@ -31,7 +31,8 @@ func digest256(data []byte) []byte {
return d.Sum(nil)
}
func NewSQLStorageAuthority(logger *blog.AuditLogger, driver string, name string) (ssa *SQLStorageAuthority, err error) {
func NewSQLStorageAuthority(driver string, name string) (ssa *SQLStorageAuthority, err error) {
logger := blog.GetAuditLogger()
logger.Notice("Storage Authority Starting")
db, err := sql.Open(driver, name)
@ -66,52 +67,52 @@ func (ssa *SQLStorageAuthority) InitTables() (err error) {
// handle null values well (see, e.g. https://github.com/go-sql-driver/mysql/issues/59)
statements := []string{
// Create registrations table
`CREATE TABLE IF NOT EXISTS registrations (
// Create registrations table
`CREATE TABLE IF NOT EXISTS registrations (
id VARCHAR(255) NOT NULL,
thumbprint VARCHAR(255) NOT NULL,
value BLOB NOT NULL
);`,
// Create pending authorizations table
// TODO: Add NOT NULL to value. Right now it causes test failures because some
// inserts to not fill all fields.
`CREATE TABLE IF NOT EXISTS pending_authz (
// Create pending authorizations table
// TODO: Add NOT NULL to value. Right now it causes test failures because some
// inserts to not fill all fields.
`CREATE TABLE IF NOT EXISTS pending_authz (
id VARCHAR(255) NOT NULL,
value BLOB
);`,
// Create finalized authorizations table
`CREATE TABLE IF NOT EXISTS authz (
// Create finalized authorizations table
`CREATE TABLE IF NOT EXISTS authz (
sequence INTEGER NOT NULL,
id VARCHAR(255) NOT NULL,
digest TEXT NOT NULL,
value BLOB NOT NULL
);`,
// Create certificates table. This should be effectively append-only, enforced
// by DB permissions.
`CREATE TABLE IF NOT EXISTS certificates (
// Create certificates table. This should be effectively append-only, enforced
// by DB permissions.
`CREATE TABLE IF NOT EXISTS certificates (
serial VARCHAR(255) NOT NULL,
digest VARCHAR(255) NOT NULL,
value BLOB NOT NULL,
issued DATETIME NOT NULL
);`,
// Create certificate status table. This provides metadata about a certificate
// that can change over its lifetime, and rows are updateable unlike the
// certificates table. The serial number primary key matches up with the one
// on certificates.
// subscriberApproved: 1 iff the subscriber has posted back to the server
// that they accept the certificate, otherwise 0.
// status: 'good' or 'revoked'. Note that good, expired certificates remain
// with status 'good' but don't necessarily get fresh OCSP responses.
// revokedDate: If status is 'revoked', this is the date and time it was
// revoked. Otherwise it has the zero value of time.Time, i.e. Jan 1 1970.
// ocspLastUpdated: The date and time of the last time we generated an OCSP
// response. If we have never generated one, this has the zero value of
// time.Time, i.e. Jan 1 1970.
`CREATE TABLE IF NOT EXISTS certificateStatus (
// Create certificate status table. This provides metadata about a certificate
// that can change over its lifetime, and rows are updateable unlike the
// certificates table. The serial number primary key matches up with the one
// on certificates.
// subscriberApproved: 1 iff the subscriber has posted back to the server
// that they accept the certificate, otherwise 0.
// status: 'good' or 'revoked'. Note that good, expired certificates remain
// with status 'good' but don't necessarily get fresh OCSP responses.
// revokedDate: If status is 'revoked', this is the date and time it was
// revoked. Otherwise it has the zero value of time.Time, i.e. Jan 1 1970.
// ocspLastUpdated: The date and time of the last time we generated an OCSP
// response. If we have never generated one, this has the zero value of
// time.Time, i.e. Jan 1 1970.
`CREATE TABLE IF NOT EXISTS certificateStatus (
serial VARCHAR(255) NOT NULL,
subscriberApproved INTEGER NOT NULL,
status VARCHAR(255) NOT NULL,
@ -224,7 +225,7 @@ func (ssa *SQLStorageAuthority) GetCertificate(id string) (cert []byte, err erro
}
err = ssa.db.QueryRow(
"SELECT value FROM certificates WHERE serial LIKE ? LIMIT 1;",
id + "%").Scan(&cert)
id+"%").Scan(&cert)
return
}
@ -236,7 +237,7 @@ func (ssa *SQLStorageAuthority) GetCertificateStatus(id string) (status core.Cer
err = errors.New("Invalid certificate serial " + id)
return
}
var statusString string;
var statusString string
err = ssa.db.QueryRow(
`SELECT subscriberApproved, status, ocspLastUpdated
FROM certificateStatus

View File

@ -6,16 +6,15 @@
package sa
import (
"io/ioutil"
"testing"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/test"
blog "github.com/letsencrypt/boulder/log"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"io/ioutil"
"testing"
)
func TestAddCertificate(t *testing.T) {
sa, err := NewSQLStorageAuthority(blog.TestLogger(), "sqlite3", ":memory:")
sa, err := NewSQLStorageAuthority("sqlite3", ":memory:")
test.AssertNotError(t, err, "Failed to create SA")
sa.InitTables()
@ -61,7 +60,7 @@ func TestAddCertificate(t *testing.T) {
// TestGetCertificate tests some failure conditions for GetCertificate.
// Success conditions are tested above in TestAddCertificate.
func TestGetCertificate(t *testing.T) {
sa, err := NewSQLStorageAuthority(blog.TestLogger(), "sqlite3", ":memory:")
sa, err := NewSQLStorageAuthority("sqlite3", ":memory:")
test.AssertNotError(t, err, "Failed to create SA")
sa.InitTables()

View File

@ -7,11 +7,11 @@ package test
import (
"bytes"
"fmt"
"strings"
"runtime"
"testing"
"encoding/base64"
"fmt"
"runtime"
"strings"
"testing"
)
// Return short format caller info for printing errors, so errors don't all
@ -19,7 +19,7 @@ import (
func caller() string {
_, file, line, _ := runtime.Caller(2)
splits := strings.Split(file, "/")
filename := splits[len(splits) - 1]
filename := splits[len(splits)-1]
return fmt.Sprintf("%s:%d:", filename, line)
}
@ -29,6 +29,12 @@ func Assert(t *testing.T, result bool, message string) {
}
}
func AssertNotNil(t *testing.T, obj interface{}, message string) {
if obj == nil {
t.Error(caller(), message)
}
}
func AssertNotError(t *testing.T, err error, message string) {
if err != nil {
t.Error(caller(), message, ":", err)
@ -41,9 +47,15 @@ func AssertError(t *testing.T, err error, message string) {
}
}
func AssertEquals(t *testing.T, one string, two string) {
func AssertEquals(t *testing.T, one interface{}, two interface{}) {
if one != two {
t.Errorf("%s String [%s] != [%s]", caller(), one, two)
t.Errorf("%s [%v] != [%v]", caller(), one, two)
}
}
func AssertNotEquals(t *testing.T, one interface{}, two interface{}) {
if one == two {
t.Errorf("%s [%v] == [%v]", caller(), one, two)
}
}

View File

@ -24,7 +24,8 @@ type ValidationAuthorityImpl struct {
TestMode bool
}
func NewValidationAuthorityImpl(logger *blog.AuditLogger, tm bool) ValidationAuthorityImpl {
func NewValidationAuthorityImpl(tm bool) ValidationAuthorityImpl {
logger := blog.GetAuditLogger()
logger.Notice("Validation Authority Starting")
return ValidationAuthorityImpl{log: logger, TestMode: tm}
}
@ -72,7 +73,7 @@ func (va ValidationAuthorityImpl) validateSimpleHTTPS(identifier core.AcmeIdenti
}
client := http.Client{
Transport: tr,
Timeout: 5 * time.Second,
Timeout: 5 * time.Second,
}
httpResponse, err := client.Do(httpRequest)

View File

@ -45,7 +45,8 @@ type WebFrontEndImpl struct {
TermsPath string
}
func NewWebFrontEndImpl(logger *blog.AuditLogger) WebFrontEndImpl {
func NewWebFrontEndImpl() WebFrontEndImpl {
logger := blog.GetAuditLogger()
logger.Notice("Web Front End Starting")
return WebFrontEndImpl{
log: logger,

View File

@ -16,10 +16,9 @@ import (
"strings"
"testing"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/jose"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/ra"
"github.com/letsencrypt/boulder/test"
)
@ -28,21 +27,13 @@ func makeBody(s string) io.ReadCloser {
return ioutil.NopCloser(strings.NewReader(s))
}
func mockLog(t *testing.T) (log *blog.AuditLogger) {
stats, _ := statsd.NewNoopClient(nil)
log, err := blog.Dial("", "", "tag", stats)
test.AssertNotError(t, err, "Could not construct audit logger")
return
}
// TODO: Write additional test cases for:
// - RA returns with a cert success
// - RA returns with a failure
func TestIssueCertificate(t *testing.T) {
log := mockLog(t)
// TODO: Use a mock RA so we can test various conditions of authorized, not authorized, etc.
ra := ra.NewRegistrationAuthorityImpl(log)
wfe := NewWebFrontEndImpl(log)
ra := ra.NewRegistrationAuthorityImpl()
wfe := NewWebFrontEndImpl()
wfe.RA = &ra
responseWriter := httptest.NewRecorder()
@ -203,8 +194,7 @@ func (ra *MockRegistrationAuthority) OnValidationUpdate(authz core.Authorization
}
func TestChallenge(t *testing.T) {
log := mockLog(t)
wfe := NewWebFrontEndImpl(log)
wfe := NewWebFrontEndImpl()
wfe.RA = &MockRegistrationAuthority{}
wfe.HandlePaths()
responseWriter := httptest.NewRecorder()