conjur-api 5.3.8.pre.319 → 5.3.8.pre.321

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +10 -0
  3. data/.dockerignore +1 -0
  4. data/.github/CODEOWNERS +10 -0
  5. data/.gitignore +32 -0
  6. data/.gitleaks.toml +219 -0
  7. data/.overcommit.yml +16 -0
  8. data/.project +18 -0
  9. data/.rubocop.yml +3 -0
  10. data/.rubocop_settings.yml +86 -0
  11. data/.rubocop_todo.yml +709 -0
  12. data/.yardopts +1 -0
  13. data/CHANGELOG.md +448 -0
  14. data/CONTRIBUTING.md +138 -0
  15. data/Dockerfile +16 -0
  16. data/Gemfile +7 -0
  17. data/Jenkinsfile +136 -0
  18. data/LICENSE +202 -0
  19. data/README.md +162 -0
  20. data/Rakefile +47 -0
  21. data/SECURITY.md +42 -0
  22. data/VERSION +1 -1
  23. data/bin/parse-changelog.sh +12 -0
  24. data/ci/configure_v4.sh +12 -0
  25. data/ci/configure_v5.sh +19 -0
  26. data/ci/oauth/keycloak/create_client +18 -0
  27. data/ci/oauth/keycloak/create_user +21 -0
  28. data/ci/oauth/keycloak/fetch_certificate +18 -0
  29. data/ci/oauth/keycloak/keycloak_functions.sh +71 -0
  30. data/ci/oauth/keycloak/standalone.xml +578 -0
  31. data/ci/oauth/keycloak/wait_for_server +56 -0
  32. data/ci/submit-coverage +36 -0
  33. data/conjur-api.gemspec +41 -0
  34. data/dev/Dockerfile.dev +12 -0
  35. data/dev/docker-compose.yml +56 -0
  36. data/dev/start +22 -0
  37. data/dev/stop +5 -0
  38. data/docker-compose.yml +98 -0
  39. data/example/demo_v4.rb +49 -0
  40. data/example/demo_v5.rb +57 -0
  41. data/features/authenticators.feature +41 -0
  42. data/features/authn.feature +14 -0
  43. data/features/authn_local.feature +32 -0
  44. data/features/exists.feature +37 -0
  45. data/features/group.feature +11 -0
  46. data/features/host.feature +50 -0
  47. data/features/host_factory_create_host.feature +28 -0
  48. data/features/host_factory_token.feature +63 -0
  49. data/features/load_policy.feature +61 -0
  50. data/features/members.feature +51 -0
  51. data/features/new_api.feature +36 -0
  52. data/features/permitted.feature +70 -0
  53. data/features/permitted_roles.feature +30 -0
  54. data/features/public_keys.feature +11 -0
  55. data/features/resource_fields.feature +53 -0
  56. data/features/role_fields.feature +15 -0
  57. data/features/rotate_api_key.feature +13 -0
  58. data/features/step_definitions/api_steps.rb +52 -0
  59. data/features/step_definitions/policy_steps.rb +134 -0
  60. data/features/step_definitions/result_steps.rb +11 -0
  61. data/features/support/env.rb +19 -0
  62. data/features/support/hooks.rb +3 -0
  63. data/features/support/world.rb +12 -0
  64. data/features/update_password.feature +14 -0
  65. data/features/user.feature +58 -0
  66. data/features/variable_fields.feature +20 -0
  67. data/features/variable_value.feature +60 -0
  68. data/features_v4/authn_local.feature +27 -0
  69. data/features_v4/exists.feature +29 -0
  70. data/features_v4/host.feature +18 -0
  71. data/features_v4/host_factory_token.feature +49 -0
  72. data/features_v4/members.feature +39 -0
  73. data/features_v4/permitted.feature +15 -0
  74. data/features_v4/permitted_roles.feature +8 -0
  75. data/features_v4/resource_fields.feature +47 -0
  76. data/features_v4/rotate_api_key.feature +13 -0
  77. data/features_v4/step_definitions/api_steps.rb +17 -0
  78. data/features_v4/step_definitions/result_steps.rb +3 -0
  79. data/features_v4/support/env.rb +23 -0
  80. data/features_v4/support/policy.yml +34 -0
  81. data/features_v4/support/world.rb +12 -0
  82. data/features_v4/variable_fields.feature +11 -0
  83. data/features_v4/variable_value.feature +54 -0
  84. data/lib/conjur/acts_as_resource.rb +123 -0
  85. data/lib/conjur/acts_as_role.rb +142 -0
  86. data/lib/conjur/acts_as_rolsource.rb +32 -0
  87. data/lib/conjur/acts_as_user.rb +68 -0
  88. data/lib/conjur/api/authenticators.rb +43 -0
  89. data/lib/conjur/api/authn.rb +144 -0
  90. data/lib/conjur/api/host_factories.rb +71 -0
  91. data/lib/conjur/api/ldap_sync.rb +38 -0
  92. data/lib/conjur/api/policies.rb +56 -0
  93. data/lib/conjur/api/pubkeys.rb +53 -0
  94. data/lib/conjur/api/resources.rb +109 -0
  95. data/lib/conjur/api/roles.rb +98 -0
  96. data/lib/conjur/api/router/v4.rb +206 -0
  97. data/lib/conjur/api/router/v5.rb +269 -0
  98. data/lib/conjur/api/variables.rb +59 -0
  99. data/lib/conjur/api.rb +105 -0
  100. data/lib/conjur/base.rb +355 -0
  101. data/lib/conjur/base_object.rb +57 -0
  102. data/lib/conjur/build_object.rb +47 -0
  103. data/lib/conjur/cache.rb +26 -0
  104. data/lib/conjur/cert_utils.rb +63 -0
  105. data/lib/conjur/cidr.rb +71 -0
  106. data/lib/conjur/configuration.rb +460 -0
  107. data/lib/conjur/escape.rb +129 -0
  108. data/lib/conjur/exceptions.rb +4 -0
  109. data/lib/conjur/group.rb +41 -0
  110. data/lib/conjur/has_attributes.rb +98 -0
  111. data/lib/conjur/host.rb +27 -0
  112. data/lib/conjur/host_factory.rb +75 -0
  113. data/lib/conjur/host_factory_token.rb +78 -0
  114. data/lib/conjur/id.rb +71 -0
  115. data/lib/conjur/layer.rb +9 -0
  116. data/lib/conjur/log.rb +72 -0
  117. data/lib/conjur/log_source.rb +60 -0
  118. data/lib/conjur/policy.rb +34 -0
  119. data/lib/conjur/policy_load_result.rb +61 -0
  120. data/lib/conjur/query_string.rb +12 -0
  121. data/lib/conjur/resource.rb +29 -0
  122. data/lib/conjur/role.rb +29 -0
  123. data/lib/conjur/role_grant.rb +85 -0
  124. data/lib/conjur/routing.rb +29 -0
  125. data/lib/conjur/user.rb +40 -0
  126. data/lib/conjur/variable.rb +208 -0
  127. data/lib/conjur/webservice.rb +30 -0
  128. data/lib/conjur-api/version.rb +24 -0
  129. data/lib/conjur-api.rb +2 -0
  130. data/publish.sh +5 -0
  131. data/spec/api/host_factories_spec.rb +34 -0
  132. data/spec/api_spec.rb +254 -0
  133. data/spec/base_object_spec.rb +13 -0
  134. data/spec/cert_utils_spec.rb +173 -0
  135. data/spec/cidr_spec.rb +34 -0
  136. data/spec/configuration_spec.rb +330 -0
  137. data/spec/has_attributes_spec.rb +63 -0
  138. data/spec/helpers/errors_matcher.rb +34 -0
  139. data/spec/helpers/request_helpers.rb +10 -0
  140. data/spec/id_spec.rb +29 -0
  141. data/spec/ldap_sync_spec.rb +21 -0
  142. data/spec/log_source_spec.rb +13 -0
  143. data/spec/log_spec.rb +42 -0
  144. data/spec/roles_spec.rb +24 -0
  145. data/spec/spec_helper.rb +113 -0
  146. data/spec/ssl_spec.rb +109 -0
  147. data/spec/uri_escape_spec.rb +21 -0
  148. data/test.sh +76 -0
  149. data/tmp/.keep +0 -0
  150. metadata +194 -3
@@ -0,0 +1,330 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::Configuration do
4
+ before {
5
+ Conjur.configuration = Conjur::Configuration.new
6
+ }
7
+ after(:all) do
8
+ # reset the configuration so it doesn't clobber other tests
9
+ Conjur.configuration = Conjur::Configuration.new
10
+ end
11
+
12
+ subject(:configuration) { Conjur.configuration }
13
+ context "thread-local behavior" do
14
+ it "can swap the Configuration in a new thread" do
15
+ original = Conjur.configuration
16
+ c = Conjur::Configuration.new
17
+ Thread.new do
18
+ Thread.current[:conjur_configuration] = :foo
19
+ Conjur.with_configuration c do
20
+ expect(Conjur.configuration).to eq(c)
21
+ end
22
+ expect(Thread.current[:conjur_configuration]).to eq(:foo)
23
+ end.join
24
+ expect(Conjur.configuration).to eq(original)
25
+ end
26
+ end
27
+ context "with various options" do
28
+ before {
29
+ configuration.account = "the-account"
30
+ configuration.appliance_url = "https://conjur/api"
31
+ }
32
+
33
+ it "rest_client_options defaults" do
34
+ expected = {
35
+ ssl_cert_store: OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
36
+ }
37
+ expect(configuration.rest_client_options).to eq(expected)
38
+ end
39
+
40
+ it "rest_client_options propagate to RestClient::Resource" do
41
+ expected = {
42
+ ssl_ca_file: "ca_certificate.pem",
43
+ proxy: "http://proxy.example.com/"
44
+ }
45
+ configuration.rest_client_options = {
46
+ ssl_ca_file: "ca_certificate.pem",
47
+ proxy: "http://proxy.example.com/"
48
+ }
49
+
50
+ resource = Conjur::API.url_for(:authn_login, *["account", "username", "password"])
51
+ expect(resource.options).to include(expected)
52
+ end
53
+
54
+ it "can still be changed by changing the appliance_url" do
55
+ configuration.appliance_url = "https://other/api"
56
+ expect(configuration.core_url).to eq "https://other/api"
57
+ end
58
+
59
+ it "can still be changed by changing the authn_url" do
60
+ configuration.authn_url = "http://authn-docker"
61
+ expect(configuration.core_url).to eq "https://conjur/api"
62
+ expect(configuration.authn_url).to eq "http://authn-docker"
63
+ end
64
+
65
+ context "and duplicated" do
66
+ subject { configuration.clone override_options }
67
+ let(:override_options) { Hash.new }
68
+
69
+ describe '#account' do
70
+ subject { super().account }
71
+ it { is_expected.to eq(configuration.account) }
72
+ end
73
+
74
+ describe '#appliance_url' do
75
+ subject { super().appliance_url }
76
+ it { is_expected.to eq(configuration.appliance_url) }
77
+ end
78
+
79
+ describe '#core_url' do
80
+ subject { super().core_url }
81
+ it { is_expected.to eq(configuration.appliance_url) }
82
+ end
83
+
84
+ context "appliance_url overridden" do
85
+ let(:override_options) {
86
+ { :appliance_url => "https://example/api" }
87
+ }
88
+ it "is ignored by the configuration core_url" do
89
+ expect(configuration.core_url).to eq("https://conjur/api")
90
+ end
91
+ it "is reflected in the copy core_url" do
92
+ expect(subject.core_url).to eq("https://example/api")
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "url generation" do
99
+ describe 'authn_url' do
100
+ before {
101
+ allow_any_instance_of(Conjur::Configuration).to receive(:account).and_return "the-account"
102
+ }
103
+ context "with appliance_url" do
104
+ before {
105
+ allow_any_instance_of(Conjur::Configuration).to receive(:appliance_url).and_return "http://example.com"
106
+ }
107
+
108
+ describe '#authn_url' do
109
+ subject { super().authn_url }
110
+ it { is_expected.to eq("http://example.com/authn") }
111
+ end
112
+ end
113
+ context "without appliance_url" do
114
+ describe '#authn_url' do
115
+ subject { super().authn_url }
116
+ it { is_expected.to eq("http://localhost:5000") }
117
+ end
118
+ end
119
+ end
120
+
121
+ describe 'core_url' do
122
+ before {
123
+ allow_any_instance_of(Conjur::Configuration).to receive(:account).and_return "the-account"
124
+ }
125
+ subject { super().core_url }
126
+ context "with appliance_url" do
127
+ before {
128
+ allow_any_instance_of(Conjur::Configuration).to receive(:appliance_url).and_return "http://example.com"
129
+ }
130
+
131
+ it { is_expected.to eq("http://example.com") }
132
+ end
133
+ context "without appliance_url" do
134
+ it { is_expected.to eq("http://localhost:5000") }
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "apply_cert_config!" do
140
+ let (:cert_exists) { true }
141
+ let (:cert_readable) { true }
142
+ subject{ Conjur.configuration.apply_cert_config! }
143
+
144
+ let(:store){ double('default store') }
145
+
146
+ before do
147
+ stub_const 'OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE', store
148
+ allow_any_instance_of(Conjur::Configuration).to receive(:ssl_certificate).and_return ssl_certificate
149
+ allow_any_instance_of(Conjur::Configuration).to receive(:cert_file).and_return cert_file
150
+ allow_any_instance_of(Conjur::Configuration).to receive(:ensure_cert_readable!).with(cert_file) do
151
+ raise Errno::ENOENT unless cert_exists
152
+ raise Errno::EPERM unless cert_readable
153
+ end
154
+ end
155
+
156
+ context 'when cert file may exist' do
157
+ context "when neither cert_file or ssl_certificate is present" do
158
+ let(:cert_file){ nil }
159
+ let(:ssl_certificate){ nil }
160
+
161
+ it 'does nothing to the store' do
162
+ expect(store).to_not receive(:add_file)
163
+ expect(store).to_not receive(:add_cert)
164
+ expect(subject).to be_falsey
165
+ end
166
+ end
167
+
168
+ context 'when both are given' do
169
+ let(:cert_file){ '/path/to/cert.pem' }
170
+ let(:ssl_certificate){ "-----BEGIN CERTIFICATE-----\nfoo\n-----END CERTIFICATE-----\n" }
171
+ let(:cert){ double('certificate') }
172
+ it 'calls store.add_cert with a certificate created from ssl_certificate' do
173
+ expect(OpenSSL::X509::Certificate).to receive(:new).with(ssl_certificate).once.and_return cert
174
+ expect(store).to receive(:add_cert).once.with(cert)
175
+ expect(subject).to be_truthy
176
+ end
177
+ end
178
+
179
+ context 'when cert_file is given and ssl_certificate is not' do
180
+ let(:cert_file){ '/path/to/cert.pem' }
181
+ let(:ssl_certificate){ nil }
182
+ it 'calls store.add_file with cert_file' do
183
+ expect(store).to receive(:add_file).with(cert_file).once
184
+ expect(subject).to be_truthy
185
+ end
186
+ end
187
+
188
+ context 'when ssl_certificate is given' do
189
+ let(:cert_file){ nil }
190
+ let(:ssl_certificate){ "-----BEGIN CERTIFICATE----- MIIDUTCCAjmgAwIBAgIJAO4Lf1Rf2cciMA0GCSqGSIb3DQEBBQUAMDMxMTAvBgNV BAMTKGVjMi01NC05MS0yNDYtODQuY29tcHV0ZS0xLmFtYXpvbmF3cy5jb20wHhcN MTQxMDA4MjEwNTA5WhcNMjQxMDA1MjEwNTA5WjAzMTEwLwYDVQQDEyhlYzItNTQt OTEtMjQ2LTg0LmNvbXB1dGUtMS5hbWF6b25hd3MuY29tMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAx+OFANXNEYNsMR3Uvg4/72VG3LZO8yxrYaYzc3FZ NN3NpIOCZvRTC5S+OawsdEljHwfhdVoXdWNKgVJakSxsAnnaj11fA6XpfN60o6Fk i4q/BqwqgeNJjKAlElFsNz2scWFWRe49NHlj9qaq/yWZ8Cn0IeHy8j8F+jMek4zt dCSxVEayVG/k8RFmYCcluQc/1LuCjPiFwJU43AGkO+yvmOuYGivsNKY+54yuEZqF VDsjAjMsYXxgLx9y1F7Rq3CfeqY6IajR7pmmRup8/D9NyyyQuIML83mjTSvo0UYu rkdXPObd/m6gumscvXMl6SoJ5IPItvTA42MZqTaNzimF0QIDAQABo2gwZjBkBgNV HREEXTBbgglsb2NhbGhvc3SCBmNvbmp1coIcY29uanVyLW1hc3Rlci5pdHAuY29u anVyLm5ldIIoZWMyLTU0LTkxLTI0Ni04NC5jb21wdXRlLTEuYW1hem9uYXdzLmNv bTANBgkqhkiG9w0BAQUFAAOCAQEANk7P3ZEZHLgiTrLG13VAkm33FAvFzRG6akx1 jgNeRDgSaxRtrfJq3mnhsmD6hdvv+e6prPCFOjeEDheyCZyQDESdVEJBwytHVjnH dbvgMRaPm6OO8CyRyNjg3YcC36T//oQKOdAXXEcrtd0QbelBDYlKA7smJtznfhAb XypVdeS/6I4qvJi3Ckp5sQ1GszYhVXAvEeWeY59WwsTWYHLkzss9QShnigPyo3LY ZA5JVXofYi9DJ6VexP7sJNhCMrY2WnMpPcAOB9T7a6lcoXj6mWxvFys0xDIEOnc6 NGb+d47blphUKRZMAUZgYgFfMfmlyu1IXj03J8AuKtIMEwkXAA== -----END CERTIFICATE----- " }
191
+ let(:actual_certificate) {
192
+ <<-CERT
193
+ -----BEGIN CERTIFICATE-----
194
+ MIIDUTCCAjmgAwIBAgIJAO4Lf1Rf2cciMA0GCSqGSIb3DQEBBQUAMDMxMTAvBgNV
195
+ BAMTKGVjMi01NC05MS0yNDYtODQuY29tcHV0ZS0xLmFtYXpvbmF3cy5jb20wHhcN
196
+ MTQxMDA4MjEwNTA5WhcNMjQxMDA1MjEwNTA5WjAzMTEwLwYDVQQDEyhlYzItNTQt
197
+ OTEtMjQ2LTg0LmNvbXB1dGUtMS5hbWF6b25hd3MuY29tMIIBIjANBgkqhkiG9w0B
198
+ AQEFAAOCAQ8AMIIBCgKCAQEAx+OFANXNEYNsMR3Uvg4/72VG3LZO8yxrYaYzc3FZ
199
+ NN3NpIOCZvRTC5S+OawsdEljHwfhdVoXdWNKgVJakSxsAnnaj11fA6XpfN60o6Fk
200
+ i4q/BqwqgeNJjKAlElFsNz2scWFWRe49NHlj9qaq/yWZ8Cn0IeHy8j8F+jMek4zt
201
+ dCSxVEayVG/k8RFmYCcluQc/1LuCjPiFwJU43AGkO+yvmOuYGivsNKY+54yuEZqF
202
+ VDsjAjMsYXxgLx9y1F7Rq3CfeqY6IajR7pmmRup8/D9NyyyQuIML83mjTSvo0UYu
203
+ rkdXPObd/m6gumscvXMl6SoJ5IPItvTA42MZqTaNzimF0QIDAQABo2gwZjBkBgNV
204
+ HREEXTBbgglsb2NhbGhvc3SCBmNvbmp1coIcY29uanVyLW1hc3Rlci5pdHAuY29u
205
+ anVyLm5ldIIoZWMyLTU0LTkxLTI0Ni04NC5jb21wdXRlLTEuYW1hem9uYXdzLmNv
206
+ bTANBgkqhkiG9w0BAQUFAAOCAQEANk7P3ZEZHLgiTrLG13VAkm33FAvFzRG6akx1
207
+ jgNeRDgSaxRtrfJq3mnhsmD6hdvv+e6prPCFOjeEDheyCZyQDESdVEJBwytHVjnH
208
+ dbvgMRaPm6OO8CyRyNjg3YcC36T//oQKOdAXXEcrtd0QbelBDYlKA7smJtznfhAb
209
+ XypVdeS/6I4qvJi3Ckp5sQ1GszYhVXAvEeWeY59WwsTWYHLkzss9QShnigPyo3LY
210
+ ZA5JVXofYi9DJ6VexP7sJNhCMrY2WnMpPcAOB9T7a6lcoXj6mWxvFys0xDIEOnc6
211
+ NGb+d47blphUKRZMAUZgYgFfMfmlyu1IXj03J8AuKtIMEwkXAA==
212
+ -----END CERTIFICATE-----
213
+ CERT
214
+ }
215
+ let(:cert){ double('cert') }
216
+
217
+ before do
218
+ expect(OpenSSL::X509::Certificate).to receive(:new).with(actual_certificate).at_least(:once).and_return cert
219
+ end
220
+
221
+ it 'calls store.add_cert with a certificate created from ssl_certificate' do
222
+ expect(store).to receive(:add_cert).with(cert).once
223
+ expect(subject).to be_truthy
224
+ end
225
+
226
+ it 'rescues from a StoreError with message "cert already in hash tabble"' do
227
+ expect(store).to receive(:add_cert).with(cert).once.and_raise(OpenSSL::X509::StoreError.new('cert already in hash table'))
228
+ expect(subject).to be_truthy
229
+ end
230
+
231
+
232
+ it 'does not rescue from other exceptions' do
233
+ exn = OpenSSL::X509::StoreError.new('some other message')
234
+ expect(store).to receive(:add_cert).with(cert).once.and_raise(exn)
235
+ expect{subject}.to raise_error exn
236
+ exn = ArgumentError.new('bad news')
237
+ expect(store).to receive(:add_cert).with(cert).once.and_raise(exn)
238
+ expect{subject}.to raise_error exn
239
+ end
240
+ end
241
+
242
+ context 'when given a store argument' do
243
+ let(:cert_file){ '/path/to/cert.pem' }
244
+ let(:ssl_certificate){ nil }
245
+ let(:alt_store){ double('alt store') }
246
+ subject{ Conjur.configuration.apply_cert_config! alt_store }
247
+
248
+ it 'uses that store instead' do
249
+ expect(alt_store).to receive(:add_file).with(cert_file).once
250
+ expect(subject).to be_truthy
251
+ end
252
+ end
253
+
254
+ context 'with two certificates in a string' do
255
+ let(:cert_file) { nil }
256
+ let(:ssl_certificate) do
257
+ """-----BEGIN CERTIFICATE-----
258
+ MIIDPjCCAiagAwIBAgIVAKW1gdmOFrXt6xB0iQmYQ4z8Pf+kMA0GCSqGSIb3DQEB
259
+ CwUAMD0xETAPBgNVBAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDAS
260
+ BgNVBAMTC2N1a2UtbWFzdGVyMB4XDTE1MTAwNzE2MzAwNloXDTI1MTAwNDE2MzAw
261
+ NlowFjEUMBIGA1UEAwwLY3VrZS1tYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
262
+ DwAwggEKAoIBAQC9e8bGIHOLOypKA4lsLcAOcDLAq+ICuVxn9Vg0No0m32Ok/K7G
263
+ uEGtlC8RidObntblUwqdX2uP7mqAQm19j78UTl1KT97vMmmFrpVZ7oQvEm1FUq3t
264
+ FBmJglthJrSbpdZjLf7a7eL1NnunkfBdI1DK9QL9ndMjNwZNFbXhld4fC5zuSr/L
265
+ PxawSzTEsoTaB0Nw0DdRowaZgrPxc0hQsrj9OF20gTIJIYO7ctZzE/JJchmBzgI4
266
+ CdfAYg7zNS+0oc0ylV0CWMerQtLICI6BtiQ482bCuGYJ00NlDcdjd3w+A2cj7PrH
267
+ wH5UhtORL5Q6i9EfGGUCDbmfpiVD9Bd3ukbXAgMBAAGjXDBaMA4GA1UdDwEB/wQE
268
+ AwIFoDAdBgNVHQ4EFgQU2jmj7l5rSw0yVb/vlWAYkK/YBwkwKQYDVR0RBCIwIIIL
269
+ Y3VrZS1tYXN0ZXKCCWxvY2FsaG9zdIIGY29uanVyMA0GCSqGSIb3DQEBCwUAA4IB
270
+ AQBCepy6If67+sjuVnT9NGBmjnVaLa11kgGNEB1BZQnvCy0IN7gpLpshoZevxYDR
271
+ 3DnPAetQiZ70CSmCwjL4x6AVxQy59rRj0Awl9E1dgFTYI3JxxgLsI9ePdIRVEPnH
272
+ dhXqPY5ZIZhvdHlLStjsXX7laaclEtMeWfSzxe4AmP/Sm/er4ks0gvLQU6/XJNIu
273
+ RnRH59ZB1mZMsIv9Ii790nnioYFR54JmQu1JsIib77ZdSXIJmxAtraJSTLcZbU1E
274
+ +SM3XCE423Xols7onyluMYDy3MCUTFwoVMRBcRWCAk5gcv6XvZDfLi6Zwdne6x3Y
275
+ bGenr4vsPuSFsycM03/EcQDT
276
+ -----END CERTIFICATE-----
277
+ -----BEGIN CERTIFICATE-----
278
+ MIIDhzCCAm+gAwIBAgIJAJnsrJ1+j9MhMA0GCSqGSIb3DQEBCwUAMD0xETAPBgNV
279
+ BAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDASBgNVBAMTC2N1a2Ut
280
+ bWFzdGVyMB4XDTE1MTAwNzE2MzAwM1oXDTI1MTAwNDE2MzAwM1owPTERMA8GA1UE
281
+ ChMIY3VjdW1iZXIxEjAQBgNVBAsTCUNvbmp1ciBDQTEUMBIGA1UEAxMLY3VrZS1t
282
+ YXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsuZ06Ld4JDhxZ
283
+ FcxKVxu7MTjXVv6W8pI7qFKmgr39aNqmDpKYJ1H9aM+r9zaTAeithpM4wJpVswkJ
284
+ d0RSuKdm1LOx11yHLyZ1OvlPHFhsVWdZIQZ6R9srhPYBUCMem4sHR5IAcBBX+HkR
285
+ 35gaPYUl1uFV/9zCniekt92Kdta+it1WL7XinXTBURlhDawiD/kv1C9x6dICEJVe
286
+ IT/jRohmqHAoM/JSOQTthaDli3Qvu5K8XAx8UXvWVmv3eStZFVDbC4ZEueRd9KAe
287
+ 4IZ5FxdpFYkPBgt2lBYeydYKRShyYrDKye1uJBDkeplNaYW4cS4mOhYuRkdKn7MH
288
+ uY/xb1lFAgMBAAGjgYkwgYYwKQYDVR0RBCIwIIILY3VrZS1tYXN0ZXKCCWxvY2Fs
289
+ aG9zdIIGY29uanVyMB0GA1UdDgQWBBRHpGF7aQbHdORYgQKDC2hV6NzEKzAfBgNV
290
+ HSMEGDAWgBRHpGF7aQbHdORYgQKDC2hV6NzEKzAMBgNVHRMEBTADAQH/MAsGA1Ud
291
+ DwQEAwIB5jANBgkqhkiG9w0BAQsFAAOCAQEAGZT9Wek1hYluIVaxu03wSKCKIJ4p
292
+ KxTHw+mLDapg1y9t3Fa/5IQQK0Bx0xGU2qWiQKjda3vdFPJWO6l6XJvsUY5Nwtm5
293
+ Gcsk8l3L/zWCrjrFTH3TdVad5E+DTwVhThelmEjw68AyM+WuOL61j0MItd9mLW74
294
+ Lv2zouj9nQBdnUBHWQ0EL/9d5cfaCVu/bFlDfYt7Yj0IzXCuaWZfJeHodU1hmqVX
295
+ BvYRjnTB2LSxfmSnkrCeFPmhE11bWVtsLIdrGIgtEMX0/s9xg58QuNnva1U3pJsW
296
+ RjvSxre4Xg2qlI9Laybb4oZ4g6DI8hRbL0VdFAsveg6SXg2RxgJcXeJUFw==
297
+ -----END CERTIFICATE-----
298
+ """
299
+ end
300
+
301
+ it 'adds both to the store' do
302
+ expect(store).to receive(:add_cert).twice
303
+ expect(subject).to be_truthy
304
+ end
305
+ end
306
+
307
+ end
308
+
309
+ context 'when cert file is not readable' do
310
+ let(:cert_file) { '/path/to/not_cert.pem' }
311
+ let(:ssl_certificate) { nil }
312
+
313
+ context 'raises ENOENT when cert file does not exist' do
314
+ let(:cert_exists) { false }
315
+ it 'raises the exception' do
316
+ expect{subject}.to raise_error(Errno::ENOENT)
317
+ end
318
+ end
319
+
320
+ context "raises EPERM when cert file does not have read permission" do
321
+ let(:cert_readable) {false}
322
+ it 'raises the exception' do
323
+ expect{subject}.to raise_error(Errno::EPERM)
324
+ end
325
+ end
326
+
327
+ end
328
+
329
+ end
330
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::HasAttributes do
4
+ class ObjectWithAttributes
5
+ include Conjur::HasAttributes
6
+
7
+ def id; "the-object"; end
8
+ def credentials; {}; end
9
+ def username; 'alice'; end
10
+ def url; 'http://example.com/the-object'; end
11
+ end
12
+
13
+ def new_object
14
+ ObjectWithAttributes.new
15
+ end
16
+
17
+ let(:object) { new_object }
18
+ let(:second_object) { new_object }
19
+ let(:attributes) { { 'id' => 'the-id' } }
20
+ let(:rbac_resource_resource) { double(:rbac_resource_resource, url: object.url) }
21
+
22
+ before {
23
+ allow(object).to receive(:url_for).with(:resources_resource, {}, "the-object").and_return(rbac_resource_resource)
24
+ allow(second_object).to receive(:url_for).with(:resources_resource, {}, "the-object").and_return(rbac_resource_resource)
25
+ expect(rbac_resource_resource).to receive(:get).with(no_args).and_return(double(:response, body: attributes.to_json))
26
+ }
27
+
28
+ it "should fetch attributes from the server" do
29
+ expect(object.attributes).to eq(attributes)
30
+ end
31
+
32
+ describe "caching" do
33
+ let(:cache) {
34
+ Struct.new(:dummy) do
35
+ def table; @table ||= Hash.new; end
36
+
37
+ def fetch_attributes cache_key, &block
38
+ table[cache_key] || table[cache_key] = yield
39
+ end
40
+ end.new
41
+ }
42
+
43
+ around do |example|
44
+ saved = Conjur.cache
45
+ Conjur.cache = cache
46
+
47
+ begin
48
+ example.run
49
+ ensure
50
+ Conjur.cache = saved
51
+ end
52
+ end
53
+ context "enabled" do
54
+ it "caches the attributes across objects" do
55
+ expect(object.attributes).to eq(attributes)
56
+ expect(second_object.attributes).to eq(attributes)
57
+ expect(cache.table).to eq({
58
+ "alice.http://example.com/the-object" => attributes
59
+ })
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,34 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :raise_one_of do |*exn_classes|
4
+ supports_block_expectations
5
+
6
+ match do |block|
7
+ expect(&block).to raise_error do |error|
8
+ @actual_error = error
9
+ expect(exn_classes).to include error.class
10
+ end
11
+ end
12
+
13
+ failure_message do
14
+ "expected #{expected_error}#{given_error}"
15
+ end
16
+
17
+ define_method :expected_error do
18
+ "one of " + exn_classes.join(', ')
19
+ end
20
+
21
+ def given_error
22
+ return " but nothing was raised" unless @actual_error
23
+ backtrace = format_backtrace(@actual_error.backtrace)
24
+ [
25
+ ", got #{@actual_error.inspect} with backtrace:",
26
+ *backtrace
27
+ ].join("\n # ")
28
+ end
29
+
30
+ def format_backtrace backtrace
31
+ formatter = RSpec::Matchers.configuration.backtrace_formatter
32
+ formatter.format_backtrace(backtrace)
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ # Helpers for REST client tests
2
+ module RequestHelpers
3
+ def expect_request details, &block
4
+ expect(RestClient::Request).to receive(:execute).with(hash_including(details), &block)
5
+ end
6
+
7
+ def allow_request details, &block
8
+ allow(RestClient::Request).to receive(:execute).with(hash_including(details), &block)
9
+ end
10
+ end
data/spec/id_spec.rb ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Conjur::Id do
6
+ it 'requires the id to be fully qualified' do
7
+ expect { Conjur::Id.new 'foo:bar' }.to raise_error ArgumentError
8
+ end
9
+
10
+ it 'can be constructed from a string' do
11
+ id = Conjur::Id.new 'foo:bar:baz'
12
+ expect(id).to be
13
+ {
14
+ account: 'foo',
15
+ kind: 'bar',
16
+ identifier: 'baz'
17
+ }.each { |k, v| expect(id.send(k)).to eq v }
18
+ end
19
+
20
+ it 'can be constructed from an array' do
21
+ id = Conjur::Id.new %w(foo bar baz)
22
+ expect(id).to be
23
+ {
24
+ account: 'foo',
25
+ kind: 'bar',
26
+ identifier: 'baz'
27
+ }.each { |k, v| expect(id.send(k)).to eq v }
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::API, api: :dummy do
4
+ let(:router) { double('router', :get => "{}") }
5
+ before do
6
+ allow_any_instance_of(Conjur::API).to receive(:url_for).with(:ldap_sync_policy, any_args).and_return(router)
7
+ end
8
+
9
+ # verify that the method exists, and takes the correct argument.
10
+ describe '#ldap_sync_policy' do
11
+ context 'with default config' do
12
+ subject { api.ldap_sync_policy }
13
+ it { is_expected.to eq({}) }
14
+ end
15
+
16
+ context 'with a config specified' do
17
+ subject { api.ldap_sync_policy config_name: 'non-default-config' }
18
+ it { is_expected.to eq({}) }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::LogSource, logging: :temp, api: :dummy do
4
+ describe "#log" do
5
+ it "adds a username to the log" do
6
+ api.log do |log|
7
+ log << 'foo'
8
+ end
9
+
10
+ expect(log).to eq("[#{username}] foo\n")
11
+ end
12
+ end
13
+ end
data/spec/log_spec.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'io/grab'
3
+ require 'tempfile'
4
+
5
+ describe Conjur do
6
+ describe '::log=' do
7
+ before { @old_log = Conjur.log }
8
+ let(:log) { double 'log' }
9
+ it "creates the log with given type and makes it available" do
10
+ allow(Conjur).to receive(:create_log).with(:param).and_return log
11
+ Conjur::log = :param
12
+ expect(Conjur::log).to eq(log)
13
+ end
14
+ after { Conjur.class_variable_set :@@log, @old_log }
15
+ end
16
+
17
+ describe '::create_log' do
18
+ let(:log) { Conjur::create_log param }
19
+ context "with 'stdout'" do
20
+ let(:param) { 'stdout' }
21
+ it "creates something which writes to STDOUT" do
22
+ expect($stdout.grab { log << "foo" }).to eq('foo')
23
+ end
24
+ end
25
+
26
+ context "with 'stderr'" do
27
+ let(:param) { 'stderr' }
28
+ it "creates something which writes to STDERR" do
29
+ expect($stderr.grab { log << "foo" }).to eq('foo')
30
+ end
31
+ end
32
+
33
+ context "with a filename" do
34
+ let(:tempfile) { Tempfile.new 'spec' }
35
+ let(:param) { tempfile.path }
36
+ it "creates something which writes to the file" do
37
+ log << "foo"
38
+ expect(tempfile.read).to eq("foo")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::API do
4
+ describe '#role_name_from_username' do
5
+ let(:account) { "the-account" }
6
+ context "when username is" do
7
+ [
8
+ [ 'the-user', 'the-account:user:the-user' ],
9
+ [ 'host/the-host', 'the-account:host:the-host' ],
10
+ [ 'host/a/quite/long/host/name', 'the-account:host:a/quite/long/host/name' ],
11
+ [ 'newkind/host/name', 'the-account:newkind:host/name' ],
12
+ ].each do |p|
13
+ context "'#{p[0]}'" do
14
+ let(:username) { p[0] }
15
+
16
+ describe '#role_name_from_username' do
17
+ subject { Conjur::API.role_name_from_username username, account }
18
+ it { is_expected.to eq(p[1]) }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,113 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start do
4
+ command_name "#{ENV['RUBY_VERSION']}"
5
+ end
6
+
7
+ require 'rubygems'
8
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
9
+ $:.unshift File.join(File.dirname(__FILE__), "lib")
10
+
11
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
12
+ # from the project root directory.
13
+ ENV["CONJUR_ENV"] ||= 'test'
14
+
15
+ # Allows loading of an environment config based on the environment
16
+ require 'rspec'
17
+ require 'securerandom'
18
+
19
+ # Uncomment the next line to use webrat's matchers
20
+ #require 'webrat/integrations/rspec-rails'
21
+
22
+ RSpec.configure do |config|
23
+ config.before do
24
+ # test with a clean environment
25
+ stub_const 'ENV', 'CONJUR_ENV' => 'test'
26
+ end
27
+
28
+
29
+ # If you're not using ActiveRecord you should remove these
30
+ # lines, delete config/database.yml and disable :active_record
31
+ # in your config/boot.rb
32
+ #config.use_transactional_fixtures = true
33
+ #config.use_instantiated_fixtures = false
34
+ #config.fixture_path = File.join(redmine_root, 'test', 'fixtures')
35
+
36
+ # == Fixtures
37
+ #
38
+ # You can declare fixtures for each example_group like this:
39
+ # describe "...." do
40
+ # fixtures :table_a, :table_b
41
+ #
42
+ # Alternatively, if you prefer to declare them only once, you can
43
+ # do so right here. Just uncomment the next line and replace the fixture
44
+ # names with your fixtures.
45
+ #
46
+ #
47
+ # If you declare global fixtures, be aware that they will be declared
48
+ # for all of your examples, even those that don't use them.
49
+ #
50
+ # You can also declare which fixtures to use (for example fixtures for test/fixtures):
51
+ #
52
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
53
+ #
54
+ # == Mock Framework
55
+ #
56
+ # RSpec uses its own mocking framework by default. If you prefer to
57
+ # use mocha, flexmock or RR, uncomment the appropriate line:
58
+ #
59
+ # config.mock_with :mocha
60
+ # config.mock_with :flexmock
61
+ # config.mock_with :rr
62
+ #
63
+ # == Notes
64
+ #
65
+ # For more information take a look at Spec::Runner::Configuration and Spec::Runner
66
+ end
67
+
68
+ # This code will be run each time you run your specs.
69
+
70
+ # Requires supporting files with custom matchers and macros, etc,
71
+ # in ./support/ and its subdirectories.
72
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
73
+
74
+ shared_examples_for "http response" do
75
+ let(:http_response) { double(:response) }
76
+
77
+ before(:each) do
78
+ allow(http_response).to receive(:code).and_return 200
79
+ allow(http_response).to receive(:message).and_return nil
80
+ allow(http_response).to receive(:body).and_return http_json.to_json
81
+ end
82
+ end
83
+
84
+ require 'conjur/api'
85
+
86
+ KIND="asset_kind"
87
+ ID="unique_id"
88
+ ROLE='<role>'
89
+ MEMBER='<member>'
90
+ PRIVILEGE='<privilege>'
91
+ OWNER='<owner/userid>'
92
+ ACCOUNT='<core_account>'
93
+ OPTIONS={}
94
+
95
+ shared_context api: :dummy do
96
+ let(:username) { "user" }
97
+ let(:api){ Conjur::API.new_from_key username, 'key' }
98
+ let(:authn_host) { 'http://authn.example.com' }
99
+ let(:core_host) { 'http://core.example.com' }
100
+ let(:credentials) { { headers: { authorization: "Token token=\"stub\"" } } } #, username: username } }
101
+ let(:account) { 'the-account' }
102
+
103
+ before do
104
+ allow(Conjur.configuration).to receive_messages account: account, core_url: core_host, authn_url: authn_host
105
+ allow(api).to receive_messages credentials: credentials
106
+ end
107
+ end
108
+
109
+ shared_context logging: :temp do
110
+ let(:logfile) { Tempfile.new("log") }
111
+ before { Conjur.log = logfile.path }
112
+ let(:log) { logfile.read }
113
+ end