conjur-api 5.3.8.pre.319 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
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 +196 -5
@@ -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