Co-authored-by: Young Bu Park <youngp@microsoft.com>
This commit is contained in:
Carlos Mendible 2020-06-17 00:32:26 +02:00 committed by GitHub
parent f46249c554
commit 3221db9709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 55 deletions

View File

@ -3,7 +3,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
// ------------------------------------------------------------ // ------------------------------------------------------------
package jsonsecretstore package localsecretstore
import ( import (
"encoding/json" "encoding/json"
@ -18,41 +18,31 @@ import (
"github.com/dapr/dapr/pkg/logger" "github.com/dapr/dapr/pkg/logger"
) )
const ( type localSecretStoreMetaData struct {
/* #nosec */
enableSecretStoreVariable = "DAPR_ENABLE_JSON_SECRET_STORE"
)
type jsonSecretStoreMetaData struct {
SecretsFile string `json:"secretsFile"` SecretsFile string `json:"secretsFile"`
NestedSeparator string `json:"nestedSeparator"` NestedSeparator string `json:"nestedSeparator"`
} }
type jsonSecretStore struct { type localSecretStore struct {
secretsFile string secretsFile string
nestedSeparator string nestedSeparator string
currenContext []string currenContext []string
currentPath string currentPath string
secrets map[string]string secrets map[string]string
readJSONFileFn func(secretsFile string) (map[string]interface{}, error) readLocalFileFn func(secretsFile string) (map[string]interface{}, error)
logger logger.Logger logger logger.Logger
} }
// NewJSONSecretStore returns a new JSON secret store // NewLocalSecretStore returns a new Local secret store
func NewJSONSecretStore(logger logger.Logger) secretstores.SecretStore { func NewLocalSecretStore(logger logger.Logger) secretstores.SecretStore {
return &jsonSecretStore{ return &localSecretStore{
logger: logger, logger: logger,
} }
} }
// Init creates a JSON secret store // Init creates a Local secret store
func (j *jsonSecretStore) Init(metadata secretstores.Metadata) error { func (j *localSecretStore) Init(metadata secretstores.Metadata) error {
enable := os.Getenv(enableSecretStoreVariable) meta, err := j.getLocalSecretStoreMetadata(metadata)
if enable != "1" {
return fmt.Errorf("jsonsecretstore must be explicitly enabled setting %s environment variable value to 1", enableSecretStoreVariable)
}
meta, err := j.getJSONSecretStoreMetadata(metadata)
if err != nil { if err != nil {
return err return err
} }
@ -61,13 +51,13 @@ func (j *jsonSecretStore) Init(metadata secretstores.Metadata) error {
j.nestedSeparator = ":" j.nestedSeparator = ":"
} }
if j.readJSONFileFn == nil { if j.readLocalFileFn == nil {
j.readJSONFileFn = j.readJSONFile j.readLocalFileFn = j.readLocalFile
} }
j.secrets = map[string]string{} j.secrets = map[string]string{}
jsonConfig, err := j.readJSONFileFn(meta.SecretsFile) jsonConfig, err := j.readLocalFileFn(meta.SecretsFile)
if err != nil { if err != nil {
return err return err
} }
@ -78,7 +68,7 @@ func (j *jsonSecretStore) Init(metadata secretstores.Metadata) error {
} }
// GetSecret retrieves a secret using a key and returns a map of decrypted string/string values // GetSecret retrieves a secret using a key and returns a map of decrypted string/string values
func (j *jsonSecretStore) GetSecret(req secretstores.GetSecretRequest) (secretstores.GetSecretResponse, error) { func (j *localSecretStore) GetSecret(req secretstores.GetSecretRequest) (secretstores.GetSecretResponse, error) {
secretValue, exists := j.secrets[req.Name] secretValue, exists := j.secrets[req.Name]
if !exists { if !exists {
return secretstores.GetSecretResponse{}, fmt.Errorf("secret %s not found", req.Name) return secretstores.GetSecretResponse{}, fmt.Errorf("secret %s not found", req.Name)
@ -91,7 +81,7 @@ func (j *jsonSecretStore) GetSecret(req secretstores.GetSecretRequest) (secretst
}, nil }, nil
} }
func (j *jsonSecretStore) visitJSONObject(jsonConfig map[string]interface{}) error { func (j *localSecretStore) visitJSONObject(jsonConfig map[string]interface{}) error {
for key, element := range jsonConfig { for key, element := range jsonConfig {
j.enterContext(key) j.enterContext(key)
err := j.visitProperty(element) err := j.visitProperty(element)
@ -103,12 +93,12 @@ func (j *jsonSecretStore) visitJSONObject(jsonConfig map[string]interface{}) err
return nil return nil
} }
func (j *jsonSecretStore) enterContext(context string) { func (j *localSecretStore) enterContext(context string) {
j.currenContext = append(j.currenContext, context) j.currenContext = append(j.currenContext, context)
j.currentPath = j.combine(j.currenContext) j.currentPath = j.combine(j.currenContext)
} }
func (j *jsonSecretStore) visitPrimitive(context string) error { func (j *localSecretStore) visitPrimitive(context string) error {
key := j.currentPath key := j.currentPath
_, exists := j.secrets[key] _, exists := j.secrets[key]
@ -121,7 +111,7 @@ func (j *jsonSecretStore) visitPrimitive(context string) error {
return nil return nil
} }
func (j *jsonSecretStore) visitArray(array []interface{}) error { func (j *localSecretStore) visitArray(array []interface{}) error {
for i := 0; i < len(array); i++ { for i := 0; i < len(array); i++ {
j.enterContext(strconv.Itoa(i)) j.enterContext(strconv.Itoa(i))
err := j.visitProperty(array[i]) err := j.visitProperty(array[i])
@ -133,7 +123,7 @@ func (j *jsonSecretStore) visitArray(array []interface{}) error {
return nil return nil
} }
func (j *jsonSecretStore) visitProperty(property interface{}) error { func (j *localSecretStore) visitProperty(property interface{}) error {
switch v := property.(type) { switch v := property.(type) {
case map[string]interface{}: case map[string]interface{}:
return j.visitJSONObject(v) return j.visitJSONObject(v)
@ -146,39 +136,39 @@ func (j *jsonSecretStore) visitProperty(property interface{}) error {
} }
} }
func (j *jsonSecretStore) exitContext() { func (j *localSecretStore) exitContext() {
j.pop() j.pop()
j.currentPath = j.combine(j.currenContext) j.currentPath = j.combine(j.currenContext)
} }
func (j *jsonSecretStore) pop() { func (j *localSecretStore) pop() {
n := len(j.currenContext) - 1 // Top element n := len(j.currenContext) - 1 // Top element
j.currenContext[n] = "" j.currenContext[n] = ""
j.currenContext = j.currenContext[:n] // Pop j.currenContext = j.currenContext[:n] // Pop
} }
func (j *jsonSecretStore) combine(values []string) string { func (j *localSecretStore) combine(values []string) string {
return strings.Join(values, j.nestedSeparator) return strings.Join(values, j.nestedSeparator)
} }
func (j *jsonSecretStore) getJSONSecretStoreMetadata(spec secretstores.Metadata) (*jsonSecretStoreMetaData, error) { func (j *localSecretStore) getLocalSecretStoreMetadata(spec secretstores.Metadata) (*localSecretStoreMetaData, error) {
b, err := json.Marshal(spec.Properties) b, err := json.Marshal(spec.Properties)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var meta jsonSecretStoreMetaData var meta localSecretStoreMetaData
err = json.Unmarshal(b, &meta) err = json.Unmarshal(b, &meta)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if meta.SecretsFile == "" { if meta.SecretsFile == "" {
return nil, fmt.Errorf("missing JSON secrets file in metadata") return nil, fmt.Errorf("missing local secrets file in metadata")
} }
return &meta, nil return &meta, nil
} }
func (j *jsonSecretStore) readJSONFile(secretsFile string) (map[string]interface{}, error) { func (j *localSecretStore) readLocalFile(secretsFile string) (map[string]interface{}, error) {
j.secretsFile = secretsFile j.secretsFile = secretsFile
jsonFile, err := os.Open(secretsFile) jsonFile, err := os.Open(secretsFile)
if err != nil { if err != nil {

View File

@ -2,11 +2,10 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
// ------------------------------------------------------------ // ------------------------------------------------------------
package jsonsecretstore package localsecretstore
import ( import (
"fmt" "fmt"
"os"
"testing" "testing"
"github.com/dapr/components-contrib/secretstores" "github.com/dapr/components-contrib/secretstores"
@ -17,11 +16,10 @@ import (
const secretValue = "secret" const secretValue = "secret"
func TestInit(t *testing.T) { func TestInit(t *testing.T) {
os.Setenv(enableSecretStoreVariable, "1")
m := secretstores.Metadata{} m := secretstores.Metadata{}
s := jsonSecretStore{ s := localSecretStore{
logger: logger.NewLogger("test"), logger: logger.NewLogger("test"),
readJSONFileFn: func(secretsFile string) (map[string]interface{}, error) { readLocalFileFn: func(secretsFile string) (map[string]interface{}, error) {
return nil, nil return nil, nil
}, },
} }
@ -40,30 +38,19 @@ func TestInit(t *testing.T) {
} }
err := s.Init(m) err := s.Init(m)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, err, fmt.Errorf("missing JSON secrets file in metadata")) assert.Equal(t, err, fmt.Errorf("missing local secrets file in metadata"))
})
t.Run("Init with disabled store", func(t *testing.T) {
os.Setenv(enableSecretStoreVariable, "0")
m.Properties = map[string]string{
"Dummy": "a",
}
err := s.Init(m)
assert.NotNil(t, err)
assert.Equal(t, err, fmt.Errorf("jsonsecretstore must be explicitly enabled setting %s environment variable value to 1", enableSecretStoreVariable))
}) })
} }
func TestGetSecret(t *testing.T) { func TestGetSecret(t *testing.T) {
os.Setenv(enableSecretStoreVariable, "1")
m := secretstores.Metadata{} m := secretstores.Metadata{}
m.Properties = map[string]string{ m.Properties = map[string]string{
"SecretsFile": "a", "SecretsFile": "a",
"NestedSeparator": "a", "NestedSeparator": "a",
} }
s := jsonSecretStore{ s := localSecretStore{
logger: logger.NewLogger("test"), logger: logger.NewLogger("test"),
readJSONFileFn: func(secretsFile string) (map[string]interface{}, error) { readLocalFileFn: func(secretsFile string) (map[string]interface{}, error) {
secrets := make(map[string]interface{}) secrets := make(map[string]interface{})
secrets["secret"] = secretValue secrets["secret"] = secretValue
return secrets, nil return secrets, nil