|
|
@@ -20,6 +20,7 @@ import (
|
|
|
"context"
|
|
|
"testing"
|
|
|
|
|
|
+ "github.com/gophercloud/gophercloud/v2"
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
@@ -30,14 +31,17 @@ import (
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
- testAuthURL = "https://keystone.example.com/v3"
|
|
|
- testTenantName = "test-tenant"
|
|
|
- testDomainName = "default"
|
|
|
- testRegion = "RegionOne"
|
|
|
- testUsername = "test-user"
|
|
|
- testPassword = "test-password"
|
|
|
- testSecretName = "barbican-creds"
|
|
|
- testNamespace = "default"
|
|
|
+ testAuthURL = "https://keystone.example.com/v3"
|
|
|
+ testTenantName = "test-tenant"
|
|
|
+ testDomainName = "default"
|
|
|
+ testRegion = "RegionOne"
|
|
|
+ testUsername = "test-user"
|
|
|
+ testPassword = "test-password"
|
|
|
+ testSecretName = "barbican-creds"
|
|
|
+ testNamespace = "default"
|
|
|
+ testAppCredID = "app-cred-id-123"
|
|
|
+ testAppCredSecret = "app-cred-secret-456"
|
|
|
+ testAppCredSecName = "barbican-app-creds"
|
|
|
)
|
|
|
|
|
|
type validateStoreTestCase struct {
|
|
|
@@ -65,17 +69,33 @@ func TestValidateStore(t *testing.T) {
|
|
|
errorMsg: "store is nil",
|
|
|
},
|
|
|
{
|
|
|
- name: "valid store should pass validation",
|
|
|
+ name: "valid password store should pass validation",
|
|
|
store: makeValidSecretStore(),
|
|
|
expectError: false,
|
|
|
},
|
|
|
{
|
|
|
- name: "username as value should pass validation",
|
|
|
- store: makeSecretStoreWithValueUsername(),
|
|
|
+ name: "valid password store with explicit authType should pass",
|
|
|
+ store: makeSecretStoreWithExplicitPasswordAuthType(),
|
|
|
expectError: false,
|
|
|
},
|
|
|
{
|
|
|
- name: "nil barbican provider should return error",
|
|
|
+ name: "valid appCredential store should pass validation",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "valid appCredential store with inline ID should pass",
|
|
|
+ store: makeSecretStoreWithAppCredValueID(),
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "nil provider should return error",
|
|
|
+ store: makeSecretStoreWithNilProvider(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "provider barbican is nil",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "nil barbican should return error",
|
|
|
store: makeSecretStoreWithNilBarbican(),
|
|
|
expectError: true,
|
|
|
errorMsg: "provider barbican is nil",
|
|
|
@@ -87,27 +107,52 @@ func TestValidateStore(t *testing.T) {
|
|
|
errorMsg: "authURL is required",
|
|
|
},
|
|
|
{
|
|
|
- name: "username without value or secretRef should return error",
|
|
|
+ name: "password auth missing username should return error",
|
|
|
+ store: makeSecretStorePasswordNoUsername(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "username is required for password auth",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password auth missing password should return error",
|
|
|
+ store: makeSecretStorePasswordNoPassword(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "password secretRef is required",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password auth username present but empty should return error",
|
|
|
store: makeSecretStoreWithEmptyUsername(),
|
|
|
expectError: true,
|
|
|
- errorMsg: "auth.username",
|
|
|
+ errorMsg: "username must specify either value or secretRef",
|
|
|
},
|
|
|
{
|
|
|
- name: "missing password secretRef should return error",
|
|
|
+ name: "password auth password present with nil secretRef should return error",
|
|
|
store: makeSecretStoreWithNoPasswordRef(),
|
|
|
expectError: true,
|
|
|
- errorMsg: "auth.password",
|
|
|
+ errorMsg: "password secretRef is required",
|
|
|
},
|
|
|
{
|
|
|
- name: "cluster store without secretRef namespace should return error",
|
|
|
- store: makeClusterSecretStoreNoNamespace(),
|
|
|
+ name: "appCredential auth missing ID should return error",
|
|
|
+ store: makeSecretStoreAppCredNoID(),
|
|
|
expectError: true,
|
|
|
- errorMsg: "namespace",
|
|
|
+ errorMsg: "applicationCredentialID is required",
|
|
|
},
|
|
|
{
|
|
|
- name: "cluster store with secretRef namespace should pass",
|
|
|
- store: makeClusterSecretStoreWithNamespace(),
|
|
|
- expectError: false,
|
|
|
+ name: "appCredential auth ID with no value or secretRef should return error",
|
|
|
+ store: makeSecretStoreAppCredEmptyID(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialID must specify either value or secretRef",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredential auth missing secret should return error",
|
|
|
+ store: makeSecretStoreAppCredNoSecret(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialSecret secretRef is required",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "unsupported auth type should return error",
|
|
|
+ store: makeSecretStoreWithUnsupportedAuthType(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "unsupported auth type",
|
|
|
},
|
|
|
}
|
|
|
|
|
|
@@ -178,6 +223,7 @@ func TestNewClient(t *testing.T) {
|
|
|
name string
|
|
|
store esv1.GenericStore
|
|
|
kube *clientfake.ClientBuilder
|
|
|
+ namespace string
|
|
|
expectError bool
|
|
|
errorMsg string
|
|
|
}{
|
|
|
@@ -221,23 +267,172 @@ func TestNewClient(t *testing.T) {
|
|
|
expectError: true,
|
|
|
errorMsg: "provider barbican is nil",
|
|
|
},
|
|
|
+ // Backward compatibility: password auth with no authType set (defaults to password)
|
|
|
+ {
|
|
|
+ name: "password auth without explicit authType should pass (backward compat)",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ // Backward compatibility: password auth with explicit authType=password
|
|
|
+ {
|
|
|
+ name: "password auth with explicit authType=password should pass",
|
|
|
+ store: makeSecretStoreWithExplicitPasswordAuthType(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ // Application credential auth type tests
|
|
|
+ {
|
|
|
+ name: "appCredential auth with valid secret should pass",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidAppCredSecret()),
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredential auth with value appCredID should pass",
|
|
|
+ store: makeSecretStoreWithAppCredValueID(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeAppCredSecretWithNoID()),
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredential auth missing appCredID secret should return error",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredential auth missing appCredSecret in secret should return error",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeAppCredSecretWithMissingSecret()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredential auth missing authURL should return error",
|
|
|
+ store: makeSecretStoreWithAppCredMissingAuthURL(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidAppCredSecret()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "unsupported auth type should return error",
|
|
|
+ store: makeSecretStoreWithUnsupportedAuthType(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "unsupported auth type",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "cluster secret store without explicit secretRef namespace should use the ExternalSecret namespace",
|
|
|
+ store: makeClusterSecretStoreNoNamespace(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
|
|
|
+ namespace: testNamespace,
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "cluster secret store with explicit secretRef namespace should use that namespace instead of the ExternalSecret namespace",
|
|
|
+ store: makeClusterSecretStoreWithNamespace(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
|
|
|
+ namespace: "some-other-namespace",
|
|
|
+ expectError: false,
|
|
|
+ },
|
|
|
}
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
+ // Stub the OpenStack auth/client boundary so happy-path cases succeed
|
|
|
+ // deterministically without a real OpenStack endpoint.
|
|
|
+ origAuthClient := authenticatedClient
|
|
|
+ origKeyManager := newKeyManagerV1
|
|
|
+ authenticatedClient = func(_ context.Context, _ gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
|
|
|
+ return &gophercloud.ProviderClient{}, nil
|
|
|
+ }
|
|
|
+ newKeyManagerV1 = func(_ *gophercloud.ProviderClient, _ gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
|
|
+ return &gophercloud.ServiceClient{}, nil
|
|
|
+ }
|
|
|
+ t.Cleanup(func() {
|
|
|
+ authenticatedClient = origAuthClient
|
|
|
+ newKeyManagerV1 = origKeyManager
|
|
|
+ })
|
|
|
+
|
|
|
+ namespace := tc.namespace
|
|
|
+ if namespace == "" {
|
|
|
+ namespace = testNamespace
|
|
|
+ }
|
|
|
+
|
|
|
provider := &Provider{}
|
|
|
fakeClient := tc.kube.Build()
|
|
|
-
|
|
|
- // Note: This test will fail when trying to actually connect to OpenStack
|
|
|
- // In a real test environment, we would need to mock the OpenStack client
|
|
|
- _, err := provider.NewClient(context.Background(), tc.store, fakeClient, testNamespace)
|
|
|
+ _, err := provider.NewClient(context.Background(), tc.store, fakeClient, namespace)
|
|
|
|
|
|
if tc.expectError {
|
|
|
assert.Error(t, err)
|
|
|
assert.Contains(t, err.Error(), tc.errorMsg)
|
|
|
} else {
|
|
|
- // This would only pass with proper OpenStack mocking
|
|
|
- assert.Error(t, err) // We expect an error due to missing OpenStack mock
|
|
|
+ assert.NoError(t, err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestNewClientAuthTypeDefaultsToPassword(t *testing.T) {
|
|
|
+ // Verify that when AuthType is nil, the provider defaults to password auth
|
|
|
+ // and resolves username/password credentials correctly.
|
|
|
+ store := makeValidSecretStore()
|
|
|
+ assert.Nil(t, store.Spec.Provider.Barbican.Auth.AuthType, "AuthType should be nil for backward compatibility test")
|
|
|
+
|
|
|
+ // Stub the OpenStack boundary so the call succeeds deterministically.
|
|
|
+ origAuthClient := authenticatedClient
|
|
|
+ origKeyManager := newKeyManagerV1
|
|
|
+ authenticatedClient = func(_ context.Context, _ gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
|
|
|
+ return &gophercloud.ProviderClient{}, nil
|
|
|
+ }
|
|
|
+ newKeyManagerV1 = func(_ *gophercloud.ProviderClient, _ gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
|
|
+ return &gophercloud.ServiceClient{}, nil
|
|
|
+ }
|
|
|
+ t.Cleanup(func() {
|
|
|
+ authenticatedClient = origAuthClient
|
|
|
+ newKeyManagerV1 = origKeyManager
|
|
|
+ })
|
|
|
+
|
|
|
+ fakeClient := clientfake.NewClientBuilder().WithObjects(makeValidSecret()).Build()
|
|
|
+ provider := &Provider{}
|
|
|
+ _, err := provider.NewClient(context.Background(), store, fakeClient, testNamespace)
|
|
|
+ assert.NoError(t, err)
|
|
|
+}
|
|
|
+
|
|
|
+func TestGetProviderWithAuthType(t *testing.T) {
|
|
|
+ testCases := []struct {
|
|
|
+ name string
|
|
|
+ store esv1.GenericStore
|
|
|
+ expectedAuthType *esv1.BarbicanAuthType
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "password store with no authType set (backward compat)",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ expectedAuthType: nil,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password store with explicit authType",
|
|
|
+ store: makeSecretStoreWithExplicitPasswordAuthType(),
|
|
|
+ expectedAuthType: barbicanAuthTypePtr(esv1.BarbicanAuthTypePassword),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredential store with authType",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ expectedAuthType: barbicanAuthTypePtr(esv1.BarbicanAuthTypeApplicationCredential),
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tc := range testCases {
|
|
|
+ t.Run(tc.name, func(t *testing.T) {
|
|
|
+ provider, err := getProvider(tc.store)
|
|
|
+
|
|
|
+ assert.NoError(t, err)
|
|
|
+ assert.NotNil(t, provider)
|
|
|
+ if tc.expectedAuthType == nil {
|
|
|
+ assert.Nil(t, provider.Auth.AuthType)
|
|
|
+ } else {
|
|
|
+ assert.Equal(t, *tc.expectedAuthType, *provider.Auth.AuthType)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
@@ -259,13 +454,13 @@ func makeValidSecretStore() *esv1.SecretStore {
|
|
|
DomainName: testDomainName,
|
|
|
Region: testRegion,
|
|
|
Auth: esv1.BarbicanAuth{
|
|
|
- Username: esv1.BarbicanProviderUsernameRef{
|
|
|
+ Username: &esv1.BarbicanProviderUsernameRef{
|
|
|
SecretRef: &esmeta.SecretKeySelector{
|
|
|
Name: testSecretName,
|
|
|
Key: "username",
|
|
|
},
|
|
|
},
|
|
|
- Password: esv1.BarbicanProviderPasswordRef{
|
|
|
+ Password: &esv1.BarbicanProviderPasswordRef{
|
|
|
SecretRef: &esmeta.SecretKeySelector{
|
|
|
Name: testSecretName,
|
|
|
Key: "password",
|
|
|
@@ -280,7 +475,7 @@ func makeValidSecretStore() *esv1.SecretStore {
|
|
|
|
|
|
func makeSecretStoreWithValueUsername() *esv1.SecretStore {
|
|
|
store := makeValidSecretStore()
|
|
|
- store.Spec.Provider.Barbican.Auth.Username = esv1.BarbicanProviderUsernameRef{
|
|
|
+ store.Spec.Provider.Barbican.Auth.Username = &esv1.BarbicanProviderUsernameRef{
|
|
|
Value: testUsername,
|
|
|
}
|
|
|
return store
|
|
|
@@ -306,13 +501,13 @@ func makeSecretStoreWithMissingAuthURL() *esv1.SecretStore {
|
|
|
|
|
|
func makeSecretStoreWithEmptyUsername() *esv1.SecretStore {
|
|
|
store := makeValidSecretStore()
|
|
|
- store.Spec.Provider.Barbican.Auth.Username = esv1.BarbicanProviderUsernameRef{}
|
|
|
+ store.Spec.Provider.Barbican.Auth.Username = &esv1.BarbicanProviderUsernameRef{}
|
|
|
return store
|
|
|
}
|
|
|
|
|
|
func makeSecretStoreWithNoPasswordRef() *esv1.SecretStore {
|
|
|
store := makeValidSecretStore()
|
|
|
- store.Spec.Provider.Barbican.Auth.Password = esv1.BarbicanProviderPasswordRef{}
|
|
|
+ store.Spec.Provider.Barbican.Auth.Password = &esv1.BarbicanProviderPasswordRef{}
|
|
|
return store
|
|
|
}
|
|
|
|
|
|
@@ -369,3 +564,365 @@ func makeSecretWithMissingPassword() *corev1.Secret {
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// Helper: returns a pointer to a BarbicanAuthType.
|
|
|
+func barbicanAuthTypePtr(t esv1.BarbicanAuthType) *esv1.BarbicanAuthType {
|
|
|
+ return new(t)
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: password auth store with explicit authType=password.
|
|
|
+func makeSecretStoreWithExplicitPasswordAuthType() *esv1.SecretStore {
|
|
|
+ store := makeValidSecretStore()
|
|
|
+ store.Spec.Provider.Barbican.Auth.AuthType = barbicanAuthTypePtr(esv1.BarbicanAuthTypePassword)
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: application credential auth store.
|
|
|
+func makeSecretStoreWithAppCredAuth() *esv1.SecretStore {
|
|
|
+ return &esv1.SecretStore{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: "test-store-appcred",
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Spec: esv1.SecretStoreSpec{
|
|
|
+ Provider: &esv1.SecretStoreProvider{
|
|
|
+ Barbican: &esv1.BarbicanProvider{
|
|
|
+ AuthURL: testAuthURL,
|
|
|
+ TenantName: testTenantName,
|
|
|
+ DomainName: testDomainName,
|
|
|
+ Region: testRegion,
|
|
|
+ Auth: esv1.BarbicanAuth{
|
|
|
+ AuthType: barbicanAuthTypePtr(esv1.BarbicanAuthTypeApplicationCredential),
|
|
|
+ ApplicationCredentialID: &esv1.BarbicanProviderAppCredIDRef{
|
|
|
+ SecretRef: &esmeta.SecretKeySelector{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Key: "app-cred-id",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ApplicationCredentialSecret: &esv1.BarbicanProviderAppCredSecretRef{
|
|
|
+ SecretRef: &esmeta.SecretKeySelector{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Key: "app-cred-secret",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: application credential auth store with inline value for appCredID.
|
|
|
+func makeSecretStoreWithAppCredValueID() *esv1.SecretStore {
|
|
|
+ store := makeSecretStoreWithAppCredAuth()
|
|
|
+ store.Spec.Provider.Barbican.Auth.ApplicationCredentialID = &esv1.BarbicanProviderAppCredIDRef{
|
|
|
+ Value: testAppCredID,
|
|
|
+ }
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: application credential auth store missing authURL.
|
|
|
+func makeSecretStoreWithAppCredMissingAuthURL() *esv1.SecretStore {
|
|
|
+ store := makeSecretStoreWithAppCredAuth()
|
|
|
+ store.Spec.Provider.Barbican.AuthURL = ""
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: unsupported auth type store.
|
|
|
+func makeSecretStoreWithUnsupportedAuthType() *esv1.SecretStore {
|
|
|
+ store := makeValidSecretStore()
|
|
|
+ unsupported := esv1.BarbicanAuthType("kerberos")
|
|
|
+ store.Spec.Provider.Barbican.Auth.AuthType = &unsupported
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: valid k8s secret for application credentials.
|
|
|
+func makeValidAppCredSecret() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "app-cred-id": []byte(testAppCredID),
|
|
|
+ "app-cred-secret": []byte(testAppCredSecret),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: k8s secret with only the app credential secret (no ID).
|
|
|
+func makeAppCredSecretWithNoID() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "app-cred-secret": []byte(testAppCredSecret),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: k8s secret with empty username value.
|
|
|
+func makeSecretWithEmptyUsername() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testSecretName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "username": []byte(""),
|
|
|
+ "password": []byte(testPassword),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: k8s secret with empty password value.
|
|
|
+func makeSecretWithEmptyPassword() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testSecretName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "username": []byte(testUsername),
|
|
|
+ "password": []byte(""),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: k8s secret with empty app-cred-id value.
|
|
|
+func makeAppCredSecretWithEmptyID() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "app-cred-id": []byte(""),
|
|
|
+ "app-cred-secret": []byte(testAppCredSecret),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: k8s secret with empty app-cred-secret value.
|
|
|
+func makeAppCredSecretWithEmptySecret() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "app-cred-id": []byte(testAppCredID),
|
|
|
+ "app-cred-secret": []byte(""),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: k8s secret with app credential ID but missing app credential secret.
|
|
|
+func makeAppCredSecretWithMissingSecret() *corev1.Secret {
|
|
|
+ return &corev1.Secret{
|
|
|
+ ObjectMeta: metav1.ObjectMeta{
|
|
|
+ Name: testAppCredSecName,
|
|
|
+ Namespace: testNamespace,
|
|
|
+ },
|
|
|
+ Data: map[string][]byte{
|
|
|
+ "app-cred-id": []byte(testAppCredID),
|
|
|
+ // missing app-cred-secret key
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestBuildPasswordAuthOpts(t *testing.T) {
|
|
|
+ ctx := context.Background()
|
|
|
+
|
|
|
+ testCases := []struct {
|
|
|
+ name string
|
|
|
+ store *esv1.SecretStore
|
|
|
+ kube *clientfake.ClientBuilder
|
|
|
+ expectError bool
|
|
|
+ errorMsg string
|
|
|
+ wantUser string
|
|
|
+ wantPass string
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "resolve username and password from secret",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
|
|
|
+ expectError: false,
|
|
|
+ wantUser: testUsername,
|
|
|
+ wantPass: testPassword,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "missing username secret returns error",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ kube: clientfake.NewClientBuilder(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "missing password key in secret returns error",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeSecretWithMissingPassword()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "empty username in secret returns error",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeSecretWithEmptyUsername()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "username secret value is empty",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "empty password in secret returns error",
|
|
|
+ store: makeValidSecretStore(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeSecretWithEmptyPassword()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "password secret value is empty",
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tc := range testCases {
|
|
|
+ t.Run(tc.name, func(t *testing.T) {
|
|
|
+ prov := tc.store.Spec.Provider.Barbican
|
|
|
+ opts, err := buildPasswordAuthOpts(ctx, tc.store, tc.kube.Build(), testNamespace, prov)
|
|
|
+
|
|
|
+ if tc.expectError {
|
|
|
+ assert.Error(t, err)
|
|
|
+ assert.Contains(t, err.Error(), tc.errorMsg)
|
|
|
+ } else {
|
|
|
+ assert.NoError(t, err)
|
|
|
+ assert.Equal(t, tc.wantUser, opts.Username)
|
|
|
+ assert.Equal(t, tc.wantPass, opts.Password)
|
|
|
+ assert.Equal(t, testAuthURL, opts.IdentityEndpoint)
|
|
|
+ assert.Equal(t, testTenantName, opts.TenantName)
|
|
|
+ assert.Equal(t, testDomainName, opts.DomainName)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestBuildAppCredAuthOpts(t *testing.T) {
|
|
|
+ ctx := context.Background()
|
|
|
+
|
|
|
+ testCases := []struct {
|
|
|
+ name string
|
|
|
+ store *esv1.SecretStore
|
|
|
+ kube *clientfake.ClientBuilder
|
|
|
+ expectError bool
|
|
|
+ errorMsg string
|
|
|
+ wantCredID string
|
|
|
+ wantCredSec string
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "resolve appCredID and appCredSecret from secret",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeValidAppCredSecret()),
|
|
|
+ expectError: false,
|
|
|
+ wantCredID: testAppCredID,
|
|
|
+ wantCredSec: testAppCredSecret,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "nil applicationCredentialID returns error",
|
|
|
+ store: makeSecretStoreAppCredNoID(),
|
|
|
+ kube: clientfake.NewClientBuilder(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialID is required for applicationCredential auth",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "nil applicationCredentialSecret returns error",
|
|
|
+ store: makeSecretStoreAppCredNoSecret(),
|
|
|
+ kube: clientfake.NewClientBuilder(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialSecret secretRef is required for applicationCredential auth",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "appCredID with no value and no secretRef returns error",
|
|
|
+ store: makeSecretStoreAppCredEmptyID(),
|
|
|
+ kube: clientfake.NewClientBuilder(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialID must specify either value or secretRef",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "missing appCredID secret object returns error",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder(),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "missing appCredSecret key in secret returns error",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeAppCredSecretWithMissingSecret()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "missing required field",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "empty appCredID in secret returns error",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeAppCredSecretWithEmptyID()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialID secret value is empty",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "empty appCredSecret in secret returns error",
|
|
|
+ store: makeSecretStoreWithAppCredAuth(),
|
|
|
+ kube: clientfake.NewClientBuilder().WithObjects(makeAppCredSecretWithEmptySecret()),
|
|
|
+ expectError: true,
|
|
|
+ errorMsg: "applicationCredentialSecret secret value is empty",
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tc := range testCases {
|
|
|
+ t.Run(tc.name, func(t *testing.T) {
|
|
|
+ prov := tc.store.Spec.Provider.Barbican
|
|
|
+ opts, err := buildAppCredAuthOpts(ctx, tc.store, tc.kube.Build(), testNamespace, prov)
|
|
|
+
|
|
|
+ if tc.expectError {
|
|
|
+ assert.Error(t, err)
|
|
|
+ assert.Contains(t, err.Error(), tc.errorMsg)
|
|
|
+ } else {
|
|
|
+ assert.NoError(t, err)
|
|
|
+ assert.Equal(t, tc.wantCredID, opts.ApplicationCredentialID)
|
|
|
+ assert.Equal(t, tc.wantCredSec, opts.ApplicationCredentialSecret)
|
|
|
+ assert.Equal(t, testAuthURL, opts.IdentityEndpoint)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: password auth store with no username (empty value, nil secretRef).
|
|
|
+func makeSecretStorePasswordNoUsername() *esv1.SecretStore {
|
|
|
+ store := makeValidSecretStore()
|
|
|
+ store.Spec.Provider.Barbican.Auth.Username = nil
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: password auth store with no password secretRef.
|
|
|
+func makeSecretStorePasswordNoPassword() *esv1.SecretStore {
|
|
|
+ store := makeValidSecretStore()
|
|
|
+ store.Spec.Provider.Barbican.Auth.Password = nil
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: appCredential auth with nil ApplicationCredentialID.
|
|
|
+func makeSecretStoreAppCredNoID() *esv1.SecretStore {
|
|
|
+ store := makeSecretStoreWithAppCredAuth()
|
|
|
+ store.Spec.Provider.Barbican.Auth.ApplicationCredentialID = nil
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: appCredential auth with ApplicationCredentialID present but empty (no value, no secretRef).
|
|
|
+func makeSecretStoreAppCredEmptyID() *esv1.SecretStore {
|
|
|
+ store := makeSecretStoreWithAppCredAuth()
|
|
|
+ store.Spec.Provider.Barbican.Auth.ApplicationCredentialID = &esv1.BarbicanProviderAppCredIDRef{}
|
|
|
+ return store
|
|
|
+}
|
|
|
+
|
|
|
+// Helper: appCredential auth with nil ApplicationCredentialSecret.
|
|
|
+func makeSecretStoreAppCredNoSecret() *esv1.SecretStore {
|
|
|
+ store := makeSecretStoreWithAppCredAuth()
|
|
|
+ store.Spec.Provider.Barbican.Auth.ApplicationCredentialSecret = nil
|
|
|
+ return store
|
|
|
+}
|