passbolt_test.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package passbolt
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "strings"
  18. "testing"
  19. "github.com/google/go-cmp/cmp"
  20. g "github.com/onsi/gomega"
  21. "github.com/passbolt/go-passbolt/api"
  22. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  23. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  24. )
  25. type PassboltClientMock struct {
  26. }
  27. func (p *PassboltClientMock) CheckSession(_ context.Context) bool {
  28. return true
  29. }
  30. func (p *PassboltClientMock) Login(_ context.Context) error {
  31. return nil
  32. }
  33. func (p *PassboltClientMock) Logout(_ context.Context) error {
  34. return nil
  35. }
  36. func (p *PassboltClientMock) GetResource(_ context.Context, resourceID string) (*api.Resource, error) {
  37. resmap := map[string]api.Resource{
  38. "some-key1": {ID: "some-key1", Name: "some-name1", URI: "some-uri1"},
  39. "some-key2": {ID: "some-key2", Name: "some-name2", URI: "some-uri2"},
  40. }
  41. if res, ok := resmap[resourceID]; ok {
  42. return &res, nil
  43. }
  44. return nil, errors.New("ID not found")
  45. }
  46. func (p *PassboltClientMock) GetResources(_ context.Context, _ *api.GetResourcesOptions) ([]api.Resource, error) {
  47. res := []api.Resource{
  48. {ID: "some-key1", Name: "some-name1", URI: "some-uri1"},
  49. {ID: "some-key2", Name: "some-name2", URI: "some-uri2"},
  50. }
  51. return res, nil
  52. }
  53. func (p *PassboltClientMock) GetResourceType(_ context.Context, _ string) (*api.ResourceType, error) {
  54. res := &api.ResourceType{Slug: "password-and-description"}
  55. return res, nil
  56. }
  57. func (p *PassboltClientMock) DecryptMessage(message string) (string, error) {
  58. return message, nil
  59. }
  60. func (p *PassboltClientMock) GetSecret(_ context.Context, resourceID string) (*api.Secret, error) {
  61. resmap := map[string]api.Secret{
  62. "some-key1": {Data: `{"password": "some-password1", "description": "some-description1"}`},
  63. "some-key2": {Data: `{"password": "some-password2", "description": "some-description2"}`},
  64. }
  65. if res, ok := resmap[resourceID]; ok {
  66. return &res, nil
  67. }
  68. return nil, errors.New("ID not found")
  69. }
  70. var clientMock = &PassboltClientMock{}
  71. func TestValidateStore(t *testing.T) {
  72. p := &ProviderPassbolt{client: clientMock}
  73. g.RegisterTestingT(t)
  74. store := &esv1beta1.SecretStore{
  75. Spec: esv1beta1.SecretStoreSpec{
  76. Provider: &esv1beta1.SecretStoreProvider{
  77. Passbolt: &esv1beta1.PassboltProvider{},
  78. },
  79. },
  80. }
  81. // missing auth
  82. _, err := p.ValidateStore(store)
  83. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errPassboltStoreMissingAuth)))
  84. // missing password
  85. store.Spec.Provider.Passbolt.Auth = &esv1beta1.PassboltAuth{
  86. PrivateKeySecretRef: &esmeta.SecretKeySelector{Key: "some-secret", Name: "privatekey"},
  87. }
  88. _, err = p.ValidateStore(store)
  89. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errPassboltStoreMissingAuthPassword)))
  90. // missing privateKey
  91. store.Spec.Provider.Passbolt.Auth = &esv1beta1.PassboltAuth{
  92. PasswordSecretRef: &esmeta.SecretKeySelector{Key: "some-secret", Name: "password"},
  93. }
  94. _, err = p.ValidateStore(store)
  95. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errPassboltStoreMissingAuthPrivateKey)))
  96. store.Spec.Provider.Passbolt.Auth = &esv1beta1.PassboltAuth{
  97. PasswordSecretRef: &esmeta.SecretKeySelector{Key: "some-secret", Name: "password"},
  98. PrivateKeySecretRef: &esmeta.SecretKeySelector{Key: "some-secret", Name: "privatekey"},
  99. }
  100. // missing host
  101. _, err = p.ValidateStore(store)
  102. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errPassboltStoreMissingHost)))
  103. // not https
  104. store.Spec.Provider.Passbolt.Host = "http://passbolt.test"
  105. _, err = p.ValidateStore(store)
  106. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errPassboltStoreHostSchemeNotHTTPS)))
  107. // spec ok
  108. store.Spec.Provider.Passbolt.Host = "https://passbolt.test"
  109. _, err = p.ValidateStore(store)
  110. g.Expect(err).To(g.BeNil())
  111. }
  112. func TestClose(t *testing.T) {
  113. p := &ProviderPassbolt{client: clientMock}
  114. g.RegisterTestingT(t)
  115. err := p.Close(context.TODO())
  116. g.Expect(err).To(g.BeNil())
  117. }
  118. func TestGetAllSecrets(t *testing.T) {
  119. cases := []struct {
  120. desc string
  121. ref esv1beta1.ExternalSecretFind
  122. expected map[string][]byte
  123. expectedErr string
  124. }{
  125. {
  126. desc: "no matches",
  127. ref: esv1beta1.ExternalSecretFind{
  128. Name: &esv1beta1.FindName{
  129. RegExp: "nonexistant",
  130. },
  131. },
  132. expected: map[string][]byte{},
  133. },
  134. {
  135. desc: "matches",
  136. ref: esv1beta1.ExternalSecretFind{
  137. Name: &esv1beta1.FindName{
  138. RegExp: "some-name.*",
  139. },
  140. },
  141. expected: map[string][]byte{
  142. "some-key1": []byte(`{"name":"some-name1","username":"","password":"some-password1","uri":"some-uri1","description":"some-description1"}`),
  143. "some-key2": []byte(`{"name":"some-name2","username":"","password":"some-password2","uri":"some-uri2","description":"some-description2"}`),
  144. },
  145. },
  146. {
  147. desc: "missing find.name",
  148. ref: esv1beta1.ExternalSecretFind{},
  149. expectedErr: errPassboltExternalSecretMissingFindNameRegExp,
  150. },
  151. {
  152. desc: "empty find.name.regexp",
  153. ref: esv1beta1.ExternalSecretFind{
  154. Name: &esv1beta1.FindName{
  155. RegExp: "",
  156. },
  157. },
  158. expectedErr: errPassboltExternalSecretMissingFindNameRegExp,
  159. },
  160. }
  161. for _, tc := range cases {
  162. t.Run(tc.desc, func(t *testing.T) {
  163. ctx := context.Background()
  164. p := ProviderPassbolt{client: clientMock}
  165. got, err := p.GetAllSecrets(ctx, tc.ref)
  166. if err != nil {
  167. if tc.expectedErr == "" {
  168. t.Fatalf("failed to call GetAllSecrets: %v", err)
  169. }
  170. if !strings.Contains(err.Error(), tc.expectedErr) {
  171. t.Fatalf("%q expected to contain substring %q", err.Error(), tc.expectedErr)
  172. }
  173. return
  174. }
  175. if tc.expectedErr != "" {
  176. t.Fatal("expected to receive an error but got nil")
  177. }
  178. if diff := cmp.Diff(tc.expected, got); diff != "" {
  179. t.Fatalf("(-got, +want)\n%s", diff)
  180. }
  181. })
  182. }
  183. }
  184. func TestGetSecret(t *testing.T) {
  185. g.RegisterTestingT(t)
  186. tbl := []struct {
  187. name string
  188. request esv1beta1.ExternalSecretDataRemoteRef
  189. expValue string
  190. expErr string
  191. }{
  192. {
  193. name: "return err when not found",
  194. request: esv1beta1.ExternalSecretDataRemoteRef{
  195. Key: "nonexistent",
  196. },
  197. expErr: "ID not found",
  198. },
  199. {
  200. name: "get property from secret",
  201. request: esv1beta1.ExternalSecretDataRemoteRef{
  202. Key: "some-key1",
  203. Property: "password",
  204. },
  205. expValue: "some-password1",
  206. },
  207. {
  208. name: "get full secret",
  209. request: esv1beta1.ExternalSecretDataRemoteRef{
  210. Key: "some-key1",
  211. },
  212. expValue: `{"name":"some-name1","username":"","password":"some-password1","uri":"some-uri1","description":"some-description1"}`,
  213. },
  214. {
  215. name: "return err when using invalid property",
  216. request: esv1beta1.ExternalSecretDataRemoteRef{
  217. Key: "some-key1",
  218. Property: "invalid",
  219. },
  220. expErr: errPassboltSecretPropertyInvalid,
  221. },
  222. }
  223. for _, row := range tbl {
  224. t.Run(row.name, func(_ *testing.T) {
  225. p := &ProviderPassbolt{client: clientMock}
  226. out, err := p.GetSecret(context.Background(), row.request)
  227. if row.expErr != "" {
  228. g.Expect(err).To(g.MatchError(row.expErr))
  229. } else {
  230. g.Expect(err).ToNot(g.HaveOccurred())
  231. }
  232. g.Expect(string(out)).To(g.Equal(row.expValue))
  233. })
  234. }
  235. }
  236. func TestSecretExists(t *testing.T) {
  237. p := &ProviderPassbolt{client: clientMock}
  238. g.RegisterTestingT(t)
  239. _, err := p.SecretExists(context.TODO(), nil)
  240. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errNotImplemented)))
  241. }
  242. func TestPushSecret(t *testing.T) {
  243. p := &ProviderPassbolt{client: clientMock}
  244. g.RegisterTestingT(t)
  245. err := p.PushSecret(context.TODO(), nil, nil)
  246. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errNotImplemented)))
  247. }
  248. func TestDeleteSecret(t *testing.T) {
  249. p := &ProviderPassbolt{client: clientMock}
  250. g.RegisterTestingT(t)
  251. err := p.DeleteSecret(context.TODO(), nil)
  252. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errNotImplemented)))
  253. }
  254. func TestGetSecretMap(t *testing.T) {
  255. p := &ProviderPassbolt{client: clientMock}
  256. g.RegisterTestingT(t)
  257. _, err := p.GetSecretMap(context.TODO(), esv1beta1.ExternalSecretDataRemoteRef{})
  258. g.Expect(err).To(g.BeEquivalentTo(fmt.Errorf(errNotImplemented)))
  259. }