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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +10 -0
- data/.dockerignore +1 -0
- data/.github/CODEOWNERS +10 -0
- data/.gitignore +32 -0
- data/.gitleaks.toml +219 -0
- data/.overcommit.yml +16 -0
- data/.project +18 -0
- data/.rubocop.yml +3 -0
- data/.rubocop_settings.yml +86 -0
- data/.rubocop_todo.yml +709 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +448 -0
- data/CONTRIBUTING.md +138 -0
- data/Dockerfile +16 -0
- data/Gemfile +7 -0
- data/Jenkinsfile +136 -0
- data/LICENSE +202 -0
- data/README.md +162 -0
- data/Rakefile +47 -0
- data/SECURITY.md +42 -0
- data/VERSION +1 -1
- data/bin/parse-changelog.sh +12 -0
- data/ci/configure_v4.sh +12 -0
- data/ci/configure_v5.sh +19 -0
- data/ci/oauth/keycloak/create_client +18 -0
- data/ci/oauth/keycloak/create_user +21 -0
- data/ci/oauth/keycloak/fetch_certificate +18 -0
- data/ci/oauth/keycloak/keycloak_functions.sh +71 -0
- data/ci/oauth/keycloak/standalone.xml +578 -0
- data/ci/oauth/keycloak/wait_for_server +56 -0
- data/ci/submit-coverage +36 -0
- data/conjur-api.gemspec +41 -0
- data/dev/Dockerfile.dev +12 -0
- data/dev/docker-compose.yml +56 -0
- data/dev/start +22 -0
- data/dev/stop +5 -0
- data/docker-compose.yml +98 -0
- data/example/demo_v4.rb +49 -0
- data/example/demo_v5.rb +57 -0
- data/features/authenticators.feature +41 -0
- data/features/authn.feature +14 -0
- data/features/authn_local.feature +32 -0
- data/features/exists.feature +37 -0
- data/features/group.feature +11 -0
- data/features/host.feature +50 -0
- data/features/host_factory_create_host.feature +28 -0
- data/features/host_factory_token.feature +63 -0
- data/features/load_policy.feature +61 -0
- data/features/members.feature +51 -0
- data/features/new_api.feature +36 -0
- data/features/permitted.feature +70 -0
- data/features/permitted_roles.feature +30 -0
- data/features/public_keys.feature +11 -0
- data/features/resource_fields.feature +53 -0
- data/features/role_fields.feature +15 -0
- data/features/rotate_api_key.feature +13 -0
- data/features/step_definitions/api_steps.rb +52 -0
- data/features/step_definitions/policy_steps.rb +134 -0
- data/features/step_definitions/result_steps.rb +11 -0
- data/features/support/env.rb +19 -0
- data/features/support/hooks.rb +3 -0
- data/features/support/world.rb +12 -0
- data/features/update_password.feature +14 -0
- data/features/user.feature +58 -0
- data/features/variable_fields.feature +20 -0
- data/features/variable_value.feature +60 -0
- data/features_v4/authn_local.feature +27 -0
- data/features_v4/exists.feature +29 -0
- data/features_v4/host.feature +18 -0
- data/features_v4/host_factory_token.feature +49 -0
- data/features_v4/members.feature +39 -0
- data/features_v4/permitted.feature +15 -0
- data/features_v4/permitted_roles.feature +8 -0
- data/features_v4/resource_fields.feature +47 -0
- data/features_v4/rotate_api_key.feature +13 -0
- data/features_v4/step_definitions/api_steps.rb +17 -0
- data/features_v4/step_definitions/result_steps.rb +3 -0
- data/features_v4/support/env.rb +23 -0
- data/features_v4/support/policy.yml +34 -0
- data/features_v4/support/world.rb +12 -0
- data/features_v4/variable_fields.feature +11 -0
- data/features_v4/variable_value.feature +54 -0
- data/lib/conjur/acts_as_resource.rb +123 -0
- data/lib/conjur/acts_as_role.rb +142 -0
- data/lib/conjur/acts_as_rolsource.rb +32 -0
- data/lib/conjur/acts_as_user.rb +68 -0
- data/lib/conjur/api/authenticators.rb +43 -0
- data/lib/conjur/api/authn.rb +144 -0
- data/lib/conjur/api/host_factories.rb +71 -0
- data/lib/conjur/api/ldap_sync.rb +38 -0
- data/lib/conjur/api/policies.rb +56 -0
- data/lib/conjur/api/pubkeys.rb +53 -0
- data/lib/conjur/api/resources.rb +109 -0
- data/lib/conjur/api/roles.rb +98 -0
- data/lib/conjur/api/router/v4.rb +206 -0
- data/lib/conjur/api/router/v5.rb +269 -0
- data/lib/conjur/api/variables.rb +59 -0
- data/lib/conjur/api.rb +105 -0
- data/lib/conjur/base.rb +355 -0
- data/lib/conjur/base_object.rb +57 -0
- data/lib/conjur/build_object.rb +47 -0
- data/lib/conjur/cache.rb +26 -0
- data/lib/conjur/cert_utils.rb +63 -0
- data/lib/conjur/cidr.rb +71 -0
- data/lib/conjur/configuration.rb +460 -0
- data/lib/conjur/escape.rb +129 -0
- data/lib/conjur/exceptions.rb +4 -0
- data/lib/conjur/group.rb +41 -0
- data/lib/conjur/has_attributes.rb +98 -0
- data/lib/conjur/host.rb +27 -0
- data/lib/conjur/host_factory.rb +75 -0
- data/lib/conjur/host_factory_token.rb +78 -0
- data/lib/conjur/id.rb +71 -0
- data/lib/conjur/layer.rb +9 -0
- data/lib/conjur/log.rb +72 -0
- data/lib/conjur/log_source.rb +60 -0
- data/lib/conjur/policy.rb +34 -0
- data/lib/conjur/policy_load_result.rb +61 -0
- data/lib/conjur/query_string.rb +12 -0
- data/lib/conjur/resource.rb +29 -0
- data/lib/conjur/role.rb +29 -0
- data/lib/conjur/role_grant.rb +85 -0
- data/lib/conjur/routing.rb +29 -0
- data/lib/conjur/user.rb +40 -0
- data/lib/conjur/variable.rb +208 -0
- data/lib/conjur/webservice.rb +30 -0
- data/lib/conjur-api/version.rb +24 -0
- data/lib/conjur-api.rb +2 -0
- data/publish.sh +5 -0
- data/spec/api/host_factories_spec.rb +34 -0
- data/spec/api_spec.rb +254 -0
- data/spec/base_object_spec.rb +13 -0
- data/spec/cert_utils_spec.rb +173 -0
- data/spec/cidr_spec.rb +34 -0
- data/spec/configuration_spec.rb +330 -0
- data/spec/has_attributes_spec.rb +63 -0
- data/spec/helpers/errors_matcher.rb +34 -0
- data/spec/helpers/request_helpers.rb +10 -0
- data/spec/id_spec.rb +29 -0
- data/spec/ldap_sync_spec.rb +21 -0
- data/spec/log_source_spec.rb +13 -0
- data/spec/log_spec.rb +42 -0
- data/spec/roles_spec.rb +24 -0
- data/spec/spec_helper.rb +113 -0
- data/spec/ssl_spec.rb +109 -0
- data/spec/uri_escape_spec.rb +21 -0
- data/test.sh +76 -0
- data/tmp/.keep +0 -0
- 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
|
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
|
data/spec/roles_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|