From 50942bbb65fd2d14b7b1a21fc38126932de276a4 Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Wed, 10 Jul 2024 15:28:49 +0100 Subject: [PATCH 1/7] support for token authentication --- maestro/config/authentication_builder.go | 53 ++++ maestro/config/config_builder_test.go | 30 +- maestro/config/types.go | 14 +- pkg/errors/types.go | 14 +- .../bearertokenauth/authentication.go | 280 ++++++++++++++++++ .../bearertokenauth/authentication_test.go | 181 +++++++++++ sinks/service.go | 9 +- 7 files changed, 568 insertions(+), 13 deletions(-) create mode 100644 sinks/authentication_type/bearertokenauth/authentication.go create mode 100644 sinks/authentication_type/bearertokenauth/authentication_test.go diff --git a/maestro/config/authentication_builder.go b/maestro/config/authentication_builder.go index 6555193a1..bbef54884 100644 --- a/maestro/config/authentication_builder.go +++ b/maestro/config/authentication_builder.go @@ -4,6 +4,7 @@ import ( "github.com/orb-community/orb/maestro/password" "github.com/orb-community/orb/pkg/types" "github.com/orb-community/orb/sinks/authentication_type/basicauth" + "github.com/orb-community/orb/sinks/authentication_type/bearertokenauth" ) const AuthenticationKey = "authentication" @@ -20,7 +21,12 @@ func GetAuthService(authType string, service password.EncryptionService) AuthBui return &BasicAuthBuilder{ encryptionService: service, } + case bearertokenauth.AuthType: + return &BearerTokenAuthBuilder{ + encryptionService: service, + } } + return nil } @@ -65,3 +71,50 @@ func (b *BasicAuthBuilder) EncodeAuth(config types.Metadata) (types.Metadata, er config[AuthenticationKey] = authcfg return config, nil } + +type BearerTokenAuthBuilder struct { + encryptionService password.EncryptionService +} + +func (b *BearerTokenAuthBuilder) GetExtensionsFromMetadata(c types.Metadata) (Extensions, string) { + authcfg := c.GetSubMetadata(AuthenticationKey) + scheme := authcfg["scheme"].(string) + token := authcfg["token"].(string) + + return Extensions{ + BearerAuth: &BearerTokenAuthExtension{ + Scheme: scheme, + Token: token, + }, + }, "bearertokenauth/withscheme" +} + +func (b *BearerTokenAuthBuilder) DecodeAuth(config types.Metadata) (types.Metadata, error) { + authCfg := config.GetSubMetadata(AuthenticationKey) + token := authCfg["token"].(string) + + decodedToken, err := b.encryptionService.DecodePassword(token) + if err != nil { + return nil, err + } + + authCfg["token"] = decodedToken + config[AuthenticationKey] = authCfg + + return config, nil +} + +func (b *BearerTokenAuthBuilder) EncodeAuth(config types.Metadata) (types.Metadata, error) { + authcfg := config.GetSubMetadata(AuthenticationKey) + token := authcfg["token"].(string) + + encodedToken, err := b.encryptionService.EncodePassword(token) + if err != nil { + return nil, err + } + + authcfg["token"] = encodedToken + config[AuthenticationKey] = authcfg + + return config, nil +} diff --git a/maestro/config/config_builder_test.go b/maestro/config/config_builder_test.go index 8981220a6..0c33732a0 100644 --- a/maestro/config/config_builder_test.go +++ b/maestro/config/config_builder_test.go @@ -3,10 +3,12 @@ package config import ( "context" "fmt" + "testing" + + "go.uber.org/zap" + "github.com/orb-community/orb/maestro/password" "github.com/orb-community/orb/pkg/types" - "go.uber.org/zap" - "testing" ) func TestReturnConfigYamlFromSink(t *testing.T) { @@ -97,6 +99,30 @@ func TestReturnConfigYamlFromSink(t *testing.T) { want: `---\nreceivers:\n kafka:\n brokers:\n - kafka:9092\n topic: otlp_metrics-sink-id-22\n protocol_version: 2.0.0\nextensions:\n pprof:\n endpoint: 0.0.0.0:1888\n basicauth/exporter:\n client_auth:\n username: otlp-user\n password: dbpass\nexporters:\n otlphttp:\n endpoint: https://acme.com/otlphttp/push\n auth:\n authenticator: basicauth/exporter\nservice:\n extensions:\n - pprof\n - basicauth/exporter\n pipelines:\n metrics:\n receivers:\n - kafka\n exporters:\n - otlphttp\n`, wantErr: false, }, + { + name: "otlp, token auth", + args: args{ + in0: context.Background(), + kafkaUrlConfig: "kafka:9092", + sink: &DeploymentRequest{ + SinkID: "sink-id-22", + OwnerID: "22", + Backend: "otlphttp", + Config: types.Metadata{ + "exporter": types.Metadata{ + "endpoint": "https://acme.com/otlphttp/push", + }, + "authentication": types.Metadata{ + "type": "bearertokenauth", + "scheme": "Api-Token", + "token": "abcdefg", + }, + }, + }, + }, + want: `---\nreceivers:\n kafka:\n brokers:\n - kafka:9092\n topic: otlp_metrics-sink-id-22\n protocol_version: 2.0.0\nextensions:\n pprof:\n endpoint: 0.0.0.0:1888\n bearertokenauth/withscheme:\n scheme: Api-Token\n token: abcdefg\nexporters:\n otlphttp:\n endpoint: https://acme.com/otlphttp/push\n auth:\n authenticator: bearertokenauth/withscheme\nservice:\n extensions:\n - pprof\n - bearertokenauth/withscheme\n pipelines:\n metrics:\n receivers:\n - kafka\n exporters:\n - otlphttp\n`, + wantErr: false, + }, } for _, tt := range tests { logger := zap.NewNop() diff --git a/maestro/config/types.go b/maestro/config/types.go index 637abb2c2..118098bf6 100644 --- a/maestro/config/types.go +++ b/maestro/config/types.go @@ -2,8 +2,9 @@ package config import ( "database/sql/driver" - "github.com/orb-community/orb/pkg/types" "time" + + "github.com/orb-community/orb/pkg/types" ) type SinkData struct { @@ -82,8 +83,8 @@ type Extensions struct { PProf *PProfExtension `json:"pprof,omitempty" yaml:"pprof,omitempty" :"p_prof"` ZPages *ZPagesExtension `json:"zpages,omitempty" yaml:"zpages,omitempty" :"z_pages"` // Exporters Authentication - BasicAuth *BasicAuthenticationExtension `json:"basicauth/exporter,omitempty" yaml:"basicauth/exporter,omitempty" :"basic_auth"` - //BearerAuth *BearerAuthExtension `json:"bearerauth/exporter,omitempty" yaml:"bearerauth/exporter,omitempty" :"bearer_auth"` + BasicAuth *BasicAuthenticationExtension `json:"basicauth/exporter,omitempty" yaml:"basicauth/exporter,omitempty" :"basic_auth"` + BearerAuth *BearerTokenAuthExtension `json:"bearertokenauth/withscheme,omitempty" yaml:"bearertokenauth/withscheme,omitempty"` } type HealthCheckExtension struct { @@ -115,10 +116,9 @@ type BasicAuthenticationExtension struct { ClientAuth *ClientAuth `json:"client_auth" yaml:"client_auth"` } -type BearerAuthExtension struct { - BearerAuth *struct { - Token string `json:"token" yaml:"token"` - } `json:"client_auth" yaml:"client_auth"` +type BearerTokenAuthExtension struct { + Scheme string `json:"scheme" yaml:"scheme"` + Token string `json:"token" yaml:"token"` } type Exporters struct { diff --git a/pkg/errors/types.go b/pkg/errors/types.go index f09a283c4..b77f58396 100644 --- a/pkg/errors/types.go +++ b/pkg/errors/types.go @@ -41,13 +41,19 @@ var ( // ErrAuthTypeNotFound indicates that authentication type field was not found on the authentication field ErrAuthTypeNotFound = New("malformed entity specification: authentication type field is expected on configuration field") - + // ErrInvalidAuthType indicates invalid authentication type ErrInvalidAuthType = New("malformed entity specification. type key on authentication field is invalid") // ErrPasswordNotFound indicates that password key was not found ErrPasswordNotFound = New("malformed entity specification. password key is expected on authentication field") + // ErrSchemeNotFound indicates that token key was not found + ErrSchemeNotFound = New("malformed entity specification. scheme key is expected on authentication field") + + // ErrTokendNotFound indicates that token key was not found + ErrTokenNotFound = New("malformed entity specification. token key is expected on authentication field") + // ErrEndPointNotFound indicates that endpoint field was not found on exporter field for otlp backend ErrEndpointNotFound = New("malformed entity specification. endpoint field is expected on exporter field") @@ -57,6 +63,12 @@ var ( // ErrInvalidPasswordType indicates invalid password key on authentication field ErrInvalidPasswordType = New("malformed entity specification. password key on authentication field is invalid") + // ErrInvalidSchemeType indicates invalid scheme key on authentication field + ErrInvalidSchemeType = New("malformed entity specification. scheme key on authentication field is invalid") + + // ErrInvalidTokenType indicates invalid token key on authentication field + ErrInvalidTokenType = New("malformed entity specification. token key on authentication field is invalid") + // ErrInvalidUsernameType indicates invalid username key on authentication field ErrInvalidUsernameType = New("malformed entity specification. username key on authentication field is invalid") diff --git a/sinks/authentication_type/bearertokenauth/authentication.go b/sinks/authentication_type/bearertokenauth/authentication.go new file mode 100644 index 000000000..8acdee0cf --- /dev/null +++ b/sinks/authentication_type/bearertokenauth/authentication.go @@ -0,0 +1,280 @@ +package bearertokenauth + +import ( + "gopkg.in/yaml.v2" + + "github.com/orb-community/orb/pkg/errors" + "github.com/orb-community/orb/pkg/types" + "github.com/orb-community/orb/sinks/authentication_type" + "github.com/orb-community/orb/sinks/backend" +) + +const ( + AuthType = "bearertokenauth" + SchemeConfigFeature = "scheme" + TokenConfigFeature = "token" +) + +var features = []authentication_type.ConfigFeature{ + { + Type: backend.ConfigFeatureTypeText, + Input: "text", + Title: "Scheme", + Name: SchemeConfigFeature, + Required: true, + }, + { + Type: backend.ConfigFeatureTypeText, + Input: "text", + Title: "Token", + Name: TokenConfigFeature, + Required: true, + }, +} + +type ( + AuthConfig struct { + encryptionService authentication_type.PasswordService + + Scheme string `json:"scheme" ,yaml:"scheme"` + Token string `json:"token" ,yaml:"token"` + } +) + +func (a *AuthConfig) GetFeatureConfig() []authentication_type.ConfigFeature { + return features +} + +func (a *AuthConfig) ValidateConfiguration(inputFormat string, input any) error { + switch inputFormat { + case "object": + for key, value := range input.(types.Metadata) { + if _, ok := value.(string); !ok { + if key == "scheme" { + return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid auth type for field: "+key)) + } + + if key == "token" { + return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid auth type for field: "+key)) + } + } + + vs := value.(string) + + if key == SchemeConfigFeature { + if vs == "" { + return errors.New("scheme cannot be empty") + } + } + + if key == TokenConfigFeature { + if vs == "" { + return errors.New("token cannot be empty") + } + } + } + case "yaml": + err := yaml.Unmarshal([]byte(input.(string)), &a) + if err != nil { + return err + } + + if a.Scheme == "" { + return errors.New("scheme cannot be empty") + } + + if a.Token == "" { + return errors.New("token cannot be empty") + } + } + + return nil +} + +func (a *AuthConfig) ConfigToFormat(outputFormat string, input any) (any, error) { + switch input.(type) { + case types.Metadata: + if outputFormat == "yaml" { + retVal, err := yaml.Marshal(input) + + return string(retVal), err + } + case string: + if outputFormat == "object" { + retVal := make(types.Metadata) + val := input.(string) + err := yaml.Unmarshal([]byte(val), &retVal) + + return retVal, err + } + } + + return nil, errors.New("unsupported format") +} + +func (a *AuthConfig) OmitInformation(outputFormat string, input any) (any, error) { + switch input.(type) { + case types.Metadata: + inputMeta := input.(types.Metadata) + authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) + authMeta[TokenConfigFeature] = "" + inputMeta[authentication_type.AuthenticationKey] = authMeta + + if outputFormat == "yaml" { + return a.ConfigToFormat("yaml", inputMeta) + } + + if outputFormat == "object" { + return inputMeta, nil + } + + return nil, errors.New("unsupported format") + case string: + iia, err := a.ConfigToFormat("object", input) + if err != nil { + return nil, err + } + inputMeta := iia.(types.Metadata) + authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) + authMeta[TokenConfigFeature] = "" + inputMeta[authentication_type.AuthenticationKey] = authMeta + + if outputFormat == "yaml" { + return a.ConfigToFormat("yaml", inputMeta) + } + + if outputFormat == "object" { + return inputMeta, nil + } + + return nil, errors.New("unsupported format") + } + + return nil, errors.New("unsupported format") +} + +func (a *AuthConfig) EncodeInformation(outputFormat string, input interface{}) (interface{}, error) { + switch input.(type) { + case types.Metadata: + inputMeta := input.(types.Metadata) + authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) + + if _, ok := authMeta[TokenConfigFeature].(string); !ok { + return nil, errors.Wrap(errors.ErrTokenNotFound, errors.New("token field was not found")) + } + + encoded, err := a.encryptionService.EncodePassword(authMeta[TokenConfigFeature].(string)) + if err != nil { + return nil, err + } + + authMeta[TokenConfigFeature] = encoded + inputMeta[authentication_type.AuthenticationKey] = authMeta + + if outputFormat == "yaml" { + return a.ConfigToFormat("yaml", inputMeta) + } + + if outputFormat == "object" { + return inputMeta, nil + } + + return nil, errors.New("unsupported format") + case string: + iia, err := a.ConfigToFormat("object", input) + if err != nil { + return nil, err + } + inputMeta := iia.(types.Metadata) + authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) + + encoded, err := a.encryptionService.EncodePassword(authMeta[TokenConfigFeature].(string)) + if err != nil { + return nil, err + } + + authMeta[TokenConfigFeature] = encoded + inputMeta[authentication_type.AuthenticationKey] = authMeta + + if outputFormat == "yaml" { + return a.ConfigToFormat("yaml", inputMeta) + } + + if outputFormat == "object" { + return inputMeta, nil + } + + return nil, errors.New("unsupported format") + } + + return nil, errors.New("unsupported format") +} + +func (a *AuthConfig) DecodeInformation(outputFormat string, input any) (any, error) { + switch input.(type) { + case types.Metadata: + inputMeta := input.(types.Metadata) + authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) + + decoded, err := a.encryptionService.DecodePassword(authMeta[TokenConfigFeature].(string)) + if err != nil { + return nil, err + } + + authMeta[TokenConfigFeature] = decoded + inputMeta[authentication_type.AuthenticationKey] = authMeta + + if outputFormat == "yaml" { + return a.ConfigToFormat("yaml", inputMeta) + } + + if outputFormat == "object" { + return inputMeta, nil + } + + return nil, errors.New("unsupported format") + case string: + iia, err := a.ConfigToFormat("object", input) + if err != nil { + return nil, err + } + + inputMeta := iia.(types.Metadata) + authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) + + decoded, err := a.encryptionService.DecodePassword(authMeta[TokenConfigFeature].(string)) + if err != nil { + return nil, err + } + + authMeta[TokenConfigFeature] = decoded + inputMeta[authentication_type.AuthenticationKey] = authMeta + + if outputFormat == "yaml" { + return a.ConfigToFormat("yaml", inputMeta) + } + + if outputFormat == "object" { + return inputMeta, nil + } + + return nil, errors.New("unsupported format") + } + + return nil, errors.New("unsupported format") +} + +func (a *AuthConfig) Metadata() authentication_type.AuthenticationTypeConfig { + return authentication_type.AuthenticationTypeConfig{ + Type: AuthType, + Description: "Token authentication", + Config: features, + } +} + +func Register(encryptionService authentication_type.PasswordService) { + bearerTokenAuth := AuthConfig{ + encryptionService: encryptionService, + } + authentication_type.Register(AuthType, &bearerTokenAuth) +} diff --git a/sinks/authentication_type/bearertokenauth/authentication_test.go b/sinks/authentication_type/bearertokenauth/authentication_test.go new file mode 100644 index 000000000..2864fad41 --- /dev/null +++ b/sinks/authentication_type/bearertokenauth/authentication_test.go @@ -0,0 +1,181 @@ +package bearertokenauth + +import ( + "testing" + + "github.com/orb-community/orb/pkg/types" + "github.com/orb-community/orb/sinks/authentication_type" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAuthConfig_ValidateConfiguration(t *testing.T) { + type args struct { + inputFormat string + input types.Metadata + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "missing_schema", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "", + "token": "test_api_key", + }, + }, + wantErr: true, + }, + { + name: "missing_token", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "Bearer", + "token": "", + }, + }, + wantErr: true, + }, + { + name: "valid", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "Bearer", + "token": "abcdefg", + }, + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var a AuthConfig + err := a.ValidateConfiguration(tt.args.inputFormat, tt.args.input) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestAuthConfig_OmitInformation(t *testing.T) { + t.Run("invalid output format", func(t *testing.T) { + input := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "abcdefg", + }, + } + + var a AuthConfig + + _, err := a.OmitInformation("blah", input) + assert.Error(t, err) + }) + t.Run("successfully stripped the secret token", func(t *testing.T) { + input := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "abcdefg", + }, + } + + want := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "", + }, + } + + var a AuthConfig + + got, err := a.OmitInformation("object", input) + require.NoError(t, err) + assert.Equal(t, want, got) + }) +} + +func TestAuthConfig_EncodeInformation(t *testing.T) { + t.Run("invalid output format", func(t *testing.T) { + input := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "abcdefg", + }, + } + + a := AuthConfig{ + encryptionService: authentication_type.NewPasswordService(nil, "test"), + } + + _, err := a.EncodeInformation("blah", input) + assert.Error(t, err) + }) + + t.Run("successfully encrypted token", func(t *testing.T) { + input := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "abcdefg", + }, + } + + a := AuthConfig{ + encryptionService: authentication_type.NewPasswordService(nil, "test"), + } + + _, err := a.EncodeInformation("object", input) + require.NoError(t, err) + }) +} + +func TestAuthConfig_DecodeInformation(t *testing.T) { + t.Run("invalid output format", func(t *testing.T) { + input := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "dca8757dee5dfcc592c97355396dc2bdb95c6a3f58d4acb4453717c960827602acaf49", + }, + } + + a := AuthConfig{ + encryptionService: authentication_type.NewPasswordService(nil, "test"), + } + + _, err := a.DecodeInformation("blah", input) + assert.Error(t, err) + }) + + t.Run("successfully decrypted token", func(t *testing.T) { + input := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "dca8757dee5dfcc592c97355396dc2bdb95c6a3f58d4acb4453717c960827602acaf49", + }, + } + + want := types.Metadata{ + "authentication": types.Metadata{ + "scheme": "Bearer", + "token": "abcdefg", + }, + } + + a := AuthConfig{ + encryptionService: authentication_type.NewPasswordService(nil, "test"), + } + + got, err := a.DecodeInformation("object", input) + require.NoError(t, err) + assert.Equal(t, want, got) + }) +} diff --git a/sinks/service.go b/sinks/service.go index 24c73a174..31a5e9b6a 100644 --- a/sinks/service.go +++ b/sinks/service.go @@ -10,16 +10,19 @@ package sinks import ( "context" + "time" + "github.com/mainflux/mainflux" mfsdk "github.com/mainflux/mainflux/pkg/sdk/go" + "go.uber.org/zap" + "github.com/orb-community/orb/pkg/errors" "github.com/orb-community/orb/pkg/types" "github.com/orb-community/orb/sinks/authentication_type" "github.com/orb-community/orb/sinks/authentication_type/basicauth" + "github.com/orb-community/orb/sinks/authentication_type/bearertokenauth" "github.com/orb-community/orb/sinks/backend/otlphttpexporter" "github.com/orb-community/orb/sinks/backend/prometheus" - "go.uber.org/zap" - "time" ) // PageMetadata contains page metadata that helps navigation @@ -67,7 +70,7 @@ func NewSinkService(logger *zap.Logger, auth mainflux.AuthServiceClient, sinkRep otlphttpexporter.Register() prometheus.Register() basicauth.Register(passwordService) - // bearerauth.Register(passwordService) + bearertokenauth.Register(passwordService) return &sinkService{ logger: logger, auth: auth, From 739e722b76de630038bb0e2f3d27703721d48843 Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Wed, 10 Jul 2024 16:24:54 +0100 Subject: [PATCH 2/7] return correct status codes, and dont disable create button --- sinks/api/http/transport.go | 13 ++++++++++--- ui/src/app/pages/sinks/add/sink-add.component.ts | 9 +-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sinks/api/http/transport.go b/sinks/api/http/transport.go index 8f0277f76..d04ca3ac9 100644 --- a/sinks/api/http/transport.go +++ b/sinks/api/http/transport.go @@ -236,7 +236,6 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { case errors.Contains(errorVal, errors.ErrUnsupportedContentType): w.WriteHeader(http.StatusUnsupportedMediaType) - case errors.Contains(errorVal, errors.ErrInvalidEndpoint): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrEndpointNotFound): @@ -251,8 +250,16 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrInvalidPasswordType): w.WriteHeader(http.StatusBadRequest) + case errors.Contains(errorVal, errors.ErrInvalidTokenType): + w.WriteHeader(http.StatusBadRequest) + case errors.Contains(errorVal, errors.ErrTokenNotFound): + w.WriteHeader(http.StatusBadRequest) + case errors.Contains(errorVal, errors.ErrInvalidSchemeType): + w.WriteHeader(http.StatusBadRequest) + case errors.Contains(errorVal, errors.ErrSchemeNotFound): + w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrInvalidAuthType): - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrRemoteHostNotFound): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrAuthFieldNotFound): @@ -262,7 +269,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { case errors.Contains(errorVal, errors.ErrExporterFieldNotFound): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrInvalidBackend): - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrEntityNameNotFound): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrMalformedEntity): diff --git a/ui/src/app/pages/sinks/add/sink-add.component.ts b/ui/src/app/pages/sinks/add/sink-add.component.ts index 71ac47e5f..66cdc096e 100644 --- a/ui/src/app/pages/sinks/add/sink-add.component.ts +++ b/ui/src/app/pages/sinks/add/sink-add.component.ts @@ -79,14 +79,7 @@ export class SinkAddComponent { return !this.editor.checkEmpty(config.authentication) && !this.editor.checkEmpty(config.exporter) - && detailsValid - && !this.checkString(config); - } - checkString(config: any): boolean { - if (typeof config.authentication.password !== 'string' || typeof config.authentication.username !== 'string') { - return true; - } - return false; + && detailsValid; } createSink() { From 3673b95607fafd3ebb631b7a4ec6310378e03c09 Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Wed, 10 Jul 2024 17:12:01 +0100 Subject: [PATCH 3/7] fix unit test --- sinks/api/http/endpoint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sinks/api/http/endpoint_test.go b/sinks/api/http/endpoint_test.go index 4903031c1..d45c606f3 100644 --- a/sinks/api/http/endpoint_test.go +++ b/sinks/api/http/endpoint_test.go @@ -857,7 +857,7 @@ func TestAuthenticationTypesEndpoints(t *testing.T) { err = json.Unmarshal(body, &authResponse) require.NoError(t, err, "must not error") require.NotNil(t, authResponse, "response must not be nil") - require.Equal(t, 1, len(authResponse.AuthenticationTypes), "must contain basicauth for now") + require.Equal(t, 2, len(authResponse.AuthenticationTypes), "must contain basicauth and bearertokenauth") }, }, "view authentication type basicauth": { From 08d194490e6cbe969ecbc1453e34e90311dc804e Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Thu, 11 Jul 2024 09:50:08 +0100 Subject: [PATCH 4/7] more validaton for basic and token auth --- pkg/errors/types.go | 5 +- sinks/api/http/transport.go | 2 + .../basicauth/authentication.go | 66 ++++++--- .../basicauth/authentication_test.go | 132 ++++++++++++++++++ .../bearertokenauth/authentication.go | 53 ++++--- .../bearertokenauth/authentication_test.go | 82 +++++++++-- 6 files changed, 288 insertions(+), 52 deletions(-) create mode 100644 sinks/authentication_type/basicauth/authentication_test.go diff --git a/pkg/errors/types.go b/pkg/errors/types.go index b77f58396..fedb17dac 100644 --- a/pkg/errors/types.go +++ b/pkg/errors/types.go @@ -45,10 +45,13 @@ var ( // ErrInvalidAuthType indicates invalid authentication type ErrInvalidAuthType = New("malformed entity specification. type key on authentication field is invalid") + // ErrUsernameNotFound indicates that username key was not found + ErrUsernameNotFound = New("malformed entity specification. username key is expected on authentication field") + // ErrPasswordNotFound indicates that password key was not found ErrPasswordNotFound = New("malformed entity specification. password key is expected on authentication field") - // ErrSchemeNotFound indicates that token key was not found + // ErrSchemeNotFound indicates that scheme key was not found ErrSchemeNotFound = New("malformed entity specification. scheme key is expected on authentication field") // ErrTokendNotFound indicates that token key was not found diff --git a/sinks/api/http/transport.go b/sinks/api/http/transport.go index d04ca3ac9..e9fea7230 100644 --- a/sinks/api/http/transport.go +++ b/sinks/api/http/transport.go @@ -242,6 +242,8 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrBackendNotFound): w.WriteHeader(http.StatusBadRequest) + case errors.Contains(errorVal, errors.ErrUsernameNotFound): + w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrPasswordNotFound): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrAuthTypeNotFound): diff --git a/sinks/authentication_type/basicauth/authentication.go b/sinks/authentication_type/basicauth/authentication.go index 71de2fa66..69eee6588 100644 --- a/sinks/authentication_type/basicauth/authentication.go +++ b/sinks/authentication_type/basicauth/authentication.go @@ -1,11 +1,14 @@ package basicauth import ( + "strings" + + "gopkg.in/yaml.v3" + "github.com/orb-community/orb/pkg/errors" "github.com/orb-community/orb/pkg/types" "github.com/orb-community/orb/sinks/authentication_type" "github.com/orb-community/orb/sinks/backend" - "gopkg.in/yaml.v3" ) const ( @@ -35,8 +38,8 @@ var ( const AuthType = "basicauth" type AuthConfig struct { - Username string `json:"username" ,yaml:"username"` - Password string `json:"password" ,yaml:"password"` + Username *string `json:"username" ,yaml:"username"` + Password *string `json:"password" ,yaml:"password"` encryptionService authentication_type.PasswordService } @@ -56,27 +59,32 @@ func (a *AuthConfig) GetFeatureConfig() []authentication_type.ConfigFeature { func (a *AuthConfig) ValidateConfiguration(inputFormat string, input interface{}) error { switch inputFormat { case "object": + if _, ok := input.(types.Metadata)[UsernameConfigFeature]; !ok { + return errors.Wrap(errors.ErrUsernameNotFound, errors.New("username field was not found")) + } + + if _, ok := input.(types.Metadata)[PasswordConfigFeature]; !ok { + return errors.Wrap(errors.ErrPasswordNotFound, errors.New("password field was not found")) + } + for key, value := range input.(types.Metadata) { - if _, ok := value.(string); !ok { - if key == "password" { - return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid auth type for field: " + key)) - } - if key == "type" { - return errors.Wrap(errors.ErrInvalidAuthType, errors.New("invalid auth type for field: " + key)) - } - if key == "username" { - return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid auth type for field: " + key)) - } - } - vs := value.(string) if key == UsernameConfigFeature { - if len(vs) == 0 { - return errors.New("username cannot be empty") + if _, ok := value.(string); !ok { + return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid auth type for field: "+key)) + } + + if len(strings.Fields(value.(string))) == 0 { + return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid authentication username")) } } + if key == PasswordConfigFeature { - if len(vs) == 0 { - return errors.New("password cannot be empty") + if _, ok := value.(string); !ok { + return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid auth type for field: "+key)) + } + + if len(strings.Fields(value.(string))) == 0 { + return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid authentication password")) } } } @@ -85,12 +93,24 @@ func (a *AuthConfig) ValidateConfiguration(inputFormat string, input interface{} if err != nil { return err } - if len(a.Username) == 0 { - return errors.New("username cannot be empty") - } else if len(a.Password) == 0 { - return errors.New("password cannot be empty") + + if a.Username == nil { + return errors.Wrap(errors.ErrUsernameNotFound, errors.New("username field was not found")) + } + + if len(strings.Fields(*a.Username)) == 0 { + return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid authentication username")) + } + + if a.Password == nil { + return errors.Wrap(errors.ErrPasswordNotFound, errors.New("password field was not found")) + } + + if len(strings.Fields(*a.Password)) == 0 { + return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid authentication password")) } } + return nil } diff --git a/sinks/authentication_type/basicauth/authentication_test.go b/sinks/authentication_type/basicauth/authentication_test.go new file mode 100644 index 000000000..b1329f772 --- /dev/null +++ b/sinks/authentication_type/basicauth/authentication_test.go @@ -0,0 +1,132 @@ +package basicauth + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/orb-community/orb/pkg/errors" + "github.com/orb-community/orb/pkg/types" +) + +func TestAuthConfig_ValidateConfiguration(t *testing.T) { + type args struct { + inputFormat string + input types.Metadata + } + tests := []struct { + name string + args args + wantErr error + }{ + { + name: "missing_username", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "password": "test-password", + }, + }, + wantErr: errors.ErrUsernameNotFound, + }, + { + name: "empty_username", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": "", + "password": "test-password", + }, + }, + wantErr: errors.ErrInvalidUsernameType, + }, + { + name: "invalid_username_type", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": 1234, + "password": "test-password", + }, + }, + wantErr: errors.ErrInvalidUsernameType, + }, + { + name: "invalid_username", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": " ", + "password": "test-password", + }, + }, + wantErr: errors.ErrInvalidUsernameType, + }, + { + name: "missing_password", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": "test-user", + }, + }, + wantErr: errors.ErrPasswordNotFound, + }, + { + name: "empty_password", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": "test-user", + "password": "", + }, + }, + wantErr: errors.ErrInvalidPasswordType, + }, + { + name: "invalid_password_type", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": "test-user", + "password": 1234, + }, + }, + wantErr: errors.ErrInvalidPasswordType, + }, + { + name: "invalid_password", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": "test-user", + "password": " ", + }, + }, + wantErr: errors.ErrInvalidPasswordType, + }, + { + name: "valid", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "username": "test-user", + "password": "test-password", + }, + }, + wantErr: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var a AuthConfig + err := a.ValidateConfiguration(tt.args.inputFormat, tt.args.input) + if tt.wantErr != nil { + assert.ErrorContains(t, err, tt.wantErr.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/sinks/authentication_type/bearertokenauth/authentication.go b/sinks/authentication_type/bearertokenauth/authentication.go index 8acdee0cf..0246d0d74 100644 --- a/sinks/authentication_type/bearertokenauth/authentication.go +++ b/sinks/authentication_type/bearertokenauth/authentication.go @@ -1,6 +1,8 @@ package bearertokenauth import ( + "strings" + "gopkg.in/yaml.v2" "github.com/orb-community/orb/pkg/errors" @@ -36,8 +38,8 @@ type ( AuthConfig struct { encryptionService authentication_type.PasswordService - Scheme string `json:"scheme" ,yaml:"scheme"` - Token string `json:"token" ,yaml:"token"` + Scheme *string `json:"scheme" ,yaml:"scheme"` + Token *string `json:"token" ,yaml:"token"` } ) @@ -48,28 +50,31 @@ func (a *AuthConfig) GetFeatureConfig() []authentication_type.ConfigFeature { func (a *AuthConfig) ValidateConfiguration(inputFormat string, input any) error { switch inputFormat { case "object": + if _, ok := input.(types.Metadata)[SchemeConfigFeature]; !ok { + return errors.Wrap(errors.ErrSchemeNotFound, errors.New("scheme field was not found")) + } + + if _, ok := input.(types.Metadata)[TokenConfigFeature]; !ok { + return errors.Wrap(errors.ErrTokenNotFound, errors.New("token field was not found")) + } + for key, value := range input.(types.Metadata) { - if _, ok := value.(string); !ok { - if key == "scheme" { + if key == SchemeConfigFeature { + if _, ok := value.(string); !ok { return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid auth type for field: "+key)) } - if key == "token" { - return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid auth type for field: "+key)) - } - } - - vs := value.(string) - - if key == SchemeConfigFeature { - if vs == "" { - return errors.New("scheme cannot be empty") + if len(strings.Fields(value.(string))) != 1 { + return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid authentication scheme")) } } if key == TokenConfigFeature { - if vs == "" { - return errors.New("token cannot be empty") + if _, ok := value.(string); !ok { + return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid auth type for field: "+key)) + } + if len(strings.Fields(value.(string))) != 1 { + return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid authentication token")) } } } @@ -79,12 +84,20 @@ func (a *AuthConfig) ValidateConfiguration(inputFormat string, input any) error return err } - if a.Scheme == "" { - return errors.New("scheme cannot be empty") + if a.Scheme == nil { + return errors.Wrap(errors.ErrSchemeNotFound, errors.New("scheme field was not found")) + } + + if len(strings.Fields(*a.Scheme)) != 1 { + return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid authentication scheme")) + } + + if a.Token == nil { + return errors.Wrap(errors.ErrTokenNotFound, errors.New("token field was not found")) } - if a.Token == "" { - return errors.New("token cannot be empty") + if len(strings.Fields(*a.Token)) != 1 { + return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid authentication token")) } } diff --git a/sinks/authentication_type/bearertokenauth/authentication_test.go b/sinks/authentication_type/bearertokenauth/authentication_test.go index 2864fad41..fb06c48be 100644 --- a/sinks/authentication_type/bearertokenauth/authentication_test.go +++ b/sinks/authentication_type/bearertokenauth/authentication_test.go @@ -3,10 +3,12 @@ package bearertokenauth import ( "testing" - "github.com/orb-community/orb/pkg/types" - "github.com/orb-community/orb/sinks/authentication_type" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/orb-community/orb/pkg/errors" + "github.com/orb-community/orb/pkg/types" + "github.com/orb-community/orb/sinks/authentication_type" ) func TestAuthConfig_ValidateConfiguration(t *testing.T) { @@ -17,10 +19,20 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { tests := []struct { name string args args - wantErr bool + wantErr error }{ { name: "missing_schema", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "token": "test_api_key", + }, + }, + wantErr: errors.ErrSchemeNotFound, + }, + { + name: "empty_schema", args: args{ inputFormat: "object", input: types.Metadata{ @@ -28,10 +40,42 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "test_api_key", }, }, - wantErr: true, + wantErr: errors.ErrInvalidSchemeType, + }, + { + name: "invalid_schema_type", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": 1234, + "token": "test_api_key", + }, + }, + wantErr: errors.ErrInvalidSchemeType, + }, + { + name: "invalid_schema", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "fake schema", + "token": "test_api_key", + }, + }, + wantErr: errors.ErrInvalidSchemeType, }, { name: "missing_token", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "Bearer", + }, + }, + wantErr: errors.ErrTokenNotFound, + }, + { + name: "empty_token", args: args{ inputFormat: "object", input: types.Metadata{ @@ -39,7 +83,29 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "", }, }, - wantErr: true, + wantErr: errors.ErrInvalidTokenType, + }, + { + name: "invalid_token_type", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "Bearer", + "token": 1234, + }, + }, + wantErr: errors.ErrInvalidTokenType, + }, + { + name: "invalid_token_value", + args: args{ + inputFormat: "object", + input: types.Metadata{ + "scheme": "Bearer", + "token": "invalid api key", + }, + }, + wantErr: errors.ErrInvalidTokenType, }, { name: "valid", @@ -50,7 +116,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "abcdefg", }, }, - wantErr: false, + wantErr: nil, }, } @@ -58,8 +124,8 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var a AuthConfig err := a.ValidateConfiguration(tt.args.inputFormat, tt.args.input) - if tt.wantErr { - assert.Error(t, err) + if tt.wantErr != nil { + assert.ErrorContains(t, err, tt.wantErr.Error()) } else { assert.NoError(t, err) } From 52b8cebdf9e31be333edc549185d13e2989415f8 Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Fri, 9 Aug 2024 12:13:27 +0100 Subject: [PATCH 5/7] better auth error names --- pkg/errors/types.go | 48 +++++++++---------- sinks/api/http/requests.go | 6 +-- sinks/api/http/transport.go | 18 +++---- .../basicauth/authentication.go | 22 ++++----- .../basicauth/authentication_test.go | 16 +++---- .../bearertokenauth/authentication.go | 22 ++++----- .../bearertokenauth/authentication_test.go | 16 +++---- sinks/sinks_service.go | 4 +- 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/pkg/errors/types.go b/pkg/errors/types.go index fedb17dac..c0405759e 100644 --- a/pkg/errors/types.go +++ b/pkg/errors/types.go @@ -36,44 +36,44 @@ var ( // ErrExporterFieldNotFound indicates that exporter field was not found ErrExporterFieldNotFound = New("malformed entity specification. exporter field is expected on configuration field") + // ErrEndPointNotFound indicates that endpoint field was not found on exporter field for otlp backend + ErrEndpointNotFound = New("malformed entity specification. endpoint field is expected on exporter field") + + // ErrInvalidEndpoint indicates that endpoint field is not valid + ErrInvalidEndpoint = New("malformed entity specification. endpoint field is invalid") + // ErrAuthFieldNotFound indicates that authentication field was not found on configuration field ErrAuthFieldNotFound = New("malformed entity specification. authentication fields are expected on configuration field") // ErrAuthTypeNotFound indicates that authentication type field was not found on the authentication field ErrAuthTypeNotFound = New("malformed entity specification: authentication type field is expected on configuration field") - // ErrInvalidAuthType indicates invalid authentication type - ErrInvalidAuthType = New("malformed entity specification. type key on authentication field is invalid") + // ErrAuthInvalidType indicates invalid authentication type + ErrAuthInvalidType = New("malformed entity specification. type key on authentication field is invalid") - // ErrUsernameNotFound indicates that username key was not found - ErrUsernameNotFound = New("malformed entity specification. username key is expected on authentication field") + // ErrAuthUsernameNotFound indicates that username key was not found + ErrAuthUsernameNotFound = New("malformed entity specification. username key is expected on authentication field") - // ErrPasswordNotFound indicates that password key was not found - ErrPasswordNotFound = New("malformed entity specification. password key is expected on authentication field") + // ErrAuthPasswordNotFound indicates that password key was not found + ErrAuthPasswordNotFound = New("malformed entity specification. password key is expected on authentication field") - // ErrSchemeNotFound indicates that scheme key was not found - ErrSchemeNotFound = New("malformed entity specification. scheme key is expected on authentication field") + // ErrAuthSchemeNotFound indicates that scheme key was not found + ErrAuthSchemeNotFound = New("malformed entity specification. scheme key is expected on authentication field") - // ErrTokendNotFound indicates that token key was not found - ErrTokenNotFound = New("malformed entity specification. token key is expected on authentication field") - - // ErrEndPointNotFound indicates that endpoint field was not found on exporter field for otlp backend - ErrEndpointNotFound = New("malformed entity specification. endpoint field is expected on exporter field") - - // ErrInvalidEndpoint indicates that endpoint field is not valid - ErrInvalidEndpoint = New("malformed entity specification. endpoint field is invalid") + // ErrAuthTokenNotFound indicates that token key was not found + ErrAuthTokenNotFound = New("malformed entity specification. token key is expected on authentication field") - // ErrInvalidPasswordType indicates invalid password key on authentication field - ErrInvalidPasswordType = New("malformed entity specification. password key on authentication field is invalid") + // ErrAuthInvalidPasswordType indicates invalid password key on authentication field + ErrAuthInvalidPasswordType = New("malformed entity specification. password key on authentication field is invalid") - // ErrInvalidSchemeType indicates invalid scheme key on authentication field - ErrInvalidSchemeType = New("malformed entity specification. scheme key on authentication field is invalid") + // ErrAuthInvalidSchemeType indicates invalid scheme key on authentication field + ErrAuthInvalidSchemeType = New("malformed entity specification. scheme key on authentication field is invalid") - // ErrInvalidTokenType indicates invalid token key on authentication field - ErrInvalidTokenType = New("malformed entity specification. token key on authentication field is invalid") + // ErrAuthInvalidTokenType indicates invalid token key on authentication field + ErrAuthInvalidTokenType = New("malformed entity specification. token key on authentication field is invalid") - // ErrInvalidUsernameType indicates invalid username key on authentication field - ErrInvalidUsernameType = New("malformed entity specification. username key on authentication field is invalid") + // ErrAuthInvalidUsernameType indicates invalid username key on authentication field + ErrAuthInvalidUsernameType = New("malformed entity specification. username key on authentication field is invalid") // ErrRemoteHostNotFound indicates that remote host field was not found ErrRemoteHostNotFound = New("malformed entity specification. remote host is expected on exporter field") diff --git a/sinks/api/http/requests.go b/sinks/api/http/requests.go index 9d7922d5e..02994fa41 100644 --- a/sinks/api/http/requests.go +++ b/sinks/api/http/requests.go @@ -76,7 +76,7 @@ func GetConfigurationAndMetadataFromMeta(backendName string, config types.Metada } authTypeSvc, ok := authentication_type.GetAuthType(authtype.(string)) if !ok { - err = errors.Wrap(errors.ErrInvalidAuthType, errors.New("invalid required field authentication type")) + err = errors.Wrap(errors.ErrAuthInvalidType, errors.New("invalid required field authentication type")) return } configSvc.Authentication = authTypeSvc @@ -119,12 +119,12 @@ func GetConfigurationAndMetadataFromYaml(backendName string, config string) (con case string: break default: - err = errors.ErrInvalidAuthType + err = errors.ErrAuthInvalidType return } authTypeSvc, ok := authentication_type.GetAuthType(authtype.(string)) if !ok { - err = errors.Wrap(errors.ErrInvalidAuthType, errors.New("invalid required field authentication type")) + err = errors.Wrap(errors.ErrAuthInvalidType, errors.New("invalid required field authentication type")) return } configSvc.Authentication = authTypeSvc diff --git a/sinks/api/http/transport.go b/sinks/api/http/transport.go index e9fea7230..a03370740 100644 --- a/sinks/api/http/transport.go +++ b/sinks/api/http/transport.go @@ -242,25 +242,25 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrBackendNotFound): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrUsernameNotFound): + case errors.Contains(errorVal, errors.ErrAuthUsernameNotFound): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrPasswordNotFound): + case errors.Contains(errorVal, errors.ErrAuthPasswordNotFound): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrAuthTypeNotFound): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrInvalidUsernameType): + case errors.Contains(errorVal, errors.ErrAuthInvalidUsernameType): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrInvalidPasswordType): + case errors.Contains(errorVal, errors.ErrAuthInvalidPasswordType): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrInvalidTokenType): + case errors.Contains(errorVal, errors.ErrAuthInvalidTokenType): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrTokenNotFound): + case errors.Contains(errorVal, errors.ErrAuthTokenNotFound): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrInvalidSchemeType): + case errors.Contains(errorVal, errors.ErrAuthInvalidSchemeType): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrSchemeNotFound): + case errors.Contains(errorVal, errors.ErrAuthSchemeNotFound): w.WriteHeader(http.StatusBadRequest) - case errors.Contains(errorVal, errors.ErrInvalidAuthType): + case errors.Contains(errorVal, errors.ErrAuthInvalidType): w.WriteHeader(http.StatusBadRequest) case errors.Contains(errorVal, errors.ErrRemoteHostNotFound): w.WriteHeader(http.StatusBadRequest) diff --git a/sinks/authentication_type/basicauth/authentication.go b/sinks/authentication_type/basicauth/authentication.go index 69eee6588..7556b20e5 100644 --- a/sinks/authentication_type/basicauth/authentication.go +++ b/sinks/authentication_type/basicauth/authentication.go @@ -60,31 +60,31 @@ func (a *AuthConfig) ValidateConfiguration(inputFormat string, input interface{} switch inputFormat { case "object": if _, ok := input.(types.Metadata)[UsernameConfigFeature]; !ok { - return errors.Wrap(errors.ErrUsernameNotFound, errors.New("username field was not found")) + return errors.Wrap(errors.ErrAuthUsernameNotFound, errors.New("username field was not found")) } if _, ok := input.(types.Metadata)[PasswordConfigFeature]; !ok { - return errors.Wrap(errors.ErrPasswordNotFound, errors.New("password field was not found")) + return errors.Wrap(errors.ErrAuthPasswordNotFound, errors.New("password field was not found")) } for key, value := range input.(types.Metadata) { if key == UsernameConfigFeature { if _, ok := value.(string); !ok { - return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid auth type for field: "+key)) + return errors.Wrap(errors.ErrAuthInvalidUsernameType, errors.New("invalid auth type for field: "+key)) } if len(strings.Fields(value.(string))) == 0 { - return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid authentication username")) + return errors.Wrap(errors.ErrAuthInvalidUsernameType, errors.New("invalid authentication username")) } } if key == PasswordConfigFeature { if _, ok := value.(string); !ok { - return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid auth type for field: "+key)) + return errors.Wrap(errors.ErrAuthInvalidPasswordType, errors.New("invalid auth type for field: "+key)) } if len(strings.Fields(value.(string))) == 0 { - return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid authentication password")) + return errors.Wrap(errors.ErrAuthInvalidPasswordType, errors.New("invalid authentication password")) } } } @@ -95,19 +95,19 @@ func (a *AuthConfig) ValidateConfiguration(inputFormat string, input interface{} } if a.Username == nil { - return errors.Wrap(errors.ErrUsernameNotFound, errors.New("username field was not found")) + return errors.Wrap(errors.ErrAuthUsernameNotFound, errors.New("username field was not found")) } if len(strings.Fields(*a.Username)) == 0 { - return errors.Wrap(errors.ErrInvalidUsernameType, errors.New("invalid authentication username")) + return errors.Wrap(errors.ErrAuthInvalidUsernameType, errors.New("invalid authentication username")) } if a.Password == nil { - return errors.Wrap(errors.ErrPasswordNotFound, errors.New("password field was not found")) + return errors.Wrap(errors.ErrAuthPasswordNotFound, errors.New("password field was not found")) } if len(strings.Fields(*a.Password)) == 0 { - return errors.Wrap(errors.ErrInvalidPasswordType, errors.New("invalid authentication password")) + return errors.Wrap(errors.ErrAuthInvalidPasswordType, errors.New("invalid authentication password")) } } @@ -176,7 +176,7 @@ func (a *AuthConfig) EncodeInformation(outputFormat string, input interface{}) ( inputMeta := input.(types.Metadata) authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) if _, ok := authMeta[PasswordConfigFeature].(string); !ok { - return nil, errors.Wrap(errors.ErrPasswordNotFound, errors.New("password field was not found")) + return nil, errors.Wrap(errors.ErrAuthPasswordNotFound, errors.New("password field was not found")) } encoded, err := a.encryptionService.EncodePassword(authMeta[PasswordConfigFeature].(string)) if err != nil { diff --git a/sinks/authentication_type/basicauth/authentication_test.go b/sinks/authentication_type/basicauth/authentication_test.go index b1329f772..c0c950154 100644 --- a/sinks/authentication_type/basicauth/authentication_test.go +++ b/sinks/authentication_type/basicauth/authentication_test.go @@ -27,7 +27,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": "test-password", }, }, - wantErr: errors.ErrUsernameNotFound, + wantErr: errors.ErrAuthUsernameNotFound, }, { name: "empty_username", @@ -38,7 +38,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": "test-password", }, }, - wantErr: errors.ErrInvalidUsernameType, + wantErr: errors.ErrAuthInvalidUsernameType, }, { name: "invalid_username_type", @@ -49,7 +49,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": "test-password", }, }, - wantErr: errors.ErrInvalidUsernameType, + wantErr: errors.ErrAuthInvalidUsernameType, }, { name: "invalid_username", @@ -60,7 +60,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": "test-password", }, }, - wantErr: errors.ErrInvalidUsernameType, + wantErr: errors.ErrAuthInvalidUsernameType, }, { name: "missing_password", @@ -70,7 +70,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "username": "test-user", }, }, - wantErr: errors.ErrPasswordNotFound, + wantErr: errors.ErrAuthPasswordNotFound, }, { name: "empty_password", @@ -81,7 +81,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": "", }, }, - wantErr: errors.ErrInvalidPasswordType, + wantErr: errors.ErrAuthInvalidPasswordType, }, { name: "invalid_password_type", @@ -92,7 +92,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": 1234, }, }, - wantErr: errors.ErrInvalidPasswordType, + wantErr: errors.ErrAuthInvalidPasswordType, }, { name: "invalid_password", @@ -103,7 +103,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "password": " ", }, }, - wantErr: errors.ErrInvalidPasswordType, + wantErr: errors.ErrAuthInvalidPasswordType, }, { name: "valid", diff --git a/sinks/authentication_type/bearertokenauth/authentication.go b/sinks/authentication_type/bearertokenauth/authentication.go index 0246d0d74..7efe48406 100644 --- a/sinks/authentication_type/bearertokenauth/authentication.go +++ b/sinks/authentication_type/bearertokenauth/authentication.go @@ -51,30 +51,30 @@ func (a *AuthConfig) ValidateConfiguration(inputFormat string, input any) error switch inputFormat { case "object": if _, ok := input.(types.Metadata)[SchemeConfigFeature]; !ok { - return errors.Wrap(errors.ErrSchemeNotFound, errors.New("scheme field was not found")) + return errors.Wrap(errors.ErrAuthSchemeNotFound, errors.New("scheme field was not found")) } if _, ok := input.(types.Metadata)[TokenConfigFeature]; !ok { - return errors.Wrap(errors.ErrTokenNotFound, errors.New("token field was not found")) + return errors.Wrap(errors.ErrAuthTokenNotFound, errors.New("token field was not found")) } for key, value := range input.(types.Metadata) { if key == SchemeConfigFeature { if _, ok := value.(string); !ok { - return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid auth type for field: "+key)) + return errors.Wrap(errors.ErrAuthInvalidSchemeType, errors.New("invalid auth type for field: "+key)) } if len(strings.Fields(value.(string))) != 1 { - return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid authentication scheme")) + return errors.Wrap(errors.ErrAuthInvalidSchemeType, errors.New("invalid authentication scheme")) } } if key == TokenConfigFeature { if _, ok := value.(string); !ok { - return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid auth type for field: "+key)) + return errors.Wrap(errors.ErrAuthInvalidTokenType, errors.New("invalid auth type for field: "+key)) } if len(strings.Fields(value.(string))) != 1 { - return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid authentication token")) + return errors.Wrap(errors.ErrAuthInvalidTokenType, errors.New("invalid authentication token")) } } } @@ -85,19 +85,19 @@ func (a *AuthConfig) ValidateConfiguration(inputFormat string, input any) error } if a.Scheme == nil { - return errors.Wrap(errors.ErrSchemeNotFound, errors.New("scheme field was not found")) + return errors.Wrap(errors.ErrAuthSchemeNotFound, errors.New("scheme field was not found")) } if len(strings.Fields(*a.Scheme)) != 1 { - return errors.Wrap(errors.ErrInvalidSchemeType, errors.New("invalid authentication scheme")) + return errors.Wrap(errors.ErrAuthInvalidSchemeType, errors.New("invalid authentication scheme")) } if a.Token == nil { - return errors.Wrap(errors.ErrTokenNotFound, errors.New("token field was not found")) + return errors.Wrap(errors.ErrAuthTokenNotFound, errors.New("token field was not found")) } if len(strings.Fields(*a.Token)) != 1 { - return errors.Wrap(errors.ErrInvalidTokenType, errors.New("invalid authentication token")) + return errors.Wrap(errors.ErrAuthInvalidTokenType, errors.New("invalid authentication token")) } } @@ -173,7 +173,7 @@ func (a *AuthConfig) EncodeInformation(outputFormat string, input interface{}) ( authMeta := inputMeta.GetSubMetadata(authentication_type.AuthenticationKey) if _, ok := authMeta[TokenConfigFeature].(string); !ok { - return nil, errors.Wrap(errors.ErrTokenNotFound, errors.New("token field was not found")) + return nil, errors.Wrap(errors.ErrAuthTokenNotFound, errors.New("token field was not found")) } encoded, err := a.encryptionService.EncodePassword(authMeta[TokenConfigFeature].(string)) diff --git a/sinks/authentication_type/bearertokenauth/authentication_test.go b/sinks/authentication_type/bearertokenauth/authentication_test.go index fb06c48be..f62cb073d 100644 --- a/sinks/authentication_type/bearertokenauth/authentication_test.go +++ b/sinks/authentication_type/bearertokenauth/authentication_test.go @@ -29,7 +29,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "test_api_key", }, }, - wantErr: errors.ErrSchemeNotFound, + wantErr: errors.ErrAuthSchemeNotFound, }, { name: "empty_schema", @@ -40,7 +40,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "test_api_key", }, }, - wantErr: errors.ErrInvalidSchemeType, + wantErr: errors.ErrAuthInvalidSchemeType, }, { name: "invalid_schema_type", @@ -51,7 +51,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "test_api_key", }, }, - wantErr: errors.ErrInvalidSchemeType, + wantErr: errors.ErrAuthInvalidSchemeType, }, { name: "invalid_schema", @@ -62,7 +62,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "test_api_key", }, }, - wantErr: errors.ErrInvalidSchemeType, + wantErr: errors.ErrAuthInvalidSchemeType, }, { name: "missing_token", @@ -72,7 +72,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "scheme": "Bearer", }, }, - wantErr: errors.ErrTokenNotFound, + wantErr: errors.ErrAuthTokenNotFound, }, { name: "empty_token", @@ -83,7 +83,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "", }, }, - wantErr: errors.ErrInvalidTokenType, + wantErr: errors.ErrAuthInvalidTokenType, }, { name: "invalid_token_type", @@ -94,7 +94,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": 1234, }, }, - wantErr: errors.ErrInvalidTokenType, + wantErr: errors.ErrAuthInvalidTokenType, }, { name: "invalid_token_value", @@ -105,7 +105,7 @@ func TestAuthConfig_ValidateConfiguration(t *testing.T) { "token": "invalid api key", }, }, - wantErr: errors.ErrInvalidTokenType, + wantErr: errors.ErrAuthInvalidTokenType, }, { name: "valid", diff --git a/sinks/sinks_service.go b/sinks/sinks_service.go index ab1617266..b181ed840 100644 --- a/sinks/sinks_service.go +++ b/sinks/sinks_service.go @@ -96,12 +96,12 @@ func validateAuthType(s *Sink) (authentication_type.AuthenticationType, error) { } if _, ok := authTypeStr.(string); !ok { - return nil, errors.Wrap(errors.ErrInvalidAuthType, errors.New("invalid authentication type")) + return nil, errors.Wrap(errors.ErrAuthInvalidType, errors.New("invalid authentication type")) } authType, ok := authentication_type.GetAuthType(authTypeStr.(string)) if !ok { - return nil, errors.Wrap(errors.ErrInvalidAuthType, errors.New("invalid authentication type")) + return nil, errors.Wrap(errors.ErrAuthInvalidType, errors.New("invalid authentication type")) } err := authType.ValidateConfiguration("object", authMetadata) From f2ba65674f5c7b90ffc36aee28cf0e4fb7d3825a Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Fri, 9 Aug 2024 12:16:25 +0100 Subject: [PATCH 6/7] remove redundant comma from structs and use single const block --- .../authentication_type/basicauth/authentication.go | 7 +++---- .../bearertokenauth/authentication.go | 12 +++++------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/sinks/authentication_type/basicauth/authentication.go b/sinks/authentication_type/basicauth/authentication.go index 7556b20e5..cf0e1e7d2 100644 --- a/sinks/authentication_type/basicauth/authentication.go +++ b/sinks/authentication_type/basicauth/authentication.go @@ -12,6 +12,7 @@ import ( ) const ( + AuthType = "basicauth" UsernameConfigFeature = "username" PasswordConfigFeature = "password" ) @@ -35,11 +36,9 @@ var ( } ) -const AuthType = "basicauth" - type AuthConfig struct { - Username *string `json:"username" ,yaml:"username"` - Password *string `json:"password" ,yaml:"password"` + Username *string `json:"username" yaml:"username"` + Password *string `json:"password" yaml:"password"` encryptionService authentication_type.PasswordService } diff --git a/sinks/authentication_type/bearertokenauth/authentication.go b/sinks/authentication_type/bearertokenauth/authentication.go index 7efe48406..fdc01c47a 100644 --- a/sinks/authentication_type/bearertokenauth/authentication.go +++ b/sinks/authentication_type/bearertokenauth/authentication.go @@ -34,14 +34,12 @@ var features = []authentication_type.ConfigFeature{ }, } -type ( - AuthConfig struct { - encryptionService authentication_type.PasswordService +type AuthConfig struct { + encryptionService authentication_type.PasswordService - Scheme *string `json:"scheme" ,yaml:"scheme"` - Token *string `json:"token" ,yaml:"token"` - } -) + Scheme *string `json:"scheme" yaml:"scheme"` + Token *string `json:"token" yaml:"token"` +} func (a *AuthConfig) GetFeatureConfig() []authentication_type.ConfigFeature { return features From 9920aa2410f5bc8f71aec42c94446eec3fdf0679 Mon Sep 17 00:00:00 2001 From: pburrows-ns1 Date: Mon, 19 Aug 2024 10:01:30 +0100 Subject: [PATCH 7/7] fix casing --- pkg/errors/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/errors/types.go b/pkg/errors/types.go index c0405759e..d9c214d27 100644 --- a/pkg/errors/types.go +++ b/pkg/errors/types.go @@ -36,7 +36,7 @@ var ( // ErrExporterFieldNotFound indicates that exporter field was not found ErrExporterFieldNotFound = New("malformed entity specification. exporter field is expected on configuration field") - // ErrEndPointNotFound indicates that endpoint field was not found on exporter field for otlp backend + // ErrEndpointNotFound indicates that endpoint field was not found on exporter field for otlp backend ErrEndpointNotFound = New("malformed entity specification. endpoint field is expected on exporter field") // ErrInvalidEndpoint indicates that endpoint field is not valid