ICU-743/Domain errors internal/kms refactor (#848)
* Domain errors internal/kms refactor * Update changelog * Update internal/host error op * Incorrect error returned in read_writer
This commit is contained in:
1 parent
9de928318d
commit
8151b30ce9
68 files changed
+802
-725
No files matched your search
@@ -4,6 +4,11 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
|
||||
|
||||
## Next
|
||||
|
||||
### New and Improved
|
||||
|
||||
* controller: Improved error handling in kms repo
|
||||
([PR](https://github.com/hashicorp/boundary/pull/848))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cli: When `output-curl-string` is used with `update` or `add-/remove-/set-`
|
||||
|
||||
@@ -563,13 +563,13 @@ func (rw *Db) Delete(ctx context.Context, i interface{}, opt ...Option) (int, er
|
||||
if rowsDeleted > 0 && (withOplog || opts.newOplogMsg != nil) {
|
||||
if withOplog {
|
||||
if err := rw.addOplog(ctx, DeleteOp, opts, ticket, i); err != nil {
|
||||
return rowsDeleted, errors.Wrap(db.Error, op, errors.WithMsg("add oplog failed"))
|
||||
return rowsDeleted, errors.Wrap(err, op, errors.WithMsg("add oplog failed"))
|
||||
}
|
||||
}
|
||||
if opts.newOplogMsg != nil {
|
||||
msg, err := rw.newOplogMessage(ctx, DeleteOp, i)
|
||||
if err != nil {
|
||||
return rowsDeleted, errors.Wrap(db.Error, op, errors.WithMsg("returning oplog failed"))
|
||||
return rowsDeleted, errors.Wrap(err, op, errors.WithMsg("returning oplog failed"))
|
||||
}
|
||||
*opts.newOplogMsg = *msg
|
||||
}
|
||||
|
||||
@@ -1329,9 +1329,7 @@ func TestDb_Delete(t *testing.T) {
|
||||
assert.Equal(tt.want, got)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "received unexpected error: %v", err)
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "received unexpected error: %v", err)
|
||||
err := TestVerifyOplog(t, rw, tt.args.i.GetPublicId(), WithOperation(oplog.OpType_OP_TYPE_DELETE), WithCreateNotBefore(5*time.Second))
|
||||
assert.Error(err)
|
||||
return
|
||||
@@ -1660,9 +1658,7 @@ func TestDb_CreateItems(t *testing.T) {
|
||||
err := rw.CreateItems(context.Background(), tt.args.createItems, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error: %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -1857,9 +1853,7 @@ func TestDb_DeleteItems(t *testing.T) {
|
||||
rowsDeleted, err := rw.DeleteItems(context.Background(), tt.args.deleteItems, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error: %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -2108,9 +2102,7 @@ func TestDb_GetTicket(t *testing.T) {
|
||||
got, err := rw.GetTicket(tt.aggregateType)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error type: %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error type: %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -2252,9 +2244,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
|
||||
err := rw.WriteOplogEntryWith(context.Background(), tt.args.wrapper, tt.args.ticket, tt.args.metadata, tt.args.msgs, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
if tt.wantErrContains != "" {
|
||||
assert.Contains(err.Error(), tt.wantErrContains)
|
||||
}
|
||||
@@ -2283,7 +2273,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
want interface{}
|
||||
err error
|
||||
err errors.Code
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
@@ -2292,7 +2282,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
f: []string{"field"},
|
||||
d: 1,
|
||||
},
|
||||
err: errors.ErrInvalidParameter,
|
||||
err: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
@@ -2301,7 +2291,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
f: []string{"field"},
|
||||
d: 1,
|
||||
},
|
||||
err: errors.ErrInvalidParameter,
|
||||
err: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "pointer-to-nil-struct",
|
||||
@@ -2310,7 +2300,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
f: []string{"field"},
|
||||
d: 1,
|
||||
},
|
||||
err: errors.ErrInvalidParameter,
|
||||
err: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "pointer-to-string",
|
||||
@@ -2319,7 +2309,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
f: []string{"field"},
|
||||
d: 1,
|
||||
},
|
||||
err: errors.ErrInvalidParameter,
|
||||
err: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "not-pointer",
|
||||
@@ -2330,7 +2320,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
f: []string{"field"},
|
||||
d: 1,
|
||||
},
|
||||
err: errors.ErrInvalidParameter,
|
||||
err: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "map",
|
||||
@@ -2342,7 +2332,7 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
f: []string{"field"},
|
||||
d: 1,
|
||||
},
|
||||
err: errors.ErrInvalidParameter,
|
||||
err: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "pointer-to-struct",
|
||||
@@ -2364,8 +2354,8 @@ func TestClear_InputTypes(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
input := tt.args.v
|
||||
err := Clear(input, tt.args.f, tt.args.d)
|
||||
if tt.err != nil {
|
||||
assert.Error(err)
|
||||
if tt.err != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.err), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -2844,9 +2834,7 @@ func TestDb_oplogMsgsForItems(t *testing.T) {
|
||||
got, err := rw.oplogMsgsForItems(context.Background(), tt.args.opType, tt.args.opts, tt.args.items)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -26,6 +26,7 @@ const (
|
||||
InvalidPublicId Code = 102 // InvalidPublicId represents an invalid public Id for an operation
|
||||
InvalidFieldMask Code = 103 // InvalidFieldMask represents an invalid field mast for an operation
|
||||
EmptyFieldMask Code = 104 // EmptyFieldMask represents an empty field mask for an operation
|
||||
KeyNotFound Code = 105 // KeyNotFound represents that a key/version was not found in the KMS
|
||||
|
||||
// PasswordTooShort results from attempting to set a password which is to short.
|
||||
PasswordTooShort Code = 200
|
||||
@@ -42,6 +43,9 @@ const (
|
||||
// new passwords are equal.
|
||||
PasswordsEqual Code = 203
|
||||
|
||||
Encrypt Code = 300 // Encrypt represents an error occurred during the underlying encryption process
|
||||
Decrypt Code = 301 // Decrypt represents an error occurred during the underlying decryption process
|
||||
|
||||
// DB errors are reserved Codes from 1000-1999
|
||||
CheckConstraint Code = 1000 // CheckConstraint represents a check constraint error
|
||||
NotNull Code = 1001 // NotNull represents a value must not be null error
|
||||
|
||||
@@ -52,6 +52,11 @@ func TestCode_Both_String_Info(t *testing.T) {
|
||||
c: EmptyFieldMask,
|
||||
want: EmptyFieldMask,
|
||||
},
|
||||
{
|
||||
name: "KeyNotFound",
|
||||
c: KeyNotFound,
|
||||
want: KeyNotFound,
|
||||
},
|
||||
{
|
||||
name: "PasswordTooShort",
|
||||
c: PasswordTooShort,
|
||||
@@ -72,6 +77,16 @@ func TestCode_Both_String_Info(t *testing.T) {
|
||||
c: PasswordsEqual,
|
||||
want: PasswordsEqual,
|
||||
},
|
||||
{
|
||||
name: "Encrypt",
|
||||
c: Encrypt,
|
||||
want: Encrypt,
|
||||
},
|
||||
{
|
||||
name: "Decrypt",
|
||||
c: Decrypt,
|
||||
want: Decrypt,
|
||||
},
|
||||
{
|
||||
name: "CheckConstraint",
|
||||
c: CheckConstraint,
|
||||
|
||||
@@ -23,7 +23,9 @@ type Err struct {
|
||||
// Msg for the error
|
||||
Msg string
|
||||
|
||||
// Op represents the operation raising/propagating an error and is optional
|
||||
// Op represents the operation raising/propagating an error and is optional.
|
||||
// Op should be formatted as "package.func" for functions, while methods should
|
||||
// include the receiver type in parentheses "package.(type).func"
|
||||
Op Op
|
||||
|
||||
// Wrapped is the error which this Err wraps and will be nil if there's no
|
||||
@@ -101,7 +103,7 @@ func Wrap(e error, op Op, opt ...Option) error {
|
||||
// this convert can be removed
|
||||
err := Convert(e)
|
||||
if err != nil {
|
||||
// wrapped converted error
|
||||
// wrap the converted error
|
||||
e = err
|
||||
}
|
||||
opt = append(opt, WithWrap(e))
|
||||
|
||||
@@ -36,6 +36,10 @@ var errorCodeInfo = map[Code]Info{
|
||||
Message: "empty field mask",
|
||||
Kind: Parameter,
|
||||
},
|
||||
KeyNotFound: {
|
||||
Message: "key/version not found",
|
||||
Kind: Integrity,
|
||||
},
|
||||
PasswordTooShort: {
|
||||
Message: "too short",
|
||||
Kind: Password,
|
||||
@@ -52,6 +56,14 @@ var errorCodeInfo = map[Code]Info{
|
||||
Message: "old and new password are equal",
|
||||
Kind: Password,
|
||||
},
|
||||
Encrypt: {
|
||||
Message: "error occurred during encrypt",
|
||||
Kind: Encryption,
|
||||
},
|
||||
Decrypt: {
|
||||
Message: "error occurred during decrypt",
|
||||
Kind: Encryption,
|
||||
},
|
||||
CheckConstraint: {
|
||||
Message: "constraint check failed",
|
||||
Kind: Integrity,
|
||||
|
||||
@@ -10,6 +10,7 @@ const (
|
||||
Search
|
||||
Password
|
||||
Transaction
|
||||
Encryption
|
||||
)
|
||||
|
||||
func (e Kind) String() string {
|
||||
@@ -20,5 +21,6 @@ func (e Kind) String() string {
|
||||
Search: "search issue",
|
||||
Password: "password violation",
|
||||
Transaction: "db transaction issue",
|
||||
Encryption: "encryption issue",
|
||||
}[e]
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
// Both h.Name and h.Description are optional. If h.Name is set, it must be
|
||||
// unique within h.CatalogId.
|
||||
func (r *Repository) CreateHost(ctx context.Context, scopeId string, h *Host, opt ...Option) (*Host, error) {
|
||||
const op = "static.CreateHost"
|
||||
const op = "static.(Repository).CreateHost"
|
||||
if h == nil {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "nil Host")
|
||||
}
|
||||
@@ -72,7 +72,11 @@ func (r *Repository) CreateHost(ctx context.Context, scopeId string, h *Host, op
|
||||
_, err = r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
newHost = h.clone()
|
||||
return w.Create(ctx, newHost, db.WithOplog(oplogWrapper, h.oplog(oplog.OpType_OP_TYPE_CREATE)))
|
||||
err := w.Create(ctx, newHost, db.WithOplog(oplogWrapper, h.oplog(oplog.OpType_OP_TYPE_CREATE)))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
@@ -106,7 +110,7 @@ func (r *Repository) CreateHost(ctx context.Context, scopeId string, h *Host, op
|
||||
// An attribute of h will be set to NULL in the database if the attribute
|
||||
// in h is the zero value and it is included in fieldMaskPaths.
|
||||
func (r *Repository) UpdateHost(ctx context.Context, scopeId string, h *Host, version uint32, fieldMaskPaths []string, opt ...Option) (*Host, int, error) {
|
||||
const op = "static.UpdateHost"
|
||||
const op = "static.(Repository).UpdateHost"
|
||||
if h == nil {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "nil Host")
|
||||
}
|
||||
@@ -168,7 +172,7 @@ func (r *Repository) UpdateHost(ctx context.Context, scopeId string, h *Host, ve
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsUpdated > 1 {
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been updated")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -195,7 +199,7 @@ func (r *Repository) UpdateHost(ctx context.Context, scopeId string, h *Host, ve
|
||||
// LookupHost will look up a host in the repository. If the host is not
|
||||
// found, it will return nil, nil. All options are ignored.
|
||||
func (r *Repository) LookupHost(ctx context.Context, publicId string, opt ...Option) (*Host, error) {
|
||||
const op = "static.LookupHost"
|
||||
const op = "static.(Repository).LookupHost"
|
||||
if publicId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
@@ -213,7 +217,7 @@ func (r *Repository) LookupHost(ctx context.Context, publicId string, opt ...Opt
|
||||
// ListHosts returns a slice of Hosts for the catalogId.
|
||||
// WithLimit is the only option supported.
|
||||
func (r *Repository) ListHosts(ctx context.Context, catalogId string, opt ...Option) ([]*Host, error) {
|
||||
const op = "static.ListHosts"
|
||||
const op = "static.(Repository).ListHosts"
|
||||
if catalogId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "no catalog id")
|
||||
}
|
||||
@@ -235,7 +239,7 @@ func (r *Repository) ListHosts(ctx context.Context, catalogId string, opt ...Opt
|
||||
// returning a count of the number of records deleted. All options are
|
||||
// ignored.
|
||||
func (r *Repository) DeleteHost(ctx context.Context, scopeId string, publicId string, opt ...Option) (int, error) {
|
||||
const op = "static.DeleteHost"
|
||||
const op = "static.(Repository).DeleteHost"
|
||||
if publicId == "" {
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
@@ -257,7 +261,7 @@ func (r *Repository) DeleteHost(ctx context.Context, scopeId string, publicId st
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsDeleted > 1 {
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
//
|
||||
// Both c.CreateTime and c.UpdateTime are ignored.
|
||||
func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, opt ...Option) (*HostCatalog, error) {
|
||||
const op = "static.CreateCatalog"
|
||||
const op = "static.(Repository).CreateCatalog"
|
||||
if c == nil {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "nil HostCatalog")
|
||||
}
|
||||
@@ -69,11 +69,15 @@ func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, opt ...O
|
||||
db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
newHostCatalog = c.clone()
|
||||
return w.Create(
|
||||
err := w.Create(
|
||||
ctx,
|
||||
newHostCatalog,
|
||||
db.WithOplog(oplogWrapper, metadata),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
@@ -98,7 +102,7 @@ func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, opt ...O
|
||||
// An attribute of c will be set to NULL in the database if the attribute
|
||||
// in c is the zero value and it is included in fieldMask.
|
||||
func (r *Repository) UpdateCatalog(ctx context.Context, c *HostCatalog, version uint32, fieldMask []string, opt ...Option) (*HostCatalog, int, error) {
|
||||
const op = "static.UpdateCatalog"
|
||||
const op = "static.(Repository).UpdateCatalog"
|
||||
if c == nil {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "nil HostCatalog")
|
||||
}
|
||||
@@ -162,7 +166,7 @@ func (r *Repository) UpdateCatalog(ctx context.Context, c *HostCatalog, version
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsUpdated > 1 {
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been updated")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -181,7 +185,7 @@ func (r *Repository) UpdateCatalog(ctx context.Context, c *HostCatalog, version
|
||||
// LookupCatalog returns the HostCatalog for id. Returns nil, nil if no
|
||||
// HostCatalog is found for id.
|
||||
func (r *Repository) LookupCatalog(ctx context.Context, id string, opt ...Option) (*HostCatalog, error) {
|
||||
const op = "static.LookupCatalog"
|
||||
const op = "static.(Repository).LookupCatalog"
|
||||
if id == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
@@ -198,7 +202,7 @@ func (r *Repository) LookupCatalog(ctx context.Context, id string, opt ...Option
|
||||
|
||||
// ListCatalogs returns a slice of HostCatalogs for the scopeId. WithLimit is the only option supported.
|
||||
func (r *Repository) ListCatalogs(ctx context.Context, scopeId string, opt ...Option) ([]*HostCatalog, error) {
|
||||
const op = "static.ListCatalogs"
|
||||
const op = "static.(Repository).ListCatalogs"
|
||||
if scopeId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "no scope id")
|
||||
}
|
||||
@@ -219,7 +223,7 @@ func (r *Repository) ListCatalogs(ctx context.Context, scopeId string, opt ...Op
|
||||
// DeleteCatalog deletes id from the repository returning a count of the
|
||||
// number of records deleted.
|
||||
func (r *Repository) DeleteCatalog(ctx context.Context, id string, opt ...Option) (int, error) {
|
||||
const op = "static.DeleteCatalog"
|
||||
const op = "static.(Repository).DeleteCatalog"
|
||||
if id == "" {
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
@@ -260,7 +264,7 @@ func (r *Repository) DeleteCatalog(ctx context.Context, id string, opt ...Option
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsDeleted > 1 {
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
// Both s.Name and s.Description are optional. If s.Name is set, it must be
|
||||
// unique within s.CatalogId.
|
||||
func (r *Repository) CreateSet(ctx context.Context, scopeId string, s *HostSet, opt ...Option) (*HostSet, error) {
|
||||
const op = "static.CreateSet"
|
||||
const op = "static.(Repository).CreateSet"
|
||||
if s == nil {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "nil HostSet")
|
||||
}
|
||||
@@ -66,7 +66,11 @@ func (r *Repository) CreateSet(ctx context.Context, scopeId string, s *HostSet,
|
||||
_, err = r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
newHostSet = s.clone()
|
||||
return w.Create(ctx, newHostSet, db.WithOplog(oplogWrapper, s.oplog(oplog.OpType_OP_TYPE_CREATE)))
|
||||
err := w.Create(ctx, newHostSet, db.WithOplog(oplogWrapper, s.oplog(oplog.OpType_OP_TYPE_CREATE)))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
@@ -94,7 +98,7 @@ func (r *Repository) CreateSet(ctx context.Context, scopeId string, s *HostSet,
|
||||
// The WithLimit option can be used to limit the number of hosts returned.
|
||||
// All other options are ignored.
|
||||
func (r *Repository) UpdateSet(ctx context.Context, scopeId string, s *HostSet, version uint32, fieldMaskPaths []string, opt ...Option) (*HostSet, []*Host, int, error) {
|
||||
const op = "static.UpdateSet"
|
||||
const op = "static.(Repository).UpdateSet"
|
||||
if s == nil {
|
||||
return nil, nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "nil HostSet")
|
||||
}
|
||||
@@ -158,7 +162,7 @@ func (r *Repository) UpdateSet(ctx context.Context, scopeId string, s *HostSet,
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsUpdated > 1 {
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been updated")
|
||||
}
|
||||
hosts, err = getHosts(ctx, reader, s.PublicId, limit)
|
||||
if err != nil {
|
||||
@@ -183,7 +187,7 @@ func (r *Repository) UpdateSet(ctx context.Context, scopeId string, s *HostSet,
|
||||
// found, it will return nil, nil, nil. The WithLimit option can be used to
|
||||
// limit the number of hosts returned. All other options are ignored.
|
||||
func (r *Repository) LookupSet(ctx context.Context, publicId string, opt ...Option) (*HostSet, []*Host, error) {
|
||||
const op = "static.LookupSet"
|
||||
const op = "static.(Repository).LookupSet"
|
||||
if publicId == "" {
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
@@ -226,7 +230,7 @@ func (r *Repository) LookupSet(ctx context.Context, publicId string, opt ...Opti
|
||||
// ListSets returns a slice of HostSets for the catalogId. WithLimit is the
|
||||
// only option supported.
|
||||
func (r *Repository) ListSets(ctx context.Context, catalogId string, opt ...Option) ([]*HostSet, error) {
|
||||
const op = "static.ListSets"
|
||||
const op = "static.(Repository).ListSets"
|
||||
if catalogId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "no catalog id")
|
||||
}
|
||||
@@ -248,7 +252,7 @@ func (r *Repository) ListSets(ctx context.Context, catalogId string, opt ...Opti
|
||||
// returning a count of the number of records deleted. All options are
|
||||
// ignored.
|
||||
func (r *Repository) DeleteSet(ctx context.Context, scopeId string, publicId string, opt ...Option) (int, error) {
|
||||
const op = "static.DeleteSet"
|
||||
const op = "static.(Repository).DeleteSet"
|
||||
if publicId == "" {
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
@@ -273,7 +277,7 @@ func (r *Repository) DeleteSet(ctx context.Context, scopeId string, publicId str
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsDeleted > 1 {
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
// the set to be added. The version must match the current version of the
|
||||
// setId in the repository.
|
||||
func (r *Repository) AddSetMembers(ctx context.Context, scopeId string, setId string, version uint32, hostIds []string, opt ...Option) ([]*Host, error) {
|
||||
const op = "static.AddSetMembers"
|
||||
const op = "static.(Repository).AddSetMembers"
|
||||
if scopeId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "no scope id")
|
||||
}
|
||||
@@ -100,7 +100,7 @@ func updateVersion(ctx context.Context, w db.Writer, wrapper wrapping.Wrapper, m
|
||||
case err != nil:
|
||||
return errors.Wrap(err, op)
|
||||
case rowsUpdated > 1:
|
||||
return errors.E(errors.WithCode(errors.MultipleRecords))
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been updated")
|
||||
}
|
||||
msgs = append(msgs, setMsg)
|
||||
|
||||
@@ -159,7 +159,7 @@ func getHosts(ctx context.Context, reader db.Reader, setId string, limit int) ([
|
||||
// returns the number of hosts deleted from the set. The version must match
|
||||
// the current version of the setId in the repository.
|
||||
func (r *Repository) DeleteSetMembers(ctx context.Context, scopeId string, setId string, version uint32, hostIds []string, opt ...Option) (int, error) {
|
||||
const op = "static.DeleteSetMembers"
|
||||
const op = "static.(Repository).DeleteSetMembers"
|
||||
if scopeId == "" {
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "no scope id")
|
||||
}
|
||||
@@ -227,7 +227,7 @@ func deleteMembers(ctx context.Context, w db.Writer, members []interface{}) ([]*
|
||||
// set to be added. The version must match the current version of the setId
|
||||
// in the repository. If hostIds is empty, all hosts will be removed setId.
|
||||
func (r *Repository) SetSetMembers(ctx context.Context, scopeId string, setId string, version uint32, hostIds []string, opt ...Option) ([]*Host, int, error) {
|
||||
const op = "static.SetSetMembers"
|
||||
const op = "static.(Repository).SetSetMembers"
|
||||
if scopeId == "" {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "no scope id")
|
||||
}
|
||||
@@ -295,7 +295,7 @@ func (r *Repository) SetSetMembers(ctx context.Context, scopeId string, setId st
|
||||
if len(additions) > 0 {
|
||||
createdMsgs, err := createMembers(ctx, w, additions)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
msgs = append(msgs, createdMsgs...)
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
|
||||
@@ -326,7 +326,7 @@ type change struct {
|
||||
}
|
||||
|
||||
func (r *Repository) changes(ctx context.Context, setId string, hostIds []string) ([]*change, error) {
|
||||
const op = "static.changes"
|
||||
const op = "static.(Repository).changes"
|
||||
var inClauseSpots []string
|
||||
// starts at 2 because there is already a $1 in the query
|
||||
for i := 2; i < len(hostIds)+2; i++ {
|
||||
|
||||
@@ -245,9 +245,7 @@ func Test_GroupMemberCreate(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
|
||||
@@ -82,9 +82,7 @@ func TestNewGroup(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -257,9 +257,7 @@ func TestUserRole_Create(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
@@ -635,9 +633,7 @@ func TestGroupRole_Create(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
|
||||
@@ -94,11 +94,15 @@ func (r *Repository) create(ctx context.Context, resource Resource, _ ...Option)
|
||||
db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
returnedResource = resourceCloner.Clone()
|
||||
return w.Create(
|
||||
err := w.Create(
|
||||
ctx,
|
||||
returnedResource,
|
||||
db.WithOplog(oplogWrapper, metadata),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -430,9 +430,7 @@ func TestRepository_UpdateGroup(t *testing.T) {
|
||||
}
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
assert.Nil(groupAfterUpdate)
|
||||
assert.Equal(0, updatedRows)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
@@ -979,9 +977,7 @@ func TestRepository_DeleteGroupMembers(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.group.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.Match(errors.T(errors.RecordNotFound), err))
|
||||
|
||||
@@ -494,9 +494,7 @@ func TestRepository_DeletePrincipalRoles(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.role.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
|
||||
@@ -375,9 +375,7 @@ func TestRepository_DeleteRoleGrants(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "unexpected error %s", err.Error())
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.role.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
|
||||
@@ -424,9 +424,7 @@ func TestRepository_UpdateRole(t *testing.T) {
|
||||
roleAfterUpdate, principals, grants, updatedRows, err := repo.UpdateRole(context.Background(), &updateRole, r.Version, tt.args.fieldMaskPaths, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
assert.Nil(roleAfterUpdate)
|
||||
assert.Equal(0, updatedRows)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
|
||||
@@ -339,9 +339,7 @@ func TestRepository_UpdateUser(t *testing.T) {
|
||||
}
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
assert.Nil(userAfterUpdate)
|
||||
assert.Equal(0, updatedRows)
|
||||
switch tt.name {
|
||||
@@ -649,9 +647,7 @@ func TestRepository_LookupUserWithLogin(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
if tt.args.withAccountId != "" && tt.args.withAccountId != id {
|
||||
// need to assert that userid in auth_account is still null
|
||||
acct := allocAccount()
|
||||
@@ -820,9 +816,7 @@ func TestRepository_associateUserWithAccounts(t *testing.T) {
|
||||
err := associateUserWithAccounts(context.Background(), kms, rw, rw, tt.args.Ids.user, tt.args.Ids.accts, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -966,9 +960,7 @@ func TestRepository_dissociateUserWithAccount(t *testing.T) {
|
||||
err := dissociateUserFromAccounts(context.Background(), kms, rw, rw, tt.args.Ids.user, tt.args.Ids.accts, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -82,9 +82,7 @@ func TestNewRole(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -21,9 +20,10 @@ type DatabaseKey struct {
|
||||
|
||||
// NewDatabaseKey creates a new in memory database key. No options
|
||||
// are currently supported.
|
||||
func NewDatabaseKey(rootKeyId string, opt ...Option) (*DatabaseKey, error) {
|
||||
func NewDatabaseKey(rootKeyId string, _ ...Option) (*DatabaseKey, error) {
|
||||
const op = "kms.NewDatabaseKey"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("new root key: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
c := &DatabaseKey{
|
||||
DatabaseKey: &store.DatabaseKey{
|
||||
@@ -51,16 +51,17 @@ func (k *DatabaseKey) Clone() interface{} {
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// before it's written.
|
||||
func (k *DatabaseKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
const op = "kms.(DatabaseKey).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("database key vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
switch opType {
|
||||
case db.CreateOp:
|
||||
if k.RootKeyId == "" {
|
||||
return fmt.Errorf("database key vet for write: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
case db.UpdateOp:
|
||||
return fmt.Errorf("database key vet for write: key is immutable: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "key is immutable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestDatabaseKey_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.DatabaseKey
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -41,7 +41,7 @@ func TestDatabaseKey_Create(t *testing.T) {
|
||||
name: "empty-rootKeyId",
|
||||
args: args{},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -63,7 +63,7 @@ func TestDatabaseKey_Create(t *testing.T) {
|
||||
got, err := kms.NewDatabaseKey(tt.args.rootKeyId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -23,15 +22,16 @@ type DatabaseKeyVersion struct {
|
||||
|
||||
// NewDatabaseKeyVersion creates a new in memory database key version. No options are
|
||||
// currently supported.
|
||||
func NewDatabaseKeyVersion(databaseKeyId string, key []byte, rootKeyVersionId string, opt ...Option) (*DatabaseKeyVersion, error) {
|
||||
func NewDatabaseKeyVersion(databaseKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*DatabaseKeyVersion, error) {
|
||||
const op = "kms.NewDatabaseKeyVersion"
|
||||
if databaseKeyId == "" {
|
||||
return nil, fmt.Errorf("new database key version: missing database key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing database key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("new database key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if rootKeyVersionId == "" {
|
||||
return nil, fmt.Errorf("new database key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
|
||||
k := &DatabaseKeyVersion{
|
||||
@@ -62,22 +62,23 @@ func (k *DatabaseKeyVersion) Clone() interface{} {
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the database key
|
||||
// version before it's written.
|
||||
func (k *DatabaseKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
const op = "kms.(DatabaseKeyVersion).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("database key version vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
switch opType {
|
||||
case db.CreateOp:
|
||||
if k.CtKey == nil {
|
||||
return fmt.Errorf("database key version vet for write: missing key: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if k.DatabaseKeyId == "" {
|
||||
return fmt.Errorf("database key version vet for write: missing database key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing database key id")
|
||||
}
|
||||
if k.RootKeyVersionId == "" {
|
||||
return fmt.Errorf("database key version vet for write: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
case db.UpdateOp:
|
||||
return fmt.Errorf("database key version vet for write: key is immutable: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "key is immutable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -99,20 +100,22 @@ func (k *DatabaseKeyVersion) SetTableName(n string) {
|
||||
|
||||
// Encrypt will encrypt the database key version's key
|
||||
func (k *DatabaseKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(DatabaseKeyVersion).Encrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.DatabaseKeyVersion directly
|
||||
if err := structwrapping.WrapStruct(ctx, cipher, k.DatabaseKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error encrypting kms database key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Encrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt will decrypt the database key version's key
|
||||
func (k *DatabaseKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(DatabaseKeyVersion).Decrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.DatabaseKeyVersion directly
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, k.DatabaseKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error decrypting kms database key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Decrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func TestDatabaseKeyVersion_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.DatabaseKeyVersion
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -49,7 +49,7 @@ func TestDatabaseKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -58,7 +58,7 @@ func TestDatabaseKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-root-key-version-id",
|
||||
@@ -67,7 +67,7 @@ func TestDatabaseKeyVersion_Create(t *testing.T) {
|
||||
key: []byte("database key"),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -93,7 +93,7 @@ func TestDatabaseKeyVersion_Create(t *testing.T) {
|
||||
got, err := kms.NewDatabaseKeyVersion(tt.args.databaseKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
+21
-12
@@ -1,9 +1,8 @@
|
||||
package kms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -20,81 +19,91 @@ const (
|
||||
)
|
||||
|
||||
func newRootKeyId() (string, error) {
|
||||
const op = "kms.newRootKeyId"
|
||||
id, err := db.NewPublicId(RootKeyPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new root key id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newRootKeyVersionId() (string, error) {
|
||||
const op = "kms.newRootKeyVersionId"
|
||||
id, err := db.NewPublicId(RootKeyVersionPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new root key version id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newDatabaseKeyId() (string, error) {
|
||||
const op = "kms.newDatabaseKeyId"
|
||||
id, err := db.NewPublicId(DatabaseKeyPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new database key id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newDatabaseKeyVersionId() (string, error) {
|
||||
const op = "kms.newDatabaseKeyVersionId"
|
||||
id, err := db.NewPublicId(DatabaseKeyVersionPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new database key version id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newOplogKeyId() (string, error) {
|
||||
const op = "kms.newOplogKeyId"
|
||||
id, err := db.NewPublicId(OplogKeyPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new oplog key id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newOplogKeyVersionId() (string, error) {
|
||||
const op = "kms.newOplogKeyVersionId"
|
||||
id, err := db.NewPublicId(OplogKeyVersionPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new oplog key version id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newTokenKeyId() (string, error) {
|
||||
const op = "kms.newTokenKeyId"
|
||||
id, err := db.NewPublicId(TokenKeyPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new token key id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newTokenKeyVersionId() (string, error) {
|
||||
const op = "kms.newTokenKeyVersionId"
|
||||
id, err := db.NewPublicId(TokenKeyVersionPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new token key version id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newSessionKeyId() (string, error) {
|
||||
const op = "kms.newSessionKeyId"
|
||||
id, err := db.NewPublicId(SessionKeyPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new session key id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func newSessionKeyVersionId() (string, error) {
|
||||
const op = "kms.newSessionKeyVersionId"
|
||||
id, err := db.NewPublicId(SessionKeyVersionPrefix)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new session key version id: %w", err)
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
+34
-29
@@ -2,10 +2,10 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping"
|
||||
@@ -61,8 +61,9 @@ type Kms struct {
|
||||
|
||||
// NewKms takes in a repo and returns a Kms. Supported options: WithLogger.
|
||||
func NewKms(repo *Repository, opt ...Option) (*Kms, error) {
|
||||
const op = "kms.NewKms"
|
||||
if repo == nil {
|
||||
return nil, stderrors.New("new kms created without an underlying repo")
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing underlying repo")
|
||||
}
|
||||
|
||||
opts := getOpts(opt...)
|
||||
@@ -87,6 +88,7 @@ func (k *Kms) GetScopePurposeCache() *sync.Map {
|
||||
// of a key loss, there will need to be some refactoring here to have the values
|
||||
// being stored in the struct be a multiwrapper, but that's for a later project.
|
||||
func (k *Kms) AddExternalWrappers(opt ...Option) error {
|
||||
const op = "kms.AddExternalWrappers"
|
||||
k.externalScopeCacheMutex.Lock()
|
||||
defer k.externalScopeCacheMutex.Unlock()
|
||||
|
||||
@@ -101,19 +103,19 @@ func (k *Kms) AddExternalWrappers(opt ...Option) error {
|
||||
if opts.withRootWrapper != nil {
|
||||
ext.root = opts.withRootWrapper
|
||||
if ext.root.KeyID() == "" {
|
||||
return fmt.Errorf("root wrapper has no key ID")
|
||||
return errors.New(errors.InvalidParameter, op, "root wrapper has no key ID")
|
||||
}
|
||||
}
|
||||
if opts.withWorkerAuthWrapper != nil {
|
||||
ext.workerAuth = opts.withWorkerAuthWrapper
|
||||
if ext.workerAuth.KeyID() == "" {
|
||||
return fmt.Errorf("worker auth wrapper has no key ID")
|
||||
return errors.New(errors.InvalidParameter, op, "worker auth wrapper has no key ID")
|
||||
}
|
||||
}
|
||||
if opts.withRecoveryWrapper != nil {
|
||||
ext.recovery = opts.withRecoveryWrapper
|
||||
if ext.recovery.KeyID() == "" {
|
||||
return fmt.Errorf("recovery wrapper has no key ID")
|
||||
return errors.New(errors.InvalidParameter, op, "recovery wrapper has no key ID")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,16 +148,17 @@ func generateKeyId(scopeId string, purpose KeyPurpose, version uint32) string {
|
||||
// multiwrapper. This is not necesary for encryption but should be supplied for
|
||||
// decryption.
|
||||
func (k *Kms) GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose, opt ...Option) (wrapping.Wrapper, error) {
|
||||
const op = "kms.GetWrapper"
|
||||
if scopeId == "" {
|
||||
return nil, stderrors.New("no scope ID provided")
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing scope id")
|
||||
}
|
||||
|
||||
switch purpose {
|
||||
case KeyPurposeOplog, KeyPurposeDatabase, KeyPurposeTokens, KeyPurposeSessions:
|
||||
case KeyPurposeUnknown:
|
||||
return nil, stderrors.New("key purpose not specified")
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key purpose")
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported purpose %q", purpose)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("unsupported purpose %q", purpose))
|
||||
}
|
||||
|
||||
opts := getOpts(opt...)
|
||||
@@ -177,15 +180,15 @@ func (k *Kms) GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose
|
||||
// scope-purpose cache will catch everything in steady-state.
|
||||
rootWrapper, rootKeyId, err := k.loadRoot(ctx, scopeId, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading root key for scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error loading root key for scope %s", scopeId)))
|
||||
}
|
||||
if rootWrapper == nil {
|
||||
return nil, fmt.Errorf("got nil root wrapper for scope %s", scopeId)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("got nil root wrapper for scope %s", scopeId))
|
||||
}
|
||||
|
||||
wrapper, err := k.loadDek(ctx, scopeId, purpose, rootWrapper, rootKeyId, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading %s for scope %s: %w", purpose.String(), scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error loading %s for scope %s", purpose.String(), scopeId)))
|
||||
}
|
||||
k.scopePurposeCache.Store(scopeId+purpose.String(), wrapper)
|
||||
|
||||
@@ -193,6 +196,7 @@ func (k *Kms) GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose
|
||||
}
|
||||
|
||||
func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*multiwrapper.MultiWrapper, string, error) {
|
||||
const op = "kms.loadRoot"
|
||||
opts := getOpts(opt...)
|
||||
repo := opts.withRepository
|
||||
if repo == nil {
|
||||
@@ -200,7 +204,7 @@ func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*mul
|
||||
}
|
||||
rootKeys, err := repo.ListRootKeys(ctx)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("error listing root keys: %w", err)
|
||||
return nil, "", errors.Wrap(err, op)
|
||||
}
|
||||
var rootKeyId string
|
||||
for _, k := range rootKeys {
|
||||
@@ -210,7 +214,7 @@ func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*mul
|
||||
}
|
||||
}
|
||||
if rootKeyId == "" {
|
||||
return nil, "", fmt.Errorf("error finding root key for scope %s", scopeId)
|
||||
return nil, "", errors.New(errors.KeyNotFound, op, fmt.Sprintf("missing root key for scope %s", scopeId))
|
||||
}
|
||||
|
||||
// Now: find the external KMS that can be used to decrypt the root values
|
||||
@@ -219,21 +223,21 @@ func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*mul
|
||||
externalWrappers := k.externalScopeCache[scope.Global.String()]
|
||||
k.externalScopeCacheMutex.Unlock()
|
||||
if externalWrappers == nil {
|
||||
return nil, "", stderrors.New("could not find kms information at either the needed scope or global fallback")
|
||||
return nil, "", errors.New(errors.KeyNotFound, op, "could not find kms information at either the needed scope or global fallback")
|
||||
}
|
||||
|
||||
externalWrappers.m.RLock()
|
||||
defer externalWrappers.m.RUnlock()
|
||||
|
||||
if externalWrappers.root == nil {
|
||||
return nil, "", fmt.Errorf("root key wrapper for scope %s is nil", scopeId)
|
||||
return nil, "", errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key wrapper for scope %s is nil", scopeId))
|
||||
}
|
||||
rootKeyVersions, err := repo.ListRootKeyVersions(ctx, externalWrappers.root, rootKeyId, WithOrder("version desc"))
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("error looking up root key versions for scope %s with key ID %s: %w", scopeId, externalWrappers.root.KeyID(), err)
|
||||
return nil, "", errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error looking up root key versions for scope %s with key ID %s", scopeId, externalWrappers.root.KeyID())))
|
||||
}
|
||||
if len(rootKeyVersions) == 0 {
|
||||
return nil, "", fmt.Errorf("no root key versions found for scope %s", scopeId)
|
||||
return nil, "", errors.New(errors.KeyNotFound, op, fmt.Sprintf("no root key versions found for scope %s", scopeId))
|
||||
}
|
||||
|
||||
var multi *multiwrapper.MultiWrapper
|
||||
@@ -242,10 +246,10 @@ func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*mul
|
||||
if _, err := wrapper.SetConfig(map[string]string{
|
||||
"key_id": key.GetPrivateId(),
|
||||
}); err != nil {
|
||||
return nil, "", fmt.Errorf("error setting config on aead root wrapper in scope %s: %w", scopeId, err)
|
||||
return nil, "", errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead root wrapper in scope %s", scopeId)))
|
||||
}
|
||||
if err := wrapper.SetAESGCMKeyBytes(key.GetKey()); err != nil {
|
||||
return nil, "", fmt.Errorf("error setting key bytes on aead root wrapper in scope %s: %w", scopeId, err)
|
||||
return nil, "", errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead root wrapper in scope %s", scopeId)))
|
||||
}
|
||||
if i == 0 {
|
||||
multi = multiwrapper.NewMultiWrapper(wrapper)
|
||||
@@ -254,7 +258,7 @@ func (k *Kms) loadRoot(ctx context.Context, scopeId string, opt ...Option) (*mul
|
||||
}
|
||||
}
|
||||
|
||||
return multi, rootKeyId, err
|
||||
return multi, rootKeyId, nil
|
||||
}
|
||||
|
||||
// Dek is an interface wrapping dek types to allow a lot less switching in loadDek
|
||||
@@ -270,11 +274,12 @@ type DekVersion interface {
|
||||
}
|
||||
|
||||
func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, rootWrapper wrapping.Wrapper, rootKeyId string, opt ...Option) (*multiwrapper.MultiWrapper, error) {
|
||||
const op = "kms.loadDek"
|
||||
if rootWrapper == nil {
|
||||
return nil, fmt.Errorf("got nil root wrapper in loadDek for scope %s", scopeId)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("nil root wrapper for scope %s", scopeId))
|
||||
}
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("no root key ID provided for scope %s", scopeId)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("missing root key ID for scope %s", scopeId))
|
||||
}
|
||||
|
||||
opts := getOpts(opt...)
|
||||
@@ -296,7 +301,7 @@ func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, r
|
||||
keys, err = repo.ListSessionKeys(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing root keys: %w", err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg("error listing root keys"))
|
||||
}
|
||||
var keyId string
|
||||
for _, k := range keys {
|
||||
@@ -306,7 +311,7 @@ func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, r
|
||||
}
|
||||
}
|
||||
if keyId == "" {
|
||||
return nil, fmt.Errorf("error finding %s key for scope %s", purpose.String(), scopeId)
|
||||
return nil, errors.New(errors.KeyNotFound, op, fmt.Sprintf("error finding %s key for scope %s", purpose.String(), scopeId))
|
||||
}
|
||||
|
||||
var keyVersions []DekVersion
|
||||
@@ -321,10 +326,10 @@ func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, r
|
||||
keyVersions, err = repo.ListSessionKeyVersions(ctx, rootWrapper, keyId, WithOrder("version desc"))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error looking up %s key versions for scope %s with key ID %s: %w", purpose.String(), scopeId, rootWrapper.KeyID(), err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error looking up %s key versions for scope %s with key ID %s", purpose.String(), scopeId, rootWrapper.KeyID())))
|
||||
}
|
||||
if len(keyVersions) == 0 {
|
||||
return nil, fmt.Errorf("no %s key versions found for scope %s", purpose.String(), scopeId)
|
||||
return nil, errors.New(errors.KeyNotFound, op, fmt.Sprintf("no %s key versions found for scope %s", purpose.String(), scopeId))
|
||||
}
|
||||
|
||||
var multi *multiwrapper.MultiWrapper
|
||||
@@ -333,10 +338,10 @@ func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, r
|
||||
if _, err := wrapper.SetConfig(map[string]string{
|
||||
"key_id": keyVersion.GetPrivateId(),
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("error setting config on aead %s wrapper in scope %s: %w", purpose.String(), scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead %s wrapper in scope %s", purpose.String(), scopeId)))
|
||||
}
|
||||
if err := wrapper.SetAESGCMKeyBytes(keyVersion.GetKey()); err != nil {
|
||||
return nil, fmt.Errorf("error setting key bytes on aead %s wrapper in scope %s: %w", purpose.String(), scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead %s wrapper in scope %s", purpose.String(), scopeId)))
|
||||
}
|
||||
if i == 0 {
|
||||
multi = multiwrapper.NewMultiWrapper(wrapper)
|
||||
@@ -345,5 +350,5 @@ func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, r
|
||||
}
|
||||
}
|
||||
|
||||
return multi, err
|
||||
return multi, nil
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -21,9 +20,10 @@ type OplogKey struct {
|
||||
|
||||
// NewOplogKey creates a new in memory key. No options
|
||||
// are currently supported.
|
||||
func NewOplogKey(rootKeyId string, opt ...Option) (*OplogKey, error) {
|
||||
func NewOplogKey(rootKeyId string, _ ...Option) (*OplogKey, error) {
|
||||
const op = "kms.NewOplogKey"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("new root key: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
c := &OplogKey{
|
||||
OplogKey: &store.OplogKey{
|
||||
@@ -50,13 +50,14 @@ func (k *OplogKey) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// before it's written.
|
||||
func (k *OplogKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *OplogKey) VetForWrite(_ context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(OplogKey).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("oplog key vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if opType == db.CreateOp {
|
||||
if k.RootKeyId == "" {
|
||||
return fmt.Errorf("oplog key vet for write: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestOplogKey_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.OplogKey
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -41,7 +41,7 @@ func TestOplogKey_Create(t *testing.T) {
|
||||
name: "empty-rootKeyId",
|
||||
args: args{},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -63,7 +63,7 @@ func TestOplogKey_Create(t *testing.T) {
|
||||
got, err := kms.NewOplogKey(tt.args.rootKeyId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -23,15 +22,16 @@ type OplogKeyVersion struct {
|
||||
|
||||
// OplogKeyVersion creates a new in memory key version. No options are
|
||||
// currently supported.
|
||||
func NewOplogKeyVersion(oplogKeyId string, key []byte, rootKeyVersionId string, opt ...Option) (*OplogKeyVersion, error) {
|
||||
func NewOplogKeyVersion(oplogKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*OplogKeyVersion, error) {
|
||||
const op = "kms.NewOplogKeyVersion"
|
||||
if oplogKeyId == "" {
|
||||
return nil, fmt.Errorf("new oplog key version: missing oplog key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing oplog key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("new oplog key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if rootKeyVersionId == "" {
|
||||
return nil, fmt.Errorf("new oplog key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
|
||||
k := &OplogKeyVersion{
|
||||
@@ -61,19 +61,20 @@ func (k *OplogKeyVersion) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// version before it's written.
|
||||
func (k *OplogKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *OplogKeyVersion) VetForWrite(_ context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(OplogKeyVersion).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("oplog key version vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if opType == db.CreateOp {
|
||||
if k.CtKey == nil {
|
||||
return fmt.Errorf("oplog key version vet for write: missing key: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if k.OplogKeyId == "" {
|
||||
return fmt.Errorf("oplog key version vet for write: missing oplog key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing oplog key id")
|
||||
}
|
||||
if k.RootKeyVersionId == "" {
|
||||
return fmt.Errorf("oplog key version vet for write: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -96,20 +97,22 @@ func (k *OplogKeyVersion) SetTableName(n string) {
|
||||
|
||||
// Encrypt will encrypt the key version's key
|
||||
func (k *OplogKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(OplogKeyVersion).Encrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.OplogKeyVersion directly
|
||||
if err := structwrapping.WrapStruct(ctx, cipher, k.OplogKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error encrypting kms oplog key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Encrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt will decrypt the key version's key
|
||||
func (k *OplogKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(OplogKeyVersion).Decrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.OplogKeyVersion directly
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, k.OplogKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error decrypting kms oplog key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Decrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func TestOplogKeyVersion_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.OplogKeyVersion
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -49,7 +49,7 @@ func TestOplogKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -58,7 +58,7 @@ func TestOplogKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-root-key-version-id",
|
||||
@@ -67,7 +67,7 @@ func TestOplogKeyVersion_Create(t *testing.T) {
|
||||
key: []byte("test key"),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -93,7 +93,7 @@ func TestOplogKeyVersion_Create(t *testing.T) {
|
||||
got, err := kms.NewOplogKeyVersion(tt.args.oplogKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
+23
-21
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@@ -24,11 +23,12 @@ type Repository struct {
|
||||
// NewRepository creates a new kms Repository. Supports the options: WithLimit
|
||||
// which sets a default limit on results returned by repo operations.
|
||||
func NewRepository(r db.Reader, w db.Writer, opt ...Option) (*Repository, error) {
|
||||
const op = "kms.NewRepository"
|
||||
if r == nil {
|
||||
return nil, stderrors.New("error creating db repository with nil reader")
|
||||
return nil, errors.New(errors.InvalidParameter, op, "nil reader")
|
||||
}
|
||||
if w == nil {
|
||||
return nil, stderrors.New("error creating db repository with nil writer")
|
||||
return nil, errors.New(errors.InvalidParameter, op, "nil writer")
|
||||
}
|
||||
opts := getOpts(opt...)
|
||||
if opts.withLimit == 0 {
|
||||
@@ -78,74 +78,75 @@ type Keys map[KeyType]KeyIder
|
||||
// This function encapsulates all the work required within a db.TxHandler and
|
||||
// allows this capability to be shared with the iam repo.
|
||||
func CreateKeysTx(ctx context.Context, dbReader db.Reader, dbWriter db.Writer, rootWrapper wrapping.Wrapper, randomReader io.Reader, scopeId string) (Keys, error) {
|
||||
const op = "kms.CreateKeysTx"
|
||||
if dbReader == nil {
|
||||
return nil, fmt.Errorf("create keys: missing db reader: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing db reader")
|
||||
}
|
||||
if dbWriter == nil {
|
||||
return nil, fmt.Errorf("create keys: missing db writer: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing db writer")
|
||||
}
|
||||
if rootWrapper == nil {
|
||||
return nil, fmt.Errorf("create keys: missing root wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root wrapper")
|
||||
}
|
||||
if randomReader == nil {
|
||||
return nil, fmt.Errorf("create keys: missing random reader: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing random reader")
|
||||
}
|
||||
if scopeId == "" {
|
||||
return nil, fmt.Errorf("create keys: missing scope id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing scope id")
|
||||
}
|
||||
k, err := generateKey(randomReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: error generating random bytes for root key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for root key in scope %s", scopeId)))
|
||||
}
|
||||
rootKey, rootKeyVersion, err := createRootKeyTx(ctx, dbWriter, rootWrapper, scopeId, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: unable to create root key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create root key in scope %s", scopeId)))
|
||||
}
|
||||
|
||||
rkvWrapper := aead.NewWrapper(nil)
|
||||
if _, err := rkvWrapper.SetConfig(map[string]string{
|
||||
"key_id": rootKeyVersion.GetPrivateId(),
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("create keys: error setting config on aead root wrapper in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead root wrapper in scope %s", scopeId)))
|
||||
}
|
||||
if err := rkvWrapper.SetAESGCMKeyBytes(rootKeyVersion.GetKey()); err != nil {
|
||||
return nil, fmt.Errorf("create keys: error setting key bytes on aead root wrapper in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead root wrapper in scope %s", scopeId)))
|
||||
}
|
||||
|
||||
k, err = generateKey(randomReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: error generating random bytes for database key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for database key in scope %s", scopeId)))
|
||||
}
|
||||
dbKey, dbKeyVersion, err := createDatabaseKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: unable to create database key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create database key in scope %s", scopeId)))
|
||||
}
|
||||
|
||||
k, err = generateKey(randomReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: error generating random bytes for oplog key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for oplog key in scope %s", scopeId)))
|
||||
}
|
||||
oplogKey, oplogKeyVersion, err := createOplogKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: unable to create oplog key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create oplog key in scope %s", scopeId)))
|
||||
}
|
||||
|
||||
k, err = generateKey(randomReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: error generating random bytes for session key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for session key in scope %s", scopeId)))
|
||||
}
|
||||
sessionKey, sessionKeyVersion, err := createSessionKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: unable to create session key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create session key in scope %s", scopeId)))
|
||||
}
|
||||
|
||||
k, err = generateKey(randomReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: error generating random bytes for token key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for token key in scope %s", scopeId)))
|
||||
}
|
||||
tokenKey, tokenKeyVersion, err := createTokenKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create keys: unable to create token key in scope %s: %w", scopeId, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create token key in scope %s", scopeId)))
|
||||
}
|
||||
|
||||
keys := Keys{
|
||||
@@ -164,9 +165,10 @@ func CreateKeysTx(ctx context.Context, dbReader db.Reader, dbWriter db.Writer, r
|
||||
}
|
||||
|
||||
func generateKey(randomReader io.Reader) ([]byte, error) {
|
||||
const op = "kms.generateKey"
|
||||
k, err := uuid.GenerateRandomBytesWithReader(32, randomReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating random bytes for key: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return k, nil
|
||||
}
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
// CreateDatabaseKey inserts into the repository and returns the new database key and
|
||||
// database key version. There are no valid options at this time.
|
||||
func (r *Repository) CreateDatabaseKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, opt ...Option) (*DatabaseKey, *DatabaseKeyVersion, error) {
|
||||
func (r *Repository) CreateDatabaseKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*DatabaseKey, *DatabaseKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateDatabaseKey"
|
||||
var returnedDk, returnedDv interface{}
|
||||
_, err := r.writer.DoTx(
|
||||
ctx,
|
||||
@@ -21,84 +22,86 @@ func (r *Repository) CreateDatabaseKey(ctx context.Context, rkvWrapper wrapping.
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
var err error
|
||||
if returnedDk, returnedDv, err = createDatabaseKeyTx(ctx, reader, w, rkvWrapper, key); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
return returnedDk.(*DatabaseKey), returnedDv.(*DatabaseKeyVersion), err
|
||||
return returnedDk.(*DatabaseKey), returnedDv.(*DatabaseKeyVersion), nil
|
||||
}
|
||||
|
||||
// createDatabaseKeyTx inserts into the db (via db.Writer) and returns the new database key
|
||||
// and database key version. This function encapsulates all the work required within
|
||||
// a db.TxHandler and allows this capability to be shared with the iam repo.
|
||||
func createDatabaseKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*DatabaseKey, *DatabaseKeyVersion, error) {
|
||||
const op = "kms.createDatabaseKeyTx"
|
||||
if rkvWrapper == nil {
|
||||
return nil, nil, fmt.Errorf("create database key: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, nil, fmt.Errorf("create database key: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, nil, fmt.Errorf("create database key: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, nil, fmt.Errorf("create database key: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
rv := AllocRootKeyVersion()
|
||||
rv.PrivateId = rootKeyVersionId
|
||||
err := r.LookupById(ctx, &rv)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: unable to lookup root key version %s: %w", rootKeyVersionId, err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId)))
|
||||
}
|
||||
|
||||
dk := AllocDatabaseKey()
|
||||
dv := AllocDatabaseKeyVersion()
|
||||
id, err := newDatabaseKeyId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
dk.PrivateId = id
|
||||
dk.RootKeyId = rv.RootKeyId
|
||||
|
||||
id, err = newDatabaseKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
dv.PrivateId = id
|
||||
dv.DatabaseKeyId = dk.PrivateId
|
||||
dv.RootKeyVersionId = rootKeyVersionId
|
||||
dv.Key = key
|
||||
if err := dv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
// no oplog entries for keys
|
||||
if err := w.Create(ctx, &dk); err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: database create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("keys create"))
|
||||
}
|
||||
// no oplog entries for key versions
|
||||
if err := w.Create(ctx, &dv); err != nil {
|
||||
return nil, nil, fmt.Errorf("create database key: version create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("key versions create"))
|
||||
}
|
||||
|
||||
return &dk, &dv, err
|
||||
return &dk, &dv, nil
|
||||
}
|
||||
|
||||
// LookupDatabaseKey will look up a key in the repository. If the key is not
|
||||
// found, it will return nil, nil.
|
||||
func (r *Repository) LookupDatabaseKey(ctx context.Context, privateId string, opt ...Option) (*DatabaseKey, error) {
|
||||
func (r *Repository) LookupDatabaseKey(ctx context.Context, privateId string, _ ...Option) (*DatabaseKey, error) {
|
||||
const op = "kms.(Repository).LookupDatabaseKey"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup database key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocDatabaseKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup database key: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -106,14 +109,15 @@ func (r *Repository) LookupDatabaseKey(ctx context.Context, privateId string, op
|
||||
// DeleteDatabaseKey deletes the key for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteDatabaseKey(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteDatabaseKey(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).LookupDatabaseKey"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete database key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocDatabaseKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete database key: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -125,24 +129,28 @@ func (r *Repository) DeleteDatabaseKey(ctx context.Context, privateId string, op
|
||||
dk := k.Clone()
|
||||
// no oplog entries for root keys
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete database key: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// ListDatabaseKeys will list the keys. Supports the WithLimit option.
|
||||
func (r *Repository) ListDatabaseKeys(ctx context.Context, opt ...Option) ([]Dek, error) {
|
||||
const op = "kms.(Repository).ListDatabaseKeys"
|
||||
var keys []*DatabaseKey
|
||||
err := r.list(ctx, &keys, "1=1", nil, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list database keys: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
deks := make([]Dek, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
|
||||
@@ -114,9 +114,7 @@ func TestRepository_CreateDatabaseKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(dk)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -209,9 +207,7 @@ func TestRepository_DeleteDatabaseKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
// make sure there was no oplog written
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
|
||||
@@ -12,34 +12,35 @@ import (
|
||||
|
||||
// CreateDatabaseKeyVersion inserts into the repository and returns the new key
|
||||
// version with its PrivateId. There are no valid options at this time.
|
||||
func (r *Repository) CreateDatabaseKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, key []byte, opt ...Option) (*DatabaseKeyVersion, error) {
|
||||
func (r *Repository) CreateDatabaseKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, key []byte, _ ...Option) (*DatabaseKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateDatabaseKeyVersion"
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("create database key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, fmt.Errorf("create database key version: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, fmt.Errorf("create database key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
if databaseKeyId == "" {
|
||||
return nil, fmt.Errorf("create database key version: missing database key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing database key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("create database key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
kv := AllocDatabaseKeyVersion()
|
||||
id, err := newDatabaseKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create database key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
kv.PrivateId = id
|
||||
kv.RootKeyVersionId = rootKeyVersionId
|
||||
kv.Key = key
|
||||
kv.DatabaseKeyId = databaseKeyId
|
||||
if err := kv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("create database key version: encrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
var returnedKey interface{}
|
||||
@@ -51,33 +52,34 @@ func (r *Repository) CreateDatabaseKeyVersion(ctx context.Context, rkvWrapper wr
|
||||
returnedKey = kv.Clone()
|
||||
// no oplog entries for root key version
|
||||
if err := w.Create(ctx, returnedKey); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create database key version: %w for %s database key id", err, kv.DatabaseKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s database key id", kv.DatabaseKeyId)))
|
||||
}
|
||||
return returnedKey.(*DatabaseKeyVersion), err
|
||||
return returnedKey.(*DatabaseKeyVersion), nil
|
||||
}
|
||||
|
||||
// LookupDatabaseKeyVersion will look up a key version in the repository. If
|
||||
// the key version is not found, it will return nil, nil.
|
||||
func (r *Repository) LookupDatabaseKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, opt ...Option) (*DatabaseKeyVersion, error) {
|
||||
func (r *Repository) LookupDatabaseKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*DatabaseKeyVersion, error) {
|
||||
const op = "kms.(Repository).LookupDatabaseKeyVersion"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup database key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("lookup database key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
k := AllocDatabaseKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup database key version: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
if err := k.Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("lookup database key version: decrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -85,14 +87,15 @@ func (r *Repository) LookupDatabaseKeyVersion(ctx context.Context, keyWrapper wr
|
||||
// DeleteDatabaseKeyVersion deletes the key version for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteDatabaseKeyVersion(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteDatabaseKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteDatabaseKeyVersion"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete database key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocDatabaseKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete database key version: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -104,57 +107,62 @@ func (r *Repository) DeleteDatabaseKeyVersion(ctx context.Context, privateId str
|
||||
dk := k.Clone()
|
||||
// no oplog entries for the key version
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete database key version: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// LatestDatabaseKeyVersion searches for the key version with the highest
|
||||
// version number. When no results are found, it returns nil,
|
||||
// errors.ErrRecordNotFound.
|
||||
func (r *Repository) LatestDatabaseKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, opt ...Option) (*DatabaseKeyVersion, error) {
|
||||
// version number. When no results are found, it returns nil with an
|
||||
// errors.RecordNotFound error.
|
||||
func (r *Repository) LatestDatabaseKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, _ ...Option) (*DatabaseKeyVersion, error) {
|
||||
const op = "kms.(Repository).LatestDatabaseKeyVersion"
|
||||
if databaseKeyId == "" {
|
||||
return nil, fmt.Errorf("latest database key version: missing database key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing database key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("latest database key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var foundKeys []*DatabaseKeyVersion
|
||||
if err := r.reader.SearchWhere(ctx, &foundKeys, "database_key_id = ?", []interface{}{databaseKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil {
|
||||
return nil, fmt.Errorf("latest database key version: failed %w for %s", err, databaseKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", databaseKeyId)))
|
||||
}
|
||||
if len(foundKeys) == 0 {
|
||||
return nil, errors.ErrRecordNotFound
|
||||
return nil, errors.E(errors.WithCode(errors.RecordNotFound), errors.WithOp(op))
|
||||
}
|
||||
if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("latest database key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return foundKeys[0], nil
|
||||
}
|
||||
|
||||
// ListDatabaseKeyVersions will lists versions of a key. Supports the WithLimit option.
|
||||
func (r *Repository) ListDatabaseKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, databaseKeyId string, opt ...Option) ([]DekVersion, error) {
|
||||
const op = "kms.(Repository).ListDatabaseKeyVersions"
|
||||
if databaseKeyId == "" {
|
||||
return nil, fmt.Errorf("list database key versions: missing database key id %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing database key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("list database key versions: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var versions []*DatabaseKeyVersion
|
||||
err := r.list(ctx, &versions, "database_key_id = ?", []interface{}{databaseKeyId}, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list database key versions: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
for i, k := range versions {
|
||||
if err := k.Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("list database key versions: error decrypting key num %d: %w", i, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i)))
|
||||
}
|
||||
}
|
||||
dekVersions := make([]DekVersion, 0, len(versions))
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateDatabaseKeyVersion(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateDatabaseKeyVersion(t *testing.T) {
|
||||
databaseKeyId: dk.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -76,7 +76,7 @@ func TestRepository_CreateDatabaseKeyVersion(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -86,9 +86,7 @@ func TestRepository_CreateDatabaseKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(k)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -173,9 +171,7 @@ func TestRepository_DeleteDatabaseKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
@@ -260,9 +256,7 @@ func TestRepository_LatestDatabaseKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
// CreateOplogKey inserts into the repository and returns the new key and the
|
||||
// key version. There are no valid options at this time.
|
||||
func (r *Repository) CreateOplogKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, opt ...Option) (*OplogKey, *OplogKeyVersion, error) {
|
||||
func (r *Repository) CreateOplogKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*OplogKey, *OplogKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateOplogKey"
|
||||
var returnedDk, returnedDv interface{}
|
||||
_, err := r.writer.DoTx(
|
||||
ctx,
|
||||
@@ -21,84 +22,86 @@ func (r *Repository) CreateOplogKey(ctx context.Context, rkvWrapper wrapping.Wra
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
var err error
|
||||
if returnedDk, returnedDv, err = createOplogKeyTx(ctx, reader, w, rkvWrapper, key); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
return returnedDk.(*OplogKey), returnedDv.(*OplogKeyVersion), err
|
||||
return returnedDk.(*OplogKey), returnedDv.(*OplogKeyVersion), nil
|
||||
}
|
||||
|
||||
// createOplogKeyTx inserts into the db (via db.Writer) and returns the new key
|
||||
// and the key version. This function encapsulates all the work required within
|
||||
// a db.TxHandler and allows this capability to be shared with the iam repo.
|
||||
func createOplogKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*OplogKey, *OplogKeyVersion, error) {
|
||||
const op = "kms.createOplogKeyTx"
|
||||
if rkvWrapper == nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, nil, fmt.Errorf("create oplog key: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, nil, fmt.Errorf("create oplog key: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, nil, fmt.Errorf("create oplog key: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
rv := AllocRootKeyVersion()
|
||||
rv.PrivateId = rootKeyVersionId
|
||||
err := r.LookupById(ctx, &rv)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: unable to lookup root key version %s: %w", rootKeyVersionId, err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId)))
|
||||
}
|
||||
|
||||
opk := AllocOplogKey()
|
||||
opv := AllocOplogKeyVersion()
|
||||
id, err := newOplogKeyId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
opk.PrivateId = id
|
||||
opk.RootKeyId = rv.RootKeyId
|
||||
|
||||
id, err = newOplogKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
opv.PrivateId = id
|
||||
opv.OplogKeyId = opk.PrivateId
|
||||
opv.RootKeyVersionId = rootKeyVersionId
|
||||
opv.Key = key
|
||||
if err := opv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
// no oplog entries for keys
|
||||
if err := w.Create(ctx, &opk); err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: key create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("key create"))
|
||||
}
|
||||
// no oplog entries for key versions
|
||||
if err := w.Create(ctx, &opv); err != nil {
|
||||
return nil, nil, fmt.Errorf("create oplog key: version create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("key versions create"))
|
||||
}
|
||||
|
||||
return &opk, &opv, err
|
||||
return &opk, &opv, nil
|
||||
}
|
||||
|
||||
// LookupOplogKey will look up a key in the repository. If the key is not
|
||||
// found, it will return nil, nil.
|
||||
func (r *Repository) LookupOplogKey(ctx context.Context, privateId string, opt ...Option) (*OplogKey, error) {
|
||||
func (r *Repository) LookupOplogKey(ctx context.Context, privateId string, _ ...Option) (*OplogKey, error) {
|
||||
const op = "kms.(Repository).LookupOplogKey"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup oplog key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocOplogKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup oplog key: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -106,14 +109,15 @@ func (r *Repository) LookupOplogKey(ctx context.Context, privateId string, opt .
|
||||
// DeleteOplogKey deletes the key for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteOplogKey(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteOplogKey(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteOplogKey"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete oplog key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocOplogKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete oplog key: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -125,24 +129,28 @@ func (r *Repository) DeleteOplogKey(ctx context.Context, privateId string, opt .
|
||||
dk := k.Clone()
|
||||
// no oplog entries for root keys
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete oplog key: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// ListOplogKeys will list the keys. Supports the WithLimit option.
|
||||
func (r *Repository) ListOplogKeys(ctx context.Context, opt ...Option) ([]Dek, error) {
|
||||
const op = "kms.(Repository).ListOplogKeys"
|
||||
var keys []*OplogKey
|
||||
err := r.list(ctx, &keys, "1=1", nil, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list oplog keys: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
deks := make([]Dek, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid-org",
|
||||
@@ -57,7 +57,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
keyWrapper: rkvWrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
key: []byte(""),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -77,7 +77,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "not-rkv-wrapper",
|
||||
@@ -87,7 +87,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
keyWrapper: wrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "wrapper-missing-id",
|
||||
@@ -104,7 +104,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -114,9 +114,7 @@ func TestRepository_CreateOplogKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(opk)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -209,9 +207,7 @@ func TestRepository_DeleteOplogKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
// make sure there was no oplog written
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
|
||||
@@ -12,34 +12,35 @@ import (
|
||||
|
||||
// CreateOplogKeyVersion inserts into the repository and returns the new key
|
||||
// version with its PrivateId. There are no valid options at this time.
|
||||
func (r *Repository) CreateOplogKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, key []byte, opt ...Option) (*OplogKeyVersion, error) {
|
||||
func (r *Repository) CreateOplogKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, key []byte, _ ...Option) (*OplogKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateOplogKeyVersion"
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("create oplog key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, fmt.Errorf("create oplog key version: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, fmt.Errorf("create oplog key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
if oplogKeyId == "" {
|
||||
return nil, fmt.Errorf("create oplog key version: missing oplog key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing oplog key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("create oplog key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
kv := AllocOplogKeyVersion()
|
||||
id, err := newOplogKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create oplog key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
kv.PrivateId = id
|
||||
kv.RootKeyVersionId = rootKeyVersionId
|
||||
kv.Key = key
|
||||
kv.OplogKeyId = oplogKeyId
|
||||
if err := kv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("create oplog key version: encrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
var returnedKey interface{}
|
||||
@@ -51,33 +52,34 @@ func (r *Repository) CreateOplogKeyVersion(ctx context.Context, rkvWrapper wrapp
|
||||
returnedKey = kv.Clone()
|
||||
// no oplog entries for root key version
|
||||
if err := w.Create(ctx, returnedKey); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create oplog key version: %w for %s oplog key id", err, kv.OplogKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s oplog key id", kv.OplogKeyId)))
|
||||
}
|
||||
return returnedKey.(*OplogKeyVersion), err
|
||||
return returnedKey.(*OplogKeyVersion), nil
|
||||
}
|
||||
|
||||
// LookupOplogKeyVersion will look up a key version in the repository. If
|
||||
// the key version is not found, it will return nil, nil.
|
||||
func (r *Repository) LookupOplogKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, opt ...Option) (*OplogKeyVersion, error) {
|
||||
func (r *Repository) LookupOplogKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*OplogKeyVersion, error) {
|
||||
const op = "kms.(Repository).LookupOplogKeyVersion"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup oplog key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("lookup oplog key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
k := AllocOplogKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup oplog key version: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
if err := k.Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("lookup oplog key version: decrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -85,14 +87,15 @@ func (r *Repository) LookupOplogKeyVersion(ctx context.Context, keyWrapper wrapp
|
||||
// DeleteOplogKeyVersion deletes the key version for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteOplogKeyVersion(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteOplogKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteOplogKeyVersion"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete oplog key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocOplogKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete oplog key version: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -104,57 +107,62 @@ func (r *Repository) DeleteOplogKeyVersion(ctx context.Context, privateId string
|
||||
dk := k.Clone()
|
||||
// no oplog entries for the key version
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete oplog key version: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// LatestOplogKeyVersion searches for the key version with the highest
|
||||
// version number. When no results are found, it returns nil,
|
||||
// errors.ErrRecordNotFound.
|
||||
func (r *Repository) LatestOplogKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, opt ...Option) (*OplogKeyVersion, error) {
|
||||
// version number. When no results are found, it returns nil with an
|
||||
// errors.RecordNotFound error.
|
||||
func (r *Repository) LatestOplogKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, _ ...Option) (*OplogKeyVersion, error) {
|
||||
const op = "kms.(Repository).LatestOplogKeyVersion"
|
||||
if oplogKeyId == "" {
|
||||
return nil, fmt.Errorf("latest oplog key version: missing oplog key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing oplog key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("latest oplog key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var foundKeys []*OplogKeyVersion
|
||||
if err := r.reader.SearchWhere(ctx, &foundKeys, "oplog_key_id = ?", []interface{}{oplogKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil {
|
||||
return nil, fmt.Errorf("latest oplog key version: failed %w for %s", err, oplogKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", oplogKeyId)))
|
||||
}
|
||||
if len(foundKeys) == 0 {
|
||||
return nil, errors.ErrRecordNotFound
|
||||
return nil, errors.E(errors.WithCode(errors.RecordNotFound), errors.WithOp(op))
|
||||
}
|
||||
if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("latest oplog key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return foundKeys[0], nil
|
||||
}
|
||||
|
||||
// ListOplogKeyVersions will lists versions of a key. Supports the WithLimit option.
|
||||
func (r *Repository) ListOplogKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, oplogKeyId string, opt ...Option) ([]DekVersion, error) {
|
||||
const op = "kms.(Repository).ListOplogKeyVersions"
|
||||
if oplogKeyId == "" {
|
||||
return nil, fmt.Errorf("list oplog key versions: missing oplog key id %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing oplog key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("list oplog key versions: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var versions []*OplogKeyVersion
|
||||
err := r.list(ctx, &versions, "oplog_key_id = ?", []interface{}{oplogKeyId}, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list oplog key versions: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
for i, k := range versions {
|
||||
if err := k.Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("list oplog key versions: error decrypting key num %d: %w", i, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i)))
|
||||
}
|
||||
}
|
||||
dekVersions := make([]DekVersion, 0, len(versions))
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateOplogKeyVersion(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateOplogKeyVersion(t *testing.T) {
|
||||
oplogKeyId: dk.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -76,7 +76,7 @@ func TestRepository_CreateOplogKeyVersion(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -86,9 +86,7 @@ func TestRepository_CreateOplogKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(k)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -173,9 +171,7 @@ func TestRepository_DeleteOplogKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
@@ -260,9 +256,7 @@ func TestRepository_LatestOplogKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
|
||||
// CreateRootKey inserts into the repository and returns the new root key and
|
||||
// root key version. There are no valid options at this time.
|
||||
func (r *Repository) CreateRootKey(ctx context.Context, keyWrapper wrapping.Wrapper, scopeId string, key []byte, opt ...Option) (*RootKey, *RootKeyVersion, error) {
|
||||
func (r *Repository) CreateRootKey(ctx context.Context, keyWrapper wrapping.Wrapper, scopeId string, key []byte, _ ...Option) (*RootKey, *RootKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateRootKey"
|
||||
var returnedRk, returnedKv interface{}
|
||||
_, err := r.writer.DoTx(
|
||||
ctx,
|
||||
@@ -20,75 +21,77 @@ func (r *Repository) CreateRootKey(ctx context.Context, keyWrapper wrapping.Wrap
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
var err error
|
||||
if returnedRk, returnedKv, err = createRootKeyTx(ctx, w, keyWrapper, scopeId, key); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create root key: %w in %s", err, scopeId)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", scopeId)))
|
||||
}
|
||||
return returnedRk.(*RootKey), returnedKv.(*RootKeyVersion), err
|
||||
return returnedRk.(*RootKey), returnedKv.(*RootKeyVersion), nil
|
||||
}
|
||||
|
||||
// createRootKeyTx inserts into the db (via db.Writer) and returns the new root key
|
||||
// and root key version. This function encapsulates all the work required within
|
||||
// a db.TxHandler and allows this capability to be shared with the iam repo.
|
||||
func createRootKeyTx(ctx context.Context, w db.Writer, keyWrapper wrapping.Wrapper, scopeId string, key []byte) (*RootKey, *RootKeyVersion, error) {
|
||||
const op = "kms.createRootKeyTx"
|
||||
if scopeId == "" {
|
||||
return nil, nil, fmt.Errorf("create root key: missing scope id: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing scope id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, nil, fmt.Errorf("create root key: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, nil, fmt.Errorf("create root key: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
rk := AllocRootKey()
|
||||
kv := AllocRootKeyVersion()
|
||||
id, err := newRootKeyId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create root key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
rk.PrivateId = id
|
||||
rk.ScopeId = scopeId
|
||||
|
||||
id, err = newRootKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create root key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
kv.PrivateId = id
|
||||
kv.RootKeyId = rk.PrivateId
|
||||
kv.Key = key
|
||||
if err := kv.Encrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, nil, fmt.Errorf("create root key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
// no oplog entries for root keys
|
||||
if err := w.Create(ctx, &rk); err != nil {
|
||||
return nil, nil, fmt.Errorf("create root key: root create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("root keys"))
|
||||
}
|
||||
// no oplog entries for root key versions
|
||||
if err := w.Create(ctx, &kv); err != nil {
|
||||
return nil, nil, fmt.Errorf("create root key: version create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("key versions")))
|
||||
}
|
||||
|
||||
return &rk, &kv, err
|
||||
return &rk, &kv, nil
|
||||
}
|
||||
|
||||
// LookupRootKey will look up a root key in the repository. If the key is not
|
||||
// found, it will return nil, nil.
|
||||
func (r *Repository) LookupRootKey(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, opt ...Option) (*RootKey, error) {
|
||||
func (r *Repository) LookupRootKey(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*RootKey, error) {
|
||||
const op = "kms.(Repository).LookupRootKey"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup root key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("lookup root key: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
k := AllocRootKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup root key: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -96,14 +99,15 @@ func (r *Repository) LookupRootKey(ctx context.Context, keyWrapper wrapping.Wrap
|
||||
// DeleteRootKey deletes the root key for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteRootKey(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteRootKey(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteRootKey"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete root key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocRootKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete root key: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -115,24 +119,28 @@ func (r *Repository) DeleteRootKey(ctx context.Context, privateId string, opt ..
|
||||
dk := k.Clone()
|
||||
// no oplog entries for root keys
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete root key: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// ListRootKeys will list the root keys. Supports the WithLimit option.
|
||||
func (r *Repository) ListRootKeys(ctx context.Context, opt ...Option) ([]*RootKey, error) {
|
||||
const op = "kms.(Repository).ListRootKeys"
|
||||
var keys []*RootKey
|
||||
err := r.list(ctx, &keys, "1=1", nil, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list root keys: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
@@ -36,7 +36,7 @@ func TestRepository_CreateRootKey(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid-org",
|
||||
@@ -72,7 +72,7 @@ func TestRepository_CreateRootKey(t *testing.T) {
|
||||
keyWrapper: wrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -82,7 +82,7 @@ func TestRepository_CreateRootKey(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -92,9 +92,7 @@ func TestRepository_CreateRootKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(rk)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -186,9 +184,7 @@ func TestRepository_DeleteRootKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
// make sure there was no oplog written
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
|
||||
@@ -11,26 +11,27 @@ import (
|
||||
|
||||
// CreateRootKeyVersion inserts into the repository and returns the new root key
|
||||
// version with its PrivateId. There are no valid options at this time.
|
||||
func (r *Repository) CreateRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, key []byte, opt ...Option) (*RootKeyVersion, error) {
|
||||
func (r *Repository) CreateRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, key []byte, _ ...Option) (*RootKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateRootKeyVersion"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("create root key version: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("create root key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("create root key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
kv := AllocRootKeyVersion()
|
||||
id, err := newRootKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create root key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
kv.PrivateId = id
|
||||
kv.RootKeyId = rootKeyId
|
||||
kv.Key = key
|
||||
if err := kv.Encrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("create root key version: encrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
var returnedKey interface{}
|
||||
@@ -42,33 +43,34 @@ func (r *Repository) CreateRootKeyVersion(ctx context.Context, keyWrapper wrappi
|
||||
returnedKey = kv.Clone()
|
||||
// no oplog entries for root key version
|
||||
if err := w.Create(ctx, returnedKey); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create root key version: %w for %s root key id", err, kv.RootKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s root key id", kv.RootKeyId)))
|
||||
}
|
||||
return returnedKey.(*RootKeyVersion), err
|
||||
return returnedKey.(*RootKeyVersion), nil
|
||||
}
|
||||
|
||||
// LookupRootKeyVersion will look up a root key version in the repository. If
|
||||
// the key version is not found, it will return nil, nil.
|
||||
func (r *Repository) LookupRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, opt ...Option) (*RootKeyVersion, error) {
|
||||
func (r *Repository) LookupRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*RootKeyVersion, error) {
|
||||
const op = "kms.(Repository).LookupRootKeyVersion"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup root key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("lookup root key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
k := AllocRootKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup root key version: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
if err := k.Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("lookup root key version: decrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -76,14 +78,15 @@ func (r *Repository) LookupRootKeyVersion(ctx context.Context, keyWrapper wrappi
|
||||
// DeleteRootKeyVersion deletes the root key version for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteRootKeyVersion(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteRootKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteRootKeyVersion"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete root key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocRootKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete root key version: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -95,57 +98,62 @@ func (r *Repository) DeleteRootKeyVersion(ctx context.Context, privateId string,
|
||||
dk := k.Clone()
|
||||
// no oplog entries for root key version
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete root key version: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// LatestRootKeyVersion searches for the root key version with the highest
|
||||
// version number. When no results are found, it returns nil,
|
||||
// errors.ErrRecordNotFound.
|
||||
func (r *Repository) LatestRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, opt ...Option) (*RootKeyVersion, error) {
|
||||
// version number. When no results are found, it returns nil with an
|
||||
// errors.RecordNotFound error.
|
||||
func (r *Repository) LatestRootKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, _ ...Option) (*RootKeyVersion, error) {
|
||||
const op = "kms.(Repository).LatestRootKeyVersion"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("latest root key version: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("latest root key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
var foundKeys []RootKeyVersion
|
||||
if err := r.reader.SearchWhere(ctx, &foundKeys, "root_key_id = ?", []interface{}{rootKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil {
|
||||
return nil, fmt.Errorf("latest root key version: failed %w for %s", err, rootKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", rootKeyId)))
|
||||
}
|
||||
if len(foundKeys) == 0 {
|
||||
return nil, errors.ErrRecordNotFound
|
||||
return nil, errors.E(errors.WithCode(errors.RecordNotFound), errors.WithOp(op))
|
||||
}
|
||||
if err := foundKeys[0].Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("latest root key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return &foundKeys[0], nil
|
||||
}
|
||||
|
||||
// ListRootKeyVersions in versions of a root key. Supports the WithLimit option.
|
||||
func (r *Repository) ListRootKeyVersions(ctx context.Context, keyWrapper wrapping.Wrapper, rootKeyId string, opt ...Option) ([]*RootKeyVersion, error) {
|
||||
const op = "kms.(Repository).ListRootKeyVersions"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("list root key versions: missing root key id %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("list root key versions: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
var versions []*RootKeyVersion
|
||||
err := r.list(ctx, &versions, "root_key_id = ?", []interface{}{rootKeyId}, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list root key versions: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
for i, k := range versions {
|
||||
if err := k.Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("list root key versions: error decrypting key num %d: %w", i, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i)))
|
||||
}
|
||||
}
|
||||
return versions, nil
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestRepository_CreateRootKeyVersion(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -65,7 +65,7 @@ func TestRepository_CreateRootKeyVersion(t *testing.T) {
|
||||
keyWrapper: wrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -75,7 +75,7 @@ func TestRepository_CreateRootKeyVersion(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -85,9 +85,7 @@ func TestRepository_CreateRootKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(k)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -173,9 +171,7 @@ func TestRepository_DeleteRootKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
@@ -258,9 +254,7 @@ func TestRepository_LatestRootKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
// CreateSessionKey inserts into the repository and returns the new key and the
|
||||
// key version. There are no valid options at this time.
|
||||
func (r *Repository) CreateSessionKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, opt ...Option) (*SessionKey, *SessionKeyVersion, error) {
|
||||
func (r *Repository) CreateSessionKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*SessionKey, *SessionKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateSessionKey"
|
||||
var returnedDk, returnedDv interface{}
|
||||
_, err := r.writer.DoTx(
|
||||
ctx,
|
||||
@@ -21,84 +22,86 @@ func (r *Repository) CreateSessionKey(ctx context.Context, rkvWrapper wrapping.W
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
var err error
|
||||
if returnedDk, returnedDv, err = createSessionKeyTx(ctx, reader, w, rkvWrapper, key); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
return returnedDk.(*SessionKey), returnedDv.(*SessionKeyVersion), err
|
||||
return returnedDk.(*SessionKey), returnedDv.(*SessionKeyVersion), nil
|
||||
}
|
||||
|
||||
// createSessionKeyTx inserts into the db (via db.Writer) and returns the new key
|
||||
// and the key version. This function encapsulates all the work required within
|
||||
// a db.TxHandler and allows this capability to be shared with the iam repo.
|
||||
func createSessionKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*SessionKey, *SessionKeyVersion, error) {
|
||||
const op = "kms.createSessionKeyTx"
|
||||
if rkvWrapper == nil {
|
||||
return nil, nil, fmt.Errorf("create session key: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, nil, fmt.Errorf("create session key: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, nil, fmt.Errorf("create session key: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, nil, fmt.Errorf("create session key: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
rv := AllocRootKeyVersion()
|
||||
rv.PrivateId = rootKeyVersionId
|
||||
err := r.LookupById(ctx, &rv)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: unable to lookup root key version %s: %w", rootKeyVersionId, err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId)))
|
||||
}
|
||||
|
||||
tk := AllocSessionKey()
|
||||
tv := AllocSessionKeyVersion()
|
||||
id, err := newSessionKeyId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
tk.PrivateId = id
|
||||
tk.RootKeyId = rv.RootKeyId
|
||||
|
||||
id, err = newSessionKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
tv.PrivateId = id
|
||||
tv.SessionKeyId = tk.PrivateId
|
||||
tv.RootKeyVersionId = rootKeyVersionId
|
||||
tv.Key = key
|
||||
if err := tv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
// no session entries for keys
|
||||
if err := w.Create(ctx, &tk); err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: key create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("keys create"))
|
||||
}
|
||||
// no session entries for key versions
|
||||
if err := w.Create(ctx, &tv); err != nil {
|
||||
return nil, nil, fmt.Errorf("create session key: version create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("key versions create"))
|
||||
}
|
||||
|
||||
return &tk, &tv, err
|
||||
return &tk, &tv, nil
|
||||
}
|
||||
|
||||
// LookupSessionKey will look up a key in the repository. If the key is not
|
||||
// found, it will return nil, nil.
|
||||
func (r *Repository) LookupSessionKey(ctx context.Context, privateId string, opt ...Option) (*SessionKey, error) {
|
||||
func (r *Repository) LookupSessionKey(ctx context.Context, privateId string, _ ...Option) (*SessionKey, error) {
|
||||
const op = "kms.(Repository).LookupSessionKey"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup session key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocSessionKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup session key: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -106,14 +109,15 @@ func (r *Repository) LookupSessionKey(ctx context.Context, privateId string, opt
|
||||
// DeleteSessionKey deletes the key for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteSessionKey(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteSessionKey(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteSessionKey"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete session key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocSessionKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete session key: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -125,24 +129,28 @@ func (r *Repository) DeleteSessionKey(ctx context.Context, privateId string, opt
|
||||
dk := k.Clone()
|
||||
// no session entries for root keys
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete session key: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// ListSessionKeys will list the keys. Supports the WithLimit option.
|
||||
func (r *Repository) ListSessionKeys(ctx context.Context, opt ...Option) ([]Dek, error) {
|
||||
const op = "kms.(Repository).ListSessionKeys"
|
||||
var keys []*SessionKey
|
||||
err := r.list(ctx, &keys, "1=1", nil, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list session keys: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
deks := make([]Dek, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid-org",
|
||||
@@ -57,7 +57,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
keyWrapper: rkvWrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
key: []byte(""),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -77,7 +77,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "not-rkv-wrapper",
|
||||
@@ -87,7 +87,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
keyWrapper: wrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "wrapper-missing-id",
|
||||
@@ -104,7 +104,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -114,9 +114,7 @@ func TestRepository_CreateSessionKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(tk)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -209,9 +207,8 @@ func TestRepository_DeleteSessionKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
|
||||
// make sure there was no session written
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
|
||||
@@ -12,34 +12,35 @@ import (
|
||||
|
||||
// CreateSessionKeyVersion inserts into the repository and returns the new key
|
||||
// version with its PrivateId. There are no valid options at this time.
|
||||
func (r *Repository) CreateSessionKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, key []byte, opt ...Option) (*SessionKeyVersion, error) {
|
||||
func (r *Repository) CreateSessionKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, key []byte, _ ...Option) (*SessionKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateSessionKeyVersion"
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("create session key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, fmt.Errorf("create session key version: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, fmt.Errorf("create session key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
if sessionKeyId == "" {
|
||||
return nil, fmt.Errorf("create session key version: missing session key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing session key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("create session key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
kv := AllocSessionKeyVersion()
|
||||
id, err := newSessionKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create session key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
kv.PrivateId = id
|
||||
kv.RootKeyVersionId = rootKeyVersionId
|
||||
kv.Key = key
|
||||
kv.SessionKeyId = sessionKeyId
|
||||
if err := kv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("create session key version: encrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
var returnedKey interface{}
|
||||
@@ -51,33 +52,34 @@ func (r *Repository) CreateSessionKeyVersion(ctx context.Context, rkvWrapper wra
|
||||
returnedKey = kv.Clone()
|
||||
// no session entries for root key version
|
||||
if err := w.Create(ctx, returnedKey); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create session key version: %w for %s session key id", err, kv.SessionKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s session key id", kv.SessionKeyId)))
|
||||
}
|
||||
return returnedKey.(*SessionKeyVersion), err
|
||||
return returnedKey.(*SessionKeyVersion), nil
|
||||
}
|
||||
|
||||
// LookupSessionKeyVersion will look up a key version in the repository. If
|
||||
// the key version is not found, it will return nil, nil.
|
||||
func (r *Repository) LookupSessionKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, opt ...Option) (*SessionKeyVersion, error) {
|
||||
func (r *Repository) LookupSessionKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*SessionKeyVersion, error) {
|
||||
const op = "kms.(Repository).LookupSessionKeyVersion"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup session key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("lookup session key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
k := AllocSessionKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup session key version: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
if err := k.Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("lookup session key version: decrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -85,14 +87,15 @@ func (r *Repository) LookupSessionKeyVersion(ctx context.Context, keyWrapper wra
|
||||
// DeleteSessionKeyVersion deletes the key version for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteSessionKeyVersion(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteSessionKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteSessionKeyVersion"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete session key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocSessionKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete session key version: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -104,57 +107,62 @@ func (r *Repository) DeleteSessionKeyVersion(ctx context.Context, privateId stri
|
||||
dk := k.Clone()
|
||||
// no session entries for the key version
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete session key version: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// LatestSessionKeyVersion searches for the key version with the highest
|
||||
// version number. When no results are found, it returns nil,
|
||||
// errors.ErrRecordNotFound.
|
||||
func (r *Repository) LatestSessionKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, opt ...Option) (*SessionKeyVersion, error) {
|
||||
// version number. When no results are found, it returns nil with an
|
||||
// errors.RecordNotFound error.
|
||||
func (r *Repository) LatestSessionKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, _ ...Option) (*SessionKeyVersion, error) {
|
||||
const op = "kms.(Repository).LatestSessionKeyVersion"
|
||||
if sessionKeyId == "" {
|
||||
return nil, fmt.Errorf("latest session key version: missing session key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing session key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("latest session key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var foundKeys []*SessionKeyVersion
|
||||
if err := r.reader.SearchWhere(ctx, &foundKeys, "session_key_id = ?", []interface{}{sessionKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil {
|
||||
return nil, fmt.Errorf("latest session key version: failed %w for %s", err, sessionKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", sessionKeyId)))
|
||||
}
|
||||
if len(foundKeys) == 0 {
|
||||
return nil, errors.ErrRecordNotFound
|
||||
return nil, errors.E(errors.WithCode(errors.RecordNotFound), errors.WithOp(op))
|
||||
}
|
||||
if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("latest session key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return foundKeys[0], nil
|
||||
}
|
||||
|
||||
// ListSessionKeyVersions will lists versions of a key. Supports the WithLimit option.
|
||||
func (r *Repository) ListSessionKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, sessionKeyId string, opt ...Option) ([]DekVersion, error) {
|
||||
const op = "kms.(Repository).ListSessionKeyVersions"
|
||||
if sessionKeyId == "" {
|
||||
return nil, fmt.Errorf("list session key versions: missing session key id %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing session key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("list session key versions: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var versions []*SessionKeyVersion
|
||||
err := r.list(ctx, &versions, "session_key_id = ?", []interface{}{sessionKeyId}, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list session key versions: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
for i, k := range versions {
|
||||
if err := k.Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("list session key versions: error decrypting key num %d: %w", i, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i)))
|
||||
}
|
||||
}
|
||||
dekVersions := make([]DekVersion, 0, len(versions))
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateSessionKeyVersion(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateSessionKeyVersion(t *testing.T) {
|
||||
sessionKeyId: sk.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -76,7 +76,7 @@ func TestRepository_CreateSessionKeyVersion(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -86,9 +86,7 @@ func TestRepository_CreateSessionKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(k)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -173,9 +171,7 @@ func TestRepository_DeleteSessionKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
@@ -260,9 +256,7 @@ func TestRepository_LatestSessionKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestNewRepository(t *testing.T) {
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
wantErrString: "error creating db repository with nil writer",
|
||||
wantErrString: "kms.NewRepository: nil writer: parameter violation: error #100",
|
||||
},
|
||||
{
|
||||
name: "nil-reader",
|
||||
@@ -61,7 +61,7 @@ func TestNewRepository(t *testing.T) {
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
wantErrString: "error creating db repository with nil reader",
|
||||
wantErrString: "kms.NewRepository: nil reader: parameter violation: error #100",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -99,7 +99,7 @@ func TestCreateKeysTx(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantErrIs error
|
||||
wantErrIs errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -121,7 +121,7 @@ func TestCreateKeysTx(t *testing.T) {
|
||||
scopeId: org.PublicId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrIs: errors.ErrInvalidParameter,
|
||||
wantErrIs: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-writer",
|
||||
@@ -133,7 +133,7 @@ func TestCreateKeysTx(t *testing.T) {
|
||||
scopeId: org.PublicId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrIs: errors.ErrInvalidParameter,
|
||||
wantErrIs: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -145,7 +145,7 @@ func TestCreateKeysTx(t *testing.T) {
|
||||
scopeId: org.PublicId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrIs: errors.ErrInvalidParameter,
|
||||
wantErrIs: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-scope",
|
||||
@@ -157,7 +157,7 @@ func TestCreateKeysTx(t *testing.T) {
|
||||
scopeId: "",
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrIs: errors.ErrInvalidParameter,
|
||||
wantErrIs: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "bad-scope",
|
||||
@@ -177,9 +177,7 @@ func TestCreateKeysTx(t *testing.T) {
|
||||
keys, err := kms.CreateKeysTx(tt.args.ctx, tt.args.dbReader, tt.args.dbWriter, tt.args.rootWrapper, tt.args.randomReader, tt.args.scopeId)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
if tt.wantErrIs != nil {
|
||||
assert.Truef(errors.Is(err, tt.wantErrIs), "unexpected error: %s", err.Error())
|
||||
}
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrIs), err), "unexpected error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
// CreateTokenKey inserts into the repository and returns the new key and the
|
||||
// key version. There are no valid options at this time.
|
||||
func (r *Repository) CreateTokenKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, opt ...Option) (*TokenKey, *TokenKeyVersion, error) {
|
||||
func (r *Repository) CreateTokenKey(ctx context.Context, rkvWrapper wrapping.Wrapper, key []byte, _ ...Option) (*TokenKey, *TokenKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateTokenKey"
|
||||
var returnedDk, returnedDv interface{}
|
||||
_, err := r.writer.DoTx(
|
||||
ctx,
|
||||
@@ -21,84 +22,86 @@ func (r *Repository) CreateTokenKey(ctx context.Context, rkvWrapper wrapping.Wra
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
var err error
|
||||
if returnedDk, returnedDv, err = createTokenKeyTx(ctx, reader, w, rkvWrapper, key); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
return returnedDk.(*TokenKey), returnedDv.(*TokenKeyVersion), err
|
||||
return returnedDk.(*TokenKey), returnedDv.(*TokenKeyVersion), nil
|
||||
}
|
||||
|
||||
// createTokenKeyTx inserts into the db (via db.Writer) and returns the new key
|
||||
// and the key version. This function encapsulates all the work required within
|
||||
// a db.TxHandler and allows this capability to be shared with the iam repo.
|
||||
func createTokenKeyTx(ctx context.Context, r db.Reader, w db.Writer, rkvWrapper wrapping.Wrapper, key []byte) (*TokenKey, *TokenKeyVersion, error) {
|
||||
const op = "kms.createTokenKeyTx"
|
||||
if rkvWrapper == nil {
|
||||
return nil, nil, fmt.Errorf("create token key: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, nil, fmt.Errorf("create token key: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, nil, fmt.Errorf("create token key: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, nil, fmt.Errorf("create token key: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
rv := AllocRootKeyVersion()
|
||||
rv.PrivateId = rootKeyVersionId
|
||||
err := r.LookupById(ctx, &rv)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: unable to lookup root key version %s: %w", rootKeyVersionId, err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to lookup root key version %s", rootKeyVersionId)))
|
||||
}
|
||||
|
||||
tk := AllocTokenKey()
|
||||
tv := AllocTokenKeyVersion()
|
||||
id, err := newTokenKeyId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
tk.PrivateId = id
|
||||
tk.RootKeyId = rv.RootKeyId
|
||||
|
||||
id, err = newTokenKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
tv.PrivateId = id
|
||||
tv.TokenKeyId = tk.PrivateId
|
||||
tv.RootKeyVersionId = rootKeyVersionId
|
||||
tv.Key = key
|
||||
if err := tv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
// no token entries for keys
|
||||
if err := w.Create(ctx, &tk); err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: key create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("keys create"))
|
||||
}
|
||||
// no token entries for key versions
|
||||
if err := w.Create(ctx, &tv); err != nil {
|
||||
return nil, nil, fmt.Errorf("create token key: version create: %w", err)
|
||||
return nil, nil, errors.Wrap(err, op, errors.WithMsg("key versions create"))
|
||||
}
|
||||
|
||||
return &tk, &tv, err
|
||||
return &tk, &tv, nil
|
||||
}
|
||||
|
||||
// LookupTokenKey will look up a key in the repository. If the key is not
|
||||
// found, it will return nil, nil.
|
||||
func (r *Repository) LookupTokenKey(ctx context.Context, privateId string, opt ...Option) (*TokenKey, error) {
|
||||
func (r *Repository) LookupTokenKey(ctx context.Context, privateId string, _ ...Option) (*TokenKey, error) {
|
||||
const op = "kms.(Repository).LookupTokenKey"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup token key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocTokenKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup token key: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -106,14 +109,15 @@ func (r *Repository) LookupTokenKey(ctx context.Context, privateId string, opt .
|
||||
// DeleteTokenKey deletes the key for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteTokenKey(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteTokenKey(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteTokenKey"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete token key: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocTokenKey()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete token key: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -125,24 +129,28 @@ func (r *Repository) DeleteTokenKey(ctx context.Context, privateId string, opt .
|
||||
dk := k.Clone()
|
||||
// no token entries for root keys
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete token key: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// ListTokenKeys will list the keys. Supports the WithLimit option.
|
||||
func (r *Repository) ListTokenKeys(ctx context.Context, opt ...Option) ([]Dek, error) {
|
||||
const op = "kms.(Repository).ListTokenKeys"
|
||||
var keys []*TokenKey
|
||||
err := r.list(ctx, &keys, "1=1", nil, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list token keys: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
deks := make([]Dek, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid-org",
|
||||
@@ -57,7 +57,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
keyWrapper: rkvWrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
key: []byte(""),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -77,7 +77,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "not-rkv-wrapper",
|
||||
@@ -87,7 +87,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
keyWrapper: wrapper,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "wrapper-missing-id",
|
||||
@@ -104,7 +104,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -114,9 +114,7 @@ func TestRepository_CreateTokenKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(tk)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -209,9 +207,7 @@ func TestRepository_DeleteTokenKey(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
// make sure there was no token written
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
|
||||
@@ -12,34 +12,35 @@ import (
|
||||
|
||||
// CreateTokenKeyVersion inserts into the repository and returns the new key
|
||||
// version with its PrivateId. There are no valid options at this time.
|
||||
func (r *Repository) CreateTokenKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, key []byte, opt ...Option) (*TokenKeyVersion, error) {
|
||||
func (r *Repository) CreateTokenKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, key []byte, _ ...Option) (*TokenKeyVersion, error) {
|
||||
const op = "kms.(Repository).CreateTokenKeyVersion"
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("create token key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
rootKeyVersionId := rkvWrapper.KeyID()
|
||||
switch {
|
||||
case !strings.HasPrefix(rootKeyVersionId, RootKeyVersionPrefix):
|
||||
return nil, fmt.Errorf("create token key version: root key version id %s doesn't start with prefix %s: %w", rootKeyVersionId, RootKeyVersionPrefix, errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, fmt.Sprintf("root key version id %s doesn't start with prefix %s", rootKeyVersionId, RootKeyVersionPrefix))
|
||||
case rootKeyVersionId == "":
|
||||
return nil, fmt.Errorf("create token key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
if tokenKeyId == "" {
|
||||
return nil, fmt.Errorf("create token key version: missing token key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing token key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("create token key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
kv := AllocTokenKeyVersion()
|
||||
id, err := newTokenKeyVersionId()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create token key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
kv.PrivateId = id
|
||||
kv.RootKeyVersionId = rootKeyVersionId
|
||||
kv.Key = key
|
||||
kv.TokenKeyId = tokenKeyId
|
||||
if err := kv.Encrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("create token key version: encrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
var returnedKey interface{}
|
||||
@@ -51,33 +52,34 @@ func (r *Repository) CreateTokenKeyVersion(ctx context.Context, rkvWrapper wrapp
|
||||
returnedKey = kv.Clone()
|
||||
// no token entries for root key version
|
||||
if err := w.Create(ctx, returnedKey); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create token key version: %w for %s token key id", err, kv.TokenKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s token key id", kv.TokenKeyId)))
|
||||
}
|
||||
return returnedKey.(*TokenKeyVersion), err
|
||||
return returnedKey.(*TokenKeyVersion), nil
|
||||
}
|
||||
|
||||
// LookupTokenKeyVersion will look up a key version in the repository. If
|
||||
// the key version is not found, it will return nil, nil.
|
||||
func (r *Repository) LookupTokenKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, opt ...Option) (*TokenKeyVersion, error) {
|
||||
func (r *Repository) LookupTokenKeyVersion(ctx context.Context, keyWrapper wrapping.Wrapper, privateId string, _ ...Option) (*TokenKeyVersion, error) {
|
||||
const op = "kms.(Repository).LookupTokenKeyVersion"
|
||||
if privateId == "" {
|
||||
return nil, fmt.Errorf("lookup token key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if keyWrapper == nil {
|
||||
return nil, fmt.Errorf("lookup token key version: missing key wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key wrapper")
|
||||
}
|
||||
k := AllocTokenKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return nil, fmt.Errorf("lookup token key version: failed %w for %s", err, privateId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
if err := k.Decrypt(ctx, keyWrapper); err != nil {
|
||||
return nil, fmt.Errorf("lookup token key version: decrypt: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
@@ -85,14 +87,15 @@ func (r *Repository) LookupTokenKeyVersion(ctx context.Context, keyWrapper wrapp
|
||||
// DeleteTokenKeyVersion deletes the key version for the provided id from the
|
||||
// repository returning a count of the number of records deleted. All options
|
||||
// are ignored.
|
||||
func (r *Repository) DeleteTokenKeyVersion(ctx context.Context, privateId string, opt ...Option) (int, error) {
|
||||
func (r *Repository) DeleteTokenKeyVersion(ctx context.Context, privateId string, _ ...Option) (int, error) {
|
||||
const op = "kms.(Repository).DeleteTokenKeyVersion"
|
||||
if privateId == "" {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete token key version: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
k := AllocTokenKeyVersion()
|
||||
k.PrivateId = privateId
|
||||
if err := r.reader.LookupById(ctx, &k); err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete token key version: failed %w for %s", err, privateId)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
@@ -104,57 +107,62 @@ func (r *Repository) DeleteTokenKeyVersion(ctx context.Context, privateId string
|
||||
dk := k.Clone()
|
||||
// no token entries for the key version
|
||||
rowsDeleted, err = w.Delete(ctx, dk)
|
||||
if err == nil && rowsDeleted > 1 {
|
||||
return errors.ErrMultipleRecords
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
return err
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, fmt.Errorf("delete token key version: %s: %w", privateId, err)
|
||||
return db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", privateId)))
|
||||
}
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// LatestTokenKeyVersion searches for the key version with the highest
|
||||
// version number. When no results are found, it returns nil,
|
||||
// errors.ErrRecordNotFound.
|
||||
func (r *Repository) LatestTokenKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, opt ...Option) (*TokenKeyVersion, error) {
|
||||
// version number. When no results are found, it returns nil with an
|
||||
// errors.RecordNotFound error.
|
||||
func (r *Repository) LatestTokenKeyVersion(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, _ ...Option) (*TokenKeyVersion, error) {
|
||||
const op = "kms.(Repository).LatestTokenKeyVersion"
|
||||
if tokenKeyId == "" {
|
||||
return nil, fmt.Errorf("latest token key version: missing token key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing token key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("latest token key version: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var foundKeys []*TokenKeyVersion
|
||||
if err := r.reader.SearchWhere(ctx, &foundKeys, "token_key_id = ?", []interface{}{tokenKeyId}, db.WithLimit(1), db.WithOrder("version desc")); err != nil {
|
||||
return nil, fmt.Errorf("latest token key version: failed %w for %s", err, tokenKeyId)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("failed for %s", tokenKeyId)))
|
||||
}
|
||||
if len(foundKeys) == 0 {
|
||||
return nil, errors.ErrRecordNotFound
|
||||
return nil, errors.E(errors.WithCode(errors.RecordNotFound), errors.WithOp(op))
|
||||
}
|
||||
if err := foundKeys[0].Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("latest token key version: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return foundKeys[0], nil
|
||||
}
|
||||
|
||||
// ListTokenKeyVersions will lists versions of a key. Supports the WithLimit option.
|
||||
func (r *Repository) ListTokenKeyVersions(ctx context.Context, rkvWrapper wrapping.Wrapper, tokenKeyId string, opt ...Option) ([]DekVersion, error) {
|
||||
const op = "kms.(Repository).ListTokenKeyVersions"
|
||||
if tokenKeyId == "" {
|
||||
return nil, fmt.Errorf("list token key versions: missing token key id %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing token key id")
|
||||
}
|
||||
if rkvWrapper == nil {
|
||||
return nil, fmt.Errorf("list token key versions: missing root key version wrapper: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version wrapper")
|
||||
}
|
||||
var versions []*TokenKeyVersion
|
||||
err := r.list(ctx, &versions, "token_key_id = ?", []interface{}{tokenKeyId}, opt...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list token key versions: %w", err)
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
for i, k := range versions {
|
||||
if err := k.Decrypt(ctx, rkvWrapper); err != nil {
|
||||
return nil, fmt.Errorf("list token key versions: error decrypting key num %d: %w", i, err)
|
||||
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error decrypting key num %d", i)))
|
||||
}
|
||||
}
|
||||
dekVersions := make([]DekVersion, 0, len(versions))
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestRepository_CreateTokenKeyVersion(t *testing.T) {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantIsError error
|
||||
wantIsError errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -67,7 +67,7 @@ func TestRepository_CreateTokenKeyVersion(t *testing.T) {
|
||||
tokenKeyId: dk.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-wrapper",
|
||||
@@ -76,7 +76,7 @@ func TestRepository_CreateTokenKeyVersion(t *testing.T) {
|
||||
keyWrapper: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.ErrInvalidParameter,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -86,9 +86,7 @@ func TestRepository_CreateTokenKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(k)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -173,9 +171,7 @@ func TestRepository_DeleteTokenKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
err = db.TestVerifyOplog(t, rw, tt.args.key.PrivateId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
assert.True(errors.IsNotFoundError(err))
|
||||
@@ -260,9 +256,7 @@ func TestRepository_LatestTokenKeyVersion(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Nil(got)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -23,9 +22,10 @@ type RootKey struct {
|
||||
// for a global or org scope, but the scope type validation will be deferred
|
||||
// until the in memory root key is written to the database. No options
|
||||
// are currently supported.
|
||||
func NewRootKey(scopeId string, opt ...Option) (*RootKey, error) {
|
||||
func NewRootKey(scopeId string, _ ...Option) (*RootKey, error) {
|
||||
const op = "kms.NewRootKey"
|
||||
if scopeId == "" {
|
||||
return nil, fmt.Errorf("new root key: missing scope id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing scope id")
|
||||
}
|
||||
c := &RootKey{
|
||||
RootKey: &store.RootKey{
|
||||
@@ -52,17 +52,18 @@ func (k *RootKey) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// before it's written.
|
||||
func (k *RootKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *RootKey) VetForWrite(_ context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(RootKey).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("root key vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
switch opType {
|
||||
case db.CreateOp:
|
||||
if k.ScopeId == "" {
|
||||
return fmt.Errorf("root key vet for write: missing scope id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing scope id")
|
||||
}
|
||||
case db.UpdateOp:
|
||||
return fmt.Errorf("root key vet for write: key is immutable: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "key is immutable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestRootKey_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.RootKey
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -38,7 +38,7 @@ func TestRootKey_Create(t *testing.T) {
|
||||
name: "empty-scopeId",
|
||||
args: args{},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid-org-config",
|
||||
@@ -72,7 +72,7 @@ func TestRootKey_Create(t *testing.T) {
|
||||
got, err := kms.NewRootKey(tt.args.scopeId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -23,12 +22,13 @@ type RootKeyVersion struct {
|
||||
|
||||
// NewRootKeyVersion creates a new in memory root key version. No options are
|
||||
// currently supported.
|
||||
func NewRootKeyVersion(rootKeyId string, key []byte, opt ...Option) (*RootKeyVersion, error) {
|
||||
func NewRootKeyVersion(rootKeyId string, key []byte, _ ...Option) (*RootKeyVersion, error) {
|
||||
const op = "kms.NewRootKeyVersion"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("new root key version: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("new root key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
|
||||
k := &RootKeyVersion{
|
||||
@@ -57,20 +57,21 @@ func (k *RootKeyVersion) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the root key
|
||||
// version before it's written.
|
||||
func (k *RootKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *RootKeyVersion) VetForWrite(_ context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(RootKeyVersion).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("root key version vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
switch opType {
|
||||
case db.CreateOp:
|
||||
if k.CtKey == nil {
|
||||
return fmt.Errorf("root key version vet for write: missing key: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if k.RootKeyId == "" {
|
||||
return fmt.Errorf("root key version vet for write: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
case db.UpdateOp:
|
||||
return fmt.Errorf("root key version vet for write: key is immutable: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "key is immutable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -92,20 +93,22 @@ func (k *RootKeyVersion) SetTableName(n string) {
|
||||
|
||||
// Encrypt will encrypt the root key version's key
|
||||
func (k *RootKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(RootKeyVersion).Encrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.RootKey directly
|
||||
if err := structwrapping.WrapStruct(ctx, cipher, k.RootKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error encrypting kms root key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Encrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt will decrypt the root key version's key
|
||||
func (k *RootKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(RootKeyVersion).Decrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.RootKeyVersion directly
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, k.RootKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error decrypting kms root key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Decrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func TestRootKeyVersion_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.RootKeyVersion
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -44,7 +44,7 @@ func TestRootKeyVersion_Create(t *testing.T) {
|
||||
key: []byte("test key"),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -52,7 +52,7 @@ func TestRootKeyVersion_Create(t *testing.T) {
|
||||
rootId: rootKey.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -76,7 +76,7 @@ func TestRootKeyVersion_Create(t *testing.T) {
|
||||
got, err := kms.NewRootKeyVersion(tt.args.rootId, tt.args.key, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -21,9 +20,10 @@ type SessionKey struct {
|
||||
|
||||
// NewSessionKey creates a new in memory key. No options
|
||||
// are currently supported.
|
||||
func NewSessionKey(rootKeyId string, opt ...Option) (*SessionKey, error) {
|
||||
func NewSessionKey(rootKeyId string, _ ...Option) (*SessionKey, error) {
|
||||
const op = "kms.NewSessionKey"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("new root key: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
c := &SessionKey{
|
||||
SessionKey: &store.SessionKey{
|
||||
@@ -50,13 +50,14 @@ func (k *SessionKey) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// before it's written.
|
||||
func (k *SessionKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *SessionKey) VetForWrite(_ context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(SessionKey).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("session key vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if opType == db.CreateOp {
|
||||
if k.RootKeyId == "" {
|
||||
return fmt.Errorf("session key vet for write: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestSessionKey_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.SessionKey
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -41,7 +41,7 @@ func TestSessionKey_Create(t *testing.T) {
|
||||
name: "empty-rootKeyId",
|
||||
args: args{},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -63,7 +63,7 @@ func TestSessionKey_Create(t *testing.T) {
|
||||
got, err := kms.NewSessionKey(tt.args.rootKeyId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -23,15 +22,16 @@ type SessionKeyVersion struct {
|
||||
|
||||
// SessionKeyVersion creates a new in memory key version. No options are
|
||||
// currently supported.
|
||||
func NewSessionKeyVersion(sessionKeyId string, key []byte, rootKeyVersionId string, opt ...Option) (*SessionKeyVersion, error) {
|
||||
func NewSessionKeyVersion(sessionKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*SessionKeyVersion, error) {
|
||||
const op = "kms.NewSessionKeyVersion"
|
||||
if sessionKeyId == "" {
|
||||
return nil, fmt.Errorf("new session key version: missing session key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing session key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("new session key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if rootKeyVersionId == "" {
|
||||
return nil, fmt.Errorf("new session key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
|
||||
k := &SessionKeyVersion{
|
||||
@@ -62,18 +62,19 @@ func (k *SessionKeyVersion) Clone() interface{} {
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// version before it's written.
|
||||
func (k *SessionKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
const op = "kms.(SessionKeyVersion).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("session key version vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if opType == db.CreateOp {
|
||||
if k.CtKey == nil {
|
||||
return fmt.Errorf("session key version vet for write: missing key: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if k.SessionKeyId == "" {
|
||||
return fmt.Errorf("session key version vet for write: missing session key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing session key id")
|
||||
}
|
||||
if k.RootKeyVersionId == "" {
|
||||
return fmt.Errorf("session key version vet for write: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -96,20 +97,22 @@ func (k *SessionKeyVersion) SetTableName(n string) {
|
||||
|
||||
// Encrypt will encrypt the key version's key
|
||||
func (k *SessionKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(SessionKeyVersion).Encrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.SessionKeyVersion directly
|
||||
if err := structwrapping.WrapStruct(ctx, cipher, k.SessionKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error encrypting kms session key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Encrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt will decrypt the key version's key
|
||||
func (k *SessionKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(SessionKeyVersion).Decrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.SessionKeyVersion directly
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, k.SessionKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error decrypting kms session key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Decrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func TestSessionKeyVersion_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.SessionKeyVersion
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -49,7 +49,7 @@ func TestSessionKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -58,7 +58,7 @@ func TestSessionKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-root-key-version-id",
|
||||
@@ -67,7 +67,7 @@ func TestSessionKeyVersion_Create(t *testing.T) {
|
||||
key: []byte("test key"),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -93,7 +93,7 @@ func TestSessionKeyVersion_Create(t *testing.T) {
|
||||
got, err := kms.NewSessionKeyVersion(tt.args.sessionKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -21,9 +20,10 @@ type TokenKey struct {
|
||||
|
||||
// NewTokenKey creates a new in memory key. No options
|
||||
// are currently supported.
|
||||
func NewTokenKey(rootKeyId string, opt ...Option) (*TokenKey, error) {
|
||||
func NewTokenKey(rootKeyId string, _ ...Option) (*TokenKey, error) {
|
||||
const op = "kms.NewTokenKey"
|
||||
if rootKeyId == "" {
|
||||
return nil, fmt.Errorf("new root key: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
c := &TokenKey{
|
||||
TokenKey: &store.TokenKey{
|
||||
@@ -50,13 +50,14 @@ func (k *TokenKey) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// before it's written.
|
||||
func (k *TokenKey) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *TokenKey) VetForWrite(_ context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(TokenKey).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("token key vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if opType == db.CreateOp {
|
||||
if k.RootKeyId == "" {
|
||||
return fmt.Errorf("token key vet for write: missing root key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key id")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestTokenKey_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.TokenKey
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -41,7 +41,7 @@ func TestTokenKey_Create(t *testing.T) {
|
||||
name: "empty-rootKeyId",
|
||||
args: args{},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -63,7 +63,7 @@ func TestTokenKey_Create(t *testing.T) {
|
||||
got, err := kms.NewTokenKey(tt.args.rootKeyId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -23,15 +22,16 @@ type TokenKeyVersion struct {
|
||||
|
||||
// TokenKeyVersion creates a new in memory key version. No options are
|
||||
// currently supported.
|
||||
func NewTokenKeyVersion(tokenKeyId string, key []byte, rootKeyVersionId string, opt ...Option) (*TokenKeyVersion, error) {
|
||||
func NewTokenKeyVersion(tokenKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*TokenKeyVersion, error) {
|
||||
const op = "kms.NewTokenKeyVersion"
|
||||
if tokenKeyId == "" {
|
||||
return nil, fmt.Errorf("new token key version: missing token key id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing token key id")
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return nil, fmt.Errorf("new token key version: missing key: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if rootKeyVersionId == "" {
|
||||
return nil, fmt.Errorf("new token key version: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
|
||||
k := &TokenKeyVersion{
|
||||
@@ -61,19 +61,20 @@ func (k *TokenKeyVersion) Clone() interface{} {
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the key
|
||||
// version before it's written.
|
||||
func (k *TokenKeyVersion) VetForWrite(ctx context.Context, r db.Reader, opType db.OpType, opt ...db.Option) error {
|
||||
func (k *TokenKeyVersion) VetForWrite(_ context.Context, _r db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "kms.(TokenKeyVersion).VetForWrite"
|
||||
if k.PrivateId == "" {
|
||||
return fmt.Errorf("token key version vet for write: missing private id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing private id")
|
||||
}
|
||||
if opType == db.CreateOp {
|
||||
if k.CtKey == nil {
|
||||
return fmt.Errorf("token key version vet for write: missing key: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing key")
|
||||
}
|
||||
if k.TokenKeyId == "" {
|
||||
return fmt.Errorf("token key version vet for write: missing token key id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing token key id")
|
||||
}
|
||||
if k.RootKeyVersionId == "" {
|
||||
return fmt.Errorf("token key version vet for write: missing root key version id: %w", errors.ErrInvalidParameter)
|
||||
return errors.New(errors.InvalidParameter, op, "missing root key version id")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -96,20 +97,22 @@ func (k *TokenKeyVersion) SetTableName(n string) {
|
||||
|
||||
// Encrypt will encrypt the key version's key
|
||||
func (k *TokenKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(TokenKeyVersion).Encrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.TokenKeyVersion directly
|
||||
if err := structwrapping.WrapStruct(ctx, cipher, k.TokenKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error encrypting kms token key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Encrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt will decrypt the key version's key
|
||||
func (k *TokenKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "kms.(TokenKeyVersion).Decrypt"
|
||||
// structwrapping doesn't support embedding, so we'll pass in the
|
||||
// store.TokenKeyVersion directly
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, k.TokenKeyVersion, nil); err != nil {
|
||||
return fmt.Errorf("error decrypting kms token key version: %w", err)
|
||||
return errors.Wrap(err, op, errors.WithCode(errors.Decrypt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func TestTokenKeyVersion_Create(t *testing.T) {
|
||||
args args
|
||||
want *kms.TokenKeyVersion
|
||||
wantErr bool
|
||||
wantIsErr error
|
||||
wantIsErr errors.Code
|
||||
create bool
|
||||
wantCreateErr bool
|
||||
}{
|
||||
@@ -49,7 +49,7 @@ func TestTokenKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-key",
|
||||
@@ -58,7 +58,7 @@ func TestTokenKeyVersion_Create(t *testing.T) {
|
||||
rootKeyVersionId: rkv.PrivateId,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-root-key-version-id",
|
||||
@@ -67,7 +67,7 @@ func TestTokenKeyVersion_Create(t *testing.T) {
|
||||
key: []byte("test key"),
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.ErrInvalidParameter,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -93,7 +93,7 @@ func TestTokenKeyVersion_Create(t *testing.T) {
|
||||
got, err := kms.NewTokenKeyVersion(tt.args.tokenKeyId, tt.args.key, tt.args.rootKeyVersionId, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.True(errors.Is(err, tt.wantIsErr))
|
||||
assert.True(errors.Match(errors.T(tt.wantIsErr), err))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
@@ -45,7 +45,7 @@ func TestNewRepository(t *testing.T) {
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
wantErrString: "error creating db repository with nil writer",
|
||||
wantErrString: "kms.NewRepository: nil writer: parameter violation: error #100",
|
||||
},
|
||||
{
|
||||
name: "nil-reader",
|
||||
@@ -55,7 +55,7 @@ func TestNewRepository(t *testing.T) {
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
wantErrString: "error creating db repository with nil reader",
|
||||
wantErrString: "kms.NewRepository: nil reader: parameter violation: error #100",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -116,9 +116,7 @@ func TestRepository_CreateTcpTarget(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(target)
|
||||
if tt.wantIsError != nil {
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
}
|
||||
assert.True(errors.Is(err, tt.wantIsError))
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
@@ -381,9 +379,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
targetAfterUpdate, hostSets, updatedRows, err := repo.UpdateTcpTarget(context.Background(), &updateTarget, target.Version, tt.args.fieldMaskPaths, tt.args.opt...)
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
if tt.wantIsError != 0 {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
}
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
assert.Nil(targetAfterUpdate)
|
||||
assert.Equal(0, updatedRows)
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
|
||||
Reference in new issue
Block a user