provider_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  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 conjur
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "reflect"
  18. "testing"
  19. "time"
  20. "github.com/cyberark/conjur-api-go/conjurapi"
  21. "github.com/cyberark/conjur-api-go/conjurapi/authn"
  22. "github.com/golang-jwt/jwt/v5"
  23. "github.com/google/go-cmp/cmp"
  24. corev1 "k8s.io/api/core/v1"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  27. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  28. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  29. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  30. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  31. "github.com/external-secrets/external-secrets/pkg/provider/conjur/fake"
  32. utilfake "github.com/external-secrets/external-secrets/pkg/provider/util/fake"
  33. )
  34. var (
  35. svcURL = "https://example.com"
  36. svcUser = "user"
  37. svcApikey = "apikey"
  38. svcAccount = "account1"
  39. jwtAuthenticator = "jwt-authenticator"
  40. jwtAuthnService = "jwt-auth-service"
  41. jwtSecretName = "jwt-secret"
  42. )
  43. func makeValidRef(k string) *esv1beta1.ExternalSecretDataRemoteRef {
  44. return &esv1beta1.ExternalSecretDataRemoteRef{
  45. Key: k,
  46. Version: "default",
  47. }
  48. }
  49. func makeValidFindRef(search string, tags map[string]string) *esv1beta1.ExternalSecretFind {
  50. var name *esv1beta1.FindName
  51. if search != "" {
  52. name = &esv1beta1.FindName{
  53. RegExp: search,
  54. }
  55. }
  56. return &esv1beta1.ExternalSecretFind{
  57. Name: name,
  58. Tags: tags,
  59. }
  60. }
  61. func TestGetSecret(t *testing.T) {
  62. type args struct {
  63. store esv1beta1.GenericStore
  64. kube kclient.Client
  65. corev1 typedcorev1.CoreV1Interface
  66. namespace string
  67. secretPath string
  68. }
  69. type want struct {
  70. err error
  71. value string
  72. }
  73. type testCase struct {
  74. reason string
  75. args args
  76. want want
  77. }
  78. cases := map[string]testCase{
  79. "ApiKeyReadSecretSuccess": {
  80. reason: "Should read a secret successfully using an ApiKey auth secret store.",
  81. args: args{
  82. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  83. kube: clientfake.NewClientBuilder().
  84. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  85. namespace: "default",
  86. secretPath: "path/to/secret",
  87. },
  88. want: want{
  89. err: nil,
  90. value: "secret",
  91. },
  92. },
  93. "ApiKeyReadSecretFailure": {
  94. reason: "Should fail to read secret using ApiKey auth secret store.",
  95. args: args{
  96. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  97. kube: clientfake.NewClientBuilder().
  98. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  99. namespace: "default",
  100. secretPath: "error",
  101. },
  102. want: want{
  103. err: errors.New("error"),
  104. value: "",
  105. },
  106. },
  107. "JwtWithServiceAccountRefReadSecretSuccess": {
  108. reason: "Should read a secret successfully using a JWT auth secret store that references a k8s service account.",
  109. args: args{
  110. store: makeJWTSecretStore(svcURL, svcAccount, "", jwtAuthenticator, "", "myconjuraccount"),
  111. kube: clientfake.NewClientBuilder().
  112. WithObjects().Build(),
  113. namespace: "default",
  114. secretPath: "path/to/secret",
  115. corev1: utilfake.NewCreateTokenMock().WithToken(createFakeJwtToken(true)),
  116. },
  117. want: want{
  118. err: nil,
  119. value: "secret",
  120. },
  121. },
  122. "JwtWithServiceAccountRefWithHostIdReadSecretSuccess": {
  123. reason: "Should read a secret successfully using a JWT auth secret store that references a k8s service account and uses a host ID.",
  124. args: args{
  125. store: makeJWTSecretStore(svcURL, svcAccount, "", jwtAuthenticator, "myhostid", "myconjuraccount"),
  126. kube: clientfake.NewClientBuilder().
  127. WithObjects().Build(),
  128. namespace: "default",
  129. secretPath: "path/to/secret",
  130. corev1: utilfake.NewCreateTokenMock().WithToken(createFakeJwtToken(true)),
  131. },
  132. want: want{
  133. err: nil,
  134. value: "secret",
  135. },
  136. },
  137. "JwtWithSecretRefReadSecretSuccess": {
  138. reason: "Should read a secret successfully using an JWT auth secret store that references a k8s secret.",
  139. args: args{
  140. store: makeJWTSecretStore(svcURL, "", jwtSecretName, jwtAuthenticator, "", "myconjuraccount"),
  141. kube: clientfake.NewClientBuilder().
  142. WithObjects(&corev1.Secret{
  143. ObjectMeta: metav1.ObjectMeta{
  144. Name: jwtSecretName,
  145. Namespace: "default",
  146. },
  147. Data: map[string][]byte{
  148. "token": []byte(createFakeJwtToken(true)),
  149. },
  150. }).Build(),
  151. namespace: "default",
  152. secretPath: "path/to/secret",
  153. },
  154. want: want{
  155. err: nil,
  156. value: "secret",
  157. },
  158. },
  159. "JwtWithCABundleSuccess": {
  160. reason: "Should read a secret successfully using a JWT auth secret store that references a k8s service account.",
  161. args: args{
  162. store: makeJWTSecretStore(svcURL, svcAccount, "", jwtAuthenticator, "", "myconjuraccount"),
  163. kube: clientfake.NewClientBuilder().
  164. WithObjects().Build(),
  165. namespace: "default",
  166. secretPath: "path/to/secret",
  167. corev1: utilfake.NewCreateTokenMock().WithToken(createFakeJwtToken(true)),
  168. },
  169. want: want{
  170. err: nil,
  171. value: "secret",
  172. },
  173. },
  174. }
  175. runTest := func(t *testing.T, _ string, tc testCase) {
  176. provider, _ := newConjurProvider(context.Background(), tc.args.store, tc.args.kube, tc.args.namespace, tc.args.corev1, &ConjurMockAPIClient{})
  177. ref := makeValidRef(tc.args.secretPath)
  178. secret, err := provider.GetSecret(context.Background(), *ref)
  179. if diff := cmp.Diff(tc.want.err, err, EquateErrors()); diff != "" {
  180. t.Errorf("\n%s\nconjur.GetSecret(...): -want error, +got error:\n%s", tc.reason, diff)
  181. }
  182. secretString := string(secret)
  183. if secretString != tc.want.value {
  184. t.Errorf("\n%s\nconjur.GetSecret(...): want value %v got %v", tc.reason, tc.want.value, secretString)
  185. }
  186. }
  187. for name, tc := range cases {
  188. t.Run(name, func(t *testing.T) {
  189. runTest(t, name, tc)
  190. })
  191. }
  192. }
  193. func TestGetAllSecrets(t *testing.T) {
  194. type args struct {
  195. store esv1beta1.GenericStore
  196. kube kclient.Client
  197. corev1 typedcorev1.CoreV1Interface
  198. namespace string
  199. search string
  200. tags map[string]string
  201. }
  202. type want struct {
  203. err error
  204. values map[string][]byte
  205. }
  206. type testCase struct {
  207. reason string
  208. args args
  209. want want
  210. }
  211. cases := map[string]testCase{
  212. "SimpleSearchSingleResultSuccess": {
  213. reason: "Should search for secrets successfully using a simple string.",
  214. args: args{
  215. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  216. kube: clientfake.NewClientBuilder().
  217. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  218. namespace: "default",
  219. search: "secret1",
  220. },
  221. want: want{
  222. err: nil,
  223. values: map[string][]byte{
  224. "secret1": []byte("secret"),
  225. },
  226. },
  227. },
  228. "RegexSearchMultipleResultsSuccess": {
  229. reason: "Should search for secrets successfully using a regex and return multiple results.",
  230. args: args{
  231. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  232. kube: clientfake.NewClientBuilder().
  233. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  234. namespace: "default",
  235. search: "^secret[1,2]$",
  236. },
  237. want: want{
  238. err: nil,
  239. values: map[string][]byte{
  240. "secret1": []byte("secret"),
  241. "secret2": []byte("secret"),
  242. },
  243. },
  244. },
  245. "RegexSearchInvalidRegexFailure": {
  246. reason: "Should fail to search for secrets using an invalid regex.",
  247. args: args{
  248. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  249. kube: clientfake.NewClientBuilder().
  250. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  251. namespace: "default",
  252. search: "^secret[1,2", // Missing `]`
  253. },
  254. want: want{
  255. err: fmt.Errorf("could not compile find.name.regexp [%s]: %w", "^secret[1,2", fmt.Errorf("error parsing regexp: missing closing ]: `[1,2`")),
  256. values: nil,
  257. },
  258. },
  259. "SimpleSearchNoResultsSuccess": {
  260. reason: "Should search for secrets successfully using a simple string and return no results.",
  261. args: args{
  262. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  263. kube: clientfake.NewClientBuilder().
  264. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  265. namespace: "default",
  266. search: "nonexistent",
  267. },
  268. want: want{
  269. err: nil,
  270. values: map[string][]byte{},
  271. },
  272. },
  273. "TagSearchSingleResultSuccess": {
  274. reason: "Should search for secrets successfully using a tag.",
  275. args: args{
  276. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  277. kube: clientfake.NewClientBuilder().
  278. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  279. namespace: "default",
  280. tags: map[string]string{
  281. "conjur/kind": "password",
  282. },
  283. },
  284. want: want{
  285. err: nil,
  286. values: map[string][]byte{
  287. "secret2": []byte("secret"),
  288. },
  289. },
  290. },
  291. }
  292. runTest := func(t *testing.T, _ string, tc testCase) {
  293. provider, _ := newConjurProvider(context.Background(), tc.args.store, tc.args.kube, tc.args.namespace, tc.args.corev1, &ConjurMockAPIClient{})
  294. ref := makeValidFindRef(tc.args.search, tc.args.tags)
  295. secrets, err := provider.GetAllSecrets(context.Background(), *ref)
  296. if diff := cmp.Diff(tc.want.err, err, EquateErrors()); diff != "" {
  297. t.Errorf("\n%s\nconjur.GetAllSecrets(...): -want error, +got error:\n%s", tc.reason, diff)
  298. }
  299. if diff := cmp.Diff(tc.want.values, secrets); diff != "" {
  300. t.Errorf("\n%s\nconjur.GetAllSecrets(...): -want, +got:\n%s", tc.reason, diff)
  301. }
  302. }
  303. for name, tc := range cases {
  304. t.Run(name, func(t *testing.T) {
  305. runTest(t, name, tc)
  306. })
  307. }
  308. }
  309. func TestGetSecretMap(t *testing.T) {
  310. type args struct {
  311. store esv1beta1.GenericStore
  312. kube kclient.Client
  313. corev1 typedcorev1.CoreV1Interface
  314. namespace string
  315. ref *esv1beta1.ExternalSecretDataRemoteRef
  316. }
  317. type want struct {
  318. err error
  319. val map[string][]byte
  320. }
  321. type testCase struct {
  322. reason string
  323. args args
  324. want want
  325. }
  326. cases := map[string]testCase{
  327. "ReadJsonSecret": {
  328. reason: "Should read a JSON key value secret.",
  329. args: args{
  330. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  331. kube: clientfake.NewClientBuilder().
  332. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  333. namespace: "default",
  334. ref: makeValidRef("json_map"),
  335. },
  336. want: want{
  337. err: nil,
  338. val: map[string][]byte{
  339. "key1": []byte("value1"),
  340. "key2": []byte("value2"),
  341. },
  342. },
  343. },
  344. "ReadJsonSecretFailure": {
  345. reason: "Should fail to read a non JSON secret",
  346. args: args{
  347. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  348. kube: clientfake.NewClientBuilder().
  349. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  350. namespace: "default",
  351. ref: makeValidRef("secret1"),
  352. },
  353. want: want{
  354. err: fmt.Errorf("%w", fmt.Errorf("unable to unmarshal secret secret1: invalid character 's' looking for beginning of value")),
  355. val: nil,
  356. },
  357. },
  358. "ReadJsonSecretSpecificKey": {
  359. reason: "Should read a specific key from a JSON secret.",
  360. args: args{
  361. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  362. kube: clientfake.NewClientBuilder().
  363. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  364. namespace: "default",
  365. ref: &esv1beta1.ExternalSecretDataRemoteRef{
  366. Key: "json_nested",
  367. Version: "default",
  368. Property: "key2",
  369. },
  370. },
  371. want: want{
  372. err: nil,
  373. val: map[string][]byte{
  374. "key3": []byte("value3"),
  375. "key4": []byte("value4"),
  376. },
  377. },
  378. },
  379. "ReadJsonSecretSpecificKeyNotFound": {
  380. reason: "Should fail to read a nonexistent key from a JSON secret.",
  381. args: args{
  382. store: makeAPIKeySecretStore(svcURL, "conjur-hostid", "conjur-apikey", "myconjuraccount"),
  383. kube: clientfake.NewClientBuilder().
  384. WithObjects(makeFakeAPIKeySecrets()...).Build(),
  385. namespace: "default",
  386. ref: &esv1beta1.ExternalSecretDataRemoteRef{
  387. Key: "json_map",
  388. Version: "default",
  389. Property: "key3",
  390. },
  391. },
  392. want: want{
  393. err: fmt.Errorf("%w", fmt.Errorf("error getting secret json_map: cannot find secret data for key: \"key3\"")),
  394. val: nil,
  395. },
  396. },
  397. }
  398. runTest := func(t *testing.T, _ string, tc testCase) {
  399. provider, _ := newConjurProvider(context.Background(), tc.args.store, tc.args.kube, tc.args.namespace, tc.args.corev1, &ConjurMockAPIClient{})
  400. val, err := provider.GetSecretMap(context.Background(), *tc.args.ref)
  401. if diff := cmp.Diff(tc.want.err, err, EquateErrors()); diff != "" {
  402. t.Errorf("\n%s\nconjur.GetSecretMap(...): -want error, +got error:\n%s", tc.reason, diff)
  403. }
  404. if diff := cmp.Diff(tc.want.val, val); diff != "" {
  405. t.Errorf("\n%s\nconjur.GetSecretMap(...): -want val, +got val:\n%s", tc.reason, diff)
  406. }
  407. }
  408. for name, tc := range cases {
  409. t.Run(name, func(t *testing.T) {
  410. runTest(t, name, tc)
  411. })
  412. }
  413. }
  414. func TestGetCA(t *testing.T) {
  415. type args struct {
  416. store esv1beta1.GenericStore
  417. kube kclient.Client
  418. corev1 typedcorev1.CoreV1Interface
  419. namespace string
  420. }
  421. type want struct {
  422. err error
  423. cert string
  424. }
  425. type testCase struct {
  426. reason string
  427. args args
  428. want want
  429. }
  430. certData := "mycertdata"
  431. certDataEncoded := "bXljZXJ0ZGF0YQo="
  432. cases := map[string]testCase{
  433. "UseCABundleSuccess": {
  434. reason: "Should read a caBundle successfully.",
  435. args: args{
  436. store: makeStoreWithCA("cabundle", certDataEncoded),
  437. kube: clientfake.NewClientBuilder().
  438. WithObjects().Build(),
  439. namespace: "default",
  440. corev1: utilfake.NewCreateTokenMock().WithToken(createFakeJwtToken(true)),
  441. },
  442. want: want{
  443. err: nil,
  444. cert: certDataEncoded,
  445. },
  446. },
  447. "UseCAProviderConfigMapSuccess": {
  448. reason: "Should read a ca from a ConfigMap successfully.",
  449. args: args{
  450. store: makeStoreWithCA("configmap", ""),
  451. kube: clientfake.NewClientBuilder().
  452. WithObjects(makeFakeCASource("configmap", certData)).Build(),
  453. namespace: "default",
  454. corev1: utilfake.NewCreateTokenMock().WithToken(createFakeJwtToken(true)),
  455. },
  456. want: want{
  457. err: nil,
  458. cert: certDataEncoded,
  459. },
  460. },
  461. "UseCAProviderSecretSuccess": {
  462. reason: "Should read a ca from a Secret successfully.",
  463. args: args{
  464. store: makeStoreWithCA("secret", ""),
  465. kube: clientfake.NewClientBuilder().
  466. WithObjects(makeFakeCASource("secret", certData)).Build(),
  467. namespace: "default",
  468. corev1: utilfake.NewCreateTokenMock().WithToken(createFakeJwtToken(true)),
  469. },
  470. want: want{
  471. err: nil,
  472. cert: certDataEncoded,
  473. },
  474. },
  475. }
  476. runTest := func(t *testing.T, _ string, tc testCase) {
  477. provider, _ := newConjurProvider(context.Background(), tc.args.store, tc.args.kube, tc.args.namespace, tc.args.corev1, &ConjurMockAPIClient{})
  478. _, err := provider.GetSecret(context.Background(), esv1beta1.ExternalSecretDataRemoteRef{
  479. Key: "path/to/secret",
  480. })
  481. if diff := cmp.Diff(tc.want.err, err, EquateErrors()); diff != "" {
  482. t.Errorf("\n%s\nconjur.GetCA(...): -want error, +got error:\n%s", tc.reason, diff)
  483. }
  484. }
  485. for name, tc := range cases {
  486. t.Run(name, func(t *testing.T) {
  487. runTest(t, name, tc)
  488. })
  489. }
  490. }
  491. func makeAPIKeySecretStore(svcURL, svcUser, svcApikey, svcAccount string) *esv1beta1.SecretStore {
  492. uref := &esmeta.SecretKeySelector{
  493. Name: "user",
  494. Key: "conjur-hostid",
  495. }
  496. if svcUser == "" {
  497. uref = nil
  498. }
  499. aref := &esmeta.SecretKeySelector{
  500. Name: "apikey",
  501. Key: "conjur-apikey",
  502. }
  503. if svcApikey == "" {
  504. aref = nil
  505. }
  506. store := &esv1beta1.SecretStore{
  507. Spec: esv1beta1.SecretStoreSpec{
  508. Provider: &esv1beta1.SecretStoreProvider{
  509. Conjur: &esv1beta1.ConjurProvider{
  510. URL: svcURL,
  511. Auth: esv1beta1.ConjurAuth{
  512. APIKey: &esv1beta1.ConjurAPIKey{
  513. Account: svcAccount,
  514. UserRef: uref,
  515. APIKeyRef: aref,
  516. },
  517. },
  518. },
  519. },
  520. },
  521. }
  522. return store
  523. }
  524. func makeJWTSecretStore(svcURL, serviceAccountName, secretName, jwtServiceID, jwtHostID, conjurAccount string) *esv1beta1.SecretStore {
  525. serviceAccountRef := &esmeta.ServiceAccountSelector{
  526. Name: serviceAccountName,
  527. Audiences: []string{"conjur"},
  528. }
  529. if serviceAccountName == "" {
  530. serviceAccountRef = nil
  531. }
  532. secretRef := &esmeta.SecretKeySelector{
  533. Name: secretName,
  534. Key: "token",
  535. }
  536. if secretName == "" {
  537. secretRef = nil
  538. }
  539. store := &esv1beta1.SecretStore{
  540. Spec: esv1beta1.SecretStoreSpec{
  541. Provider: &esv1beta1.SecretStoreProvider{
  542. Conjur: &esv1beta1.ConjurProvider{
  543. URL: svcURL,
  544. Auth: esv1beta1.ConjurAuth{
  545. Jwt: &esv1beta1.ConjurJWT{
  546. Account: conjurAccount,
  547. ServiceID: jwtServiceID,
  548. ServiceAccountRef: serviceAccountRef,
  549. SecretRef: secretRef,
  550. HostID: jwtHostID,
  551. },
  552. },
  553. },
  554. },
  555. },
  556. }
  557. return store
  558. }
  559. func makeStoreWithCA(caSource, caData string) *esv1beta1.SecretStore {
  560. store := makeJWTSecretStore(svcURL, "conjur", "", jwtAuthnService, "", "myconjuraccount")
  561. if caSource == "secret" {
  562. store.Spec.Provider.Conjur.CAProvider = &esv1beta1.CAProvider{
  563. Type: esv1beta1.CAProviderTypeSecret,
  564. Name: "conjur-cert",
  565. Key: "ca",
  566. }
  567. } else if caSource == "configmap" {
  568. store.Spec.Provider.Conjur.CAProvider = &esv1beta1.CAProvider{
  569. Type: esv1beta1.CAProviderTypeConfigMap,
  570. Name: "conjur-cert",
  571. Key: "ca",
  572. }
  573. } else {
  574. store.Spec.Provider.Conjur.CABundle = caData
  575. }
  576. return store
  577. }
  578. func makeNoAuthSecretStore(svcURL string) *esv1beta1.SecretStore {
  579. store := &esv1beta1.SecretStore{
  580. Spec: esv1beta1.SecretStoreSpec{
  581. Provider: &esv1beta1.SecretStoreProvider{
  582. Conjur: &esv1beta1.ConjurProvider{
  583. URL: svcURL,
  584. },
  585. },
  586. },
  587. }
  588. return store
  589. }
  590. func makeFakeAPIKeySecrets() []kclient.Object {
  591. return []kclient.Object{
  592. &corev1.Secret{
  593. ObjectMeta: metav1.ObjectMeta{
  594. Name: "user",
  595. Namespace: "default",
  596. },
  597. Data: map[string][]byte{
  598. "conjur-hostid": []byte("myhostid"),
  599. },
  600. },
  601. &corev1.Secret{
  602. ObjectMeta: metav1.ObjectMeta{
  603. Name: "apikey",
  604. Namespace: "default",
  605. },
  606. Data: map[string][]byte{
  607. "conjur-apikey": []byte("apikey"),
  608. },
  609. },
  610. }
  611. }
  612. func makeFakeCASource(kind, caData string) kclient.Object {
  613. if kind == "secret" {
  614. return &corev1.Secret{
  615. ObjectMeta: metav1.ObjectMeta{
  616. Name: "conjur-cert",
  617. Namespace: "default",
  618. },
  619. Data: map[string][]byte{
  620. "ca": []byte(caData),
  621. },
  622. }
  623. }
  624. return &corev1.ConfigMap{
  625. ObjectMeta: metav1.ObjectMeta{
  626. Name: "conjur-cert",
  627. Namespace: "default",
  628. },
  629. Data: map[string]string{
  630. "ca": caData,
  631. },
  632. }
  633. }
  634. func createFakeJwtToken(expires bool) string {
  635. signingKey := []byte("fakekey")
  636. token := jwt.New(jwt.SigningMethodHS256)
  637. claims := token.Claims.(jwt.MapClaims)
  638. if expires {
  639. claims["exp"] = time.Now().Add(time.Minute * 30).Unix()
  640. }
  641. jwtTokenString, err := token.SignedString(signingKey)
  642. if err != nil {
  643. panic(err)
  644. }
  645. return jwtTokenString
  646. }
  647. // ConjurMockAPIClient is a mock implementation of the ApiClient interface.
  648. type ConjurMockAPIClient struct {
  649. }
  650. func (c *ConjurMockAPIClient) NewClientFromKey(_ conjurapi.Config, _ authn.LoginPair) (SecretsClient, error) {
  651. return &fake.ConjurMockClient{}, nil
  652. }
  653. func (c *ConjurMockAPIClient) NewClientFromJWT(_ conjurapi.Config, _, _, _ string) (SecretsClient, error) {
  654. return &fake.ConjurMockClient{}, nil
  655. }
  656. // EquateErrors returns true if the supplied errors are of the same type and
  657. // produce identical strings. This mirrors the error comparison behavior of
  658. // https://github.com/go-test/deep, which most Crossplane tests targeted before
  659. // we switched to go-cmp.
  660. //
  661. // This differs from cmpopts.EquateErrors, which does not test for error strings
  662. // and instead returns whether one error 'is' (in the errors.Is sense) the
  663. // other.
  664. func EquateErrors() cmp.Option {
  665. return cmp.Comparer(func(a, b error) bool {
  666. if a == nil || b == nil {
  667. return a == nil && b == nil
  668. }
  669. av := reflect.ValueOf(a)
  670. bv := reflect.ValueOf(b)
  671. if av.Type() != bv.Type() {
  672. return false
  673. }
  674. return a.Error() == b.Error()
  675. })
  676. }