From 81db527f12f15e09229fa84dc7c27ec71c24114f Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 7 May 2019 11:38:27 -0700 Subject: [PATCH] NoopDB -> SimpleDB --- authority/authority.go | 6 ++-- authority/authorize.go | 31 +++++------------- authority/authorize_test.go | 5 ++- authority/tls_test.go | 3 -- db/db.go | 2 +- db/noop.go | 43 ------------------------- db/noop_test.go | 21 ------------- db/simple.go | 63 +++++++++++++++++++++++++++++++++++++ db/simple_test.go | 37 ++++++++++++++++++++++ 9 files changed, 112 insertions(+), 99 deletions(-) delete mode 100644 db/noop.go delete mode 100644 db/noop_test.go create mode 100644 db/simple.go create mode 100644 db/simple_test.go diff --git a/authority/authority.go b/authority/authority.go index aad8c3e2..5497dc2d 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -22,7 +22,6 @@ type Authority struct { intermediateIdentity *x509util.Identity validateOnce bool certificates *sync.Map - ottMap *sync.Map startTime time.Time provisioners *provisioner.Collection db db.AuthDB @@ -40,7 +39,6 @@ func New(config *Config) (*Authority, error) { var a = &Authority{ config: config, certificates: new(sync.Map), - ottMap: new(sync.Map), provisioners: provisioner.NewCollection(config.getAudiences()), } if err := a.init(); err != nil { @@ -58,8 +56,8 @@ func (a *Authority) init() error { var err error - // Initialize step-ca Database if defined in configuration. - // If a.config.DB is nil then a noopDB will be returned. + // Initialize step-ca Database. + // If a.config.DB is nil then a simple, barebones in memory DB will be used. if a.db, err = db.New(a.config.DB); err != nil { return err } diff --git a/authority/authorize.go b/authority/authorize.go index 3f4d048a..bf4ce15f 100644 --- a/authority/authorize.go +++ b/authority/authorize.go @@ -4,19 +4,12 @@ import ( "crypto/x509" "net/http" "strings" - "time" "github.com/pkg/errors" "github.com/smallstep/certificates/authority/provisioner" - "github.com/smallstep/certificates/db" "github.com/smallstep/cli/jose" ) -type idUsed struct { - UsedAt int64 `json:"ua,omitempty"` - Subject string `json:"sub,omitempty"` -} - // Claims extends jose.Claims with step attributes. type Claims struct { jose.Claims @@ -73,23 +66,13 @@ func (a *Authority) authorizeToken(ott string) (provisioner.Interface, error) { reuseKey = claims.Nonce } if reuseKey != "" { - switch a.db.(type) { - case *db.NoopDB: - if _, ok := a.ottMap.LoadOrStore(reuseKey, &idUsed{ - UsedAt: time.Now().Unix(), - Subject: claims.Subject, - }); ok { - return nil, &apiError{errors.Errorf("authorizeToken: token already used"), http.StatusUnauthorized, errContext} - } - default: - ok, err := a.db.UseToken(reuseKey, ott) - if err != nil { - return nil, &apiError{errors.Wrap(err, "authorizeToken: failed when checking if token already used"), - http.StatusInternalServerError, errContext} - } - if !ok { - return nil, &apiError{errors.Errorf("authorizeToken: token already used"), http.StatusUnauthorized, errContext} - } + ok, err := a.db.UseToken(reuseKey, ott) + if err != nil { + return nil, &apiError{errors.Wrap(err, "authorizeToken: failed when checking if token already used"), + http.StatusInternalServerError, errContext} + } + if !ok { + return nil, &apiError{errors.Errorf("authorizeToken: token already used"), http.StatusUnauthorized, errContext} } } diff --git a/authority/authorize_test.go b/authority/authorize_test.go index 43b51ff8..368e9807 100644 --- a/authority/authorize_test.go +++ b/authority/authorize_test.go @@ -117,7 +117,7 @@ func TestAuthority_authorizeToken(t *testing.T) { http.StatusUnauthorized, context{"ott": raw}}, } }, - "ok/noopdb": func(t *testing.T) *authorizeTest { + "ok/simpledb": func(t *testing.T) *authorizeTest { cl := jwt.Claims{ Subject: "test.smallstep.com", Issuer: validIssuer, @@ -133,9 +133,8 @@ func TestAuthority_authorizeToken(t *testing.T) { ott: raw, } }, - "fail/noopdb/token-already-used": func(t *testing.T) *authorizeTest { + "fail/simpledb/token-already-used": func(t *testing.T) *authorizeTest { _a := testAuthority(t) - cl := jwt.Claims{ Subject: "test.smallstep.com", Issuer: validIssuer, diff --git a/authority/tls_test.go b/authority/tls_test.go index 7efe7ab9..142eedde 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -592,7 +592,6 @@ func TestRevoke(t *testing.T) { tests := map[string]func() test{ "error/token/authorizeRevoke error": func() test { a := testAuthority(t) - a.db = new(db.NoopDB) ctx := getCtx() ctx["ott"] = "foo" return test{ @@ -609,8 +608,6 @@ func TestRevoke(t *testing.T) { }, "error/nil-db": func() test { a := testAuthority(t) - a.db = new(db.NoopDB) - cl := jwt.Claims{ Subject: "sn", Issuer: validIssuer, diff --git a/db/db.go b/db/db.go index 3687b113..0494c1ac 100644 --- a/db/db.go +++ b/db/db.go @@ -45,7 +45,7 @@ type DB struct { // New returns a new database client that implements the AuthDB interface. func New(c *Config) (AuthDB, error) { if c == nil { - return new(NoopDB), nil + return newSimpleDB(c) } db, err := nosql.New(c.Type, c.DataSource, nosql.WithDatabase(c.Database), diff --git a/db/noop.go b/db/noop.go deleted file mode 100644 index 27373fa1..00000000 --- a/db/noop.go +++ /dev/null @@ -1,43 +0,0 @@ -package db - -import ( - "crypto/x509" - - "github.com/pkg/errors" -) - -// ErrNotImplemented is an error returned when an operation is Not Implemented. -var ErrNotImplemented = errors.Errorf("not implemented") - -// NoopDB implements the DB interface with Noops -type NoopDB int - -// Init noop -func (n *NoopDB) Init(c *Config) (AuthDB, error) { - return n, nil -} - -// IsRevoked noop -func (n *NoopDB) IsRevoked(sn string) (bool, error) { - return false, nil -} - -// Revoke returns a "NotImplemented" error. -func (n *NoopDB) Revoke(rci *RevokedCertificateInfo) error { - return ErrNotImplemented -} - -// StoreCertificate returns a "NotImplemented" error. -func (n *NoopDB) StoreCertificate(crt *x509.Certificate) error { - return ErrNotImplemented -} - -// UseToken returns a "NotImplemented" error. -func (n *NoopDB) UseToken(id, tok string) (bool, error) { - return false, ErrNotImplemented -} - -// Shutdown returns nil -func (n *NoopDB) Shutdown() error { - return nil -} diff --git a/db/noop_test.go b/db/noop_test.go deleted file mode 100644 index 564a586c..00000000 --- a/db/noop_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package db - -import ( - "testing" - - "github.com/smallstep/assert" -) - -func Test_noop(t *testing.T) { - db := new(NoopDB) - - _db, err := db.Init(&Config{}) - assert.FatalError(t, err) - assert.Equals(t, db, _db) - - isRevoked, err := db.IsRevoked("foo") - assert.False(t, isRevoked) - assert.Nil(t, err) - - assert.Equals(t, db.Revoke(&RevokedCertificateInfo{}), ErrNotImplemented) -} diff --git a/db/simple.go b/db/simple.go new file mode 100644 index 00000000..657a518f --- /dev/null +++ b/db/simple.go @@ -0,0 +1,63 @@ +package db + +import ( + "crypto/x509" + "sync" + "time" + + "github.com/pkg/errors" +) + +// ErrNotImplemented is an error returned when an operation is Not Implemented. +var ErrNotImplemented = errors.Errorf("not implemented") + +// SimpleDB is a barebones implementation of the DB interface. It is NOT an +// in memory implementation of the DB, but rather the bare minimum of +// functionality that the CA requires to operate securely. +type SimpleDB struct { + usedTokens *sync.Map +} + +func newSimpleDB(c *Config) (AuthDB, error) { + db := &SimpleDB{} + db.usedTokens = new(sync.Map) + return db, nil +} + +// IsRevoked noop +func (s *SimpleDB) IsRevoked(sn string) (bool, error) { + return false, nil +} + +// Revoke returns a "NotImplemented" error. +func (s *SimpleDB) Revoke(rci *RevokedCertificateInfo) error { + return ErrNotImplemented +} + +// StoreCertificate returns a "NotImplemented" error. +func (s *SimpleDB) StoreCertificate(crt *x509.Certificate) error { + return ErrNotImplemented +} + +type usedToken struct { + UsedAt int64 `json:"ua,omitempty"` + Token string `json:"tok,omitempty"` +} + +// UseToken returns a "NotImplemented" error. +func (s *SimpleDB) UseToken(id, tok string) (bool, error) { + if _, ok := s.usedTokens.LoadOrStore(id, &usedToken{ + UsedAt: time.Now().Unix(), + Token: tok, + }); ok { + // Token already exists in DB. + return false, nil + } + // Successfully stored token. + return true, nil +} + +// Shutdown returns nil +func (s *SimpleDB) Shutdown() error { + return nil +} diff --git a/db/simple_test.go b/db/simple_test.go new file mode 100644 index 00000000..ad5aa70c --- /dev/null +++ b/db/simple_test.go @@ -0,0 +1,37 @@ +package db + +import ( + "testing" + + "github.com/smallstep/assert" +) + +func TestSimpleDB(t *testing.T) { + db, err := newSimpleDB(nil) + assert.FatalError(t, err) + + // Revoke + assert.Equals(t, ErrNotImplemented, db.Revoke(nil)) + + // IsRevoked -- verify noop + isRevoked, err := db.IsRevoked("foo") + assert.False(t, isRevoked) + assert.Nil(t, err) + + // StoreCertificate + assert.Equals(t, ErrNotImplemented, db.StoreCertificate(nil)) + + // UseToken + ok, err := db.UseToken("foo", "bar") + assert.True(t, ok) + assert.Nil(t, err) + ok, err = db.UseToken("foo", "cat") + assert.False(t, ok) + assert.Nil(t, err) + + // Shutdown -- verify noop + assert.FatalError(t, db.Shutdown()) + ok, err = db.UseToken("foo", "cat") + assert.False(t, ok) + assert.Nil(t, err) +}