...

Source file src/edge-infra.dev/pkg/edge/datasync/couchdb/secrets_test.go

Documentation: edge-infra.dev/pkg/edge/datasync/couchdb

     1  package couchdb
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"sigs.k8s.io/controller-runtime/pkg/client"
    10  
    11  	corev1 "k8s.io/api/core/v1"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/apimachinery/pkg/types"
    14  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    15  )
    16  
    17  func TestPBKDF2Gen(t *testing.T) {
    18  	p := []byte("security_first!")
    19  	u := "my_guy"
    20  	hashed, err := pbkdf2Hash(p)
    21  	if err != nil {
    22  		t.Fatal(err)
    23  	}
    24  	if hashed == "" {
    25  		t.Fail()
    26  	}
    27  	ini := string(toAdminIni(u, hashed))
    28  	if ini == "" {
    29  		t.Fail()
    30  	}
    31  }
    32  
    33  func TestFromSecret_MustPrehash(t *testing.T) {
    34  	name := "test-secret"
    35  	namespace := "test-namespace"
    36  	cl := fake.NewClientBuilder().WithObjects(&corev1.Secret{
    37  		ObjectMeta: metav1.ObjectMeta{
    38  			Name:      name,
    39  			Namespace: namespace,
    40  		},
    41  		Data: map[string][]byte{
    42  			SecretUsername:   []byte("edward"),
    43  			SecretPassword:   []byte("p@ssw0rd123"),
    44  			SecretCookieName: SecretCookieData,
    45  		},
    46  	}).Build()
    47  
    48  	c := &AdminCredentials{}
    49  	ctx := context.Background()
    50  	secret, err := c.FromSecret(ctx, cl, types.NamespacedName{
    51  		Name:      name,
    52  		Namespace: namespace,
    53  	})
    54  	assert.NoError(t, err)
    55  	assert.NotNil(t, secret)
    56  
    57  	n := len(c.PrehashedAdmins)
    58  	// 89 is a magic number that varies based on length of username input
    59  	if n != 89 {
    60  		t.Fatalf("prehashed admin creds invalid. len was %d, expected %d", n, 89)
    61  	}
    62  	m := adminRegex.Match(c.PrehashedAdmins)
    63  	if !m {
    64  		t.Fatalf(
    65  			"admins.ini was generated with incorrect format. was: %s, must match: %s",
    66  			c.PrehashedAdmins,
    67  			adminRegexStr,
    68  		)
    69  	}
    70  }
    71  
    72  func TestFromSecret(t *testing.T) {
    73  	name := "test-secret"
    74  	namespace := "test-namespace"
    75  	username := "edward"
    76  	password := "p@ssw0rd123"
    77  	adminsIni := "[admins]\nedward = -pbkdf2-4a4d6fdd0fac2433a9e9b21929b1f906e2cf1642,22387eb3a8e69880,4096\n"
    78  	cl := fake.NewClientBuilder().WithObjects(&corev1.Secret{
    79  		ObjectMeta: metav1.ObjectMeta{
    80  			Name:      name,
    81  			Namespace: namespace,
    82  		},
    83  		Data: map[string][]byte{
    84  			SecretUsername:   []byte(username),
    85  			SecretPassword:   []byte(password),
    86  			SecretAdminsIni:  []byte(adminsIni),
    87  			SecretCookieName: SecretCookieData,
    88  		},
    89  	}).Build()
    90  
    91  	c := &AdminCredentials{}
    92  	ctx := context.Background()
    93  	secret, err := c.FromSecret(ctx, cl, types.NamespacedName{
    94  		Name:      name,
    95  		Namespace: namespace,
    96  	})
    97  	assert.NoError(t, err)
    98  	assert.NotNil(t, secret)
    99  	// all secret data is converted to credential
   100  	if string(c.Username) != username {
   101  		t.Fatalf("incorrect username. expected %s, got %s", username, c.Username)
   102  	}
   103  	if string(c.Password) != password {
   104  		t.Fatalf("incorrect password. expected %s, got %s", password, c.Password)
   105  	}
   106  	if string(c.PrehashedAdmins) != adminsIni {
   107  		t.Fatalf("incorrect admins. expected %s, got %s", adminsIni, c.PrehashedAdmins)
   108  	}
   109  }
   110  
   111  func TestToSecret_MustPrehash(t *testing.T) {
   112  	cl := fake.NewClientBuilder().Build()
   113  	c := &AdminCredentials{
   114  		UsernamePassword: UsernamePassword{
   115  			Username: []byte("david"),
   116  			Password: []byte("p@55w0rd"),
   117  		},
   118  	}
   119  	ctx := context.Background()
   120  	nsn := types.NamespacedName{
   121  		Name:      "test-tosecret",
   122  		Namespace: "test-tosecret-ns",
   123  	}
   124  	s, err := c.ToSecret(ctx, cl, nsn)
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	m := adminRegex.Match(s.Data[SecretAdminsIni])
   129  	if !m {
   130  		t.Fatalf(
   131  			"admins.ini was generated with incorrect format. was: %s, must match: %s",
   132  			s.Data[SecretAdminsIni],
   133  			adminRegexStr,
   134  		)
   135  	}
   136  }
   137  
   138  func TestToSecret(t *testing.T) {
   139  	client := fake.NewClientBuilder().Build()
   140  	username := "edward"
   141  	password := "p@ssw0rd123"
   142  	adminsIni := "[admins]\n-pbkdf2-too-long"
   143  	c := &AdminCredentials{
   144  		UsernamePassword: UsernamePassword{
   145  			Username: []byte(username),
   146  			Password: []byte(password),
   147  		},
   148  		PrehashedAdmins: []byte(adminsIni),
   149  	}
   150  	ctx := context.Background()
   151  	nsn := types.NamespacedName{
   152  		Name:      "test-tosecret",
   153  		Namespace: "test-tosecret-ns",
   154  	}
   155  	s, err := c.ToSecret(ctx, client, nsn)
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  	// all credential data is converted to secret
   160  	if string(s.Data[SecretUsername]) != username {
   161  		t.Fatalf("incorrect username. expected %s, got %s", username, s.Data[SecretUsername])
   162  	}
   163  	if string(s.Data[SecretPassword]) != password {
   164  		t.Fatalf("incorrect password. expected %s, got %s", password, s.Data[SecretPassword])
   165  	}
   166  	if string(s.Data[SecretAdminsIni]) != adminsIni {
   167  		t.Fatalf("incorrect admins. expected %s, got %s", adminsIni, s.Data[SecretAdminsIni])
   168  	}
   169  }
   170  
   171  func TestCredentialsManagerFromSecret(t *testing.T) {
   172  	ctx := context.Background()
   173  	cl := fake.NewClientBuilder().Build()
   174  	hashed, err := pbkdf2Hash(SecretPasswordData)
   175  	assert.NoError(t, err)
   176  	testData := map[CredentialsManager]map[string][]byte{
   177  		&AdminCredentials{
   178  			UsernamePassword: UsernamePassword{
   179  				Username: SecretUsernameData,
   180  				Password: SecretPasswordData,
   181  			},
   182  			PrehashedAdmins:  toAdminIni(string(SecretUsernameData), hashed),
   183  			CookieAuthSecret: SecretCookieData,
   184  		}: {
   185  			SecretUsername:   SecretUsernameData,
   186  			SecretPassword:   SecretPasswordData,
   187  			SecretAdminsIni:  toAdminIni(string(SecretUsernameData), hashed),
   188  			SecretCookieName: SecretCookieData,
   189  		},
   190  		&UserCredentials{
   191  			UsernamePassword: UsernamePassword{
   192  				Username: SecretUsernameData,
   193  				Password: SecretPasswordData,
   194  			},
   195  			URI: SecretURIData,
   196  		}: {
   197  			SecretUsername: SecretUsernameData,
   198  			SecretPassword: SecretPasswordData,
   199  			SecretURI:      SecretURIData,
   200  		},
   201  		&ReplicationCredentials{
   202  			UserCredentials: UserCredentials{
   203  				UsernamePassword: UsernamePassword{
   204  					Username: SecretUsernameData,
   205  					Password: SecretPasswordData,
   206  				},
   207  				URI: SecretURIData,
   208  			},
   209  			DBName: SecretDBNameData,
   210  		}: {
   211  			SecretUsername: SecretUsernameData,
   212  			SecretPassword: SecretPasswordData,
   213  			SecretURI:      SecretURIData,
   214  			SecretDBName:   SecretDBNameData,
   215  		},
   216  	}
   217  
   218  	for cred, secretData := range testData {
   219  		credType := reflect.TypeOf(cred).Elem()
   220  		credName := credType.Name()
   221  		newCred := reflect.New(credType).Interface().(CredentialsManager)
   222  		nsn := types.NamespacedName{
   223  			Name:      credName + string(randStr(10)),
   224  			Namespace: "test",
   225  		}
   226  		secret, err := cred.ToSecret(ctx, cl, nsn)
   227  		assert.NoError(t, err, "ToSecret: error caught for %v", nsn)
   228  		assert.NoError(t, cl.Create(ctx, secret))
   229  
   230  		secret, err = newCred.FromSecret(ctx, cl, nsn)
   231  		assert.NoError(t, err, "FromSecret: error caught for %v", nsn)
   232  		assert.NotNil(t, secret)
   233  		assert.Equal(t, cred, newCred)
   234  
   235  		assertSecretData(ctx, t, cl, nsn, secretData)
   236  	}
   237  }
   238  
   239  func assertSecretData(ctx context.Context, t *testing.T, cl client.Client, nn types.NamespacedName, data map[string][]byte) {
   240  	secret := &corev1.Secret{}
   241  	err := cl.Get(ctx, nn, secret)
   242  	assert.NoError(t, err, "fail to get secret: error caught for %v", nn)
   243  	assert.Equal(t, len(data), len(secret.Data))
   244  	for key, value := range secret.Data {
   245  		assert.Equal(t, string(data[key]), string(value), "error for key: %s, and type %v", key, nn)
   246  	}
   247  }
   248  

View as plain text