conjur-cli 4.26.0 → 4.27.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/acceptance-features/audit/audit_event_send.feature +104 -0
- data/acceptance-features/audit/send.feature +70 -0
- data/acceptance-features/authentication/authenticate.feature +10 -0
- data/acceptance-features/authentication/login.feature +14 -0
- data/acceptance-features/authentication/logout.feature +16 -0
- data/acceptance-features/authentication/whoami.feature +5 -0
- data/acceptance-features/authorization/resource/annotate.feature +35 -0
- data/acceptance-features/authorization/resource/check.feature +22 -0
- data/acceptance-features/authorization/resource/create.feature +19 -0
- data/acceptance-features/authorization/resource/deny.feature +12 -0
- data/acceptance-features/authorization/resource/exists.feature +16 -0
- data/acceptance-features/authorization/resource/give.feature +22 -0
- data/acceptance-features/authorization/resource/permit.feature +20 -0
- data/acceptance-features/authorization/resource/permitted_roles.feature +16 -0
- data/acceptance-features/authorization/resource/show.feature +26 -0
- data/acceptance-features/authorization/role/create.feature +13 -0
- data/acceptance-features/authorization/role/exists.feature +19 -0
- data/acceptance-features/authorization/role/grant_to.feature +21 -0
- data/acceptance-features/authorization/role/graph.feature +58 -0
- data/acceptance-features/authorization/role/members.feature +23 -0
- data/acceptance-features/authorization/role/memberships.feature +27 -0
- data/acceptance-features/conjurenv/check.feature +28 -0
- data/acceptance-features/conjurenv/run.feature +10 -0
- data/acceptance-features/conjurenv/template.feature +11 -0
- data/acceptance-features/directory/group/create.feature +20 -0
- data/acceptance-features/directory/group/retire.feature +54 -0
- data/acceptance-features/directory/host/create.feature +23 -0
- data/acceptance-features/directory/host/retire.feature +6 -0
- data/acceptance-features/directory/layer/create.feature +10 -0
- data/acceptance-features/directory/layer/hosts-add.feature +9 -0
- data/acceptance-features/directory/layer/hosts-remove.feature +10 -0
- data/acceptance-features/directory/user/create.feature +23 -0
- data/acceptance-features/directory/user/retire.feature +6 -0
- data/acceptance-features/directory/user/update_password.feature +16 -0
- data/acceptance-features/directory/variable/create.feature +14 -0
- data/acceptance-features/directory/variable/retire.feature +17 -0
- data/acceptance-features/directory/variable/value.feature +13 -0
- data/acceptance-features/directory/variable/values-add.feature +12 -0
- data/acceptance-features/global-privilege/elevate.feature +20 -0
- data/acceptance-features/global-privilege/reveal.privilege +20 -0
- data/acceptance-features/pubkeys/add.feature +20 -0
- data/acceptance-features/pubkeys/delete.feature +9 -0
- data/acceptance-features/pubkeys/names.feature +23 -0
- data/acceptance-features/pubkeys/show.feature +25 -0
- data/acceptance-features/step_definitions/cli.rb +21 -0
- data/acceptance-features/step_definitions/graph_steps.rb +22 -0
- data/acceptance-features/step_definitions/user_steps.rb +54 -0
- data/acceptance-features/support/env.rb +5 -0
- data/acceptance-features/support/hooks.rb +179 -0
- data/acceptance-features/support/world.rb +153 -0
- data/conjur.gemspec +4 -1
- data/features/step_definitions/graph_steps.rb +2 -2
- data/features/support/hooks.rb +1 -5
- data/lib/conjur/cli.rb +1 -1
- data/lib/conjur/command/bootstrap.rb +3 -2
- data/lib/conjur/command/elevate.rb +76 -0
- data/lib/conjur/command/rspec/mock_services.rb +3 -3
- data/lib/conjur/command.rb +15 -0
- data/lib/conjur/version.rb +1 -1
- data/spec/command/elevate_spec.rb +28 -0
- metadata +85 -4
@@ -0,0 +1,179 @@
|
|
1
|
+
|
2
|
+
require 'conjur/api'
|
3
|
+
require 'conjur/cli'
|
4
|
+
require 'conjur/authn'
|
5
|
+
|
6
|
+
netrc = Conjur::Authn.netrc
|
7
|
+
username, password = Conjur::Authn.get_credentials
|
8
|
+
raise "Not logged in to Conjur" unless username && password
|
9
|
+
puts "Logging in as #{username}"
|
10
|
+
|
11
|
+
# Future Aruba
|
12
|
+
#Aruba.configure do |config|
|
13
|
+
# config.exit_timeout = 15
|
14
|
+
#end
|
15
|
+
|
16
|
+
Before('@conjurapi-log') do
|
17
|
+
set_env 'CONJURAPI_LOG', 'stderr'
|
18
|
+
end
|
19
|
+
|
20
|
+
Before do
|
21
|
+
Conjur::Authn.save_credentials username: username, password: password
|
22
|
+
|
23
|
+
@admin_api = conjur_api = Conjur::Authn.connect
|
24
|
+
|
25
|
+
@namespace = conjur_api.create_variable("text/plain", "id").id
|
26
|
+
user = conjur_api.create_user "admin@#{@namespace}", ownerid: "#{Conjur.configuration.account}:user:#{username}"
|
27
|
+
|
28
|
+
netrc[Conjur::Authn.host] = [ "admin@#{@namespace}", user.api_key ]
|
29
|
+
netrc.save
|
30
|
+
|
31
|
+
conjur_api = Conjur::Authn.connect
|
32
|
+
@security_admin = conjur_api.create_group [ @namespace, "security_admin" ].join('/')
|
33
|
+
@security_admin.add_member user, admin_option: true
|
34
|
+
|
35
|
+
JsonSpec.memorize "MY_ROLEID", %Q("#{user.roleid}")
|
36
|
+
|
37
|
+
@admin_api.group("pubkeys-1.0/key-managers").add_member @security_admin
|
38
|
+
@admin_api.resource('!:!:conjur').permit 'elevate', user, grant_option: true
|
39
|
+
@admin_api.resource('!:!:conjur').permit 'reveal', user, grant_option: true
|
40
|
+
|
41
|
+
conjur_api.create_user "attic@#{@namespace}"
|
42
|
+
|
43
|
+
@aruba_timeout_seconds = 30
|
44
|
+
end
|
45
|
+
|
46
|
+
After do
|
47
|
+
if @admin_api
|
48
|
+
@admin_api.group("pubkeys-1.0/key-managers").remove_member @security_admin
|
49
|
+
end
|
50
|
+
tempfiles.each { |tempfile| File.unlink(tempfile) unless tempfile.nil? }
|
51
|
+
end
|
52
|
+
|
53
|
+
at_exit do
|
54
|
+
Conjur::Authn.save_credentials username: username, password: password
|
55
|
+
end
|
56
|
+
|
57
|
+
require 'ostruct'
|
58
|
+
|
59
|
+
class MockAPI
|
60
|
+
attr_reader :things
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@things = {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def thing(kind, id)
|
67
|
+
(@things[kind.to_sym] || []).find{|r| r.id == id}
|
68
|
+
end
|
69
|
+
|
70
|
+
def thing_like(kind, id_pattern)
|
71
|
+
(@things[kind.to_sym] || []).find{|r| id_pattern.match(r.id)}
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_host(options = {})
|
75
|
+
id = options.delete(:id)
|
76
|
+
if id
|
77
|
+
host = thing(:host, id)
|
78
|
+
else
|
79
|
+
id = SecureRandom.uuid
|
80
|
+
end
|
81
|
+
host ||= create_thing(:host, id, options, role: true, api_key: true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_user(id, options = {})
|
85
|
+
thing(:user, id) || create_thing(:user, id, options, role: true, api_key: true)
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_variable(mime_type, kind)
|
89
|
+
create_thing(:user, SecureRandom.uuid, mime_type: mime_type, kind: kind)
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_resource(id, options = {})
|
93
|
+
resource(id).tap do |resource|
|
94
|
+
resource.send(:"exists?=", true)
|
95
|
+
populate_options resource, options
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_role(id, options = {})
|
100
|
+
role(id).tap do |role|
|
101
|
+
role.send(:"exists?=", true)
|
102
|
+
populate_options role, options
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
[ :user, :host ].each do |kind|
|
107
|
+
define_method kind do |id|
|
108
|
+
thing(kind, id)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def role(id)
|
113
|
+
raise "Role id must be a string" unless id.is_a?(String)
|
114
|
+
thing(:role, id) || create_thing(:role, id, { exists?: false }, role: true)
|
115
|
+
end
|
116
|
+
|
117
|
+
def resource(id)
|
118
|
+
raise "Resource id must be a string" unless id.is_a?(String)
|
119
|
+
thing(:resource, id) || create_thing(:resource, id, exists?: false)
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
def create_thing(kind, id, options, kind_options = {})
|
125
|
+
thing = OpenStruct.new(kind: kind, id: id, exists?: true)
|
126
|
+
|
127
|
+
class << thing
|
128
|
+
def permit(privilege, role, options = {})
|
129
|
+
(self.permissions ||= []) << OpenStruct.new(privilege: privilege, role: role.id, grant_option: !!options[:grant_option])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
if kind_options[:api_key]
|
134
|
+
thing.api_key = SecureRandom.uuid
|
135
|
+
end
|
136
|
+
if kind_options[:role]
|
137
|
+
thing.roleid = id
|
138
|
+
class << thing
|
139
|
+
def can(privilege, resource, options = {})
|
140
|
+
resource.permit privilege, self, options
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
populate_options(thing, options)
|
146
|
+
|
147
|
+
store_thing kind, thing
|
148
|
+
|
149
|
+
thing
|
150
|
+
end
|
151
|
+
|
152
|
+
def populate_options(thing, options)
|
153
|
+
options.each do |k,v|
|
154
|
+
thing.send("#{k}=", v)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def store_thing(kind, thing)
|
159
|
+
(things[kind] ||= []) << thing
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
Before("@dsl") do
|
164
|
+
puts "Using MockAPI"
|
165
|
+
puts "Using account 'cucumber'"
|
166
|
+
|
167
|
+
require 'conjur/api'
|
168
|
+
require 'conjur/config'
|
169
|
+
require 'conjur/dsl/runner'
|
170
|
+
|
171
|
+
Conjur.stub(:env).and_return "ci"
|
172
|
+
Conjur.stub(:stack).and_return "ci"
|
173
|
+
Conjur.stub(:account).and_return "cucumber"
|
174
|
+
|
175
|
+
Conjur::Core::API.stub(:conjur_account).and_return 'cucumber'
|
176
|
+
@mock_api ||= MockAPI.new
|
177
|
+
Conjur::DSL::Runner.any_instance.stub(:api).and_return @mock_api
|
178
|
+
end
|
179
|
+
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'aruba/api'
|
2
|
+
require 'conjur/api'
|
3
|
+
|
4
|
+
module ConjurCLIWorld
|
5
|
+
include Aruba::Api
|
6
|
+
|
7
|
+
def last_json
|
8
|
+
stdout_from(@last_cmd)
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_or_create_password(username)
|
12
|
+
@passwords ||= {}
|
13
|
+
unless password = @passwords[username]
|
14
|
+
password = @passwords[username] = SecureRandom.hex(12)
|
15
|
+
end
|
16
|
+
password
|
17
|
+
end
|
18
|
+
|
19
|
+
def namespace
|
20
|
+
@namespace or raise "@namespace is not initialized"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Aruba's method
|
24
|
+
def run(cmd, *args)
|
25
|
+
# it's a thunk now so it should be returned. puts can be added back as block if we want to
|
26
|
+
super process_cmd(cmd), *args
|
27
|
+
|
28
|
+
#puts stderr_from(cmd)
|
29
|
+
#puts stdout_from(cmd)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stderr_from(cmd)
|
33
|
+
super process_cmd(cmd)
|
34
|
+
end
|
35
|
+
def stdout_from(cmd)
|
36
|
+
super process_cmd(cmd)
|
37
|
+
end
|
38
|
+
def output_from(cmd)
|
39
|
+
super process_cmd(cmd)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Substitute the namespace for marker $ns
|
43
|
+
def unescape(string)
|
44
|
+
string = super
|
45
|
+
string.gsub("$ns", namespace)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_process(wanted)
|
49
|
+
super wanted.gsub("$ns", namespace)
|
50
|
+
end
|
51
|
+
|
52
|
+
def tempfiles
|
53
|
+
@tempfiles||=[]
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def process_cmd(cmd)
|
59
|
+
cmd = cmd.dup
|
60
|
+
cmd.gsub!("$ns", namespace)
|
61
|
+
cmd.gsub!("$pubkeys_url", Conjur.configuration.pubkeys_url)
|
62
|
+
|
63
|
+
@last_cmd = cmd
|
64
|
+
JsonSpec.memory.each do |k,v|
|
65
|
+
cmd.gsub!("%{#{k}}", v)
|
66
|
+
end
|
67
|
+
cmd
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module ConjurWorld
|
72
|
+
def last_json
|
73
|
+
last_stdout
|
74
|
+
end
|
75
|
+
|
76
|
+
def last_stdout
|
77
|
+
raise "No commands have been run" unless last_cmd
|
78
|
+
stdout_from last_cmd
|
79
|
+
end
|
80
|
+
|
81
|
+
attr_accessor :last_cmd
|
82
|
+
|
83
|
+
def account
|
84
|
+
Conjur::Core::API.conjur_account
|
85
|
+
end
|
86
|
+
|
87
|
+
def role_kind
|
88
|
+
@role_kind ||= "cli-cukes"
|
89
|
+
end
|
90
|
+
|
91
|
+
def role_id_map
|
92
|
+
@role_id_map ||= {}
|
93
|
+
end
|
94
|
+
|
95
|
+
def extract_filtered_graph json
|
96
|
+
graph = JSON.parse(json.to_s)
|
97
|
+
case graph
|
98
|
+
when Hash then filter_hash_graph(graph)
|
99
|
+
when Array then filter_array_graph(graph)
|
100
|
+
else raise "WTF: graph was #{graph.class}?"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def filter_hash_graph graph
|
105
|
+
allowed = role_id_map.values
|
106
|
+
edges = graph['graph']
|
107
|
+
filtered = edges.select do |edge|
|
108
|
+
allowed.member?(edge['parent']) and allowed.member?(edge['child'])
|
109
|
+
end
|
110
|
+
{'graph' => filtered}
|
111
|
+
end
|
112
|
+
|
113
|
+
def filter_array_graph graph
|
114
|
+
allowed = role_id_map.values
|
115
|
+
graph.select do |edge|
|
116
|
+
edge.all?{|v| allowed.member?(v)}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def graph edges
|
121
|
+
# generate roles
|
122
|
+
edges.flatten.uniq.each do |role_id|
|
123
|
+
role_id_map[role_id] = expanded = expand_role_id(role_id)
|
124
|
+
run_command "conjur role create '#{expanded}'"
|
125
|
+
end
|
126
|
+
|
127
|
+
# generate memberships
|
128
|
+
edges.each do |parent, child|
|
129
|
+
run_command "conjur role grant_to #{expand_role_id(parent)} #{expand_role_id(child)}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def run_command cmd
|
134
|
+
step "I successfully run " + '`' + cmd + '`'
|
135
|
+
end
|
136
|
+
|
137
|
+
def expand_role_id role_id
|
138
|
+
"#{account}:#{role_kind}:#{prepend_namespace role_id}"
|
139
|
+
end
|
140
|
+
|
141
|
+
def prepend_namespace id
|
142
|
+
"#{namespace}-#{id}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def expand_roles string
|
146
|
+
role_id_map.each do |role, expanded|
|
147
|
+
string.gsub! role, expanded
|
148
|
+
end
|
149
|
+
string
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
World(ConjurWorld, ConjurCLIWorld)
|
data/conjur.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
|
18
18
|
|
19
19
|
gem.add_dependency 'activesupport'
|
20
|
-
gem.add_dependency 'conjur-api', '~> 4.
|
20
|
+
gem.add_dependency 'conjur-api', '~> 4.19'
|
21
21
|
gem.add_dependency 'gli', '>=2.8.0'
|
22
22
|
gem.add_dependency 'highline'
|
23
23
|
gem.add_dependency 'netrc', '~> 0.10.2'
|
@@ -35,4 +35,7 @@ Gem::Specification.new do |gem|
|
|
35
35
|
gem.add_development_dependency 'rake', '~> 10.0'
|
36
36
|
gem.add_development_dependency 'io-grab', '~> 0.0.1'
|
37
37
|
gem.add_development_dependency 'json_spec'
|
38
|
+
# For cukes
|
39
|
+
gem.add_development_dependency 'conjur-asset-audit-send'
|
40
|
+
gem.add_development_dependency 'conjur-asset-host-factory'
|
38
41
|
end
|
@@ -14,8 +14,8 @@ When(/^I( successfully)? run with role expansion "(.*)"$/) do |successfully, cmd
|
|
14
14
|
end
|
15
15
|
self.last_cmd = cmd
|
16
16
|
if successfully
|
17
|
-
step "I successfully run
|
17
|
+
step "I successfully run `#{cmd}`"
|
18
18
|
else
|
19
|
-
step "I run
|
19
|
+
step "I run `#{cmd}`"
|
20
20
|
end
|
21
21
|
end
|
data/features/support/hooks.rb
CHANGED
@@ -122,11 +122,7 @@ Before("@dsl") do
|
|
122
122
|
end
|
123
123
|
|
124
124
|
Before('@real-api') do
|
125
|
-
|
126
|
-
cfg = File.absolute_path("#{File.dirname __FILE__}/../../.conjurrc")
|
127
|
-
puts "cfg_path = #{cfg}"
|
128
|
-
puts "contents = #{File.read(cfg)}"
|
129
|
-
Conjur::Config.load([cfg])
|
125
|
+
Conjur::Config.load
|
130
126
|
Conjur::Config.apply
|
131
127
|
@aruba_timeout_seconds = 15
|
132
128
|
end
|
data/lib/conjur/cli.rb
CHANGED
@@ -63,7 +63,7 @@ module Conjur
|
|
63
63
|
# do too much effort, and GLIs support for aliasing doesn't work out so well with
|
64
64
|
# subcommands.
|
65
65
|
def run args
|
66
|
-
|
66
|
+
args = args.shift.split(':') + args unless args.empty?
|
67
67
|
super args
|
68
68
|
end
|
69
69
|
|
@@ -49,6 +49,8 @@ class Conjur::Command::Bootstrap < Conjur::Command
|
|
49
49
|
# The admin user will always satisfy these conditions, unless they are revoked for some reason.
|
50
50
|
# Other users created by the bootstrap command will (typically) also have these powers.
|
51
51
|
def self.security_admin_manager? api
|
52
|
+
return true if elevated?
|
53
|
+
|
52
54
|
username = api.username
|
53
55
|
user = if username.index('/')
|
54
56
|
nil
|
@@ -116,7 +118,6 @@ class Conjur::Command::Bootstrap < Conjur::Command
|
|
116
118
|
puts "User created"
|
117
119
|
puts "Making '#{username}' a member and admin of group 'security_admin'"
|
118
120
|
security_admin.add_member user, admin_option: true
|
119
|
-
security_admin.resource.permit "read", user
|
120
121
|
puts "Adminship granted"
|
121
122
|
end
|
122
123
|
|
@@ -139,4 +140,4 @@ class Conjur::Command::Bootstrap < Conjur::Command
|
|
139
140
|
end
|
140
141
|
end
|
141
142
|
end
|
142
|
-
end
|
143
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2015 Conjur Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
|
22
|
+
# Implement privileged modes such as 'elevate' and 'reveal'
|
23
|
+
class Conjur::Command::Elevate < Conjur::DSLCommand
|
24
|
+
|
25
|
+
def self.subcommand args
|
26
|
+
code = Conjur::CLI.run args
|
27
|
+
raise GLI::CustomExit.new("Subcommand failed", code) unless code == 0
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Run a sub-command with elevated privileges"
|
31
|
+
long_desc <<-DESC
|
32
|
+
If you are allowed to do this by the Conjur server, all server-side permission checks will be bypassed and any
|
33
|
+
action will be allowed.
|
34
|
+
|
35
|
+
To be able to run this command, you must have the 'elevate' privilege on the resource '!:!:conjur'.
|
36
|
+
|
37
|
+
EXAMPLE
|
38
|
+
|
39
|
+
Force retirement of a user:
|
40
|
+
|
41
|
+
$ conjur elevate user retire alice
|
42
|
+
DESC
|
43
|
+
command :elevate do |c|
|
44
|
+
c.action do |global_options,options,args|
|
45
|
+
exit_now! "Subcommand is required" if args.empty?
|
46
|
+
|
47
|
+
Conjur::Command.api = api.with_privilege "elevate"
|
48
|
+
subcommand args
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Run a sub-command in 'reveal' mode"
|
53
|
+
long_desc <<-DESC
|
54
|
+
If you are allowed to do this by the Conjur server, you can inspect all data in the Conjur
|
55
|
+
authorization service. For example, you can list and search for all resources, regardless of
|
56
|
+
your ownership and privileges. You can also show details on any resource, and you can perform
|
57
|
+
permission checks on any resource.
|
58
|
+
|
59
|
+
To be able to run this command, you must have the 'reveal' privilege on the resource '!:!:conjur'.
|
60
|
+
|
61
|
+
EXAMPLE
|
62
|
+
|
63
|
+
List all groups:
|
64
|
+
|
65
|
+
$ conjur reveal group list -i
|
66
|
+
|
67
|
+
DESC
|
68
|
+
command :reveal do |c|
|
69
|
+
c.action do |global_options,options,args|
|
70
|
+
exit_now! "Subcommand is required" if args.empty?
|
71
|
+
|
72
|
+
Conjur::Command.api = api.with_privilege "reveal"
|
73
|
+
subcommand args
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -16,6 +16,9 @@ shared_context "with mock authn" do
|
|
16
16
|
let(:netrcfile) { Tempfile.new 'authtest' }
|
17
17
|
let(:netrc) { Netrc.read(netrcfile.path) }
|
18
18
|
let(:account) { 'the-account' }
|
19
|
+
let(:username) { 'dknuth' }
|
20
|
+
let(:api_key) { 'sekrit' }
|
21
|
+
let(:api) { Conjur::API.new_from_key(username, api_key) }
|
19
22
|
before do
|
20
23
|
allow(Conjur::Core::API).to receive(:conjur_account) { account }
|
21
24
|
allow(Conjur::Authn).to receive_messages(netrc: netrc, host: authn_host)
|
@@ -25,9 +28,6 @@ end
|
|
25
28
|
|
26
29
|
shared_context "when logged in", logged_in: true do
|
27
30
|
include_context "with mock authn"
|
28
|
-
let(:username) { 'dknuth' }
|
29
|
-
let(:api_key) { 'sekrit' }
|
30
|
-
let(:api) { Conjur::API.new_from_key(username, api_key) }
|
31
31
|
before do
|
32
32
|
allow(api).to receive(:credentials) { {} }
|
33
33
|
netrc[authn_host] = [username, api_key]
|
data/lib/conjur/command.rb
CHANGED
@@ -28,6 +28,7 @@ module Conjur
|
|
28
28
|
|
29
29
|
class << self
|
30
30
|
attr_accessor :prefix
|
31
|
+
|
31
32
|
def method_missing *a, &b
|
32
33
|
Conjur::CLI.send *a, &b
|
33
34
|
end
|
@@ -41,6 +42,14 @@ module Conjur
|
|
41
42
|
args.shift or raise "Missing parameter: #{name}"
|
42
43
|
end
|
43
44
|
|
45
|
+
def assert_empty(args)
|
46
|
+
exit_now! "Received extra command arguments" unless args.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
def api= api
|
50
|
+
@@api = api
|
51
|
+
end
|
52
|
+
|
44
53
|
def api
|
45
54
|
@@api ||= Conjur::Authn.connect
|
46
55
|
end
|
@@ -183,7 +192,13 @@ an alternative destination role.)
|
|
183
192
|
end
|
184
193
|
end
|
185
194
|
|
195
|
+
def elevated?
|
196
|
+
api.privilege == 'elevate' && api.global_privilege_permitted?('elevate')
|
197
|
+
end
|
198
|
+
|
186
199
|
def validate_retire_privileges record, options
|
200
|
+
return true if elevated?
|
201
|
+
|
187
202
|
if record.respond_to?(:role)
|
188
203
|
memberships = current_user.role.memberships.map(&:roleid)
|
189
204
|
validate_privileges "You can't administer this record" do
|
data/lib/conjur/version.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Conjur::Command::Elevate do
|
4
|
+
describe_command "elevate user show alice" do
|
5
|
+
include_context "with mock authn"
|
6
|
+
|
7
|
+
let(:token) { {login: 'dknuth'} }
|
8
|
+
before{
|
9
|
+
expect(Conjur::Authn).to receive(:connect).and_return(api)
|
10
|
+
}
|
11
|
+
it "invokes the sub-command with X-Conjur-Privilege header" do
|
12
|
+
allow_any_instance_of(Conjur::API).to receive(:token).and_return(token)
|
13
|
+
expect(Conjur::Command).to receive(:api=) do |api|
|
14
|
+
expect(api.api_key).to eq("sekrit")
|
15
|
+
expect(api.privilege).to eq("elevate")
|
16
|
+
end.and_call_original
|
17
|
+
|
18
|
+
expect(RestClient::Request).to receive(:execute).with({
|
19
|
+
method: :get,
|
20
|
+
url: "https://core.example.com/users/alice",
|
21
|
+
username: "dknuth",
|
22
|
+
headers: {:authorization=>"Token token=\"eyJsb2dpbiI6ImRrbnV0aCJ9\"", x_conjur_privilege: "elevate"}
|
23
|
+
}.merge(cert_store_options)).and_return(double(:response, body: "[]"))
|
24
|
+
|
25
|
+
invoke
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|