conjur-api 2.4.0 → 2.5.1

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