conjur-api 2.4.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/.gitignore +2 -0
  2. data/LICENSE +1 -1
  3. data/Rakefile +3 -1
  4. data/conjur-api.gemspec +3 -1
  5. data/lib/conjur-api/version.rb +1 -1
  6. data/lib/conjur/has_id.rb +1 -1
  7. data/lib/conjur/log.rb +6 -26
  8. data/lib/conjur/resource.rb +10 -1
  9. data/manual/asset/about.markdown +12 -0
  10. data/manual/asset/members.add.markdown +52 -0
  11. data/manual/asset/show.markdown +50 -0
  12. data/manual/group/about.markdown +6 -0
  13. data/manual/group/create.markdown +20 -0
  14. data/manual/host/about.markdown +23 -0
  15. data/manual/host/create.markdown +34 -0
  16. data/manual/host/enroll.markdown +21 -0
  17. data/manual/resource/about.markdown +11 -0
  18. data/manual/resource/create.markdown +29 -0
  19. data/manual/resource/deny.markdown +23 -0
  20. data/manual/resource/permit.markdown +35 -0
  21. data/manual/role/about.markdown +10 -0
  22. data/manual/role/members.markdown +40 -0
  23. data/manual/role/memberships.markdown +26 -0
  24. data/spec/api/authn_spec.rb +49 -0
  25. data/spec/api/groups_spec.rb +24 -0
  26. data/spec/api/hosts_spec.rb +29 -0
  27. data/spec/api/resources_spec.rb +19 -0
  28. data/spec/api/secrets_spec.rb +16 -0
  29. data/spec/api/users_spec.rb +16 -0
  30. data/spec/api/variables_spec.rb +14 -0
  31. data/spec/cas_rest_client.rb +17 -0
  32. data/spec/io_helper.rb +18 -0
  33. data/spec/lib/build_from_response_spec.rb +49 -0
  34. data/spec/lib/host_spec.rb +12 -8
  35. data/spec/lib/log_source_spec.rb +13 -0
  36. data/spec/lib/log_spec.rb +42 -0
  37. data/spec/lib/resource_spec.rb +98 -5
  38. data/spec/lib/role_grant_spec.rb +12 -0
  39. data/spec/lib/role_spec.rb +83 -3
  40. data/spec/lib/standard_methods_spec.rb +66 -0
  41. data/spec/lib/user_spec.rb +2 -1
  42. data/spec/spec_helper.rb +27 -0
  43. data/spec/standard_methods_helper.rb +30 -0
  44. data/spec/variable_spec.rb +41 -0
  45. metadata +71 -8
  46. data/.rvmrc +0 -1
@@ -0,0 +1,10 @@
1
+ Role
2
+ ====
3
+
4
+ A role is a target to which permissions are assigned. Permitting an action on a resource by a role enables the role to perform
5
+ the specified action.
6
+
7
+ In addition, roles can be "granted to" other roles. When role "A" is granted to role "B", role "B" gains the ability to perform
8
+ all the actions permitted to "A". In addition, a role can be granted with "grant option". When role "A" is granted to role "B" with
9
+ grant option, role "B" can in turn grant role "A" to other roles.
10
+
@@ -0,0 +1,40 @@
1
+ Role#members
2
+ ============
3
+
4
+ Lists the roles that have been the recipient of a role grant. The creator of the role is always a role member.
5
+
6
+ If role "A" is created by user "U" and then granted to roles "B" and "C", then the members of role "A" are [ "U", "B", "C" ].
7
+
8
+ Examples
9
+ --------
10
+
11
+ ### Command Line
12
+
13
+ #### Add a role member and list the members
14
+
15
+ ```bash
16
+ $ conjur role:create test:`conjur id:create`
17
+ Created https://authz-v3-conjur.herokuapp.com/sandbox/roles/test/2y1300
18
+ $ conjur role:members test:2y1300
19
+ [
20
+ "sandbox:user:kgilpin"
21
+ ]
22
+ $ conjur host:create
23
+ {
24
+ "id": "w43699",
25
+ <snip>
26
+ }
27
+ $ conjur role:grant_to test:2y1300 host:w43699
28
+ Role granted
29
+ $ conjur role:members test:2y1300
30
+ [
31
+ "sandbox:user:kgilpin",
32
+ "sandbox:host:w43699"
33
+ ]
34
+ ```
35
+
36
+ #### The role argument is optional and defaults to the current role
37
+
38
+ ```bash
39
+ $ conjur role:members
40
+ ```
@@ -0,0 +1,26 @@
1
+ Role#memberships
2
+ ================
3
+
4
+ List the roles that a role has been granted, transitively.
5
+
6
+ If role "A" is granted to role "B" which is granted to role "C", then the memberships of role "C" are [ "C", "B", "A" ].
7
+
8
+ Examples
9
+ --------
10
+
11
+ ### Command Line
12
+
13
+ ```bash
14
+ $ ns=`conjur id:create`
15
+ $ conjur role:create test:$ns/A
16
+ $ conjur role:create test:$ns/B
17
+ $ conjur role:create test:$ns/C
18
+ $ conjur role:grant_to test:$ns/A test:$ns/B
19
+ $ conjur role:grant_to test:$ns/B test:$ns/C
20
+ $ conjur role:memberships test:$ns/C
21
+ [
22
+ "sandbox:test:dy7mg0/C",
23
+ "sandbox:test:dy7mg0/B",
24
+ "sandbox:test:dy7mg0/A"
25
+ ]
26
+ ```
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'cas_rest_client'
3
+
4
+ describe Conjur::API do
5
+ let(:host) { 'http://authn.example.com' }
6
+ let(:user) { 'kmitnick' }
7
+ let(:password) { 'sikret' }
8
+
9
+ before do
10
+ Conjur::Authn::API.stub host: host
11
+ end
12
+
13
+ describe "::login" do
14
+ it "gets /users/login" do
15
+ RestClient::Request.should_receive(:execute).with(
16
+ method: :get, url: "http://authn.example.com/users/login", user: user,
17
+ password: password, headers: {}
18
+ ).and_return(response = double)
19
+ Conjur::API::login(user, password).should == response
20
+ end
21
+ end
22
+
23
+ describe "::login_cas" do
24
+ let(:response) { "response body" }
25
+ let(:cas_uri) { 'http://cas.example.com' }
26
+
27
+ it "uses CasRestClient to authenticate" do
28
+ stub_const 'CasRestClient', MockCasRestClient.new(double("response", body: response))
29
+ Conjur::API.login_cas(user, password, cas_uri).should == response
30
+ CasRestClient.options.should == {
31
+ username: user,
32
+ password: password,
33
+ uri: "http://cas.example.com/v1/tickets",
34
+ use_cookies: false
35
+ }
36
+ CasRestClient.url.should == "http://authn.example.com/users/login"
37
+ end
38
+ end
39
+
40
+ describe "::authenticate" do
41
+ it "posts the password and dejsons the result" do
42
+ RestClient::Request.should_receive(:execute).with(
43
+ method: :post, url: "http://authn.example.com/users/#{user}/authenticate",
44
+ payload: password, headers: { content_type: 'text/plain' }
45
+ ).and_return '{ "response": "foo"}'
46
+ Conjur::API.authenticate(user, password).should == { 'response' => 'foo' }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'standard_methods_helper'
3
+
4
+ describe Conjur::API, api: :dummy do
5
+ subject { api }
6
+
7
+ describe '#groups' do
8
+ it_should_behave_like 'standard_list with', :group, :options do
9
+ let(:invoke) { subject.groups :options }
10
+ end
11
+ end
12
+
13
+ describe '#create_group' do
14
+ it_should_behave_like 'standard_create with', :group, :id, :options do
15
+ let(:invoke) { subject.create_group :id, :options }
16
+ end
17
+ end
18
+
19
+ describe '#group' do
20
+ it_should_behave_like 'standard_show with', :group, :id do
21
+ let(:invoke) { subject.group :id }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'standard_methods_helper'
3
+
4
+ describe Conjur::API, api: :dummy do
5
+ describe '::enroll_host' do
6
+ it "uses Net::HTTP to get something" do
7
+ response = double "response",
8
+ code: '200', body: 'foobar'
9
+ response.stub(:[]).with('Content-Type').and_return 'text/whatever'
10
+
11
+ url = URI.parse "http://example.com"
12
+ Net::HTTP.stub(:get_response).with(url).and_return response
13
+
14
+ Conjur::API.enroll_host("http://example.com").should == ['text/whatever', 'foobar']
15
+ end
16
+ end
17
+
18
+ describe '#create_host' do
19
+ it_should_behave_like "standard_create with", :host, nil, :options do
20
+ let(:invoke) { subject.create_host :options }
21
+ end
22
+ end
23
+
24
+ describe '#host' do
25
+ it_should_behave_like "standard_show with", :host, :id do
26
+ let(:invoke) { subject.host :id }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::API, api: :dummy do
4
+ describe '#create_resource' do
5
+ it "passes to resource#create" do
6
+ api.stub(:resource).with(:id).and_return(resource = double)
7
+ resource.should_receive :create
8
+
9
+ api.create_resource(:id).should == resource
10
+ end
11
+ end
12
+
13
+ describe '#resource' do
14
+ it "builds a path and creates a resource from it" do
15
+ res = api.resource "some-account:a-kind:the-id"
16
+ res.url.should == "#{authz_host}/some-account/resources/a-kind/the-id"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'standard_methods_helper'
3
+
4
+ describe Conjur::API, api: :dummy do
5
+ describe '#create_secret' do
6
+ it_should_behave_like 'standard_create with', :secret, nil, value: 'val' do
7
+ let(:invoke) { api.create_secret 'val' }
8
+ end
9
+ end
10
+
11
+ describe '#secret' do
12
+ it_should_behave_like 'standard_show with', :secret, :id do
13
+ let(:invoke) { api.secret :id }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'standard_methods_helper'
3
+
4
+ describe Conjur::API, api: :dummy do
5
+ describe '#create_user' do
6
+ it_should_behave_like 'standard_create with', :user, nil, login: 'login', other: true do
7
+ let(:invoke) { api.create_user 'login', other: true }
8
+ end
9
+ end
10
+
11
+ describe '#user' do
12
+ it_should_behave_like 'standard_show with', :user, :login do
13
+ let(:invoke) { api.user :login }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'standard_methods_helper'
3
+
4
+ describe Conjur::API, api: :dummy do
5
+ describe '#create_variable' do
6
+ let(:invoke) { api.create_variable :type, :kind, other: true }
7
+ it_should_behave_like 'standard_create with', :variable, nil, mime_type: :type, kind: :kind, other: true
8
+ end
9
+
10
+ describe '#variable' do
11
+ let(:invoke) { api.variable :id }
12
+ it_should_behave_like 'standard_show with', :variable, :id
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ class MockCasRestClient
2
+ def initialize response
3
+ @response = response
4
+ end
5
+
6
+ def new options
7
+ @options = options
8
+ self
9
+ end
10
+
11
+ def get url
12
+ @url = url
13
+ @response
14
+ end
15
+
16
+ attr_reader :options, :url
17
+ end
data/spec/io_helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ class IO
2
+ def grab &block
3
+ @grabbed_output = ""
4
+ class << self
5
+ def write arg
6
+ @grabbed_output += arg
7
+ end
8
+ end
9
+
10
+ begin
11
+ yield
12
+ ensure
13
+ singleton_class.send :remove_method, :write
14
+ end
15
+
16
+ @grabbed_output
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Conjur::BuildFromResponse do
4
+ describe "::build_from_response", logging: :temp do
5
+ let(:location) { "http://example.com" }
6
+ let(:attrs) {{ 'some' => 'foo', 'other' => 'bar' }}
7
+ let(:response) do
8
+ double "response", headers: { location: location }, body: attrs.to_json
9
+ end
10
+ subject { double "class", name: 'some' }
11
+ let(:constructed) { double "object" }
12
+ let(:credentials) { "whatever" }
13
+
14
+ before do
15
+ subject.extend Conjur::BuildFromResponse
16
+ subject.should_receive(:new).with(location, credentials).and_return constructed
17
+ constructed.should_receive(:attributes=).with attrs
18
+
19
+ constructed.extend Conjur::LogSource
20
+ constructed.stub username: 'whatever'
21
+ end
22
+
23
+ it "passes the location credentials and attributes" do
24
+ subject.build_from_response response, credentials
25
+ end
26
+
27
+ context "with a resource(-ish) class" do
28
+ before do
29
+ constructed.stub resource_kind: 'chunky', resource_id: 'bacon'
30
+ end
31
+
32
+ it "logs creation correctly" do
33
+ subject.build_from_response response, credentials
34
+ log.should =~ /Created chunky bacon/
35
+ end
36
+ end
37
+
38
+ context "with a id(-ish) class" do
39
+ before do
40
+ constructed.stub id: 'bacon'
41
+ end
42
+
43
+ it "logs creation correctly" do
44
+ subject.build_from_response response, credentials
45
+ log.should =~ /Created some bacon/
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,14 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Conjur::Host do
4
- let(:login) { 'the-login' }
5
- let(:api_key) { 'the-api-key' }
6
- let(:credentials) { { user: login, password: api_key } }
7
- let(:account) { 'test-account' }
3
+ describe Conjur::Host, api: :dummy do
4
+ subject { Conjur::Host.new 'http://example.com/hosts/my/hostname', nil }
8
5
 
9
- before { Conjur::Core::API.stub conjur_account: account }
6
+ its(:resource) { should be }
7
+ its(:login) { should == 'host/my/hostname' }
10
8
 
11
- subject { Conjur::Host.new 'hostname', credentials }
9
+ let(:api_key) { 'theapikey' }
10
+ before { subject.attributes = { 'api_key' => api_key } }
11
+ its(:api_key) { should == api_key }
12
12
 
13
- its(:resource) { should be }
13
+ it "fetches enrollment_url" do
14
+ stub_request(:head, "http://example.com/hosts/my/hostname/enrollment_url").
15
+ to_return(:status => 200, :headers => {location: 'foo'})
16
+ subject.enrollment_url.should == 'foo'
17
+ end
14
18
  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
+ log.should == "[#{username}] foo\n"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'io_helper'
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
+ Conjur.stub(:create_log).with(:param).and_return log
11
+ Conjur::log = :param
12
+ Conjur::log.should == 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
+ STDOUT.grab { log << "foo" }.should == '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
+ STDERR.grab { log << "foo" }.should == '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
+ tempfile.read.should == "foo"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,13 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Conjur::Resource do
3
+ describe Conjur::Resource, api: :dummy, logging: :temp do
4
4
  let(:account) { "the-account" }
5
5
  let(:uuid) { "ddd1f59a-494d-48fb-b045-0374c4a6eef9" }
6
-
6
+
7
7
  context "identifier" do
8
8
  include Conjur::Escape
9
9
  let(:resource) { Conjur::Resource.new("#{Conjur::Authz::API.host}/#{account}/resources/#{kind}/#{path_escape identifier}") }
10
-
10
+
11
11
  context "Object with an #id" do
12
12
  let(:kind) { "host" }
13
13
  let(:identifier) do
@@ -17,7 +17,7 @@ describe Conjur::Resource do
17
17
  resource.identifier.should == "foobar"
18
18
  end
19
19
  end
20
-
20
+
21
21
  [ [ "foo", "bar/baz" ], [ "f:o", "bar" ], [ "@f", "bar.baz" ], [ "@f", "bar baz" ], [ "@f", "@:bar/baz" ] ].each do |p|
22
22
  context "of /#{p[0]}/#{p[1]}" do
23
23
  let(:kind) { p[0] }
@@ -33,4 +33,97 @@ describe Conjur::Resource do
33
33
  end
34
34
  end
35
35
  end
36
- end
36
+
37
+ let(:uri) { "#{authz_host}/some-account/resources/the-kind/resource-id" }
38
+ subject { Conjur::Resource.new uri }
39
+
40
+ describe '#create' do
41
+ it "simply puts" do
42
+ RestClient::Request.should_receive(:execute).with(
43
+ method: :put,
44
+ url: uri,
45
+ payload: {},
46
+ headers: {}
47
+ ).and_return "new resource"
48
+ subject.create.should == "new resource"
49
+ end
50
+ end
51
+
52
+ describe '#permitted_roles' do
53
+ it 'gets the list from /roles/allowed_to' do
54
+ RestClient::Request.should_receive(:execute).with(
55
+ method: :get,
56
+ url: "http://authz.example.com/some-account/roles/allowed_to/nuke/the-kind/resource-id",
57
+ headers: {}
58
+ ).and_return '["foo", "bar"]'
59
+
60
+ subject.permitted_roles("nuke").should == ['foo', 'bar']
61
+ end
62
+ end
63
+
64
+ describe '#give_to' do
65
+ it "puts the owner field" do
66
+ RestClient::Request.should_receive(:execute).with(
67
+ method: :put,
68
+ url: uri,
69
+ payload: {owner: 'new-owner' },
70
+ headers: {}
71
+ )
72
+
73
+ subject.give_to 'new-owner'
74
+ end
75
+ end
76
+
77
+ describe '#delete' do
78
+ it 'simply deletes' do
79
+ RestClient::Request.should_receive(:execute).with(
80
+ method: :delete,
81
+ url: uri,
82
+ headers: {}
83
+ )
84
+
85
+ subject.delete
86
+ end
87
+ end
88
+
89
+ describe '#permit' do
90
+ it 'posts permit for every privilege' do
91
+ privileges = [:nuke, :fry]
92
+ privileges.each do |p|
93
+ RestClient::Request.should_receive(:execute).with(
94
+ method: :post,
95
+ url: uri + "/?permit&privilege=#{p}&role=dr-strangelove",
96
+ headers: {},
97
+ payload: {}
98
+ )
99
+ end
100
+ subject.permit privileges, "dr-strangelove"
101
+ end
102
+ end
103
+
104
+ describe '#deny' do
105
+ it 'posts deny for every privilege' do
106
+ privileges = [:nuke, :fry]
107
+ privileges.each do |p|
108
+ RestClient::Request.should_receive(:execute).with(
109
+ method: :post,
110
+ url: uri + "/?deny&privilege=#{p}&role=james-bond",
111
+ headers: {},
112
+ payload: {}
113
+ )
114
+ end
115
+ subject.deny privileges, "james-bond"
116
+ end
117
+ end
118
+
119
+ describe '#permitted?' do
120
+ it 'gets the ?permitted? action' do
121
+ RestClient::Request.should_receive(:execute).with(
122
+ method: :get,
123
+ url: uri + "/?check&privilege=fry",
124
+ headers: {}
125
+ )
126
+ subject.permitted? 'fry'
127
+ end
128
+ end
129
+ end