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:
Louis Ruch authored and GitHub committed 2021-01-12 08:50:19 -08:00
1 parent 9de928318d
commit 8151b30ce9
68 files changed
+802 -725

No files matched your search

+5
View File
@@ -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-`
+2 -2
View File
@@ -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
}
+15 -27
View File
@@ -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)
+4
View File
@@ -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
+15
View File
@@ -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,
+4 -2
View File
@@ -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))
+12
View File
@@ -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,
+2
View File
@@ -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]
}
+12 -8
View File
@@ -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
},
+12 -8
View File
@@ -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++ {
+1 -3
View File
@@ -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)
+1 -3
View File
@@ -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)
+2 -6
View File
@@ -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)
+5 -1
View File
@@ -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 {
+2 -6
View File
@@ -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))
+1 -3
View File
@@ -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))
+1 -3
View File
@@ -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)
+4 -12
View File
@@ -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)
+1 -3
View File
@@ -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)
+7 -6
View File
@@ -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
}
+3 -3
View File
@@ -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)
+15 -12
View File
@@ -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
}
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+7 -6
View File
@@ -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
+3 -3
View File
@@ -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)
+15 -12
View File
@@ -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
}
+5 -5
View File
@@ -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
View File
@@ -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
}
+34 -26
View File
@@ -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 {
+2 -6
View File
@@ -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)
+43 -35
View File
@@ -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)
+34 -26
View File
@@ -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 {
+8 -12
View File
@@ -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)
+43 -35
View File
@@ -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)
+33 -25
View File
@@ -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
}
+5 -9
View File
@@ -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)
+41 -33
View File
@@ -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)
+34 -26
View File
@@ -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 {
+9 -12
View File
@@ -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)
+43 -35
View File
@@ -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)
+8 -10
View File
@@ -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)
+34 -26
View File
@@ -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 {
+8 -12
View File
@@ -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)
+43 -35
View File
@@ -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)
+8 -7
View File
@@ -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
}
+3 -3
View File
@@ -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)
+14 -11
View File
@@ -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
}
+4 -4
View File
@@ -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)
+7 -6
View File
@@ -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
+3 -3
View File
@@ -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)
+14 -11
View File
@@ -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
}
+5 -5
View File
@@ -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)
+7 -6
View File
@@ -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
+3 -3
View File
@@ -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)
+15 -12
View File
@@ -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
}
+5 -5
View File
@@ -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)
+2 -2
View File
@@ -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)