From d00a37e9c1f7caaaeaa92166df4ae9350b299708 Mon Sep 17 00:00:00 2001 From: Derek Jury Date: Thu, 29 Feb 2024 10:26:38 -0400 Subject: [PATCH] Bips 16625 (#46) * fix: fix max length file secret issue --------- Co-authored-by: EPAM\Felipe_Hernandez --- .github/settings.yaml | 5 +++++ README.md | 7 ++++++- TestClient.go | 5 +++-- api/secrets/secrets.go | 21 +++++++++++++++------ api/secrets/secrets_test.go | 8 ++++---- api/utils/validator.go | 21 +++++++++++---------- 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/.github/settings.yaml b/.github/settings.yaml index af29069..0d3655e 100644 --- a/.github/settings.yaml +++ b/.github/settings.yaml @@ -1,3 +1,8 @@ _extends: .github repository: private: false + name: go-client-library-passwordsafe + description: The Go client library for Password Safe enables Go developers to easily manage passwords from Password Safe. It provides simplifications that significantly reduce the amount of code you need to write. + homepage: https://www.beyondtrust.com/ + topics: secrets, security, golang, library, beyondtrust, passwordsafe, secretssafe + diff --git a/README.md b/README.md index 127962f..75c17fe 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,11 @@ The library supports retrieval of secrets from BeyondInsight/Password Safe versi - type: int - default: 2 minutes - required: False +- maxFileSecretSizeBytes + - description: Max file size allows the user of the library to set a limit on the file size. If max size is exceeded an error is logged and the secret is ignored. Range 1-5000000 Bytes. + - type: int + - default: 4000 + - required: false ## Methods @@ -141,7 +146,7 @@ In order to use Release Please App, we need to use conventional commits, but [he Some of the more important and common commit types are: | Type | Description | Triggers Release Please | -|:---------|:--------------------------------------------------------------|:-------------------------| +| :------- | :------------------------------------------------------------ | :---------------------- | | feat! | Introduce a major change e.g. v1.0.0 to v2.0.0 | Yes | | feat | Introduce a minor change e.g. v1.0.0 to v1.1.0 | Yes | | fix | Introduce a patch change e.g. v1.0.0 to v1.0.1 | Yes | diff --git a/TestClient.go b/TestClient.go index 84385e2..35cda28 100644 --- a/TestClient.go +++ b/TestClient.go @@ -30,9 +30,10 @@ func main() { clientTimeOutInSeconds := 30 verifyCa := true retryMaxElapsedTimeMinutes := 2 + maxFileSecretSizeBytes := 4000 // validate inputs - errorsInInputs := utils.ValidateInputs(clientId, clientSecret, apiUrl, clientTimeOutInSeconds, &separator, verifyCa, zapLogger, certificate, certificateKey, &retryMaxElapsedTimeMinutes) + errorsInInputs := utils.ValidateInputs(clientId, clientSecret, apiUrl, clientTimeOutInSeconds, &separator, verifyCa, zapLogger, certificate, certificateKey, &retryMaxElapsedTimeMinutes, &maxFileSecretSizeBytes) if errorsInInputs != nil { return @@ -51,7 +52,7 @@ func main() { } // instantiating secret obj - secretObj, _ := secrets.NewSecretObj(*authenticate, zapLogger) + secretObj, _ := secrets.NewSecretObj(*authenticate, zapLogger, maxFileSecretSizeBytes) secretPaths := []string{"fake/Client", "fake/test_file_1"} diff --git a/api/secrets/secrets.go b/api/secrets/secrets.go index e90b200..ff6f690 100644 --- a/api/secrets/secrets.go +++ b/api/secrets/secrets.go @@ -20,15 +20,17 @@ import ( // SecretObj responsible for session requests. type SecretObj struct { - log logging.Logger - authenticationObj authentication.AuthenticationObj + log logging.Logger + authenticationObj authentication.AuthenticationObj + maxFileSecretSizeBytes int } // NewSecretObj creates secret obj -func NewSecretObj(authentication authentication.AuthenticationObj, logger logging.Logger) (*SecretObj, error) { +func NewSecretObj(authentication authentication.AuthenticationObj, logger logging.Logger, maxFileSecretSizeBytes int) (*SecretObj, error) { secretObj := &SecretObj{ - log: logger, - authenticationObj: authentication, + log: logger, + authenticationObj: authentication, + maxFileSecretSizeBytes: maxFileSecretSizeBytes, } return secretObj, nil } @@ -76,7 +78,14 @@ func (secretObj *SecretObj) GetSecretFlow(secretsToRetrieve []string, separator return nil, err } - secretDictionary[secretToRetrieve] = fileSecretContent + secretInBytes := []byte(fileSecretContent) + + if len(secretInBytes) > secretObj.maxFileSecretSizeBytes { + secretObj.log.Error(fmt.Sprintf("%v%v%v: %v %v %v %v", secretPath, separator, secretTitle, "Secret file Size:", len(secretInBytes), "is greater than the maximum allowed size:", secretObj.maxFileSecretSizeBytes)) + } else { + secretDictionary[secretToRetrieve] = fileSecretContent + } + } else { secretDictionary[secretToRetrieve] = secret.Password } diff --git a/api/secrets/secrets_test.go b/api/secrets/secrets_test.go index 7087402..5026be8 100644 --- a/api/secrets/secrets_test.go +++ b/api/secrets/secrets_test.go @@ -55,7 +55,7 @@ func TestSecretGetSecretByPath(t *testing.T) { } authenticate.ApiUrl = testConfig.server.URL + "/" - secretObj, _ := NewSecretObj(*authenticate, zapLogger) + secretObj, _ := NewSecretObj(*authenticate, zapLogger, 4000) response, err := secretObj.SecretGetSecretByPath("path1/path2", "fake_title", "/", "secrets-safe/secrets") @@ -88,7 +88,7 @@ func TestSecretGetFileSecret(t *testing.T) { } authenticate.ApiUrl = testConfig.server.URL + "/" - secretObj, _ := NewSecretObj(*authenticate, zapLogger) + secretObj, _ := NewSecretObj(*authenticate, zapLogger, 4000) response, err := secretObj.SecretGetFileSecret("1", testConfig.server.URL) if response != "fake_password" { @@ -147,7 +147,7 @@ func TestSecretFlow(t *testing.T) { } authenticate.ApiUrl = testConfig.server.URL + "/" - secretObj, _ := NewSecretObj(*authenticate, zapLogger) + secretObj, _ := NewSecretObj(*authenticate, zapLogger, 4000) secretsPaths := strings.Split("oauthgrp_nocert/Test1,oauthgrp_nocert/client_id", ",") response, err := secretObj.GetSecretFlow(secretsPaths, "/") @@ -202,7 +202,7 @@ func TestSecretFlow_SecretNotFound(t *testing.T) { } authenticate.ApiUrl = testConfig.server.URL + "/" - secretObj, _ := NewSecretObj(*authenticate, zapLogger) + secretObj, _ := NewSecretObj(*authenticate, zapLogger, 4000) secretPaths := strings.Split("oauthgrp_nocert/Test1,oauthgrp_nocert/client_id", ",") _, err := secretObj.GetSecretFlow(secretPaths, "/") diff --git a/api/utils/validator.go b/api/utils/validator.go index 38d4498..adbdadf 100644 --- a/api/utils/validator.go +++ b/api/utils/validator.go @@ -21,12 +21,13 @@ type UserInputValidaton struct { ClientTimeOutinSeconds int `validate:"gte=1,lte=300"` Separator string `validate:"required,min=1,max=1"` VerifyCa bool `validate:"required"` + MaxFileSecretSizeBytes int `validate:"gte=1,lte=5000000"` } var validate *validator.Validate // ValidateInputs is responsible for validating end-user inputs. -func ValidateInputs(clientId string, clientSecret string, apiUrl string, clientTimeOutinSeconds int, separator *string, verifyCa bool, logger logging.Logger, certificate string, certificate_key string, retryMaxElapsedTimeMinutes *int) error { +func ValidateInputs(clientId string, clientSecret string, apiUrl string, clientTimeOutinSeconds int, separator *string, verifyCa bool, logger logging.Logger, certificate string, certificate_key string, retryMaxElapsedTimeMinutes *int, maxFileSecretSizeBytes *int) error { if clientTimeOutinSeconds == 0 { clientTimeOutinSeconds = 30 @@ -38,6 +39,10 @@ func ValidateInputs(clientId string, clientSecret string, apiUrl string, clientT *retryMaxElapsedTimeMinutes = 2 } + if *maxFileSecretSizeBytes == 0 { + *maxFileSecretSizeBytes = 4000 + } + validate = validator.New(validator.WithRequiredStructEnabled()) userInput := &UserInputValidaton{ @@ -47,6 +52,7 @@ func ValidateInputs(clientId string, clientSecret string, apiUrl string, clientT ClientTimeOutinSeconds: clientTimeOutinSeconds, Separator: *separator, VerifyCa: verifyCa, + MaxFileSecretSizeBytes: *maxFileSecretSizeBytes, } if !verifyCa { @@ -117,10 +123,6 @@ func ValidatePaths(secretPaths []string, isManagedAccount bool, separator string var maxSystemNameLength = 129 var maxPathLength = 1792 var maxTitleLength = 256 - var maxPath = 0 - var maxName = 0 - var invalidPathName = "" - var invalidName = "" for _, secretToRetrieve := range secretPaths { @@ -133,17 +135,16 @@ func ValidatePaths(secretPaths []string, isManagedAccount bool, separator string path := secretData[0] name := secretData[1] + maxPath := maxPathLength + maxName := maxTitleLength + invalidPathName := "path" + invalidName := "title" if isManagedAccount { maxPath = maxSystemNameLength maxName = maxAccountNameLength invalidPathName = "system name" invalidName = "account name" - } else { - maxPath = maxPathLength - maxName = maxTitleLength - invalidPathName = "path" - invalidName = "title" } path = strings.TrimSpace(path)