conjur-api 2.0.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.
- data/.gitignore +18 -0
- data/.project +18 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +20 -0
- data/conjur-api.gemspec +28 -0
- data/features/enroll_server.feature +26 -0
- data/features/login.feature +13 -0
- data/features/ping_as_server.feature +16 -0
- data/features/ping_as_user.feature +9 -0
- data/lib/conjur-api/version.rb +5 -0
- data/lib/conjur/acts_as_resource.rb +21 -0
- data/lib/conjur/acts_as_role.rb +8 -0
- data/lib/conjur/acts_as_user.rb +13 -0
- data/lib/conjur/api.rb +22 -0
- data/lib/conjur/api/authn.rb +66 -0
- data/lib/conjur/api/das.rb +33 -0
- data/lib/conjur/api/groups.rb +18 -0
- data/lib/conjur/api/hosts.rb +37 -0
- data/lib/conjur/api/resources.rb +9 -0
- data/lib/conjur/api/roles.rb +18 -0
- data/lib/conjur/api/secrets.rb +23 -0
- data/lib/conjur/api/users.rb +23 -0
- data/lib/conjur/api/variables.rb +25 -0
- data/lib/conjur/authn-api.rb +22 -0
- data/lib/conjur/authz-api.rb +23 -0
- data/lib/conjur/base.rb +50 -0
- data/lib/conjur/core-api.rb +26 -0
- data/lib/conjur/das-api.rb +22 -0
- data/lib/conjur/env.rb +24 -0
- data/lib/conjur/escape.rb +31 -0
- data/lib/conjur/exists.rb +12 -0
- data/lib/conjur/group.rb +11 -0
- data/lib/conjur/has_attributes.rb +30 -0
- data/lib/conjur/has_id.rb +8 -0
- data/lib/conjur/has_identifier.rb +13 -0
- data/lib/conjur/host.rb +20 -0
- data/lib/conjur/log.rb +52 -0
- data/lib/conjur/log_source.rb +13 -0
- data/lib/conjur/resource.rb +81 -0
- data/lib/conjur/role.rb +52 -0
- data/lib/conjur/secret.rb +12 -0
- data/lib/conjur/user.rb +13 -0
- data/lib/conjur/variable.rb +27 -0
- data/spec/lib/api_spec.rb +98 -0
- data/spec/lib/das_spec.rb +33 -0
- data/spec/lib/resource_spec.rb +84 -0
- data/spec/lib/role_spec.rb +24 -0
- data/spec/lib/user_spec.rb +33 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/vcr_cassettes/Conjur_Resource/_create/with_path-like_identifier.yml +87 -0
- data/spec/vcr_cassettes/Conjur_Resource/_create/with_un-encoded_path-like_identifier.yml +87 -0
- data/spec/vcr_cassettes/Conjur_Resource/_create/with_uuid_identifier.yml +87 -0
- metadata +266 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
module Conjur
|
2
|
+
class Resource < RestClient::Resource
|
3
|
+
include Exists
|
4
|
+
include HasAttributes
|
5
|
+
|
6
|
+
def kind
|
7
|
+
match_path(0..0)
|
8
|
+
end
|
9
|
+
|
10
|
+
def identifier
|
11
|
+
match_path(1..-1)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(options = {})
|
15
|
+
log do |logger|
|
16
|
+
logger << "Creating resource #{kind} : #{identifier}"
|
17
|
+
unless options.empty?
|
18
|
+
logger << " with options #{options.to_json}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
self.put(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Lists roles that have a specified permission on the resource.
|
25
|
+
def permitted_roles(permission, options = {})
|
26
|
+
JSON.parse RestClient::Resource.new(Conjur::Authz::API.host, self.options)["/roles/allowed_to/#{permission}/#{path_escape kind}/#{path_escape identifier}"].get(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Changes the owner of a resource
|
30
|
+
def give_to(owner, options = {})
|
31
|
+
self.put(options.merge(owner: owner))
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(options = {})
|
35
|
+
log do |logger|
|
36
|
+
logger << "Deleting resource #{kind} : #{identifier}"
|
37
|
+
unless options.empty?
|
38
|
+
logger << " with options #{options.to_json}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
super.delete(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def permit(privilege, role, options = {})
|
45
|
+
eachable(privilege).each do |p|
|
46
|
+
log do |logger|
|
47
|
+
logger << "Permitting #{p} on resource #{kind} : #{identifier} by #{role}"
|
48
|
+
unless options.empty?
|
49
|
+
logger << " with options #{options.to_json}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
self["?grant&privilege=#{query_escape p}&role=#{query_escape role}"].post(options)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def deny(privilege, role, options = {})
|
58
|
+
eachable(privilege).each do |p|
|
59
|
+
log do |logger|
|
60
|
+
logger << "Denying #{p} on resource #{kind} : #{identifier} by #{role}"
|
61
|
+
unless options.empty?
|
62
|
+
logger << " with options #{options.to_json}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
self["?revoke&privilege=#{query_escape p}&role=#{query_escape role}"].post(options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def eachable(item)
|
72
|
+
item.respond_to?(:each) ? item : [ item ]
|
73
|
+
end
|
74
|
+
|
75
|
+
def match_path(range)
|
76
|
+
require 'uri'
|
77
|
+
tokens = URI.parse(self.url).path[1..-1].split('/')[range]
|
78
|
+
tokens.map{|t| URI.unescape(t)}.join('/')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/conjur/role.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Conjur
|
2
|
+
class Role < RestClient::Resource
|
3
|
+
include Exists
|
4
|
+
include HasId
|
5
|
+
|
6
|
+
def create(options = {})
|
7
|
+
log do |logger|
|
8
|
+
logger << "Creating role #{id}"
|
9
|
+
unless options.empty?
|
10
|
+
logger << " with options #{options.to_json}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
self.put(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def all(options = {})
|
17
|
+
JSON.parse(self["/all"].get(options)).collect do |id|
|
18
|
+
Role.new("#{Conjur::Authz::API.host}/roles/#{path_escape id}", self.options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def grant_to(member, admin_option = false, options = {})
|
23
|
+
log do |logger|
|
24
|
+
logger << "Granting role #{id} to #{member}"
|
25
|
+
if admin_option
|
26
|
+
logger << " with admin option"
|
27
|
+
end
|
28
|
+
unless options.empty?
|
29
|
+
logger << " and extended options #{options.to_json}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
self["/members/#{path_escape member}?admin_option=#{query_escape admin_option}"].put(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def revoke_from(member, options = {})
|
36
|
+
log do |logger|
|
37
|
+
logger << "Revoking role #{id} from #{member}"
|
38
|
+
unless options.empty?
|
39
|
+
logger << " with options #{options.to_json}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
self["/members/#{path_escape member}"].delete(options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def permitted?(resource_kind, resource_id, privilege, options = {})
|
46
|
+
self["/permitted?resource_kind=#{query_escape resource_kind}&resource_id=#{query_escape resource_id}&privilege=#{query_escape privilege}"].get(options)
|
47
|
+
true
|
48
|
+
rescue RestClient::ResourceNotFound
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/conjur/user.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Conjur
|
2
|
+
class Variable < RestClient::Resource
|
3
|
+
include ActsAsResource
|
4
|
+
include HasAttributes
|
5
|
+
include Exists
|
6
|
+
include HasId
|
7
|
+
|
8
|
+
def add_value value
|
9
|
+
log do |logger|
|
10
|
+
logger << "Adding #{value} to variable #{id}"
|
11
|
+
end
|
12
|
+
invalidate do
|
13
|
+
self['values'].post value: value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def version_count
|
18
|
+
self.attributes['versions']
|
19
|
+
end
|
20
|
+
|
21
|
+
def value(version = nil)
|
22
|
+
url = 'value'
|
23
|
+
url << "?version=#{version}" if version
|
24
|
+
self[url].get.body
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'conjur/api'
|
4
|
+
|
5
|
+
shared_examples_for "API endpoint" do
|
6
|
+
subject { api }
|
7
|
+
let(:service_name) { api.name.split('::')[-2].downcase }
|
8
|
+
context "in development" do
|
9
|
+
before(:each) do
|
10
|
+
Conjur.stub(:env).and_return "development"
|
11
|
+
end
|
12
|
+
its "default_host" do
|
13
|
+
should == "http://localhost:#{Conjur.service_base_port + port_offset}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
context "in stage" do
|
17
|
+
before(:each) do
|
18
|
+
Conjur.stub(:env).and_return "stage"
|
19
|
+
end
|
20
|
+
its "default_host" do
|
21
|
+
should == "https://#{service_name}-stage-conjur.herokuapp.com"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
context "in ci" do
|
25
|
+
before(:each) do
|
26
|
+
Conjur.stub(:env).and_return "ci"
|
27
|
+
end
|
28
|
+
its "default_host" do
|
29
|
+
should == "https://#{service_name}-ci-conjur.herokuapp.com"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
context "in production" do
|
33
|
+
before(:each) do
|
34
|
+
Conjur.stub(:env).and_return "production"
|
35
|
+
end
|
36
|
+
its "default_host" do
|
37
|
+
should == "https://#{service_name}-v2-conjur.herokuapp.com"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
context "in named production version" do
|
41
|
+
before(:each) do
|
42
|
+
Conjur.stub(:env).and_return "production"
|
43
|
+
Conjur.stub(:stack).and_return "waffle"
|
44
|
+
end
|
45
|
+
its "default_host" do
|
46
|
+
should == "https://#{service_name}-waffle-conjur.herokuapp.com"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Conjur::API do
|
52
|
+
context "host construction" do
|
53
|
+
context "of authn service" do
|
54
|
+
let(:port_offset) { 0 }
|
55
|
+
let(:api) { Conjur::Authn::API }
|
56
|
+
it_should_behave_like "API endpoint"
|
57
|
+
end
|
58
|
+
context "of authz service" do
|
59
|
+
let(:port_offset) { 100 }
|
60
|
+
let(:api) { Conjur::Authz::API }
|
61
|
+
it_should_behave_like "API endpoint"
|
62
|
+
end
|
63
|
+
context "of das service" do
|
64
|
+
let(:port_offset) { 200 }
|
65
|
+
let(:api) { Conjur::DAS::API }
|
66
|
+
it_should_behave_like "API endpoint"
|
67
|
+
end
|
68
|
+
context "of core service" do
|
69
|
+
let(:port_offset) { 300 }
|
70
|
+
let(:api) { Conjur::Core::API }
|
71
|
+
it_should_behave_like "API endpoint"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
context ".class" do
|
75
|
+
describe '#token_valid?' do
|
76
|
+
subject { Conjur::API }
|
77
|
+
it "raises KeyError when there's no authn key in the db" do
|
78
|
+
require 'slosilo'
|
79
|
+
Slosilo.stub(:[]).with(:authn).and_return nil
|
80
|
+
expect { subject.token_valid? :whatever }.to raise_error(KeyError)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
context "credential handling" do
|
85
|
+
let(:login) { "bob" }
|
86
|
+
subject { api }
|
87
|
+
context "from token" do
|
88
|
+
let(:token) { { 'data' => login } }
|
89
|
+
let(:api) { Conjur::API.new_from_token(token) }
|
90
|
+
its(:credentials) { should == { headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login } }
|
91
|
+
end
|
92
|
+
context "from api key" do
|
93
|
+
let(:api_key) { "theapikey" }
|
94
|
+
let(:api) { Conjur::API.new_from_key(login, api_key) }
|
95
|
+
its(:credentials) { should == { user: login, password: api_key } }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'conjur/api'
|
4
|
+
|
5
|
+
describe Conjur::API do
|
6
|
+
context "data_access_service_url" do
|
7
|
+
let(:account) { "the-account" }
|
8
|
+
let(:path) { "upload" }
|
9
|
+
subject { Conjur::API.data_access_service_url(account, path, params) }
|
10
|
+
context "to test environment" do
|
11
|
+
before(:each) do
|
12
|
+
Conjur.stub(:env).and_return "development"
|
13
|
+
end
|
14
|
+
context "with empty params" do
|
15
|
+
let(:params) { {} }
|
16
|
+
it { should == "http://localhost:5200/data/the-account/inscitiv/upload" }
|
17
|
+
end
|
18
|
+
context "with params" do
|
19
|
+
let(:params) { { "foo" => "b/r" } }
|
20
|
+
it { should == "http://localhost:5200/data/the-account/inscitiv/upload?foo=b%2Fr" }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
context "to production environment" do
|
24
|
+
before(:each) do
|
25
|
+
Conjur.stub(:env).and_return "production"
|
26
|
+
end
|
27
|
+
context "with empty params" do
|
28
|
+
let(:params) { {} }
|
29
|
+
it { should == "https://das-v2-conjur.herokuapp.com/data/the-account/inscitiv/upload" }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'conjur/api'
|
4
|
+
|
5
|
+
describe Conjur::Resource do
|
6
|
+
let(:user) { 'admin' }
|
7
|
+
let(:api_key) { '^6feWZpr' }
|
8
|
+
|
9
|
+
def conjur_api
|
10
|
+
Conjur::API.new_from_key(user, api_key)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.it_creates_with code
|
14
|
+
it "should create with status #{code}" do
|
15
|
+
resource = conjur_api.resource("spec", identifier)
|
16
|
+
resource.create
|
17
|
+
resource.should exist
|
18
|
+
conjur_api.resource("spec", identifier).kind.should == "spec"
|
19
|
+
conjur_api.resource("spec", identifier).identifier.should == identifier
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.it_fails_with code
|
24
|
+
it "should fail with status #{code}" do
|
25
|
+
expect { conjur_api.resource("spec", identifier).create }.to raise_error { |error|
|
26
|
+
error.should be_a(RestClient::Exception)
|
27
|
+
error.http_code.should == code
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:uuid) { "ddd1f59a-494d-48fb-b045-0374c4a6eef9" }
|
33
|
+
|
34
|
+
context "identifier" do
|
35
|
+
include Conjur::Escape
|
36
|
+
let(:resource) { Conjur::Resource.new("#{Conjur::Authz::API.host}/#{kind}/#{path_escape identifier}") }
|
37
|
+
|
38
|
+
context "Object with an #id" do
|
39
|
+
let(:kind) { "host" }
|
40
|
+
let(:identifier) do
|
41
|
+
Conjur::Host.new("#{Conjur::Core::API.host}/hosts/foobar", {})
|
42
|
+
end
|
43
|
+
it "identifier should obtained from the id" do
|
44
|
+
resource.identifier.should == "foobar"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
[ [ "foo", "bar/baz" ], [ "f:o", "bar" ], [ "@f", "bar.baz" ], [ "@f", "bar baz" ], [ "@f", "bar?baz" ] ].each do |p|
|
49
|
+
context "of /#{p[0]}/#{p[1]}" do
|
50
|
+
let(:kind) { p[0] }
|
51
|
+
let(:identifier) { p[1] }
|
52
|
+
context "resource_kind" do
|
53
|
+
subject { resource.kind }
|
54
|
+
specify { should == p[0] }
|
55
|
+
end
|
56
|
+
context "resource_id" do
|
57
|
+
subject { resource.identifier }
|
58
|
+
specify { should == ( p[1] ) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
context "#create" do
|
64
|
+
context "with uuid identifier" do
|
65
|
+
use_vcr_cassette
|
66
|
+
let(:identifier) { uuid }
|
67
|
+
it_creates_with 204
|
68
|
+
it "is findable" do
|
69
|
+
conjur_api.resource("spec", identifier).create
|
70
|
+
conjur_api.resource("spec", identifier).should exist
|
71
|
+
end
|
72
|
+
end
|
73
|
+
context "with path-like identifier" do
|
74
|
+
use_vcr_cassette
|
75
|
+
let(:identifier) { [ uuid, "xxx" ].join("/") }
|
76
|
+
it_creates_with 204
|
77
|
+
end
|
78
|
+
context "with un-encoded path-like identifier" do
|
79
|
+
use_vcr_cassette
|
80
|
+
let(:identifier) { [ uuid, "+?!!?+/xxx" ].join("/") }
|
81
|
+
it_creates_with 204
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'conjur/api'
|
4
|
+
|
5
|
+
shared_examples_for "properties" do
|
6
|
+
subject { role }
|
7
|
+
its(:id) { should == id }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Conjur::Role do
|
11
|
+
context "#new" do
|
12
|
+
let(:url) { "#{Conjur::Authz::API.host}/roles/#{id}" }
|
13
|
+
let(:credentials) { mock(:credentials) }
|
14
|
+
let(:role) { Conjur::Role.new(url, credentials) }
|
15
|
+
context "with plain id" do
|
16
|
+
let(:id) { "foo" }
|
17
|
+
it_should_behave_like "properties"
|
18
|
+
end
|
19
|
+
context "with more complex id" do
|
20
|
+
let(:id) { "@foo;bar" }
|
21
|
+
it_should_behave_like "properties"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|