conjur-api 4.22.1 → 4.23.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 112df80d0de58ed399d501948d9003abb1afcfb3
4
- data.tar.gz: 33d13ad37bfc43d7f69643eba261b5d6367513f7
3
+ metadata.gz: 91bb6f8e907814c4dd388fef05384202a9e51a29
4
+ data.tar.gz: 4884d67d8ec68a02fdbabe297edeb1e8d95a6d88
5
5
  SHA512:
6
- metadata.gz: 64162326b7b50d050f1b46ba398b2e356cc719b0fa1520c22c6da2007288e52afa7e48e493aae01c9da70a0b15180018a32ff56d40183a7bd1dc31ca439bdb44
7
- data.tar.gz: 54695910fe7b6e085111b7ffa52adb2e3b9b7ca07117d664debaf3439cb6d5d4aa63c0a9684e287257401fb9c1cb86651154c95dde53fbb3802866df564c508b
6
+ metadata.gz: 425b6e7ecbae6f9d79ee004a522ebe51d8ee091f452d3e6d30ff041a33dad04b15d33676b29179105e19f28b537be6325a0f951412a757236e07a1d03dee5954
7
+ data.tar.gz: a4fb4478261d5f9a677c19c2b8103e1f5a9a78015b36dcf17780a1c8288c43de3e3f854b26e1dde1f17c237bde971ac1d9cd1e2544b2fafd195ee10c798f9cdc
@@ -1,3 +1,11 @@
1
+ # v4.23.0
2
+
3
+ * Add `with_audit_roles` and `with_audit_resources` to `Conjur::API`
4
+ to add additional roles and resources to audit records generated by
5
+ requests
6
+
7
+ * Fix encoding of spaces in some urls.
8
+
1
9
  # v4.22.1
2
10
 
3
11
  * `bootstrap` creates host and webservice `conjur/expiration`.
@@ -28,6 +28,7 @@ Gem::Specification.new do |gem|
28
28
  gem.add_development_dependency 'rspec', '~> 3'
29
29
  gem.add_development_dependency 'rspec-expectations', '~> 3.4'
30
30
  gem.add_development_dependency 'webmock'
31
+ gem.add_development_dependency 'aruba', '~> 0.12.0'
31
32
  gem.add_development_dependency 'cucumber'
32
33
  gem.add_development_dependency 'conjur-cli'
33
34
  gem.add_development_dependency 'conjur-debify'
@@ -0,0 +1,15 @@
1
+ Feature: audit with additional resources
2
+
3
+ Background:
4
+ Given I create the variable "$ns_foo"
5
+
6
+ Scenario: with one additional resource
7
+ When I create an api with the additional audit resource "webservice:ws1"
8
+ And I check to see if I'm permitted to "read" variable "$ns_foo"
9
+ Then an audit event for variable "$ns_foo" with action "check" and resource "webservice:ws1" is generated
10
+
11
+ Scenario: with more than one additional resource
12
+ When I create an api with the additional audit resources "webservice:ws1, webservice:ws2"
13
+ And I check to see if I'm permitted to "read" variable "$ns_foo"
14
+ Then an audit event for variable "$ns_foo" with action "check" and resources "webservice:ws1, webservice:ws2" is generated
15
+
@@ -0,0 +1,15 @@
1
+ Feature: audit with additional resources
2
+
3
+ Background:
4
+ Given I create the variable "$ns_foo"
5
+
6
+ Scenario: with one additional resource
7
+ When I create an api with the additional audit role "user:auditor1"
8
+ And I check to see if I'm permitted to "read" variable "$ns_foo"
9
+ Then an audit event for variable "$ns_foo" with action "check" and role "user:auditor1" is generated
10
+
11
+ Scenario: with more than one additional resource
12
+ When I create an api with the additional audit roles "user:auditor2,group:auditors"
13
+ And I check to see if I'm permitted to "read" variable "$ns_foo"
14
+ Then an audit event for variable "$ns_foo" with action "check" and roles "user:auditor2,group:auditors" is generated
15
+
@@ -19,6 +19,39 @@ Then(/^expressions "([^"]*)" and "([^"]*)" are equal$/) do |code, test|
19
19
  expect(eval(code)).to eq(eval(test))
20
20
  end
21
21
 
22
+ Then(/^expression "(.*?)" is equal to$/) do |code, test|
23
+ step %Q{expressions "#{code}" and "#{test}" are equal}
24
+ end
25
+
22
26
  Then(/^expression "([^"]*)" includes "([^"]*)"$/) do |code, test|
23
27
  expect(eval(code)).to include(eval(test))
24
28
  end
29
+
30
+ Then(/^I evaluate the expression "([^"]*)"$/) do |code|
31
+ eval(code)
32
+ end
33
+
34
+ Then(/^I evaluate the expression$/) do |code|
35
+ step %Q{I evaluate the expression "#{code}"}
36
+ end
37
+
38
+ Then(/^I create the variable "(.*?)"$/) do |var|
39
+ api.create_variable('text/plain', 'secret', :id => var)
40
+ end
41
+
42
+ Then(/^I create an api with the additional audit (role|resource)[s]* "(.*?)"$/) do |type, things|
43
+ @api = api.send("with_audit_#{type}s", things.split(','))
44
+ end
45
+
46
+ Then(/^I check to see if I'm permitted to "(.*?)" variable "(.*?)"$/) do |priv, var|
47
+ api.variable(var).resource.permitted?(priv)
48
+ end
49
+
50
+ Then(/^an audit event for variable "(.*?)" with action "(.*?)" and (role|resource)[s]* "(.*?)" is generated$/) do |var, action, type, things|
51
+ resource_ids = things.split(',').collect {|id| api.resource(id).resourceid }
52
+ event_found = api.audit_resource(api.resource("variable:#{var}")).any? do |e|
53
+ e['action'] == action &&
54
+ Set.new(e["#{type}s"]).superset?(Set.new(resource_ids))
55
+ end
56
+ expect(event_found).to be true
57
+ end
@@ -0,0 +1,5 @@
1
+ Transform /\$ns/ do |s|
2
+ s.gsub('$ns', namespace)
3
+ end
4
+
5
+
@@ -1,3 +1,4 @@
1
+ require 'aruba/cucumber'
1
2
  require 'conjur/cli'
2
3
 
3
4
  Conjur::Config.load
@@ -0,0 +1,13 @@
1
+ module ApiWorld
2
+
3
+ def api
4
+ @api ||= Conjur::Authn.connect(nil, :noask => true)
5
+ end
6
+
7
+ def namespace
8
+ @namespace ||= api.create_variable('text/plain', 'id').id.tap {|ns| puts "namespace: #{ns}"}
9
+ end
10
+
11
+ end
12
+
13
+ World ApiWorld
data/jenkins.sh CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash -ex
2
2
 
3
- CONJUR_VERSION=${CONJUR_VERSION:-"4.6"}
3
+ CONJUR_VERSION=${CONJUR_VERSION:-"5.0"}
4
4
  DOCKER_IMAGE=${DOCKER_IMAGE:-"registry.tld/conjur-appliance-cuke-master:$CONJUR_VERSION-stable"}
5
5
  NOKILL=${NOKILL:-"0"}
6
6
  PULL=${PULL:-"1"}
@@ -19,6 +19,6 @@
19
19
 
20
20
  module Conjur
21
21
  class API
22
- VERSION = "4.22.1"
22
+ VERSION = "4.23.0"
23
23
  end
24
24
  end
@@ -97,11 +97,10 @@ class RestClient::Resource
97
97
  # @return {Conjur::API} the new api
98
98
  def conjur_api
99
99
  api = Conjur::API.new_from_token token, remote_ip
100
- if conjur_privilege
101
- api.with_privilege conjur_privilege
102
- else
103
- api
104
- end
100
+ api = api.with_privilege(conjur_privilege) if conjur_privilege
101
+ api = api.with_audit_roles(audit_roles) if audit_roles
102
+ api = api.with_audit_resources(audit_resources) if audit_resources
103
+ api
105
104
  end
106
105
 
107
106
  # Get an authentication token from the clients Authorization header.
@@ -129,6 +128,14 @@ class RestClient::Resource
129
128
  options[:headers][:x_conjur_privilege]
130
129
  end
131
130
 
131
+ def audit_roles
132
+ options[:headers][:conjur_audit_roles].try { |r| Conjur::API.decode_audit_ids(r) }
133
+ end
134
+
135
+ def audit_resources
136
+ options[:headers][:conjur_audit_resources].try { |r| Conjur::API.decode_audit_ids(r) }
137
+ end
138
+
132
139
  # The username this resource authenticates as.
133
140
  #
134
141
  # @return [String] the username
@@ -141,6 +141,15 @@ module Conjur
141
141
  def new_from_token(token, remote_ip = nil)
142
142
  self.new nil, nil, token, remote_ip
143
143
  end
144
+
145
+ def encode_audit_ids(ids)
146
+ ids.collect{|id| CGI::escape(id)}.join('&')
147
+ end
148
+
149
+ def decode_audit_ids(ids)
150
+ ids.split('&').collect{|id| CGI::unescape(id)}
151
+ end
152
+
144
153
  end
145
154
 
146
155
  # Create a new instance from a username and api key or a token.
@@ -179,6 +188,16 @@ module Conjur
179
188
  # The optional global privilege (e.g. 'elevate' or 'reveal') which should be attempted on the request.
180
189
  attr_accessor :privilege
181
190
 
191
+ #@!attribute [rw] audit_roles
192
+ # An array of role ids that should be included in any audit
193
+ # records generated by requsts made by this instance of the api.
194
+ attr_accessor :audit_roles
195
+
196
+ #@!attribute [rw] audit_resources
197
+ # An array of resource ids that should be included in any audit
198
+ # records generated by requsts made by this instance of the api.
199
+ attr_accessor :audit_resources
200
+
182
201
  # The name of the user as which this api instance is authenticated. This is available whether the api
183
202
  # instance was created from credentials or an authentication token.
184
203
  #
@@ -233,6 +252,8 @@ module Conjur
233
252
  h[:authorization] = "Token token=\"#{Base64.strict_encode64 token.to_json}\""
234
253
  h[:x_conjur_privilege] = @privilege if @privilege
235
254
  h[:x_forwarded_for] = @remote_ip if @remote_ip
255
+ h[:conjur_audit_roles] = Conjur::API.encode_audit_ids(@audit_roles) if @audit_roles
256
+ h[:conjur_audit_resources] = Conjur::API.encode_audit_ids(@audit_resources) if @audit_resources
236
257
  end
237
258
  { headers: headers, username: username }
238
259
  end
@@ -245,7 +266,23 @@ module Conjur
245
266
  api.privilege = privilege
246
267
  end
247
268
  end
248
-
269
+
270
+ def with_audit_roles role_ids
271
+ role_ids = Array(role_ids)
272
+ self.class.new(username, api_key, token, remote_ip).tap do |api|
273
+ # Ensure that all role ids are fully qualified
274
+ api.audit_roles = role_ids.collect { |id| api.role(id).roleid }
275
+ end
276
+ end
277
+
278
+ def with_audit_resources resource_ids
279
+ resource_ids = Array(resource_ids)
280
+ self.class.new(username, api_key, token, remote_ip).tap do |api|
281
+ # Ensure that all resource ids are fully qualified
282
+ api.audit_resources = resource_ids.collect { |id| api.resource(id).resourceid }
283
+ end
284
+ end
285
+
249
286
  private
250
287
 
251
288
  def token_valid?
@@ -31,13 +31,19 @@ module Conjur
31
31
  # fully_escape 'foo/bar@baz'
32
32
  # # => "foo%2Fbar%40baz"
33
33
  #
34
+ # @example
35
+ # fully_escape 'test/Domain Controllers'
36
+ # # => "test%2FDomain%20Controllers"
37
+ #
34
38
  # @param [String] str the string to escape
35
39
  # @return [String] the escaped string
36
40
  def fully_escape(str)
37
- require 'cgi'
38
- CGI.escape(str.to_s)
41
+ # CGI escape uses + for spaces, which our services don't support :-(
42
+ # We just gsub it.
43
+ CGI.escape(str.to_s).gsub('+', '%20')
39
44
  end
40
45
 
46
+
41
47
  # Escape a URI path component.
42
48
  #
43
49
  # This method simply calls {Conjur::Escape::ClassMethods#path_or_query_escape}.
@@ -121,4 +127,4 @@ module Conjur
121
127
  self.class.query_escape str
122
128
  end
123
129
  end
124
- end
130
+ end
@@ -260,6 +260,7 @@ describe Conjur::API do
260
260
  end
261
261
  end
262
262
  end
263
+
263
264
 
264
265
  context "from api key", logged_in: true do
265
266
  let(:api_key) { "theapikey" }
@@ -299,38 +300,67 @@ describe Conjur::API do
299
300
  end
300
301
 
301
302
  context "from logged-in RestClient::Resource" do
303
+ let (:authz_header) { %Q{Token token="#{token_encoded}"} }
304
+ let (:priv_header) { nil }
305
+ let (:forwarded_for_header) { nil }
306
+ let (:audit_roles_header) { nil }
307
+ let (:audit_resources_header) { nil }
308
+ let (:username) { 'bob' }
309
+ subject { resource.conjur_api }
310
+
311
+ shared_examples "it can clone itself" do
312
+ it "has the authz header" do
313
+ expect(subject.credentials[:headers][:authorization]).to eq(authz_header)
314
+ end
315
+ it "has the conjur privilege header" do
316
+ expect(subject.credentials[:headers][:x_conjur_privilege]).to eq(priv_header)
317
+ end
318
+ it "has the forwarded for header" do
319
+ expect(subject.credentials[:headers][:x_forwarded_for]).to eq(forwarded_for_header)
320
+ end
321
+ it "has the audit_roles header" do
322
+ expect(subject.credentials[:headers][:conjur_audit_roles]).to eq(audit_roles_header)
323
+ end
324
+ it "has the audit_resources header" do
325
+ expect(subject.credentials[:headers][:conjur_audit_resources]).to eq(audit_resources_header)
326
+ end
327
+ it "has the username" do
328
+ expect(subject.credentials[:username]).to eq(username)
329
+ end
330
+ end
331
+
302
332
  let(:token_encoded) { Base64.strict_encode64(token.to_json) }
303
- let(:headers) { { authorization: "Token token=\"#{token_encoded}\"" } }
333
+ let(:base_headers) { { authorization: authz_header } }
334
+ let(:headers) { base_headers }
304
335
  let(:resource) { RestClient::Resource.new("http://example.com", { headers: headers })}
305
- it "can construct a new API instance" do
306
- api = resource.conjur_api
307
- expect(api.credentials[:headers][:authorization]).to eq("Token token=\"#{token_encoded}\"")
308
- expect(api.credentials[:headers][:x_conjur_privilege]).to be_nil
309
- expect(api.credentials[:headers][:x_forwarded_for]).to be_nil
310
- expect(api.credentials[:username]).to eq("bob")
336
+ context 'basic functioning' do
337
+ it_behaves_like 'it can clone itself'
311
338
  end
312
339
 
313
340
  context "privileged" do
314
- let(:headers) { { authorization: "Token token=\"#{token_encoded}\"", x_conjur_privilege: "elevate" } }
315
- it "can clone itself" do
316
- api = resource.conjur_api
317
- expect(api.credentials[:headers][:authorization]).to eq("Token token=\"#{token_encoded}\"")
318
- expect(api.credentials[:headers][:x_conjur_privilege]).to eq("elevate")
319
- expect(api.credentials[:headers][:x_forwarded_for]).to be_nil
320
- expect(api.credentials[:username]).to eq("bob")
321
- end
341
+ let(:priv_header) { 'elevate' }
342
+ let(:headers) { base_headers.merge(x_conjur_privilege: priv_header) }
343
+ it_behaves_like "it can clone itself"
322
344
  end
323
345
 
324
- context "privileged" do
325
- let(:headers) { { authorization: "Token token=\"#{token_encoded}\"", x_forwarded_for: "66.0.0.1" } }
326
- it "can clone itself" do
327
- api = resource.conjur_api
328
- expect(api.credentials[:headers][:authorization]).to eq("Token token=\"#{token_encoded}\"")
329
- expect(api.credentials[:headers][:x_conjur_privilege]).to be_nil
330
- expect(api.credentials[:headers][:x_forwarded_for]).to eq("66.0.0.1")
331
- expect(api.credentials[:username]).to eq("bob")
332
- end
346
+ context "forwarded for" do
347
+ let(:forwarded_for_header) { "66.0.0.1" }
348
+ let(:headers) { base_headers.merge(x_forwarded_for: forwarded_for_header) }
349
+ it_behaves_like 'it can clone itself'
350
+ end
351
+
352
+ context "audit roles" do
353
+ let(:audit_roles_header) { Conjur::API.encode_audit_ids(['account:kind:role1', 'account:kind:role2']) }
354
+ let(:headers) { base_headers.merge(:conjur_audit_roles => audit_roles_header) }
355
+ it_behaves_like 'it can clone itself'
356
+ end
357
+
358
+ context "audit resources" do
359
+ let(:audit_resources_header) { Conjur::API.encode_audit_ids(['account:kind:resource1', 'account:kind:resource2']) }
360
+ let(:headers) { base_headers.merge(:conjur_audit_resources => audit_resources_header) }
361
+ it_behaves_like 'it can clone itself'
333
362
  end
363
+
334
364
  end
335
365
  end
336
366
 
@@ -360,4 +390,21 @@ describe Conjur::API do
360
390
  end
361
391
  end
362
392
  end
393
+
394
+ describe 'url escapes' do
395
+ let(:urls){[
396
+ 'foo/bar@baz',
397
+ '/test/some group with spaces'
398
+ ]}
399
+
400
+ describe '#fully_escape' do
401
+ let(:expected){[
402
+ 'foo%2Fbar%40baz',
403
+ '%2Ftest%2Fsome%20group%20with%20spaces'
404
+ ]}
405
+ it 'escapes the urls correctly' do
406
+ expect(urls.map{|u| Conjur::API.fully_escape u}).to eq(expected)
407
+ end
408
+ end
409
+ end
363
410
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conjur-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.22.1
4
+ version: 4.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafal Rzepecki
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-13 00:00:00.000000000 Z
12
+ date: 2016-04-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
@@ -129,6 +129,20 @@ dependencies:
129
129
  - - '>='
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
+ - !ruby/object:Gem::Dependency
133
+ name: aruba
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: 0.12.0
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: 0.12.0
132
146
  - !ruby/object:Gem::Dependency
133
147
  name: cucumber
134
148
  requirement: !ruby/object:Gem::Requirement
@@ -323,9 +337,13 @@ files:
323
337
  - Rakefile
324
338
  - ci/test.sh
325
339
  - conjur-api.gemspec
340
+ - features/audit_resources.feature
341
+ - features/audit_roles.feature
326
342
  - features/bootstrap.feature
327
343
  - features/step_definitions/api_steps.rb
344
+ - features/step_definitions/cli_steps.rb
328
345
  - features/support/env.rb
346
+ - features/support/world.rb
329
347
  - jenkins.sh
330
348
  - lib/conjur-api.rb
331
349
  - lib/conjur-api/version.rb
@@ -459,9 +477,13 @@ signing_key:
459
477
  specification_version: 4
460
478
  summary: Conjur API
461
479
  test_files:
480
+ - features/audit_resources.feature
481
+ - features/audit_roles.feature
462
482
  - features/bootstrap.feature
463
483
  - features/step_definitions/api_steps.rb
484
+ - features/step_definitions/cli_steps.rb
464
485
  - features/support/env.rb
486
+ - features/support/world.rb
465
487
  - spec/api/authn_spec.rb
466
488
  - spec/api/graph_spec.rb
467
489
  - spec/api/groups_spec.rb