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:
commit
3ce61478ee
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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{}}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const (
|
|||
var openCalls int64 = 0
|
||||
|
||||
func timeDelivery(d amqp.Delivery, stats statsd.Statter, deliveryTimings map[string]time.Time) {
|
||||
// If d is a call add to deliveryTimings and increment openCalls, if it is a
|
||||
// If d is a call add to deliveryTimings and increment openCalls, if it is a
|
||||
// response then get time.Since original call from deliveryTiming, send timing metric, and
|
||||
// decrement openCalls, in both cases send the gauges RpcCallsOpen and RpcBodySize
|
||||
if d.ReplyTo != "" {
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -28,11 +28,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")
|
||||
|
||||
sai, err := sa.NewSQLStorageAuthority(auditlogger, c.SA.DBDriver, c.SA.DBName)
|
||||
cmd.FailOnError(err, "Failed to create SA impl")
|
||||
|
||||
go cmd.ProfileCmd("SA", stats)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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{})
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue