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
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fakefs/spec_helpers'
|
3
|
+
|
4
|
+
describe Conjur::API do
|
5
|
+
|
6
|
+
let(:account) { 'api-spec-acount' }
|
7
|
+
let(:remote_ip) { nil }
|
8
|
+
before { allow(Conjur.configuration).to receive_messages account: account }
|
9
|
+
|
10
|
+
shared_context "logged in", logged_in: true do
|
11
|
+
let(:login) { "bob" }
|
12
|
+
let(:token) { { 'data' => login, 'timestamp' => Time.now.to_s } }
|
13
|
+
subject(:api) { Conjur::API.new_from_token(token, remote_ip: remote_ip) }
|
14
|
+
end
|
15
|
+
|
16
|
+
shared_context "logged in with an API key", logged_in: :api_key do
|
17
|
+
include_context "logged in"
|
18
|
+
let(:api_key) { "theapikey" }
|
19
|
+
subject(:api) { Conjur::API.new_from_key(login, api_key, account: account ,remote_ip: remote_ip) }
|
20
|
+
end
|
21
|
+
|
22
|
+
shared_context "logged in with a token file", logged_in: :token_file do
|
23
|
+
include FakeFS::SpecHelpers
|
24
|
+
include_context "logged in"
|
25
|
+
let(:token_file) { "token_file" }
|
26
|
+
subject(:api) { Conjur::API.new_from_token_file(token_file, remote_ip: remote_ip) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def time_travel delta
|
30
|
+
allow(api.authenticator).to receive(:gettime).and_wrap_original do |m|
|
31
|
+
m[] + delta
|
32
|
+
end
|
33
|
+
allow(api.authenticator).to receive(:monotonic_time).and_wrap_original do |m|
|
34
|
+
m[] + delta
|
35
|
+
end
|
36
|
+
allow(Time).to receive(:now).and_wrap_original do |m|
|
37
|
+
m[] + delta
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#token' do
|
42
|
+
context 'with token file available', logged_in: :token_file do
|
43
|
+
def write_token token
|
44
|
+
File.write token_file, JSON.generate(token)
|
45
|
+
end
|
46
|
+
|
47
|
+
before do
|
48
|
+
write_token token
|
49
|
+
end
|
50
|
+
|
51
|
+
it "reads the file to get a token" do
|
52
|
+
expect(api.instance_variable_get("@token")).to eq(nil)
|
53
|
+
expect(api.token).to eq(token)
|
54
|
+
expect(api.credentials).to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login })
|
55
|
+
end
|
56
|
+
|
57
|
+
context "after expiration" do
|
58
|
+
it 'it reads a new token' do
|
59
|
+
expect(Time.parse(api.token['timestamp'])).to be_within(5.seconds).of(Time.now)
|
60
|
+
|
61
|
+
time_travel 6.minutes
|
62
|
+
new_token = token.merge "timestamp" => Time.now.to_s
|
63
|
+
write_token new_token
|
64
|
+
|
65
|
+
expect(api.token).to eq(new_token)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with API key available', logged_in: :api_key do
|
71
|
+
it "authenticates to get a token" do
|
72
|
+
expect(Conjur::API).to receive(:authenticate).with(login, api_key, account: account).and_return token
|
73
|
+
|
74
|
+
expect(api.instance_variable_get("@token")).to eq(nil)
|
75
|
+
expect(api.token).to eq(token)
|
76
|
+
expect(api.credentials).to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login })
|
77
|
+
end
|
78
|
+
|
79
|
+
context "after expiration" do
|
80
|
+
|
81
|
+
shared_examples "it gets a new token" do
|
82
|
+
it 'by refreshing' do
|
83
|
+
allow(Conjur::API).to receive(:authenticate).with(login, api_key, account: account).and_return token
|
84
|
+
expect(Time.parse(api.token['timestamp'])).to be_within(5.seconds).of(Time.now)
|
85
|
+
|
86
|
+
time_travel 6.minutes
|
87
|
+
new_token = token.merge "timestamp" => Time.now.to_s
|
88
|
+
|
89
|
+
expect(Conjur::API).to receive(:authenticate).with(login, api_key, account: account).and_return new_token
|
90
|
+
expect(api.token).to eq(new_token)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it_should_behave_like "it gets a new token"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'with no API key available', logged_in: true do
|
99
|
+
it "returns the token used to create it" do
|
100
|
+
expect(api.token).to eq token
|
101
|
+
end
|
102
|
+
|
103
|
+
it "doesn't try to refresh an old token" do
|
104
|
+
expect(Conjur::API).not_to receive :authenticate
|
105
|
+
api.token # vivify
|
106
|
+
time_travel 6.minutes
|
107
|
+
expect { api.token }.not_to raise_error
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "credential handling", logged_in: true do
|
113
|
+
context "from token" do
|
114
|
+
describe '#credentials' do
|
115
|
+
subject { super().credentials }
|
116
|
+
it { is_expected.to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login }) }
|
117
|
+
end
|
118
|
+
|
119
|
+
context "with remote_ip" do
|
120
|
+
let(:remote_ip) { "66.0.0.1" }
|
121
|
+
describe '#credentials' do
|
122
|
+
subject { super().credentials }
|
123
|
+
it { is_expected.to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"", :x_forwarded_for=>"66.0.0.1" }, username: login }) }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "from logged-in RestClient::Resource" do
|
129
|
+
let (:authz_header) { %Q{Token token="#{token_encoded}"} }
|
130
|
+
let (:priv_header) { nil }
|
131
|
+
let (:forwarded_for_header) { nil }
|
132
|
+
let (:audit_roles_header) { nil }
|
133
|
+
let (:audit_resources_header) { nil }
|
134
|
+
let (:username) { 'bob' }
|
135
|
+
subject { resource.conjur_api }
|
136
|
+
|
137
|
+
shared_examples "it can clone itself" do
|
138
|
+
it "has the authz header" do
|
139
|
+
expect(subject.credentials[:headers][:authorization]).to eq(authz_header)
|
140
|
+
end
|
141
|
+
it "has the username" do
|
142
|
+
expect(subject.credentials[:username]).to eq(username)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
let(:token_encoded) { Base64.strict_encode64(token.to_json) }
|
147
|
+
let(:base_headers) { { authorization: authz_header } }
|
148
|
+
let(:headers) { base_headers }
|
149
|
+
let(:resource) { RestClient::Resource.new("http://example.com", { headers: headers })}
|
150
|
+
context 'basic functioning' do
|
151
|
+
it_behaves_like 'it can clone itself'
|
152
|
+
end
|
153
|
+
|
154
|
+
context "forwarded for" do
|
155
|
+
let(:forwarded_for_header) { "66.0.0.1" }
|
156
|
+
let(:headers) { base_headers.merge(x_forwarded_for: forwarded_for_header) }
|
157
|
+
it_behaves_like 'it can clone itself'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#role_from_username", logged_in: true do
|
163
|
+
it "returns a user role when username is plain" do
|
164
|
+
expect(Conjur::API.role_from_username(api, "plain-username", account).id).to eq("#{account}:user:plain-username")
|
165
|
+
end
|
166
|
+
|
167
|
+
it "returns an appropriate role kind when username is qualified" do
|
168
|
+
expect(Conjur::API.role_from_username(api, "host/foo/bar", account).id).to eq("#{account}:host:foo/bar")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "#username" do
|
173
|
+
let(:jwt_payload) do
|
174
|
+
'eyJzdWIiOiJ1c2VyLTlhYjBiYmZiOWJlNjA5Yzk2ZjUyN2Y1YiIsImlhdCI6MTYwMzQ5MDA4MH0='
|
175
|
+
end
|
176
|
+
|
177
|
+
let(:jwt_header) do
|
178
|
+
'eyJhbGciOiJjb25qdXIub3JnL3Nsb3NpbG8vdjIiLCJraWQiOiI2MWZjOGRiZDM4MjA4NDll' \
|
179
|
+
'ZDI4YTZhYTAwMzFjNjM5MjkxZjJmMDQzNDVjYTU0MWI5NzUxMGQ5NjkyM2I3NDlmIn0='
|
180
|
+
end
|
181
|
+
|
182
|
+
let(:conjur_token) do
|
183
|
+
{
|
184
|
+
'data' => 'conjur-user-1234',
|
185
|
+
'timestamp' => Time.now.to_s
|
186
|
+
}
|
187
|
+
end
|
188
|
+
|
189
|
+
let(:jwt_token) do
|
190
|
+
{
|
191
|
+
'protected' => jwt_header,
|
192
|
+
'payload' => jwt_payload,
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
it "can correctly extract the username from old Conjur token" do
|
197
|
+
expect(Conjur::API.new_from_token(conjur_token).username).to(
|
198
|
+
eq('conjur-user-1234')
|
199
|
+
)
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'when using JWT token' do
|
203
|
+
it "can correctly extract username" do
|
204
|
+
expect(Conjur::API.new_from_token(jwt_token).username).to(
|
205
|
+
eq('user-9ab0bbfb9be609c96f527f5b')
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "returns nil when JWT token has no payload field" do
|
210
|
+
no_payload_jwt_token = { 'protected' => jwt_header }
|
211
|
+
expect(Conjur::API.new_from_token(no_payload_jwt_token).username).to be_nil
|
212
|
+
end
|
213
|
+
|
214
|
+
it "returns nil when JWT token has no 'sub' field in payload" do
|
215
|
+
no_sub_token = { 'payload' => 'eyJpYXQiOjE2MDM0OTAwODB9' }
|
216
|
+
expect(Conjur::API.new_from_token(no_sub_token).username).to be_nil
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "#current_role", logged_in: true do
|
222
|
+
context "when logged in as user" do
|
223
|
+
let(:login) { 'joerandom' }
|
224
|
+
it "returns a user role" do
|
225
|
+
expect(api.current_role(account).id).to eq("#{account}:user:joerandom")
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context "when logged in as host" do
|
230
|
+
let(:host) { "somehost" }
|
231
|
+
let(:login) { "host/#{host}" }
|
232
|
+
it "returns a host role" do
|
233
|
+
expect(api.current_role(account).id).to eq("#{account}:host:somehost")
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe 'url escapes' do
|
239
|
+
let(:urls){[
|
240
|
+
'foo/bar@baz',
|
241
|
+
'/test/some group with spaces'
|
242
|
+
]}
|
243
|
+
|
244
|
+
describe '#fully_escape' do
|
245
|
+
let(:expected){[
|
246
|
+
'foo%2Fbar%40baz',
|
247
|
+
'%2Ftest%2Fsome%20group%20with%20spaces'
|
248
|
+
]}
|
249
|
+
it 'escapes the urls correctly' do
|
250
|
+
expect(urls.map{|u| Conjur::API.fully_escape u}).to eq(expected)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Conjur::BaseObject do
|
6
|
+
|
7
|
+
it "returns custom string for #inspect" do
|
8
|
+
id_str = 'foo:bar:baz'
|
9
|
+
base_obj = Conjur::BaseObject.new(Conjur::Id.new(id_str), { username: 'foo' })
|
10
|
+
expect(base_obj.inspect).to include("id='#{id_str}'")
|
11
|
+
expect(base_obj.inspect).to include(Conjur::BaseObject.name)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Conjur::CertUtils do
|
4
|
+
describe '.parse_certs' do
|
5
|
+
let(:cert1_raw) do
|
6
|
+
"""-----BEGIN CERTIFICATE-----
|
7
|
+
MIIDPjCCAiagAwIBAgIVAKW1gdmOFrXt6xB0iQmYQ4z8Pf+kMA0GCSqGSIb3DQEB
|
8
|
+
CwUAMD0xETAPBgNVBAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDAS
|
9
|
+
BgNVBAMTC2N1a2UtbWFzdGVyMB4XDTE1MTAwNzE2MzAwNloXDTI1MTAwNDE2MzAw
|
10
|
+
NlowFjEUMBIGA1UEAwwLY3VrZS1tYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
11
|
+
DwAwggEKAoIBAQC9e8bGIHOLOypKA4lsLcAOcDLAq+ICuVxn9Vg0No0m32Ok/K7G
|
12
|
+
uEGtlC8RidObntblUwqdX2uP7mqAQm19j78UTl1KT97vMmmFrpVZ7oQvEm1FUq3t
|
13
|
+
FBmJglthJrSbpdZjLf7a7eL1NnunkfBdI1DK9QL9ndMjNwZNFbXhld4fC5zuSr/L
|
14
|
+
PxawSzTEsoTaB0Nw0DdRowaZgrPxc0hQsrj9OF20gTIJIYO7ctZzE/JJchmBzgI4
|
15
|
+
CdfAYg7zNS+0oc0ylV0CWMerQtLICI6BtiQ482bCuGYJ00NlDcdjd3w+A2cj7PrH
|
16
|
+
wH5UhtORL5Q6i9EfGGUCDbmfpiVD9Bd3ukbXAgMBAAGjXDBaMA4GA1UdDwEB/wQE
|
17
|
+
AwIFoDAdBgNVHQ4EFgQU2jmj7l5rSw0yVb/vlWAYkK/YBwkwKQYDVR0RBCIwIIIL
|
18
|
+
Y3VrZS1tYXN0ZXKCCWxvY2FsaG9zdIIGY29uanVyMA0GCSqGSIb3DQEBCwUAA4IB
|
19
|
+
AQBCepy6If67+sjuVnT9NGBmjnVaLa11kgGNEB1BZQnvCy0IN7gpLpshoZevxYDR
|
20
|
+
3DnPAetQiZ70CSmCwjL4x6AVxQy59rRj0Awl9E1dgFTYI3JxxgLsI9ePdIRVEPnH
|
21
|
+
dhXqPY5ZIZhvdHlLStjsXX7laaclEtMeWfSzxe4AmP/Sm/er4ks0gvLQU6/XJNIu
|
22
|
+
RnRH59ZB1mZMsIv9Ii790nnioYFR54JmQu1JsIib77ZdSXIJmxAtraJSTLcZbU1E
|
23
|
+
+SM3XCE423Xols7onyluMYDy3MCUTFwoVMRBcRWCAk5gcv6XvZDfLi6Zwdne6x3Y
|
24
|
+
bGenr4vsPuSFsycM03/EcQDT
|
25
|
+
-----END CERTIFICATE-----
|
26
|
+
"""
|
27
|
+
end
|
28
|
+
let(:cert2_raw) do
|
29
|
+
"""-----BEGIN CERTIFICATE-----
|
30
|
+
MIIDhzCCAm+gAwIBAgIJAJnsrJ1+j9MhMA0GCSqGSIb3DQEBCwUAMD0xETAPBgNV
|
31
|
+
BAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDASBgNVBAMTC2N1a2Ut
|
32
|
+
bWFzdGVyMB4XDTE1MTAwNzE2MzAwM1oXDTI1MTAwNDE2MzAwM1owPTERMA8GA1UE
|
33
|
+
ChMIY3VjdW1iZXIxEjAQBgNVBAsTCUNvbmp1ciBDQTEUMBIGA1UEAxMLY3VrZS1t
|
34
|
+
YXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsuZ06Ld4JDhxZ
|
35
|
+
FcxKVxu7MTjXVv6W8pI7qFKmgr39aNqmDpKYJ1H9aM+r9zaTAeithpM4wJpVswkJ
|
36
|
+
d0RSuKdm1LOx11yHLyZ1OvlPHFhsVWdZIQZ6R9srhPYBUCMem4sHR5IAcBBX+HkR
|
37
|
+
35gaPYUl1uFV/9zCniekt92Kdta+it1WL7XinXTBURlhDawiD/kv1C9x6dICEJVe
|
38
|
+
IT/jRohmqHAoM/JSOQTthaDli3Qvu5K8XAx8UXvWVmv3eStZFVDbC4ZEueRd9KAe
|
39
|
+
4IZ5FxdpFYkPBgt2lBYeydYKRShyYrDKye1uJBDkeplNaYW4cS4mOhYuRkdKn7MH
|
40
|
+
uY/xb1lFAgMBAAGjgYkwgYYwKQYDVR0RBCIwIIILY3VrZS1tYXN0ZXKCCWxvY2Fs
|
41
|
+
aG9zdIIGY29uanVyMB0GA1UdDgQWBBRHpGF7aQbHdORYgQKDC2hV6NzEKzAfBgNV
|
42
|
+
HSMEGDAWgBRHpGF7aQbHdORYgQKDC2hV6NzEKzAMBgNVHRMEBTADAQH/MAsGA1Ud
|
43
|
+
DwQEAwIB5jANBgkqhkiG9w0BAQsFAAOCAQEAGZT9Wek1hYluIVaxu03wSKCKIJ4p
|
44
|
+
KxTHw+mLDapg1y9t3Fa/5IQQK0Bx0xGU2qWiQKjda3vdFPJWO6l6XJvsUY5Nwtm5
|
45
|
+
Gcsk8l3L/zWCrjrFTH3TdVad5E+DTwVhThelmEjw68AyM+WuOL61j0MItd9mLW74
|
46
|
+
Lv2zouj9nQBdnUBHWQ0EL/9d5cfaCVu/bFlDfYt7Yj0IzXCuaWZfJeHodU1hmqVX
|
47
|
+
BvYRjnTB2LSxfmSnkrCeFPmhE11bWVtsLIdrGIgtEMX0/s9xg58QuNnva1U3pJsW
|
48
|
+
RjvSxre4Xg2qlI9Laybb4oZ4g6DI8hRbL0VdFAsveg6SXg2RxgJcXeJUFw==
|
49
|
+
-----END CERTIFICATE-----
|
50
|
+
"""
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:cert1) { OpenSSL::X509::Certificate.new cert1_raw }
|
54
|
+
let(:cert2) { OpenSSL::X509::Certificate.new cert2_raw }
|
55
|
+
|
56
|
+
it 'parses a certificate' do
|
57
|
+
expect(Conjur::CertUtils.parse_certs(cert1_raw).map(&:to_der))\
|
58
|
+
.to eq [cert1.to_der]
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'parses two certificates' do
|
62
|
+
expect(Conjur::CertUtils.parse_certs(cert1_raw + cert2_raw).map(&:to_der))\
|
63
|
+
.to eq [cert1.to_der, cert2.to_der]
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'parses the certificate correctly even if the whitespace is wrong' do
|
67
|
+
bad_whitespace = cert1_raw.gsub "\n", " "
|
68
|
+
expect(Conjur::CertUtils.parse_certs(bad_whitespace).map(&:to_der))\
|
69
|
+
.to eq [cert1.to_der]
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'shows a bad cert in error message' do
|
73
|
+
bad_cert = "-----BEGIN CERTIFICATE-----\nfoo\n-----END CERTIFICATE-----\n"
|
74
|
+
expect do
|
75
|
+
Conjur::CertUtils.parse_certs(bad_cert)
|
76
|
+
end.to raise_error(OpenSSL::X509::CertificateError) do |exn|
|
77
|
+
expect(exn.message).to include bad_cert
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '.add_chained_cert' do
|
83
|
+
let(:one_certificate_chain) do
|
84
|
+
"""-----BEGIN CERTIFICATE-----
|
85
|
+
MIIDPjCCAiagAwIBAgIVAKW1gdmOFrXt6xB0iQmYQ4z8Pf+kMA0GCSqGSIb3DQEB
|
86
|
+
CwUAMD0xETAPBgNVBAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDAS
|
87
|
+
BgNVBAMTC2N1a2UtbWFzdGVyMB4XDTE1MTAwNzE2MzAwNloXDTI1MTAwNDE2MzAw
|
88
|
+
NlowFjEUMBIGA1UEAwwLY3VrZS1tYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
89
|
+
DwAwggEKAoIBAQC9e8bGIHOLOypKA4lsLcAOcDLAq+ICuVxn9Vg0No0m32Ok/K7G
|
90
|
+
uEGtlC8RidObntblUwqdX2uP7mqAQm19j78UTl1KT97vMmmFrpVZ7oQvEm1FUq3t
|
91
|
+
FBmJglthJrSbpdZjLf7a7eL1NnunkfBdI1DK9QL9ndMjNwZNFbXhld4fC5zuSr/L
|
92
|
+
PxawSzTEsoTaB0Nw0DdRowaZgrPxc0hQsrj9OF20gTIJIYO7ctZzE/JJchmBzgI4
|
93
|
+
CdfAYg7zNS+0oc0ylV0CWMerQtLICI6BtiQ482bCuGYJ00NlDcdjd3w+A2cj7PrH
|
94
|
+
wH5UhtORL5Q6i9EfGGUCDbmfpiVD9Bd3ukbXAgMBAAGjXDBaMA4GA1UdDwEB/wQE
|
95
|
+
AwIFoDAdBgNVHQ4EFgQU2jmj7l5rSw0yVb/vlWAYkK/YBwkwKQYDVR0RBCIwIIIL
|
96
|
+
Y3VrZS1tYXN0ZXKCCWxvY2FsaG9zdIIGY29uanVyMA0GCSqGSIb3DQEBCwUAA4IB
|
97
|
+
AQBCepy6If67+sjuVnT9NGBmjnVaLa11kgGNEB1BZQnvCy0IN7gpLpshoZevxYDR
|
98
|
+
3DnPAetQiZ70CSmCwjL4x6AVxQy59rRj0Awl9E1dgFTYI3JxxgLsI9ePdIRVEPnH
|
99
|
+
dhXqPY5ZIZhvdHlLStjsXX7laaclEtMeWfSzxe4AmP/Sm/er4ks0gvLQU6/XJNIu
|
100
|
+
RnRH59ZB1mZMsIv9Ii790nnioYFR54JmQu1JsIib77ZdSXIJmxAtraJSTLcZbU1E
|
101
|
+
+SM3XCE423Xols7onyluMYDy3MCUTFwoVMRBcRWCAk5gcv6XvZDfLi6Zwdne6x3Y
|
102
|
+
bGenr4vsPuSFsycM03/EcQDT
|
103
|
+
-----END CERTIFICATE-----
|
104
|
+
"""
|
105
|
+
end
|
106
|
+
|
107
|
+
let(:two_certificates_chain) do
|
108
|
+
"""-----BEGIN CERTIFICATE-----
|
109
|
+
MIIDPjCCAiagAwIBAgIVAKW1gdmOFrXt6xB0iQmYQ4z8Pf+kMA0GCSqGSIb3DQEB
|
110
|
+
CwUAMD0xETAPBgNVBAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDAS
|
111
|
+
BgNVBAMTC2N1a2UtbWFzdGVyMB4XDTE1MTAwNzE2MzAwNloXDTI1MTAwNDE2MzAw
|
112
|
+
NlowFjEUMBIGA1UEAwwLY3VrZS1tYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
113
|
+
DwAwggEKAoIBAQC9e8bGIHOLOypKA4lsLcAOcDLAq+ICuVxn9Vg0No0m32Ok/K7G
|
114
|
+
uEGtlC8RidObntblUwqdX2uP7mqAQm19j78UTl1KT97vMmmFrpVZ7oQvEm1FUq3t
|
115
|
+
FBmJglthJrSbpdZjLf7a7eL1NnunkfBdI1DK9QL9ndMjNwZNFbXhld4fC5zuSr/L
|
116
|
+
PxawSzTEsoTaB0Nw0DdRowaZgrPxc0hQsrj9OF20gTIJIYO7ctZzE/JJchmBzgI4
|
117
|
+
CdfAYg7zNS+0oc0ylV0CWMerQtLICI6BtiQ482bCuGYJ00NlDcdjd3w+A2cj7PrH
|
118
|
+
wH5UhtORL5Q6i9EfGGUCDbmfpiVD9Bd3ukbXAgMBAAGjXDBaMA4GA1UdDwEB/wQE
|
119
|
+
AwIFoDAdBgNVHQ4EFgQU2jmj7l5rSw0yVb/vlWAYkK/YBwkwKQYDVR0RBCIwIIIL
|
120
|
+
Y3VrZS1tYXN0ZXKCCWxvY2FsaG9zdIIGY29uanVyMA0GCSqGSIb3DQEBCwUAA4IB
|
121
|
+
AQBCepy6If67+sjuVnT9NGBmjnVaLa11kgGNEB1BZQnvCy0IN7gpLpshoZevxYDR
|
122
|
+
3DnPAetQiZ70CSmCwjL4x6AVxQy59rRj0Awl9E1dgFTYI3JxxgLsI9ePdIRVEPnH
|
123
|
+
dhXqPY5ZIZhvdHlLStjsXX7laaclEtMeWfSzxe4AmP/Sm/er4ks0gvLQU6/XJNIu
|
124
|
+
RnRH59ZB1mZMsIv9Ii790nnioYFR54JmQu1JsIib77ZdSXIJmxAtraJSTLcZbU1E
|
125
|
+
+SM3XCE423Xols7onyluMYDy3MCUTFwoVMRBcRWCAk5gcv6XvZDfLi6Zwdne6x3Y
|
126
|
+
bGenr4vsPuSFsycM03/EcQDT
|
127
|
+
-----END CERTIFICATE-----
|
128
|
+
-----BEGIN CERTIFICATE-----
|
129
|
+
MIIDhzCCAm+gAwIBAgIJAJnsrJ1+j9MhMA0GCSqGSIb3DQEBCwUAMD0xETAPBgNV
|
130
|
+
BAoTCGN1Y3VtYmVyMRIwEAYDVQQLEwlDb25qdXIgQ0ExFDASBgNVBAMTC2N1a2Ut
|
131
|
+
bWFzdGVyMB4XDTE1MTAwNzE2MzAwM1oXDTI1MTAwNDE2MzAwM1owPTERMA8GA1UE
|
132
|
+
ChMIY3VjdW1iZXIxEjAQBgNVBAsTCUNvbmp1ciBDQTEUMBIGA1UEAxMLY3VrZS1t
|
133
|
+
YXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsuZ06Ld4JDhxZ
|
134
|
+
FcxKVxu7MTjXVv6W8pI7qFKmgr39aNqmDpKYJ1H9aM+r9zaTAeithpM4wJpVswkJ
|
135
|
+
d0RSuKdm1LOx11yHLyZ1OvlPHFhsVWdZIQZ6R9srhPYBUCMem4sHR5IAcBBX+HkR
|
136
|
+
35gaPYUl1uFV/9zCniekt92Kdta+it1WL7XinXTBURlhDawiD/kv1C9x6dICEJVe
|
137
|
+
IT/jRohmqHAoM/JSOQTthaDli3Qvu5K8XAx8UXvWVmv3eStZFVDbC4ZEueRd9KAe
|
138
|
+
4IZ5FxdpFYkPBgt2lBYeydYKRShyYrDKye1uJBDkeplNaYW4cS4mOhYuRkdKn7MH
|
139
|
+
uY/xb1lFAgMBAAGjgYkwgYYwKQYDVR0RBCIwIIILY3VrZS1tYXN0ZXKCCWxvY2Fs
|
140
|
+
aG9zdIIGY29uanVyMB0GA1UdDgQWBBRHpGF7aQbHdORYgQKDC2hV6NzEKzAfBgNV
|
141
|
+
HSMEGDAWgBRHpGF7aQbHdORYgQKDC2hV6NzEKzAMBgNVHRMEBTADAQH/MAsGA1Ud
|
142
|
+
DwQEAwIB5jANBgkqhkiG9w0BAQsFAAOCAQEAGZT9Wek1hYluIVaxu03wSKCKIJ4p
|
143
|
+
KxTHw+mLDapg1y9t3Fa/5IQQK0Bx0xGU2qWiQKjda3vdFPJWO6l6XJvsUY5Nwtm5
|
144
|
+
Gcsk8l3L/zWCrjrFTH3TdVad5E+DTwVhThelmEjw68AyM+WuOL61j0MItd9mLW74
|
145
|
+
Lv2zouj9nQBdnUBHWQ0EL/9d5cfaCVu/bFlDfYt7Yj0IzXCuaWZfJeHodU1hmqVX
|
146
|
+
BvYRjnTB2LSxfmSnkrCeFPmhE11bWVtsLIdrGIgtEMX0/s9xg58QuNnva1U3pJsW
|
147
|
+
RjvSxre4Xg2qlI9Laybb4oZ4g6DI8hRbL0VdFAsveg6SXg2RxgJcXeJUFw==
|
148
|
+
-----END CERTIFICATE-----
|
149
|
+
"""
|
150
|
+
end
|
151
|
+
|
152
|
+
let(:store){ double('default store') }
|
153
|
+
|
154
|
+
context 'with one certificate in the chain' do
|
155
|
+
subject{ Conjur::CertUtils.add_chained_cert(store, one_certificate_chain) }
|
156
|
+
|
157
|
+
it 'adds one certificate to the store' do
|
158
|
+
expect(store).to receive(:add_cert).once
|
159
|
+
expect(subject).to be_truthy
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'with two certificate in the chain' do
|
164
|
+
subject{ Conjur::CertUtils.add_chained_cert(store, two_certificates_chain) }
|
165
|
+
|
166
|
+
it 'adds both certificate to the store' do
|
167
|
+
expect(store).to receive(:add_cert).twice
|
168
|
+
expect(subject).to be_truthy
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
end
|
data/spec/cidr_spec.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'conjur/cidr'
|
2
|
+
|
3
|
+
describe Conjur::CIDR do
|
4
|
+
def cidr addr
|
5
|
+
Conjur::CIDR.validate addr
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '.validate' do
|
9
|
+
it 'rejects malformed addresses' do
|
10
|
+
expect { Conjur::CIDR.validate '192.0.2.2/255.255.0.255' }.to raise_error ArgumentError
|
11
|
+
expect { Conjur::CIDR.validate '192.0.2.2/0.255.0.0' }.to raise_error ArgumentError
|
12
|
+
expect { Conjur::CIDR.validate '192.0.256.2' }.to raise_error ArgumentError
|
13
|
+
expect { Conjur::CIDR.validate '::/:ffff:' }.to raise_error ArgumentError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#prefixlen' do
|
18
|
+
it 'calculates prefix mask length' do
|
19
|
+
expected = {
|
20
|
+
'0.0.0.0/0' => 0,
|
21
|
+
'192.0.2.0/24' => 24,
|
22
|
+
'192.0.2.1' => 32,
|
23
|
+
'192.0.2.0/255.255.255.0' => 24,
|
24
|
+
'10.0.0.0/255.0.0.0' => 8,
|
25
|
+
'1234::/42' => 42,
|
26
|
+
'1234::/ffff::' => 16,
|
27
|
+
'::/::' => 0,
|
28
|
+
}
|
29
|
+
expected.each do |addr, len|
|
30
|
+
expect(Conjur::CIDR.validate(addr).prefixlen).to eq len
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|