diff --git a/plugin/backend.go b/plugin/backend.go index 78f05ab..6174e15 100644 --- a/plugin/backend.go +++ b/plugin/backend.go @@ -27,9 +27,8 @@ func newBackend(client secretsClient) *backend { roleCache: cache.New(roleCacheExpiration, roleCacheCleanup), credCache: cache.New(credCacheExpiration, credCacheCleanup), rotateRootLock: new(int32), - checkOutHandler: &PasswordHandler{ // TODO the object model may change here but we do need to place something realistic here for testing + checkOutHandler: &checkOutHandler{ client: client, - child: &StorageHandler{}, }, checkOutLocks: locksutil.CreateLocks(), } @@ -75,7 +74,7 @@ type backend struct { credLock sync.Mutex rotateRootLock *int32 - checkOutHandler CheckOutHandler + checkOutHandler *checkOutHandler // checkOutLocks are used for avoiding races // when working with sets through the check-out system. checkOutLocks []*locksutil.LockEntry diff --git a/plugin/checkout_handler.go b/plugin/checkout_handler.go new file mode 100644 index 0000000..3164f2b --- /dev/null +++ b/plugin/checkout_handler.go @@ -0,0 +1,195 @@ +package plugin + +import ( + "context" + "errors" + "time" + + "github.com/hashicorp/vault-plugin-secrets-ad/plugin/util" + "github.com/hashicorp/vault/sdk/logical" +) + +const ( + checkoutStoragePrefix = "checkout/" + passwordStoragePrefix = "password/" +) + +var ( + // errCheckedOut is returned when a check-out request is received + // for a service account that's already checked out. + errCheckedOut = errors.New("checked out") + + // errNotFound is used when a requested item doesn't exist. + errNotFound = errors.New("not found") +) + +// CheckOut provides information for a service account that is currently +// checked out. +type CheckOut struct { + IsAvailable bool `json:"is_available"` + BorrowerEntityID string `json:"borrower_entity_id"` + BorrowerClientToken string `json:"borrower_client_token"` + Due time.Time `json:"due"` +} + +// checkOutHandler manages checkouts. It's not thread-safe and expects the caller to handle locking because +// locking may span multiple calls. +type checkOutHandler struct { + client secretsClient +} + +// CheckOut attempts to check out a service account. If the account is unavailable, it returns +// errCheckedOut. If the service account isn't managed by this plugin, it returns +// errNotFound. +func (h *checkOutHandler) CheckOut(ctx context.Context, storage logical.Storage, serviceAccountName string, checkOut *CheckOut) error { + if ctx == nil { + return errors.New("ctx must be provided") + } + if storage == nil { + return errors.New("storage must be provided") + } + if serviceAccountName == "" { + return errors.New("service account name must be provided") + } + if checkOut == nil { + return errors.New("check-out must be provided") + } + + // Check if the service account is currently checked out. + currentEntry, err := storage.Get(ctx, checkoutStoragePrefix+serviceAccountName) + if err != nil { + return err + } + if currentEntry == nil { + return errNotFound + } + currentCheckOut := &CheckOut{} + if err := currentEntry.DecodeJSON(currentCheckOut); err != nil { + return err + } + if !currentCheckOut.IsAvailable { + return errCheckedOut + } + + // Since it's not, store the new check-out. + entry, err := logical.StorageEntryJSON(checkoutStoragePrefix+serviceAccountName, checkOut) + if err != nil { + return err + } + return storage.Put(ctx, entry) +} + +// CheckIn attempts to check in a service account. If an error occurs, the account remains checked out +// and can either be retried by the caller, or eventually may be checked in if it has a ttl +// that ends. +func (h *checkOutHandler) CheckIn(ctx context.Context, storage logical.Storage, serviceAccountName string) error { + if ctx == nil { + return errors.New("ctx must be provided") + } + if storage == nil { + return errors.New("storage must be provided") + } + if serviceAccountName == "" { + return errors.New("service account name must be provided") + } + + // On check-ins, a new AD password is generated, updated in AD, and stored. + engineConf, err := readConfig(ctx, storage) + if err != nil { + return err + } + if engineConf == nil { + return errors.New("the config is currently unset") + } + newPassword, err := util.GeneratePassword(engineConf.PasswordConf.Formatter, engineConf.PasswordConf.Length) + if err != nil { + return err + } + if err := h.client.UpdatePassword(engineConf.ADConf, serviceAccountName, newPassword); err != nil { + return err + } + pwdEntry, err := logical.StorageEntryJSON(passwordStoragePrefix+serviceAccountName, newPassword) + if err != nil { + return err + } + if err := storage.Put(ctx, pwdEntry); err != nil { + return err + } + + // That ends the password-handling leg of our journey, now let's deal with the stored check-out itself. + // Store a check-out status indicating it's available. + checkOut := &CheckOut{ + IsAvailable: true, + } + entry, err := logical.StorageEntryJSON(checkoutStoragePrefix+serviceAccountName, checkOut) + if err != nil { + return err + } + return storage.Put(ctx, entry) +} + +// LoadCheckOut returns either: +// - A *CheckOut and nil error if the serviceAccountName is currently managed by this engine. +// - A nil *Checkout and errNotFound if the serviceAccountName is not currently managed by this engine. +func (h *checkOutHandler) LoadCheckOut(ctx context.Context, storage logical.Storage, serviceAccountName string) (*CheckOut, error) { + if ctx == nil { + return nil, errors.New("ctx must be provided") + } + if storage == nil { + return nil, errors.New("storage must be provided") + } + if serviceAccountName == "" { + return nil, errors.New("service account name must be provided") + } + + entry, err := storage.Get(ctx, checkoutStoragePrefix+serviceAccountName) + if err != nil { + return nil, err + } + if entry == nil { + return nil, errNotFound + } + checkOut := &CheckOut{} + if err := entry.DecodeJSON(checkOut); err != nil { + return nil, err + } + return checkOut, nil +} + +// Delete cleans up anything we were tracking from the service account that we will no longer need. +func (h *checkOutHandler) Delete(ctx context.Context, storage logical.Storage, serviceAccountName string) error { + if ctx == nil { + return errors.New("ctx must be provided") + } + if storage == nil { + return errors.New("storage must be provided") + } + if serviceAccountName == "" { + return errors.New("service account name must be provided") + } + + if err := storage.Delete(ctx, passwordStoragePrefix+serviceAccountName); err != nil { + return err + } + return storage.Delete(ctx, checkoutStoragePrefix+serviceAccountName) +} + +// retrievePassword is a utility function for grabbing a service account's password from storage. +// retrievePassword will return: +// - "password", nil if it was successfully able to retrieve the password. +// - errNotFound if there's no password presently. +// - Some other err if it was unable to complete successfully. +func retrievePassword(ctx context.Context, storage logical.Storage, serviceAccountName string) (string, error) { + entry, err := storage.Get(ctx, passwordStoragePrefix+serviceAccountName) + if err != nil { + return "", err + } + if entry == nil { + return "", errNotFound + } + password := "" + if err := entry.DecodeJSON(&password); err != nil { + return "", err + } + return password, nil +} diff --git a/plugin/checkout_handlers_test.go b/plugin/checkout_handler_test.go similarity index 59% rename from plugin/checkout_handlers_test.go rename to plugin/checkout_handler_test.go index ab5f432..33a83ca 100644 --- a/plugin/checkout_handlers_test.go +++ b/plugin/checkout_handler_test.go @@ -32,10 +32,12 @@ func setup() (context.Context, logical.Storage, string, *CheckOut) { return ctx, storage, serviceAccountName, checkOut } -func Test_StorageHandler(t *testing.T) { +func TestCheckOutHandlerStorageLayer(t *testing.T) { ctx, storage, serviceAccountName, testCheckOut := setup() - storageHandler := &StorageHandler{} + storageHandler := &checkOutHandler{ + client: &fakeSecretsClient{}, + } // Service accounts must initially be checked in to the library if err := storageHandler.CheckIn(ctx, storage, serviceAccountName); err != nil { @@ -48,7 +50,7 @@ func Test_StorageHandler(t *testing.T) { } // We should have the testCheckOut in storage now. - storedCheckOut, err := storageHandler.Status(ctx, storage, serviceAccountName) + storedCheckOut, err := storageHandler.LoadCheckOut(ctx, storage, serviceAccountName) if err != nil { t.Fatal(err) } @@ -63,8 +65,8 @@ func Test_StorageHandler(t *testing.T) { // get a CurrentlyCheckedOutErr. if err := storageHandler.CheckOut(ctx, storage, serviceAccountName, testCheckOut); err == nil { t.Fatal("expected err but received none") - } else if err != ErrCheckedOut { - t.Fatalf("expected ErrCheckedOut, but received %s", err) + } else if err != errCheckedOut { + t.Fatalf("expected errCheckedOut, but received %s", err) } // If we try to check something in, it should succeed. @@ -73,7 +75,7 @@ func Test_StorageHandler(t *testing.T) { } // We should no longer have the testCheckOut in storage. - storedCheckOut, err = storageHandler.Status(ctx, storage, serviceAccountName) + storedCheckOut, err = storageHandler.LoadCheckOut(ctx, storage, serviceAccountName) if err != nil { t.Fatal(err) } @@ -92,37 +94,16 @@ func Test_StorageHandler(t *testing.T) { } } -func TestValidateInputs(t *testing.T) { - ctx, storage, serviceAccountName, checkOut := setup() - - // Failure cases. - if err := validateInputs(nil, storage, serviceAccountName, checkOut, true); err == nil { - t.Fatal("expected err because ctx isn't provided") - } - if err := validateInputs(ctx, nil, serviceAccountName, checkOut, true); err == nil { - t.Fatal("expected err because storage isn't provided") - } - if err := validateInputs(ctx, storage, "", checkOut, true); err == nil { - t.Fatal("expected err because serviceAccountName isn't provided") - } - if err := validateInputs(ctx, storage, serviceAccountName, nil, true); err == nil { - t.Fatal("expected err because checkOut isn't provided") - } - // Success cases. - if err := validateInputs(ctx, storage, serviceAccountName, checkOut, true); err != nil { - t.Fatal(err) - } - if err := validateInputs(ctx, storage, serviceAccountName, nil, false); err != nil { - t.Fatal(err) - } -} - func TestPasswordHandlerInterfaceFulfillment(t *testing.T) { ctx, storage, serviceAccountName, checkOut := setup() - passwordHandler := &PasswordHandler{ + passwordHandler := &checkOutHandler{ client: &fakeSecretsClient{}, - child: &fakeCheckOutHandler{}, + } + + // We must always start managing a service account by checking it in. + if err := passwordHandler.CheckIn(ctx, storage, serviceAccountName); err != nil { + t.Fatal(err) } // There should be no error during check-out. @@ -131,9 +112,9 @@ func TestPasswordHandlerInterfaceFulfillment(t *testing.T) { } // The password should get rotated successfully during check-in. - _, err := retrievePassword(ctx, storage, serviceAccountName) - if err != ErrNotFound { - t.Fatal("expected ErrNotFound") + origPassword, err := retrievePassword(ctx, storage, serviceAccountName) + if err != nil { + t.Fatal(err) } if err := passwordHandler.CheckIn(ctx, storage, serviceAccountName); err != nil { t.Fatal(err) @@ -142,7 +123,7 @@ func TestPasswordHandlerInterfaceFulfillment(t *testing.T) { if err != nil { t.Fatal(err) } - if currPassword == "" { + if currPassword == "" || currPassword == origPassword { t.Fatal("expected password, but received none") } @@ -152,36 +133,15 @@ func TestPasswordHandlerInterfaceFulfillment(t *testing.T) { } currPassword, err = retrievePassword(ctx, storage, serviceAccountName) - if err != ErrNotFound { - t.Fatal("expected ErrNotFound") + if err != errNotFound { + t.Fatal("expected errNotFound") } - checkOut, err = passwordHandler.Status(ctx, storage, serviceAccountName) - if err != nil { - t.Fatal(err) + + checkOut, err = passwordHandler.LoadCheckOut(ctx, storage, serviceAccountName) + if err != errNotFound { + t.Fatal("expected err not found") } if checkOut != nil { t.Fatal("expected checkOut to be nil") } } - -type fakeCheckOutHandler struct{} - -func (f *fakeCheckOutHandler) CheckOut(ctx context.Context, storage logical.Storage, serviceAccountName string, checkOut *CheckOut) error { - return nil -} - -func (f *fakeCheckOutHandler) Renew(ctx context.Context, storage logical.Storage, serviceAccountName string, updatedCheckOut *CheckOut) error { - return nil -} - -func (f *fakeCheckOutHandler) CheckIn(ctx context.Context, storage logical.Storage, serviceAccountName string) error { - return nil -} - -func (f *fakeCheckOutHandler) Delete(ctx context.Context, storage logical.Storage, serviceAccountName string) error { - return nil -} - -func (f *fakeCheckOutHandler) Status(ctx context.Context, storage logical.Storage, serviceAccountName string) (*CheckOut, error) { - return nil, nil -} diff --git a/plugin/checkout_handlers.go b/plugin/checkout_handlers.go deleted file mode 100644 index 3e3ff46..0000000 --- a/plugin/checkout_handlers.go +++ /dev/null @@ -1,229 +0,0 @@ -package plugin - -import ( - "context" - "errors" - - "github.com/hashicorp/vault-plugin-secrets-ad/plugin/util" - "github.com/hashicorp/vault/sdk/logical" -) - -const checkoutStoragePrefix = "checkout/" - -var ( - // ErrCheckedOut is returned when a check-out request is received - // for a service account that's already checked out. - ErrCheckedOut = errors.New("checked out") - - // ErrNotFound is used when a requested item doesn't exist. - ErrNotFound = errors.New("not found") -) - -// CheckOut provides information for a service account that is currently -// checked out. -type CheckOut struct { - IsAvailable bool `json:"is_available"` - BorrowerEntityID string `json:"borrower_entity_id"` - BorrowerClientToken string `json:"borrower_client_token"` -} - -// TODO this object model needs to be flattened and moved to its own package if some methods need to remain private -// CheckOutHandler is an interface used to break down tasks involved in managing checkouts. These tasks -// are many and can be complex, so it helps to break them down into small, easily testable units -// that help us build our confidence in the code. -type CheckOutHandler interface { - // CheckOut attempts to check out a service account. If the account is unavailable, it returns - // ErrCheckedOut. If the service account isn't managed by this plugin, it returns - // ErrNotFound. - CheckOut(ctx context.Context, storage logical.Storage, serviceAccountName string, checkOut *CheckOut) error - - // CheckIn attempts to check in a service account. If an error occurs, the account remains checked out - // and can either be retried by the caller, or eventually may be checked in if it has a ttl - // that ends. - CheckIn(ctx context.Context, storage logical.Storage, serviceAccountName string) error - - // Status returns either: - // - A *CheckOut and nil error if the serviceAccountName is currently managed by this engine. - // - A nil *Checkout and ErrNotFound if the serviceAccountName is not currently managed by this engine. - Status(ctx context.Context, storage logical.Storage, serviceAccountName string) (*CheckOut, error) - - // Delete cleans up anything we were tracking from the service account that we will no longer need. - Delete(ctx context.Context, storage logical.Storage, serviceAccountName string) error -} - -// PasswordHandler is responsible for rolling and storing a service account's password upon check-in. -type PasswordHandler struct { - client secretsClient - child CheckOutHandler -} - -// CheckOut requires no further action from the password handler other than passing along the request. -func (h *PasswordHandler) CheckOut(ctx context.Context, storage logical.Storage, serviceAccountName string, checkOut *CheckOut) error { - return h.child.CheckOut(ctx, storage, serviceAccountName, checkOut) -} - -// CheckIn rotates the service account's password remotely and stores it locally. -// If this process fails part-way through: -// - An error will be returned. -// - The account will remain checked out. -// - The client may (or may not) retry the check-in. -// - The overdue watcher will still check it in if its ttl runs out. -func (h *PasswordHandler) CheckIn(ctx context.Context, storage logical.Storage, serviceAccountName string) error { - if err := validateInputs(ctx, storage, serviceAccountName, nil, false); err != nil { - return err - } - // On check-ins, a new AD password is generated, updated in AD, and stored. - engineConf, err := readConfig(ctx, storage) - if err != nil { - return err - } - if engineConf == nil { - return errors.New("the config is currently unset") - } - newPassword, err := util.GeneratePassword(engineConf.PasswordConf.Formatter, engineConf.PasswordConf.Length) - if err != nil { - return err - } - if err := h.client.UpdatePassword(engineConf.ADConf, serviceAccountName, newPassword); err != nil { - return err - } - entry, err := logical.StorageEntryJSON("password/"+serviceAccountName, newPassword) - if err != nil { - return err - } - if err := storage.Put(ctx, entry); err != nil { - return err - } - return h.child.CheckIn(ctx, storage, serviceAccountName) -} - -// Delete simply deletes the password from storage so it's not stored unnecessarily. -func (h *PasswordHandler) Delete(ctx context.Context, storage logical.Storage, serviceAccountName string) error { - if err := validateInputs(ctx, storage, serviceAccountName, nil, false); err != nil { - return err - } - if err := storage.Delete(ctx, "password/"+serviceAccountName); err != nil { - return err - } - return h.child.Delete(ctx, storage, serviceAccountName) -} - -// Status doesn't need any password work. -func (h *PasswordHandler) Status(ctx context.Context, storage logical.Storage, serviceAccountName string) (*CheckOut, error) { - return h.child.Status(ctx, storage, serviceAccountName) -} - -// retrievePassword is a utility function for grabbing a service account's password from storage. -// retrievePassword will return: -// - "password", nil if it was successfully able to retrieve the password. -// - ErrNotFound if there's no password presently. -// - Some other err if it was unable to complete successfully. -func retrievePassword(ctx context.Context, storage logical.Storage, serviceAccountName string) (string, error) { - entry, err := storage.Get(ctx, "password/"+serviceAccountName) - if err != nil { - return "", err - } - if entry == nil { - return "", ErrNotFound - } - password := "" - if err := entry.DecodeJSON(&password); err != nil { - return "", err - } - return password, nil -} - -// StorageHandler's sole responsibility is to communicate with storage regarding check-outs. -type StorageHandler struct{} - -// CheckOut will return: -// - Nil if it was successfully able to perform the requested check out. -// - ErrCheckedOut if the account was already checked out. -// - ErrNotFound if the service account isn't currently managed by this engine. -// - Some other err if it was unable to complete successfully. -func (h *StorageHandler) CheckOut(ctx context.Context, storage logical.Storage, serviceAccountName string, checkOut *CheckOut) error { - if err := validateInputs(ctx, storage, serviceAccountName, checkOut, true); err != nil { - return err - } - // Check if the service account is currently checked out. - currentEntry, err := storage.Get(ctx, checkoutStoragePrefix+serviceAccountName) - if err != nil { - return err - } - if currentEntry == nil { - return ErrNotFound - } - currentCheckOut := &CheckOut{} - if err := currentEntry.DecodeJSON(currentCheckOut); err != nil { - return err - } - if !currentCheckOut.IsAvailable { - return ErrCheckedOut - } - - // Since it's not, store the new check-out. - entry, err := logical.StorageEntryJSON(checkoutStoragePrefix+serviceAccountName, checkOut) - if err != nil { - return err - } - return storage.Put(ctx, entry) -} - -// CheckIn will return nil error if it was able to successfully check in an account. -// If the account was already checked in, it still returns no error. -func (h *StorageHandler) CheckIn(ctx context.Context, storage logical.Storage, serviceAccountName string) error { - // Store a check-out status indicating it's available. - checkOut := &CheckOut{ - IsAvailable: true, - } - entry, err := logical.StorageEntryJSON(checkoutStoragePrefix+serviceAccountName, checkOut) - if err != nil { - return err - } - return storage.Put(ctx, entry) -} - -// Status returns either: -// - A *CheckOut and nil error if the serviceAccountName is currently managed by this engine. -// - A nil *Checkout and ErrNotFound if the serviceAccountName is not currently managed by this engine. -func (h *StorageHandler) Status(ctx context.Context, storage logical.Storage, serviceAccountName string) (*CheckOut, error) { - if err := validateInputs(ctx, storage, serviceAccountName, nil, false); err != nil { - return nil, err - } - entry, err := storage.Get(ctx, checkoutStoragePrefix+serviceAccountName) - if err != nil { - return nil, err - } - if entry == nil { - return nil, ErrNotFound - } - checkOut := &CheckOut{} - if err := entry.DecodeJSON(checkOut); err != nil { - return nil, err - } - return checkOut, nil -} - -func (h *StorageHandler) Delete(ctx context.Context, storage logical.Storage, serviceAccountName string) error { - if err := validateInputs(ctx, storage, serviceAccountName, nil, false); err != nil { - return err - } - return storage.Delete(ctx, checkoutStoragePrefix+serviceAccountName) -} - -// validateInputs is a helper function for ensuring that a caller has satisfied all required arguments. -func validateInputs(ctx context.Context, storage logical.Storage, serviceAccountName string, checkOut *CheckOut, checkOutRequired bool) error { - if ctx == nil { - return errors.New("ctx is required") - } - if storage == nil { - return errors.New("storage is required") - } - if serviceAccountName == "" { - return errors.New("serviceAccountName is required") - } - if checkOutRequired && checkOut == nil { - return errors.New("checkOut is required") - } - return nil -} diff --git a/plugin/path_checkout_sets.go b/plugin/path_checkout_sets.go index 9d59248..f819038 100644 --- a/plugin/path_checkout_sets.go +++ b/plugin/path_checkout_sets.go @@ -134,8 +134,8 @@ func (b *backend) operationSetCreate(ctx context.Context, req *logical.Request, // Ensure these service accounts aren't already managed by another check-out set. for _, serviceAccountName := range serviceAccountNames { - if _, err := b.checkOutHandler.Status(ctx, req.Storage, serviceAccountName); err != nil { - if err == ErrNotFound { + if _, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, serviceAccountName); err != nil { + if err == errNotFound { // This is what we want to see. continue } @@ -210,8 +210,8 @@ func (b *backend) operationSetUpdate(ctx context.Context, req *logical.Request, // For new service accounts we receive, before we check them in, ensure they're not in another set. beingAdded = strutil.Difference(newServiceAccountNames, set.ServiceAccountNames, true) for _, newServiceAccountName := range beingAdded { - if _, err := b.checkOutHandler.Status(ctx, req.Storage, newServiceAccountName); err != nil { - if err == ErrNotFound { + if _, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, newServiceAccountName); err != nil { + if err == errNotFound { // Great, this validates that it's not in use in another set. continue } @@ -223,9 +223,9 @@ func (b *backend) operationSetUpdate(ctx context.Context, req *logical.Request, // For service accounts we won't be handling anymore, before we delete them, ensure they're not checked out. beingDeleted = strutil.Difference(set.ServiceAccountNames, newServiceAccountNames, true) for _, prevServiceAccountName := range beingDeleted { - checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, prevServiceAccountName) + checkOut, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, prevServiceAccountName) if err != nil { - if err == ErrNotFound { + if err == errNotFound { // Nothing else to do here. continue } @@ -308,9 +308,9 @@ func (b *backend) operationSetDelete(ctx context.Context, req *logical.Request, } // We need to remove all the items we'd stored for these service accounts. for _, serviceAccountName := range set.ServiceAccountNames { - checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, serviceAccountName) + checkOut, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, serviceAccountName) if err != nil { - if err == ErrNotFound { + if err == errNotFound { // Nothing else to do here. continue } diff --git a/plugin/path_checkouts.go b/plugin/path_checkouts.go index e37930a..3ffb8f4 100644 --- a/plugin/path_checkouts.go +++ b/plugin/path_checkouts.go @@ -78,7 +78,7 @@ func (b *backend) operationSetCheckOut(ctx context.Context, req *logical.Request // Check out the first service account available. for _, serviceAccountName := range set.ServiceAccountNames { if err := b.checkOutHandler.CheckOut(ctx, req.Storage, serviceAccountName, newCheckOut); err != nil { - if err == ErrCheckedOut { + if err == errCheckedOut { continue } return nil, err @@ -141,7 +141,7 @@ func (b *backend) renewCheckOut(ctx context.Context, req *logical.Request, field } serviceAccountName := req.Secret.InternalData["service_account_name"].(string) - checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, serviceAccountName) + checkOut, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, serviceAccountName) if err != nil { return nil, err } @@ -250,7 +250,7 @@ func (b *backend) operationCheckIn(overrideCheckInEnforcement bool) framework.Op // want to check in as long as they only have one checked out. // We'll assume that's the one they want to check in. for _, setServiceAccount := range set.ServiceAccountNames { - checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, setServiceAccount) + checkOut, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, setServiceAccount) if err != nil { return nil, err } @@ -267,7 +267,7 @@ func (b *backend) operationCheckIn(overrideCheckInEnforcement bool) framework.Op } } else { for _, serviceAccountName := range serviceAccountNames { - checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, serviceAccountName) + checkOut, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, serviceAccountName) if err != nil { return nil, err } @@ -330,7 +330,7 @@ func (b *backend) operationSetStatus(ctx context.Context, req *logical.Request, respData := make(map[string]interface{}) for _, serviceAccountName := range set.ServiceAccountNames { - checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, serviceAccountName) + checkOut, err := b.checkOutHandler.LoadCheckOut(ctx, req.Storage, serviceAccountName) if err != nil { return nil, err }