From 3441fa04479f26d611870733c563044b450c4635 Mon Sep 17 00:00:00 2001 From: Damian Debkowski Date: Tue, 14 Jun 2022 08:52:53 -0700 Subject: [PATCH] (fix) added more context to error details for cli command (#2170) * (test) added more context to error details for cli commands * (fix) refactor solution to utilize custom error type casting * (test) added api unit test to validate InvalidArgumentError return message * Update internal/types/subtypes/error.go Co-authored-by: Johan Brandhorst-Satzkorn * (refactor) rename InvalidArgumentError into UnknownSubtypeIDError Co-authored-by: Johan Brandhorst-Satzkorn --- .../handlers/authmethods/authmethod_service.go | 4 +++- internal/tests/api/accounts/account_test.go | 11 ++++++++++- .../tests/api/authmethods/authmethod_test.go | 16 ++++++++++++++++ internal/types/subtypes/error.go | 15 +++++++++++++++ internal/types/subtypes/interceptor.go | 13 +++++++++++-- 5 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 internal/types/subtypes/error.go diff --git a/internal/daemon/controller/handlers/authmethods/authmethod_service.go b/internal/daemon/controller/handlers/authmethods/authmethod_service.go index dd95baeb90..a04c533d82 100644 --- a/internal/daemon/controller/handlers/authmethods/authmethod_service.go +++ b/internal/daemon/controller/handlers/authmethods/authmethod_service.go @@ -1265,7 +1265,9 @@ func transformAuthenticateRequestAttributes(msg proto.Message) error { return fmt.Errorf("%s: unknown command %q", op, authRequest.GetCommand()) } default: - return fmt.Errorf("%s: unknown auth method subtype in ID %q", op, authRequest.GetAuthMethodId()) + return &subtypes.UnknownSubtypeIDError{ + ID: authRequest.GetAuthMethodId(), + } } return nil } diff --git a/internal/tests/api/accounts/account_test.go b/internal/tests/api/accounts/account_test.go index bf3e15372e..f066a33e38 100644 --- a/internal/tests/api/accounts/account_test.go +++ b/internal/tests/api/accounts/account_test.go @@ -398,5 +398,14 @@ func TestErrorsOidc(t *testing.T) { accounts.WithPasswordAccountLoginName("foo"), ) require.Error(err) - require.JSONEq(err.Error(), `{"kind":"InvalidArgument", "message":"Error in provided request.", "details":{"request_fields":[{"name":"attributes", "description":"Attribute fields do not match the expected format."}]}}`) + require.JSONEq(err.Error(), `{ + "details": { + "request_fields": [{ + "description": "Attribute fields do not match the expected format.", + "name": "attributes" + }] + }, + "kind": "InvalidArgument", + "message": "Error in provided request." + }`) } diff --git a/internal/tests/api/authmethods/authmethod_test.go b/internal/tests/api/authmethods/authmethod_test.go index 6ed4ad3dbb..ec48119b4a 100644 --- a/internal/tests/api/authmethods/authmethod_test.go +++ b/internal/tests/api/authmethods/authmethod_test.go @@ -362,4 +362,20 @@ func TestErrors(t *testing.T) { apiErr = api.AsServerError(err) require.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Response().StatusCode()) + + // Passing in a invalid authentication method sub-type should return an error + _, err = amClient.Authenticate(tc.Context(), "ampwd_1234567890", "login", map[string]interface{}{ + "login_name": "admin", + "password": "password", + }) + require.Error(err) + apiErr = api.AsServerError(err) + require.NotNil(apiErr) + assert.Len(apiErr.Details.RequestFields, 1) + assert.EqualValues(apiErr.Details.RequestFields, []*api.FieldError{ + { + Name: "attributes", + Description: "unknown subtype in ID: ampwd_1234567890", + }, + }) } diff --git a/internal/types/subtypes/error.go b/internal/types/subtypes/error.go new file mode 100644 index 0000000000..769bc7fac1 --- /dev/null +++ b/internal/types/subtypes/error.go @@ -0,0 +1,15 @@ +package subtypes + +// UnknownSubtypeIDError is an error type that describes an invalid +// resource sub-type identifer. For example, this authentication sub-type +// ID "ampwd_1234567890" is an error because the prefix "ampwd" is invalid. +type UnknownSubtypeIDError struct { + // ID is the resource identifier + ID string +} + +// Error returns a string describing an unknown subtype based on a given resource ID +// Example: "unknown subtype in ID: ampwd_1234567890" +func (e *UnknownSubtypeIDError) Error() string { + return "unknown subtype in ID: " + e.ID +} diff --git a/internal/types/subtypes/interceptor.go b/internal/types/subtypes/interceptor.go index 6ba56945a6..182023fe2c 100644 --- a/internal/types/subtypes/interceptor.go +++ b/internal/types/subtypes/interceptor.go @@ -2,6 +2,7 @@ package subtypes import ( "context" + "errors" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" @@ -297,8 +298,16 @@ func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerIntercep return func(interceptorCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { if reqMsg, ok := req.(proto.Message); ok { if err := transformRequest(reqMsg); err != nil { - return nil, handlers.InvalidArgumentErrorf("Error in provided request.", - map[string]string{"attributes": "Attribute fields do not match the expected format."}) + fieldErrs := map[string]string{ + "attributes": "Attribute fields do not match the expected format.", + } + + var unknownSubTypeIDErr *UnknownSubtypeIDError + if errors.As(err, &unknownSubTypeIDErr) { + fieldErrs["attributes"] = unknownSubTypeIDErr.Error() + } + + return nil, handlers.InvalidArgumentErrorf("Error in provided request.", fieldErrs) } }