From 68ebce7feb5f3586a98bcd69cda9ecd08693fa53 Mon Sep 17 00:00:00 2001 From: Grant Griffiths Date: Tue, 20 Aug 2019 15:59:06 -0700 Subject: [PATCH] Add Vault, KVDB, and Docker auth token_secret support (#1196) Signed-off-by: Grant Griffiths --- api/api.go | 8 + api/server/docker.go | 12 +- api/server/middleware_auth.go | 36 +++-- api/server/server.go | 2 +- api/spec/spec_handler.go | 25 ++-- api/spec/spec_handler_test.go | 43 +++--- pkg/auth/secrets/secrets.go | 105 +++++++------ pkg/auth/secrets/secrets_test.go | 246 +++++++++++++++++++------------ 8 files changed, 293 insertions(+), 184 deletions(-) diff --git a/api/api.go b/api/api.go index ef3cd0a1b..7eba2a77b 100644 --- a/api/api.go +++ b/api/api.go @@ -18,6 +18,7 @@ const ( Name = "name" Token = "token" TokenSecret = "token_secret" + TokenSecretNamespace = "token_secret_namespace" SpecNodes = "nodes" SpecParent = "parent" SpecEphemeral = "ephemeral" @@ -1141,3 +1142,10 @@ func (m *VolumeStateAction) IsMount() bool { func (m *VolumeStateAction) IsUnMount() bool { return m.GetMount() == VolumeActionParam_VOLUME_ACTION_PARAM_OFF } + +// TokenSecretContext contains all nessesary information to get a +// token secret from any provider +type TokenSecretContext struct { + SecretName string + SecretNamespace string +} diff --git a/api/server/docker.go b/api/server/docker.go index 9104455b1..a66098507 100644 --- a/api/server/docker.go +++ b/api/server/docker.go @@ -39,7 +39,7 @@ type driver struct { conn *grpc.ClientConn mu sync.Mutex - secretsStore osecrets.Auth + secretsStore *osecrets.Auth } type handshakeResp struct { @@ -78,7 +78,7 @@ type capabilitiesResponse struct { Capabilities capabilities } -func newVolumePlugin(name, sdkUds string, secretsStore osecrets.Auth) restServer { +func newVolumePlugin(name, sdkUds string, secretsStore *osecrets.Auth) restServer { d := &driver{ restBase: restBase{name: name, version: "0.3"}, SpecHandler: spec.NewSpecHandler(), @@ -263,9 +263,9 @@ func (d *driver) parseTokenInput(name string, opts map[string]string) (string, e } // get token secret - secretPath, ok := d.GetTokenSecretFromString(name) + tokenSecretContext, ok := d.GetTokenSecretContextFromString(name) if ok { - token, err := d.secretTokenFromStore(secretPath) + token, err := d.secretTokenFromStore(tokenSecretContext) if err != nil { return "", err } @@ -292,12 +292,12 @@ func addTokenMetadata(ctx context.Context, token string) context.Context { // secretTokenFromStore pulls the token from the configured secret store for // a given secret name and context. -func (d *driver) secretTokenFromStore(secret string) (string, error) { +func (d *driver) secretTokenFromStore(req *api.TokenSecretContext) (string, error) { if d.secretsStore == nil { return "", fmt.Errorf("A secret was passed in, but no secrets provider has been initialized") } - token, err := d.secretsStore.GetToken(secret, "") + token, err := d.secretsStore.GetToken(req) if err != nil { return "", err } diff --git a/api/server/middleware_auth.go b/api/server/middleware_auth.go index e91592a2d..61991fb2a 100644 --- a/api/server/middleware_auth.go +++ b/api/server/middleware_auth.go @@ -46,7 +46,7 @@ func NewAuthMiddleware( } type authMiddleware struct { - provider secrets.Auth + provider *secrets.Auth } func (a *authMiddleware) createWithAuth(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { @@ -67,14 +67,14 @@ func (a *authMiddleware) createWithAuth(w http.ResponseWriter, r *http.Request, spec := dcReq.GetSpec() locator := dcReq.GetLocator() - secretName, secretContext, err := a.parseSecret(spec.VolumeLabels, locator.VolumeLabels, true) + tokenSecretContext, err := a.parseSecret(spec.VolumeLabels, locator.VolumeLabels, true) if err != nil { a.log(locator.Name, fn).WithError(err).Error("failed to parse secret") dcRes.VolumeResponse = &api.VolumeResponse{Error: "failed to parse secret: " + err.Error()} json.NewEncoder(w).Encode(&dcRes) return } - if secretName == "" { + if tokenSecretContext.SecretName == "" { errorMessage := "Access denied, no secret found in the annotations of the persistent volume claim" + " or storage class parameters" a.log(locator.Name, fn).Error(errorMessage) @@ -84,7 +84,7 @@ func (a *authMiddleware) createWithAuth(w http.ResponseWriter, r *http.Request, return } - token, err := a.provider.GetToken(secretName, secretContext) + token, err := a.provider.GetToken(tokenSecretContext) if err != nil { a.log(locator.Name, fn).WithError(err).Error("failed to get token") dcRes.VolumeResponse = &api.VolumeResponse{Error: "failed to get token: " + err.Error()} @@ -213,14 +213,14 @@ func (a *authMiddleware) deleteWithAuth(w http.ResponseWriter, r *http.Request, } volumeResponse := &api.VolumeResponse{} - secretName, secretContext, err := a.parseSecret(vols[0].Spec.VolumeLabels, vols[0].Locator.VolumeLabels, false) + tokenSecretContext, err := a.parseSecret(vols[0].Spec.VolumeLabels, vols[0].Locator.VolumeLabels, false) if err != nil { a.log(volumeID, fn).WithError(err).Error("failed to parse secret") volumeResponse.Error = "failed to parse secret: " + err.Error() json.NewEncoder(w).Encode(volumeResponse) return } - if secretName == "" { + if tokenSecretContext.SecretName == "" { errorMessage := fmt.Sprintf("Error, unable to get secret information from the volume."+ " You may need to re-add the following keys as volume labels to point to the secret: %s and %s", secrets.SecretNameKey, secrets.SecretNamespaceKey) @@ -231,7 +231,7 @@ func (a *authMiddleware) deleteWithAuth(w http.ResponseWriter, r *http.Request, return } - token, err := a.provider.GetToken(secretName, secretContext) + token, err := a.provider.GetToken(tokenSecretContext) if err != nil { a.log(volumeID, fn).WithError(err).Error("failed to get token") volumeResponse.Error = "failed to get token: " + err.Error() @@ -315,7 +315,7 @@ func (a *authMiddleware) parseParam(r *http.Request, param string) (string, erro func (a *authMiddleware) parseSecret( specLabels, locatorLabels map[string]string, fetchCOLabels bool, -) (string, string, error) { +) (*api.TokenSecretContext, error) { if a.provider.Type() == secrets.TypeK8s && fetchCOLabels { // For k8s fetch the actual annotations pvcName, ok := locatorLabels[PVCNameLabelKey] @@ -331,20 +331,24 @@ func (a *authMiddleware) parseSecret( pvc, err := k8s.Instance().GetPersistentVolumeClaim(pvcName, pvcNamespace) if err != nil { - return "", "", err + return nil, err } secretName := pvc.ObjectMeta.Annotations[secrets.SecretNameKey] - secretNamespace := pvc.ObjectMeta.Annotations[secrets.SecretNamespaceKey] + if len(secretName) == 0 { return parseSecretFromLabels(specLabels, locatorLabels) } + secretNamespace := pvc.ObjectMeta.Annotations[secrets.SecretNamespaceKey] - return secretName, secretNamespace, nil + return &api.TokenSecretContext{ + SecretName: secretName, + SecretNamespace: secretNamespace, + }, nil } return parseSecretFromLabels(specLabels, locatorLabels) } -func parseSecretFromLabels(specLabels, locatorLabels map[string]string) (string, string, error) { +func parseSecretFromLabels(specLabels, locatorLabels map[string]string) (*api.TokenSecretContext, error) { // Locator labels take precendence secretName := locatorLabels[secrets.SecretNameKey] secretNamespace := locatorLabels[secrets.SecretNamespaceKey] @@ -352,12 +356,16 @@ func parseSecretFromLabels(specLabels, locatorLabels map[string]string) (string, secretName = specLabels[secrets.SecretNameKey] } if secretName == "" { - return "", "", fmt.Errorf("secret name is empty") + return nil, fmt.Errorf("secret name is empty") } if secretNamespace == "" { secretNamespace = specLabels[secrets.SecretNamespaceKey] } - return secretName, secretNamespace, nil + + return &api.TokenSecretContext{ + SecretName: secretName, + SecretNamespace: secretNamespace, + }, nil } func (a *authMiddleware) log(id, fn string) *logrus.Entry { diff --git a/api/server/server.go b/api/server/server.go index a3df6863e..bfbbeb692 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -105,7 +105,7 @@ func StartVolumePluginAPI( authProviderType secrets.AuthTokenProviders, authProvider osecrets.Secrets, ) error { - var secretsStore secrets.Auth + var secretsStore *secrets.Auth var err error // Only initialize secrets store if we have a valid auth provider. diff --git a/api/spec/spec_handler.go b/api/spec/spec_handler.go index 03e73386b..9f5b18365 100644 --- a/api/spec/spec_handler.go +++ b/api/spec/spec_handler.go @@ -53,12 +53,12 @@ type SpecHandler interface { // ("", false) GetTokenFromString(str string) (string, bool) - // GetTokenSecretFromString parses the full token secret path from the name. - // If the token was parsed, it returns: - // (tokenSecret, true) - // If the token wasn't parsed, it returns: - // ("", false) - GetTokenSecretFromString(str string) (string, bool) + // GetTokenSecretContextFromString parses the full token secret request from the name. + // If the token secret was parsed, it returns: + // (tokenSecretContext, true) + // If the token secret wasn't parsed, it returns: + // (nil, false) + GetTokenSecretContextFromString(str string) (*api.TokenSecretContext, bool) // SpecFromOpts parses in docker options passed in the the docker run // command of the form --opt name=value @@ -95,6 +95,7 @@ var ( nameRegex = regexp.MustCompile(api.Name + "=([0-9A-Za-z_-]+),?") tokenRegex = regexp.MustCompile(api.Token + "=([A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]+),?") tokenSecretRegex = regexp.MustCompile(api.TokenSecret + `=/*([0-9A-Za-z_/]+),?`) + tokenSecretNamespaceRegex = regexp.MustCompile(api.TokenSecretNamespace + `=/*([0-9A-Za-z_/]+),?`) nodesRegex = regexp.MustCompile(api.SpecNodes + "=([A-Za-z0-9-_;]+),?") parentRegex = regexp.MustCompile(api.SpecParent + "=([A-Za-z]+),?") sizeRegex = regexp.MustCompile(api.SpecSize + "=([0-9A-Za-z]+),?") @@ -393,15 +394,21 @@ func (d *specHandler) GetTokenFromString(str string) (string, bool) { return token, ok } -func (d *specHandler) GetTokenSecretFromString(str string) (string, bool) { +func (d *specHandler) GetTokenSecretContextFromString(str string) (*api.TokenSecretContext, bool) { submatches := tokenSecretRegex.FindStringSubmatch(str) if len(submatches) < 2 { - return "", false + // Must at least have a secret name. All other fields are optional, + // depending on the secrets provider configured. + return nil, false } secret := submatches[1] secret = strings.TrimRight(secret, "/") - return secret, true + _, secretNamespace := d.getVal(tokenSecretNamespaceRegex, str) + return &api.TokenSecretContext{ + SecretName: secret, + SecretNamespace: secretNamespace, + }, true } func (d *specHandler) SpecOptsFromString( diff --git a/api/spec/spec_handler_test.go b/api/spec/spec_handler_test.go index e34440b28..cb95d67fe 100644 --- a/api/spec/spec_handler_test.go +++ b/api/spec/spec_handler_test.go @@ -239,38 +239,47 @@ func TestGetTokenFromString(t *testing.T) { } -func TestGetTokenSecretFromString(t *testing.T) { +func TestGetTokenSecretContextFromString(t *testing.T) { s := NewSpecHandler() tt := []struct { - InputSecret string - ExpectedSecret string - Successful bool + InputName string + ExpectedRequest api.TokenSecretContext + Successful bool }{ { - "/px/secrets/alpha/token1", - "px/secrets/alpha/token1", + "name=abcd,token_secret=/px/secrets/alpha/token1," + + "token_secret_namespace=ns2,abcd=sd,token_secret_public_data=y," + + "token_secret_custom_data=n", + api.TokenSecretContext{ + SecretName: "px/secrets/alpha/token1", + SecretNamespace: "ns2", + }, true, }, { - "abcd/secrets/alpha//token1/", - "abcd/secrets/alpha//token1", + "name=abcd,token_secret=abcd/secrets/alpha//token1/", + api.TokenSecretContext{ + SecretName: "abcd/secrets/alpha//token1", + SecretNamespace: "", + }, true, }, { - "simplekey", - "simplekey", + "name=abcd,token_secret=simplekey", + api.TokenSecretContext{ + SecretName: "simplekey", + SecretNamespace: "", + }, true, }, } for _, tc := range tt { - str := "name=abcd,token_secret=" + tc.InputSecret + ",token=" - secretParsed, ok := s.GetTokenSecretFromString(str) - require.Equal(t, tc.ExpectedSecret, secretParsed) - require.Equal(t, ok, tc.Successful) + secretParsed, ok := s.GetTokenSecretContextFromString(tc.InputName) + require.Equal(t, tc.Successful, ok) + require.Equal(t, tc.ExpectedRequest, *secretParsed) } - secretParsed, ok := s.GetTokenSecretFromString(fmt.Sprintf("toabcbn_secret=abcd")) - require.Equal(t, "", secretParsed) - require.Equal(t, ok, false) + _, ok := s.GetTokenSecretContextFromString(fmt.Sprintf("toabcbn_secret=abcd")) + require.Equal(t, false, ok) } diff --git a/pkg/auth/secrets/secrets.go b/pkg/auth/secrets/secrets.go index 1ccbe1faa..beff65d4e 100644 --- a/pkg/auth/secrets/secrets.go +++ b/pkg/auth/secrets/secrets.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + "github.com/libopenstorage/openstorage/api" osecrets "github.com/libopenstorage/secrets" "github.com/libopenstorage/secrets/k8s" ) @@ -15,7 +16,7 @@ const ( SecretNameKey = "openstorage.io/auth-secret-name" // SecretNamespaceKey is a label on the openstorage.Volume object - // which corresponds to the namespeace of the secret which holds the + // which corresponds to the namespace of the secret which holds the // token information. Used for all secret providers SecretNamespaceKey = "openstorage.io/auth-secret-namespace" @@ -33,12 +34,9 @@ var ( // Auth interface provides helper routines to fetch authorization tokens // from a secrets store -type Auth interface { - // GetToken returns the auth token obtained from the secret with - // secretName with the provided secretContext from the configured secretContext - GetToken(secretName string, secretContext string) (string, error) - // Type returns the type of AuthTokenProvider - Type() AuthTokenProviders +type Auth struct { + ProviderClient osecrets.Secrets + ProviderType AuthTokenProviders } // AuthTokenProviders is an enum indicating the type of secret store that is storing @@ -49,72 +47,89 @@ const ( TypeNone AuthTokenProviders = iota TypeK8s TypeDCOS + TypeVault + TypeKVDB + TypeDocker ) // NewAuth returns a new instance of Auth implementation func NewAuth( - authProviderType AuthTokenProviders, + p AuthTokenProviders, s osecrets.Secrets, -) (Auth, error) { +) (*Auth, error) { if s == nil { return nil, ErrSecretsNotInitialized } - switch authProviderType { + + switch p { case TypeK8s: - return &k8sAuth{s}, nil + return &Auth{s, p}, nil case TypeDCOS: - return &dcosAuth{s}, nil + return &Auth{s, p}, nil + case TypeVault: + return &Auth{s, p}, nil + case TypeKVDB: + return &Auth{s, p}, nil + case TypeDocker: + return &Auth{s, p}, nil } - return nil, fmt.Errorf("secrets type %v not supported", authProviderType) + + return nil, fmt.Errorf("secrets type %v not supported", p) } -// Kubernetes as the auth token secrets provider +// GetToken returns the token for a given secret name and context +// based on the configured auth secrets provider. +func (a *Auth) GetToken(tokenSecretContext *api.TokenSecretContext) (string, error) { + var inputSecretKey string + var outputSecretKey string + secretName := tokenSecretContext.SecretName -type k8sAuth struct { - s osecrets.Secrets -} + // Handle edge cases for different providers. + switch a.ProviderType { + case TypeDCOS: + inputSecretKey = tokenSecretContext.SecretName + namespace := tokenSecretContext.SecretNamespace + if namespace != "" { + inputSecretKey = namespace + "/" + secretName + } + outputSecretKey = inputSecretKey + + case TypeK8s: + inputSecretKey = tokenSecretContext.SecretName + outputSecretKey = SecretTokenKey -func (k *k8sAuth) GetToken(secretName string, secretContext string) (string, error) { - keyContext := make(map[string]string) - keyContext[k8s.SecretNamespace] = secretContext + default: + inputSecretKey = tokenSecretContext.SecretName + outputSecretKey = SecretNameKey + } - secretValue, err := k.s.GetSecret(secretName, keyContext) + // Get secret value with standardized interface + secretValue, err := a.ProviderClient.GetSecret(inputSecretKey, a.requestToContext(tokenSecretContext)) if err != nil { return "", err } - authToken, exists := secretValue[SecretTokenKey] + + // Retrieve auth token + authToken, exists := secretValue[outputSecretKey] if !exists { return "", ErrAuthTokenNotFound } return authToken.(string), nil -} -func (k *k8sAuth) Type() AuthTokenProviders { - return TypeK8s } -// DCOS as the auth token secrets provider - -type dcosAuth struct { - s osecrets.Secrets -} +func (a *Auth) requestToContext(request *api.TokenSecretContext) map[string]string { + context := make(map[string]string) -func (d *dcosAuth) GetToken(secretName string, secretContext string) (string, error) { - key := secretName - if secretContext != "" { - key = secretContext + "/" + secretName - } - secretValue, err := d.s.GetSecret(key, nil) - if err != nil { - return "", err - } - authToken, exists := secretValue[key] - if !exists { - return "", ErrAuthTokenNotFound + // Add namespace for providers that support it. + switch a.ProviderType { + case TypeK8s: + context[k8s.SecretNamespace] = request.SecretNamespace } - return authToken.(string), nil + + return context } -func (d *dcosAuth) Type() AuthTokenProviders { - return TypeDCOS +func (a *Auth) Type() AuthTokenProviders { + return a.ProviderType } diff --git a/pkg/auth/secrets/secrets_test.go b/pkg/auth/secrets/secrets_test.go index 48e37c3b7..f4c1e21ac 100644 --- a/pkg/auth/secrets/secrets_test.go +++ b/pkg/auth/secrets/secrets_test.go @@ -4,116 +4,178 @@ import ( "testing" gomock "github.com/golang/mock/gomock" + "github.com/libopenstorage/openstorage/api" "github.com/libopenstorage/secrets" - "github.com/libopenstorage/secrets/k8s" "github.com/libopenstorage/secrets/mock" "github.com/stretchr/testify/require" ) -func TestNewAuthOnError(t *testing.T) { +func TestNewAuth(t *testing.T) { a, err := NewAuth(TypeK8s, nil) require.EqualError(t, ErrSecretsNotInitialized, err.Error(), "Expected an error on NewAuth") require.Nil(t, a, "Expected auth object to be nil") secretsInstance, _ := getSecretsMock(t) - a, err = NewAuth(5, secretsInstance) + a, err = NewAuth(111, secretsInstance) require.Error(t, err, "Expected an error on NewAuth") require.Nil(t, a, "Expected auth object to be nil") } -func TestK8sGetToken(t *testing.T) { - s, mockSecret := getSecretsMock(t) - a, err := NewAuth(TypeK8s, s) - require.NoError(t, err, "Expected no error on auth") - name := "secret-name" - namespace := "ns" - token := "auth-token" - mockSecret.EXPECT(). - GetSecret( - name, - map[string]string{ - k8s.SecretNamespace: namespace, - }). - Return(map[string]interface{}{SecretTokenKey: token}, nil). - Times(1) - gotToken, err := a.GetToken(name, namespace) - require.NoError(t, err, "Unexpected error on GetToken") - require.Equal(t, gotToken, token, "Unexpected token returned") -} +func TestGetToken(t *testing.T) { + tt := []struct { + testName string -func TestK8sGetTokenWithEmptyTokent(t *testing.T) { - s, mockSecret := getSecretsMock(t) - a, err := NewAuth(TypeK8s, s) - require.NoError(t, err, "Expected no error on auth") - name := "secret-name" - namespace := "ns" - mockSecret.EXPECT(). - GetSecret( - name, - map[string]string{ - k8s.SecretNamespace: namespace, - }). - Return(map[string]interface{}{}, nil). - Times(1) - _, err = a.GetToken(name, namespace) - require.EqualError(t, ErrAuthTokenNotFound, err.Error(), "Unexpected error on GetToken") -} + secretType AuthTokenProviders + secretName string + secretNamespace string + token string + publicData bool + customData bool -func TestDCOSGetToken(t *testing.T) { - s, mockSecret := getSecretsMock(t) - a, err := NewAuth(TypeDCOS, s) - require.NoError(t, err, "Expected no error on auth") - name := "secret-name" - namespace := "ns" - token := "auth-token" - key := namespace + "/" + name - mockSecret.EXPECT(). - GetSecret( - key, - nil, - ). - Return(map[string]interface{}{key: token}, nil). - Times(1) - gotToken, err := a.GetToken(name, namespace) - require.NoError(t, err, "Unexpected error on GetToken") - require.Equal(t, gotToken, token, "Unexpected token returned") -} + expectError bool + expectedError string + expectedToken string + }{ + { + testName: "k8s get token", -func TestDCOSGetTokenWithNoNamespace(t *testing.T) { - s, mockSecret := getSecretsMock(t) - a, err := NewAuth(TypeDCOS, s) - require.NoError(t, err, "Expected no error on auth") - name := "secret-name" - token := "auth-token" - key := name - mockSecret.EXPECT(). - GetSecret( - key, - nil, - ). - Return(map[string]interface{}{key: token}, nil). - Times(1) - gotToken, err := a.GetToken(name, "") - require.NoError(t, err, "Unexpected error on GetToken") - require.Equal(t, gotToken, token, "Unexpected token returned") -} + secretType: TypeK8s, + secretName: "secret-name-k8s", + secretNamespace: "ns", + token: "auth-token", + + expectError: false, + }, + { + testName: "k8s empty token", + + secretType: TypeK8s, + secretName: "secret-name-k8s-empty", + secretNamespace: "ns", + token: "", + + expectError: true, + expectedError: ErrAuthTokenNotFound.Error(), + }, + { + testName: "dcos get token", + + secretType: TypeDCOS, + secretName: "secret-name-dcos", + secretNamespace: "ns", + token: "auth-token", + + expectError: false, + expectedToken: "ns/secret-name-dcos", + }, + { + testName: "dcos empty token", + + secretType: TypeDCOS, + secretName: "secret-name-dcos-empty", + secretNamespace: "ns", + token: "", + + expectError: true, + expectedError: ErrAuthTokenNotFound.Error(), + }, + { + testName: "dcos empty namespace", + + secretType: TypeDCOS, + secretName: "secret-name-dcos-no-ns", + secretNamespace: "", + token: "abcd", + + expectError: false, + }, + { + testName: "vault get token", + + secretType: TypeVault, + secretName: "secret-name-vault", + token: "auth-token", + + expectError: false, + }, + { + testName: "docker get token", + + secretType: TypeDocker, + secretName: "secret-name-docker", + token: "auth-token", + + expectError: false, + }, + { + testName: "kvdb get token", + + secretType: TypeKVDB, + secretName: "secret-name-kvdb", + token: "auth-token", + + expectError: false, + }, + } + + for _, tc := range tt { + secretContext := make(map[string]string) + if tc.secretNamespace != "" { + secretContext[SecretNamespaceKey] = tc.secretNamespace + } + if tc.publicData { + secretContext[secrets.PublicSecretData] = "true" + } + if tc.customData { + secretContext[secrets.CustomSecretData] = "true" + } + s, mockSecret := getSecretsMock(t) + a, err := NewAuth(tc.secretType, s) + require.NoError(t, err, "Expected no error on auth") + expectedTokenResponse := make(map[string]interface{}) + if !tc.expectError { + switch tc.secretType { + case TypeDCOS: + key := tc.secretName + if tc.secretNamespace != "" { + key = tc.secretNamespace + "/" + key + } + expectedTokenResponse[key] = tc.expectedToken + case TypeK8s: + expectedTokenResponse[SecretTokenKey] = tc.expectedToken + default: + expectedTokenResponse[SecretNameKey] = tc.expectedToken + } + } + mockSecret.EXPECT(). + GetSecret( + gomock.Any(), + gomock.Any(), + ). + Return(expectedTokenResponse, nil). + Times(1) -func TestDCOSGetTokenWithEmptyToken(t *testing.T) { - s, mockSecret := getSecretsMock(t) - a, err := NewAuth(TypeDCOS, s) - require.NoError(t, err, "Expected no error on auth") - name := "secret-name" - namespace := "ns" - key := namespace + "/" + name - mockSecret.EXPECT(). - GetSecret( - key, - nil, - ). - Return(map[string]interface{}{}, nil). - Times(1) - _, err = a.GetToken(name, namespace) - require.EqualError(t, ErrAuthTokenNotFound, err.Error(), "Unexpected error on GetToken") + req := &api.TokenSecretContext{ + SecretName: tc.secretName, + SecretNamespace: tc.secretNamespace, + } + gotToken, err := a.GetToken(req) + if tc.expectError { + if err == nil { + t.Errorf("[%s]: Expected error on GetToken, but got nil", tc.testName) + } + if err != nil && err.Error() != tc.expectedError { + t.Errorf("[%s]: Expected error '%s' on GetToken, but got '%s'", tc.testName, err.Error(), tc.expectedError) + } + } else { + if err != nil { + t.Errorf("[%s]: Expected no error on GetToken, but got '%s'", tc.testName, err.Error()) + } + if gotToken != tc.expectedToken { + t.Errorf("[%s]: Expected token '%s' on GetToken, but got '%s'", tc.testName, tc.expectedToken, gotToken) + } + } + } } func getSecretsMock(t *testing.T) (secrets.Secrets, *mock.MockSecrets) {