conjur-cli 5.2.5 → 5.3.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -1
- data/acceptance-features/step_definitions/cli_steps.rb +21 -3
- data/acceptance-features/step_definitions/http_steps.rb +24 -0
- data/acceptance-features/step_definitions/trusted_proxy_steps.rb +44 -0
- data/acceptance-features/step_definitions/user_steps.rb +7 -11
- data/acceptance-features/support/env.rb +19 -0
- data/acceptance-features/support/hooks.rb +22 -19
- data/acceptance-features/support/world.rb +20 -1
- data/acceptance-features/trusted_proxies.feature +82 -0
- data/conjur.gemspec +6 -4
- data/lib/conjur/command/ldapsync.rb +93 -16
- data/lib/conjur/version.rb +1 -1
- data/spec/command/ldapsync_spec.rb +76 -3
- metadata +53 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45db6cca737f188f732a2684c54952df012e4da0
|
4
|
+
data.tar.gz: c39fc7be243e1508a4a71459e77c1248efff5ba4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c2db8ea4d3cef7dbb0c099e89fe02416dc2247a3463c9796d46ad572a591e4c7d796d17bee5f3b7eb479ebf047469491459116a654205575d2932cb36c019ea
|
7
|
+
data.tar.gz: 302e5e260a4169265c2b2cae9e7f23fcfb37197ef51532662cc71dac1fe2abd463e831c15db8b043d2e690c3bb3d9e3c16f513b21cd60d809b79e3beb3fbb438
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 5.3.0
|
2
|
+
|
3
|
+
* Add `jobs` subcommands for `ldap-sync`.
|
4
|
+
* Add `--detach` switch to `now` subcommand.
|
5
|
+
* Relax dependency gem versions.
|
6
|
+
|
1
7
|
# 5.2.5
|
2
8
|
|
3
9
|
* Fix behavior of `conjur env` when [policy plugin](https://github.com/conjurinc/conjur-asset-policy) is installed.
|
data/Gemfile
CHANGED
@@ -6,7 +6,7 @@ source 'https://rubygems.org'
|
|
6
6
|
# Specify your gem's dependencies in conjur.gemspec
|
7
7
|
gemspec
|
8
8
|
|
9
|
-
gem 'conjur-api', '>= 4.26', git: 'https://github.com/conjurinc/api-ruby.git', branch: 'master'
|
9
|
+
gem 'conjur-api', '>= 4.26.2', git: 'https://github.com/conjurinc/api-ruby.git', branch: 'master'
|
10
10
|
gem 'semantic', '>= 1.4.1', git: 'https://github.com/jlindsey/semantic.git'
|
11
11
|
|
12
12
|
group :test, :development do
|
@@ -1,3 +1,23 @@
|
|
1
|
+
Transform /\$ns/ do |s|
|
2
|
+
s.gsub('$ns', namespace)
|
3
|
+
end
|
4
|
+
|
5
|
+
Transform /\$user_role/ do |s|
|
6
|
+
s.gsub('$user_role', test_user.role_id)
|
7
|
+
end
|
8
|
+
|
9
|
+
Transform /^table:/ do |table|
|
10
|
+
table.tap do |t|
|
11
|
+
t.hashes.each do |row|
|
12
|
+
row.each do |_,v|
|
13
|
+
v.gsub!('$ns', namespace)
|
14
|
+
v.gsub!('$user_role', test_user.role_id)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
1
21
|
Then /^I reset the command list/ do
|
2
22
|
aruba.command_monitor.clear
|
3
23
|
end
|
@@ -9,7 +29,6 @@ When /^the command completes successfully/ do
|
|
9
29
|
end
|
10
30
|
|
11
31
|
Then /^I send the audit event:/ do |event|
|
12
|
-
event = event.gsub('$ns',@namespace)
|
13
32
|
step "I run `env RESTCLIENT_LOG=stderr conjur audit send` interactively"
|
14
33
|
last_command_started.write event
|
15
34
|
last_command_started.close_io :stdin
|
@@ -19,12 +38,11 @@ end
|
|
19
38
|
# this is step copypasted from https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber.rb#L24
|
20
39
|
# original has typo in regexp, which is fixed here
|
21
40
|
Given(/^a file named "([^"]*?)" with: '(.*?)'$/) do |file_name, file_content|
|
22
|
-
file_content.gsub!('$ns',@namespace)
|
23
41
|
write_file(file_name, file_content)
|
24
42
|
end
|
25
43
|
|
26
44
|
Given(/^a file named "([^"]*?)" with namespace substitution:$/) do |file_name, file_content|
|
27
|
-
step "a file named \"#{file_name}\" with:", file_content
|
45
|
+
step "a file named \"#{file_name}\" with:", file_content
|
28
46
|
end
|
29
47
|
|
30
48
|
Then /^it prints the path to temporary file which contains: '(.*)'$/ do |content|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
When /^I send a (GET|POST|PATCH|PUT|DELETE) request forwarded from "(.*?)" to "(.*?)"$/ do |method, ip, url|
|
2
|
+
headers['X-Forwarded-For'] = ip
|
3
|
+
step %Q{I send a #{method} request to "#{url}"}
|
4
|
+
end
|
5
|
+
|
6
|
+
When /^I send a (GET|POST|PATCH|PUT|DELETE) request forwarded from "(.*?)" to "(.*?)" with:$/ do |method, ip, url, params_table|
|
7
|
+
headers['X-Forwarded-For'] = ip
|
8
|
+
step %Q{I send a #{method} request to "#{url}" with:}, params_table
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
When /^I set the( JSON)? request body to:$/ do |is_json, body|
|
13
|
+
step("I send and accept JSON") if is_json
|
14
|
+
@body = body
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^I set the( JSON)? request body to "(.*?)"/ do |is_json, body|
|
18
|
+
step("I send and accept JSON") if is_json
|
19
|
+
@body = body
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^the HTTP JSON response at "(.*?)" should be "(.*?)"$/ do |path, value|
|
23
|
+
expect(@response.get(path)).to eq(value)
|
24
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
When /^I create a hostfactory token for "(.*?)" with CIDR "(.*?)"$/ do |hf, cidr|
|
2
|
+
step %Q{I successfully run `conjur hostfactory token create --cidr #{cidr} #{hf}`}
|
3
|
+
@hostfactory_token = JSON.parse(last_command_started.stdout)[0]['token']
|
4
|
+
end
|
5
|
+
|
6
|
+
When /^I(?: can)? use the hostfactory token from "(.*?)" to create host "(.*?)"$/ do |ip, host|
|
7
|
+
headers['Authorization'] = %Q{Token token="#{@hostfactory_token}"}
|
8
|
+
step %Q{I send a POST request forwarded from "#{ip}" to "/api/host_factories/hosts" with:}, table([["id"], [host]])
|
9
|
+
step %Q{the response status should be "201"}
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^I get the audit event for the resource "(.*?)" with action "(.*?)"$/ do |resource, action|
|
13
|
+
# resource needs to be URL-encoded, but cucumber-api URL-encodes the
|
14
|
+
# whole string.
|
15
|
+
response = RestClient.get(resolve("/api/audit/resources/#{CGI.escape(resource)}"), @headers)
|
16
|
+
@response = CucumberApi::Response.create(response)
|
17
|
+
@headers = nil
|
18
|
+
@body = nil
|
19
|
+
step %Q{the response status should be "200"}
|
20
|
+
|
21
|
+
json = JSON.parse(@response)
|
22
|
+
@audit_event = json.find {|e| e['action'] == action}
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^the audit event should show the request from "(.*?)"$/ do |ip|
|
26
|
+
expect(@audit_event['request']['ip']).to eq(ip)
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^I create a pubkey for "(.*?)" from "(.*?)" with "(.*?)"$/ do |user, ip, key|
|
30
|
+
steps %Q{
|
31
|
+
Given I send "text/plain" and accept JSON
|
32
|
+
And I set the request body to "#{key}"
|
33
|
+
When I send a POST request forwarded from "#{ip}" to "/api/pubkeys/#{user}"
|
34
|
+
Then the response status should be "200"
|
35
|
+
}
|
36
|
+
@pubkey_var = @response.get "resource_identifier"
|
37
|
+
end
|
38
|
+
|
39
|
+
When /^I get the audit event for the pubkey variable with action "(.*?)"$/ do |action|
|
40
|
+
# Need reveal, test user doesn't have privilege to see resources
|
41
|
+
# created by pubkeys.
|
42
|
+
headers['X-Conjur-Privilege'] = 'reveal'
|
43
|
+
step %Q{I get the audit event for the resource "#{@pubkey_var}" with action "#{action}"}
|
44
|
+
end
|
@@ -8,16 +8,14 @@ Given(/^I login as a new user$/) do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
Given(/^I create a new user named "(.*?)"$/) do |username|
|
11
|
-
|
12
|
-
|
13
|
-
step "I successfully run `conjur user create --as-role user:admin@#{@namespace} #{username_ns}`"
|
11
|
+
step "I successfully run `conjur user create --as-role user:admin@#{namespace} #{username}`"
|
14
12
|
|
15
13
|
user_info = JSON.parse(last_command_started.stdout)
|
16
|
-
save_password
|
14
|
+
save_password username, user_info['api_key']
|
17
15
|
end
|
18
16
|
|
19
17
|
Given(/^I create a new host with id "(.*?)"$/) do |hostid|
|
20
|
-
step "I successfully run `conjur host create #{
|
18
|
+
step "I successfully run `conjur host create #{namespace}/monitoring/server`"
|
21
19
|
host = JSON.parse(last_json)
|
22
20
|
@host_id = host['id']
|
23
21
|
@host_api_key = host['api_key']
|
@@ -29,16 +27,14 @@ Given(/^I login as the new host/) do
|
|
29
27
|
end
|
30
28
|
|
31
29
|
Given(/^I login as new user "(.*?)"$/) do |username|
|
32
|
-
|
33
|
-
step %Q(I
|
34
|
-
step %Q(I login as "#{username_ns}")
|
30
|
+
step %Q(I create a new user named "#{username}")
|
31
|
+
step %Q(I login as "#{username}")
|
35
32
|
end
|
36
33
|
|
37
34
|
Given(/^I login as "(.*?)"$/) do |username|
|
38
|
-
|
39
|
-
password = find_password(username_ns)
|
35
|
+
password = find_password(username)
|
40
36
|
|
41
|
-
step %Q(I set the environment variable "CONJUR_AUTHN_LOGIN" to "#{
|
37
|
+
step %Q(I set the environment variable "CONJUR_AUTHN_LOGIN" to "#{username}")
|
42
38
|
step %Q(I set the environment variable "CONJUR_AUTHN_API_KEY" to "#{password}")
|
43
39
|
end
|
44
40
|
|
@@ -1,4 +1,23 @@
|
|
1
1
|
require "aruba/cucumber"
|
2
2
|
require "json_spec/cucumber"
|
3
|
+
require 'cucumber-api'
|
4
|
+
require 'addressable/uri'
|
3
5
|
|
4
6
|
$LOAD_PATH.unshift File.expand_path('../..', File.dirname(__FILE__))
|
7
|
+
|
8
|
+
# Overwrite cucumber-api's resolve function so it will use the scheme
|
9
|
+
# and host from ENV['CONJUR_APPLIANCE_URL'] if url doesn't already
|
10
|
+
# have a host.
|
11
|
+
$orig_resolve = self.method(:resolve)
|
12
|
+
def resolve url
|
13
|
+
# disable cucumber-api's ill-considered cache. Re-authenticate in
|
14
|
+
# case it (cucumber-api) wiped out the headers
|
15
|
+
$cache = {}
|
16
|
+
add_user_auth_header
|
17
|
+
url = Addressable::URI.parse(url)
|
18
|
+
unless url.host
|
19
|
+
conjur_url = Addressable::URI.parse(Conjur.configuration.appliance_url)
|
20
|
+
url.merge!(:scheme => conjur_url.scheme, :host => conjur_url.host)
|
21
|
+
end
|
22
|
+
$orig_resolve.call(url.to_s)
|
23
|
+
end
|
@@ -21,32 +21,35 @@ end
|
|
21
21
|
Before do
|
22
22
|
step %Q(I set the environment variable "CONJUR_AUTHN_LOGIN" to "#{username}")
|
23
23
|
step %Q(I set the environment variable "CONJUR_AUTHN_API_KEY" to "#{password}")
|
24
|
-
|
25
|
-
@admin_api = conjur_api = Conjur::Authn.connect
|
26
|
-
|
27
|
-
@namespace = conjur_api.create_variable("text/plain", "id").id
|
28
|
-
user = conjur_api.create_user "admin@#{@namespace}", ownerid: "#{Conjur.configuration.account}:user:#{username}"
|
29
24
|
|
30
|
-
|
31
|
-
@
|
32
|
-
|
25
|
+
@admin_api = Conjur::Authn.connect
|
26
|
+
@test_user = admin_api.create_user "admin@#{namespace}", ownerid: "#{Conjur.configuration.account}:user:#{username}"
|
27
|
+
|
28
|
+
@security_admin = admin_api.create_group [ namespace, "security_admin" ].join('/')
|
29
|
+
@security_admin.add_member test_user, admin_option: true
|
33
30
|
|
34
|
-
JsonSpec.memorize "MY_ROLEID", %Q("#{
|
35
|
-
JsonSpec.memorize "NAMESPACE",
|
31
|
+
JsonSpec.memorize "MY_ROLEID", %Q("#{test_user.roleid}")
|
32
|
+
JsonSpec.memorize "NAMESPACE", namespace
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
admin_api.group("pubkeys-1.0/key-managers").add_member @security_admin
|
35
|
+
admin_api.resource('!:!:conjur').permit 'elevate', test_user, grant_option: true
|
36
|
+
admin_api.resource('!:!:conjur').permit 'reveal', test_user, grant_option: true
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
admin_api.create_user "attic@#{namespace}"
|
39
|
+
|
40
|
+
# Set up the environment so the CLI will authenticate
|
41
|
+
# correctly. Note that the API caches credentials, so these
|
42
|
+
# variables won't have any effect on future calls to
|
43
|
+
# Conjur::Authn.connect
|
44
|
+
step %Q(I set the environment variable "CONJUR_AUTHN_LOGIN" to "#{test_user.login}")
|
45
|
+
step %Q(I set the environment variable "CONJUR_AUTHN_API_KEY" to "#{test_user.api_key}")
|
45
46
|
end
|
46
47
|
|
47
48
|
After do
|
48
|
-
if
|
49
|
-
|
49
|
+
if admin_api
|
50
|
+
admin_api.group("pubkeys-1.0/key-managers").remove_member @security_admin
|
51
|
+
admin_api = nil
|
52
|
+
namespace = nil
|
50
53
|
end
|
51
54
|
tempfiles.each { |tempfile| File.unlink(tempfile) unless tempfile.nil? }
|
52
55
|
end
|
@@ -4,6 +4,8 @@ require 'conjur/api'
|
|
4
4
|
module ConjurCLIWorld
|
5
5
|
include Aruba::Api
|
6
6
|
|
7
|
+
attr_accessor :admin_api, :namespace, :test_user, :headers
|
8
|
+
|
7
9
|
def last_json
|
8
10
|
process_cmd last_command_started.stdout
|
9
11
|
end
|
@@ -28,8 +30,12 @@ module ConjurCLIWorld
|
|
28
30
|
password
|
29
31
|
end
|
30
32
|
|
33
|
+
def admin_role
|
34
|
+
admin_api.current_role.role_id
|
35
|
+
end
|
36
|
+
|
31
37
|
def namespace
|
32
|
-
@namespace
|
38
|
+
@namespace ||= admin_api.create_variable("text/plain", "id").id
|
33
39
|
end
|
34
40
|
|
35
41
|
# Aruba's method
|
@@ -51,6 +57,19 @@ module ConjurCLIWorld
|
|
51
57
|
def tempfiles
|
52
58
|
@tempfiles||=[]
|
53
59
|
end
|
60
|
+
|
61
|
+
def headers
|
62
|
+
@headers ||= {}
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_user_auth_header
|
66
|
+
return if headers['Authorization']
|
67
|
+
|
68
|
+
token = Conjur::API.authenticate(test_user.login, test_user.api_key)
|
69
|
+
headers.merge!(
|
70
|
+
'Authorization' => %Q{Token token="#{Base64.strict_encode64(token.to_json)}"}
|
71
|
+
)
|
72
|
+
end
|
54
73
|
|
55
74
|
protected
|
56
75
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
Feature: Conjur services support trusted proxies
|
2
|
+
|
3
|
+
As an administrator of the Conjur Appliance, I want to be able to
|
4
|
+
specify CIDRs for machines that should be regarded as trusted
|
5
|
+
proxies. IP addresses that match those CIDRs can be regarded as
|
6
|
+
coming from localhost. Other addresses should not be remapped (even
|
7
|
+
if those addresses are non-routable), and so will appear in audit
|
8
|
+
events and be used to validate CIDR restrictions (e.g. on
|
9
|
+
hostfactory tokens).
|
10
|
+
|
11
|
+
Scenario: authn supports trusted proxies for CIDR restrictions
|
12
|
+
Given I set the JSON request body to:
|
13
|
+
"""
|
14
|
+
{
|
15
|
+
"login": "restricted@$ns",
|
16
|
+
"password": "restricted",
|
17
|
+
"ownerid": "cucumber:user:admin@$ns",
|
18
|
+
"cidr": ["192.168.0.0/24"]
|
19
|
+
}
|
20
|
+
"""
|
21
|
+
And I send a POST request to "/api/users"
|
22
|
+
And the response status should be "201"
|
23
|
+
Given I send "text/plain" and accept JSON
|
24
|
+
And I set the request body to "restricted"
|
25
|
+
When I send a POST request forwarded from "192.168.0.1" to "/api/authn/users/restricted@$ns/authenticate"
|
26
|
+
Then the response status should be "200"
|
27
|
+
|
28
|
+
Scenario: authz supports trusted proxies
|
29
|
+
Given I send a PUT request forwarded from "192.168.0.1" to "/api/authz/cucumber/resources/test/$ns/resource?acting_as=$user_role"
|
30
|
+
And the response status should be "204"
|
31
|
+
When I successfully run `conjur audit resource test:$ns/resource`
|
32
|
+
Then the JSON response at "request/ip" should be "192.168.0.1"
|
33
|
+
|
34
|
+
Scenario: core supports trusted proxies
|
35
|
+
Given I set the JSON request body to:
|
36
|
+
"""
|
37
|
+
{
|
38
|
+
"id": "$ns/var",
|
39
|
+
"kind": "password",
|
40
|
+
"mime_type": "text/plain"
|
41
|
+
}
|
42
|
+
"""
|
43
|
+
And I send a POST request forwarded from "192.168.0.1" to "/api/variables"
|
44
|
+
And the response status should be "201"
|
45
|
+
When I successfully run `conjur audit resource variable:$ns/var`
|
46
|
+
Then the JSON response at "request/ip" should be "192.168.0.1"
|
47
|
+
|
48
|
+
Scenario: expiration supports trusted proxies
|
49
|
+
Given I successfully run `conjur variable create $ns_expiration_var value`
|
50
|
+
And I send a GET request forwarded from "192.168.0.1" to "/api/variables/$ns_expiration_var/value"
|
51
|
+
And the response status should be "200"
|
52
|
+
When I get the audit event for the resource "cucumber:variable:$ns_expiration_var" with action "check"
|
53
|
+
Then the audit event should show the request from "192.168.0.1"
|
54
|
+
|
55
|
+
Scenario: host-factory supports trusted proxies when creating hostfactories
|
56
|
+
Given I successfully run `conjur layer create --as-role $user_role $ns/layer`
|
57
|
+
When I send a POST request forwarded from "192.168.0.1" to "/api/host_factories" with:
|
58
|
+
| id | roleid | ownerid | layers[] |
|
59
|
+
| $ns/hf | $user_role | $user_role | $ns/layer |
|
60
|
+
|
61
|
+
And the response status should be "201"
|
62
|
+
And I successfully run `conjur audit resource host_factory:$ns/hf`
|
63
|
+
Then the JSON response at "request/ip" should be "192.168.0.1"
|
64
|
+
|
65
|
+
Scenario: hostfactory supports trusted proxies when creating hosts
|
66
|
+
Given I successfully run `conjur layer create --as-role $user_role $ns/layer`
|
67
|
+
And I successfully run `conjur hostfactory create --as-role $user_role --layer $ns/layer $ns/hf`
|
68
|
+
And I create a hostfactory token for "$ns/hf" with CIDR "192.168.0.0/16"
|
69
|
+
When I use the hostfactory token from "192.168.0.1" to create host "$ns/host"
|
70
|
+
And I get the audit event for the resource "cucumber:host:$ns/host" with action "create"
|
71
|
+
Then the audit event should show the request from "192.168.0.1"
|
72
|
+
|
73
|
+
Scenario: hostfactory supports trusted proxies when validating token CIDR restrictions
|
74
|
+
Given I successfully run `conjur layer create --as-role $user_role $ns/layer`
|
75
|
+
And I successfully run `conjur hostfactory create --as-role $user_role --layer $ns/layer $ns/hf`
|
76
|
+
And I create a hostfactory token for "$ns/hf" with CIDR "192.168.0.0/16"
|
77
|
+
Then I can use the hostfactory token from "192.168.0.1" to create host "$ns/host1"
|
78
|
+
|
79
|
+
Scenario: pubkeys supports trusted proxies
|
80
|
+
Given I create a pubkey for "pubkeys_user@$ns" from "192.168.0.1" with "ssh-rsa foobar pubkeys_user@host"
|
81
|
+
When I get the audit event for the pubkey variable with action "create"
|
82
|
+
Then the audit event should show the request from "192.168.0.1"
|
data/conjur.gemspec
CHANGED
@@ -16,23 +16,25 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = Conjur::VERSION
|
17
17
|
|
18
18
|
gem.add_dependency 'activesupport', '~> 4.2'
|
19
|
-
gem.add_dependency 'bundler', '< 1.12.0'
|
20
19
|
gem.add_dependency 'conjur-api', '~> 4.21'
|
21
20
|
gem.add_dependency 'gli', '>=2.8.0'
|
22
21
|
gem.add_dependency 'highline', '~> 1.7'
|
23
|
-
gem.add_dependency 'netrc', '~> 0.10
|
22
|
+
gem.add_dependency 'netrc', '~> 0.10'
|
24
23
|
gem.add_dependency 'methadone', '~> 1.9'
|
25
24
|
gem.add_dependency 'deep_merge', '~> 1.0'
|
26
25
|
gem.add_dependency 'xdg', '~> 2.2'
|
26
|
+
gem.add_dependency 'table_print', '~> 1.5'
|
27
27
|
|
28
28
|
gem.add_runtime_dependency 'cas_rest_client', '~> 1.3'
|
29
29
|
|
30
30
|
gem.add_development_dependency 'rspec', '~> 3.0'
|
31
31
|
gem.add_development_dependency 'simplecov'
|
32
|
-
gem.add_development_dependency 'aruba', '~> 0.12
|
32
|
+
gem.add_development_dependency 'aruba', '~> 0.12'
|
33
33
|
gem.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
|
34
34
|
gem.add_development_dependency 'ci_reporter_cucumber', '~> 1.0'
|
35
35
|
gem.add_development_dependency 'rake', '~> 10.0'
|
36
|
-
gem.add_development_dependency 'io-grab', '~> 0.0
|
36
|
+
gem.add_development_dependency 'io-grab', '~> 0.0'
|
37
37
|
gem.add_development_dependency 'json_spec'
|
38
|
+
gem.add_development_dependency 'cucumber-api'
|
39
|
+
gem.add_development_dependency 'addressable'
|
38
40
|
end
|
@@ -1,9 +1,74 @@
|
|
1
1
|
require 'conjur/command'
|
2
2
|
|
3
3
|
class Conjur::Command::LDAPSync < Conjur::Command
|
4
|
+
|
5
|
+
LIST_FORMATS = %w(pretty json)
|
6
|
+
|
7
|
+
def self.find_job_by_id args
|
8
|
+
job_id = require_arg args, 'JOB-ID'
|
9
|
+
|
10
|
+
if (job = api.ldap_sync_jobs.find{|j| j.id == job_id})
|
11
|
+
job
|
12
|
+
else
|
13
|
+
exit_now! "No job found with ID '#{job_id}'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
4
17
|
desc 'LDAP sync management commands'
|
5
18
|
command :'ldap-sync' do |cgrp|
|
6
19
|
|
20
|
+
cgrp.desc 'Manage detached LDAP sync jobs'
|
21
|
+
cgrp.command :jobs do |jobs|
|
22
|
+
|
23
|
+
jobs.desc 'List detached jobs'
|
24
|
+
jobs.command :list do |cmd|
|
25
|
+
|
26
|
+
cmd.desc "Specify output format (#{LIST_FORMATS.join(',')})"
|
27
|
+
cmd.flag %w(f format), default_value: 'json', must_match: LIST_FORMATS
|
28
|
+
|
29
|
+
cmd.desc 'Show only JOB ids'
|
30
|
+
cmd.switch %w(i ids-only), default_value: false
|
31
|
+
|
32
|
+
cmd.action do |_,options,_|
|
33
|
+
jobs = api.ldap_sync_jobs.map(&:to_h)
|
34
|
+
|
35
|
+
|
36
|
+
if options[:format] == 'pretty'
|
37
|
+
require 'table_print'
|
38
|
+
fields = [{id: {width: 38}}]
|
39
|
+
|
40
|
+
fields.concat([:type, :state, :exclusive]) unless options[:'ids-only']
|
41
|
+
|
42
|
+
tp jobs, *fields
|
43
|
+
else
|
44
|
+
jobs = jobs.map{|j| j[:id]} if options[:'ids-only']
|
45
|
+
|
46
|
+
display(jobs)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
jobs.desc 'Delete a detached job'
|
53
|
+
jobs.arg_name 'JOB-ID'
|
54
|
+
jobs.command :delete do |cmd|
|
55
|
+
cmd.action do |_, _, args|
|
56
|
+
find_job_by_id(args).delete
|
57
|
+
puts "Job deleted"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
jobs.desc 'Show the output from a detached job'
|
62
|
+
jobs.arg_name 'JOB-ID'
|
63
|
+
jobs.command :show do |cmd|
|
64
|
+
cmd.action do |_,_,args|
|
65
|
+
find_job_by_id(args).output do |event|
|
66
|
+
display(event)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
7
72
|
cgrp.desc 'Trigger a sync of users/groups from LDAP to Conjur'
|
8
73
|
cgrp.command :now do |cmd|
|
9
74
|
cmd.desc 'LDAP Sync profile to use (defined in UI)'
|
@@ -19,33 +84,45 @@ class Conjur::Command::LDAPSync < Conjur::Command
|
|
19
84
|
cmd.default_value 'text'
|
20
85
|
cmd.arg_name 'format'
|
21
86
|
cmd.flag ['f', 'format'], :must_match => ['text', 'yaml']
|
22
|
-
|
87
|
+
|
88
|
+
cmd.desc 'Run sync as a detached job'
|
89
|
+
cmd.default_value true
|
90
|
+
cmd.switch ['detach']
|
91
|
+
|
23
92
|
cmd.action do |_ ,options, args|
|
24
93
|
assert_empty args
|
25
94
|
|
26
95
|
format = options[:format] == 'text' ? 'application/json' : 'text/yaml'
|
27
96
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
97
|
+
dry_run = !!options[:'dry-run']
|
98
|
+
|
99
|
+
# Don't ever run dry-run jobs detached
|
100
|
+
options[:detach] = false if dry_run
|
32
101
|
|
33
102
|
$stderr.puts "Performing #{dry_run ? 'dry run ' : ''}LDAP sync"
|
34
103
|
|
35
|
-
response = api.ldap_sync_now(options[:profile],
|
104
|
+
response = api.ldap_sync_now(:config_name => options[:profile],
|
105
|
+
:format => format,
|
106
|
+
:dry_run => dry_run,
|
107
|
+
:detach_job => options[:detach]
|
108
|
+
)
|
36
109
|
|
37
|
-
if options[:
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
110
|
+
if !options[:detach]
|
111
|
+
if options[:format] == 'text'
|
112
|
+
puts "Messages:"
|
113
|
+
response['events'].each do |event|
|
114
|
+
puts [ event['timestamp'], event['severity'], event['message'] ].join("\t")
|
115
|
+
end
|
116
|
+
puts
|
117
|
+
puts "Actions:"
|
118
|
+
response['result']['actions'].each do |action|
|
119
|
+
puts action
|
120
|
+
end
|
121
|
+
else
|
122
|
+
puts response
|
46
123
|
end
|
47
124
|
else
|
48
|
-
|
125
|
+
display response
|
49
126
|
end
|
50
127
|
end
|
51
128
|
end
|
data/lib/conjur/version.rb
CHANGED
@@ -22,7 +22,78 @@ describe Conjur::Command::LDAPSync, logged_in: true do
|
|
22
22
|
}
|
23
23
|
].to_yaml }
|
24
24
|
|
25
|
-
|
25
|
+
|
26
|
+
|
27
|
+
context 'when testing ldap-sync jobs commands' do
|
28
|
+
let(:jobs){
|
29
|
+
[
|
30
|
+
Conjur::LdapSyncJob.new(api, :id => 'job-1', :type => 'sync', :state => 'running', :exclusive => true),
|
31
|
+
Conjur::LdapSyncJob.new(api, :id => 'job-2', :type => 'connect', :state => 'success', :exclusive => false)
|
32
|
+
]
|
33
|
+
}
|
34
|
+
|
35
|
+
before do
|
36
|
+
expect_any_instance_of(Conjur::API).to receive(:ldap_sync_jobs).and_return jobs
|
37
|
+
end
|
38
|
+
|
39
|
+
describe_command 'ldap-sync jobs list' do
|
40
|
+
it 'prints the jobs as json' do
|
41
|
+
expect { invoke }.to write(JSON.pretty_generate jobs.map(&:as_json))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe_command 'ldap-sync jobs list -i' do
|
46
|
+
it 'prints the job ids only' do
|
47
|
+
expect { invoke }.to write(JSON.pretty_generate jobs.map(&:id))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe_command 'ldap-sync jobs list -f pretty' do
|
52
|
+
|
53
|
+
it 'prints the jobs in a fancy table' do
|
54
|
+
expect{ invoke }.to write /ID\s*|\s*TYPE\s*|\s*STATE\s*|\s*EXCLUSIVE.*?
|
55
|
+
job-1\s*|\s*sync\s*|\s*running\s*|\s*true
|
56
|
+
job-2\s*|\s*connect\s*|\s*success\s*|\s*false/x
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
describe_command 'ldap-sync jobs delete job-2' do
|
62
|
+
let(:victim){ jobs[1] }
|
63
|
+
it 'deletes the job' do
|
64
|
+
expect(victim).to receive(:delete)
|
65
|
+
invoke
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe_command 'ldap-sync jobs delete no-such-job' do
|
70
|
+
it 'fails with a sensible error message' do
|
71
|
+
expect{ invoke }.to raise_exception(/No job found with ID 'no-such-job'/)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe_command 'ldap-sync jobs show job-1' do
|
76
|
+
let(:victim){ jobs[0] }
|
77
|
+
it 'prints the values passed to output' do
|
78
|
+
expect(victim).to receive(:output) do |&block|
|
79
|
+
block.call({foo: 'bar'})
|
80
|
+
block.call({spam: 'eggs'})
|
81
|
+
end
|
82
|
+
|
83
|
+
expect{invoke}.to write(<<EOS)
|
84
|
+
{
|
85
|
+
"foo": "bar"
|
86
|
+
}
|
87
|
+
{
|
88
|
+
"spam": "eggs"
|
89
|
+
}
|
90
|
+
EOS
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe_command 'ldap-sync now --no-detach -f text' do
|
26
97
|
before {
|
27
98
|
expect_any_instance_of(Conjur::API).to receive(:ldap_sync_now).and_return json_response
|
28
99
|
}
|
@@ -34,7 +105,7 @@ describe Conjur::Command::LDAPSync, logged_in: true do
|
|
34
105
|
end
|
35
106
|
end
|
36
107
|
|
37
|
-
describe_command 'ldap-sync now -f yaml' do
|
108
|
+
describe_command 'ldap-sync now --no-detach -f yaml' do
|
38
109
|
it 'prints out actions as unparsed yaml' do
|
39
110
|
expect_any_instance_of(Conjur::API).to receive(:ldap_sync_now).and_return yaml_response
|
40
111
|
expect { invoke }.to write(yaml_response)
|
@@ -42,9 +113,10 @@ describe Conjur::Command::LDAPSync, logged_in: true do
|
|
42
113
|
end
|
43
114
|
|
44
115
|
context 'when testing dry-run' do
|
116
|
+
let (:detach) { true }
|
45
117
|
before do
|
46
118
|
expect_any_instance_of(Conjur::API).to receive(:ldap_sync_now)
|
47
|
-
.with('default', 'application/json', dry_run)
|
119
|
+
.with(:config_name => 'default', :format => 'application/json', :dry_run => dry_run, :detach_job => detach)
|
48
120
|
.and_return json_response
|
49
121
|
end
|
50
122
|
|
@@ -64,6 +136,7 @@ describe Conjur::Command::LDAPSync, logged_in: true do
|
|
64
136
|
|
65
137
|
describe_command 'ldap-sync now --dry-run' do
|
66
138
|
let(:dry_run) { true }
|
139
|
+
let(:detach) { false }
|
67
140
|
it 'passes truthy dry-run value' do
|
68
141
|
invoke
|
69
142
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conjur-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.3.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-
|
12
|
+
date: 2016-10-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -25,20 +25,6 @@ dependencies:
|
|
25
25
|
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '4.2'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: bundler
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - <
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: 1.12.0
|
35
|
-
type: :runtime
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - <
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 1.12.0
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: conjur-api
|
44
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -87,14 +73,14 @@ dependencies:
|
|
87
73
|
requirements:
|
88
74
|
- - ~>
|
89
75
|
- !ruby/object:Gem::Version
|
90
|
-
version: 0.10
|
76
|
+
version: '0.10'
|
91
77
|
type: :runtime
|
92
78
|
prerelease: false
|
93
79
|
version_requirements: !ruby/object:Gem::Requirement
|
94
80
|
requirements:
|
95
81
|
- - ~>
|
96
82
|
- !ruby/object:Gem::Version
|
97
|
-
version: 0.10
|
83
|
+
version: '0.10'
|
98
84
|
- !ruby/object:Gem::Dependency
|
99
85
|
name: methadone
|
100
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +123,20 @@ dependencies:
|
|
137
123
|
- - ~>
|
138
124
|
- !ruby/object:Gem::Version
|
139
125
|
version: '2.2'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: table_print
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ~>
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '1.5'
|
133
|
+
type: :runtime
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ~>
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '1.5'
|
140
140
|
- !ruby/object:Gem::Dependency
|
141
141
|
name: cas_rest_client
|
142
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -185,14 +185,14 @@ dependencies:
|
|
185
185
|
requirements:
|
186
186
|
- - ~>
|
187
187
|
- !ruby/object:Gem::Version
|
188
|
-
version: 0.12
|
188
|
+
version: '0.12'
|
189
189
|
type: :development
|
190
190
|
prerelease: false
|
191
191
|
version_requirements: !ruby/object:Gem::Requirement
|
192
192
|
requirements:
|
193
193
|
- - ~>
|
194
194
|
- !ruby/object:Gem::Version
|
195
|
-
version: 0.12
|
195
|
+
version: '0.12'
|
196
196
|
- !ruby/object:Gem::Dependency
|
197
197
|
name: ci_reporter_rspec
|
198
198
|
requirement: !ruby/object:Gem::Requirement
|
@@ -241,14 +241,14 @@ dependencies:
|
|
241
241
|
requirements:
|
242
242
|
- - ~>
|
243
243
|
- !ruby/object:Gem::Version
|
244
|
-
version: 0.0
|
244
|
+
version: '0.0'
|
245
245
|
type: :development
|
246
246
|
prerelease: false
|
247
247
|
version_requirements: !ruby/object:Gem::Requirement
|
248
248
|
requirements:
|
249
249
|
- - ~>
|
250
250
|
- !ruby/object:Gem::Version
|
251
|
-
version: 0.0
|
251
|
+
version: '0.0'
|
252
252
|
- !ruby/object:Gem::Dependency
|
253
253
|
name: json_spec
|
254
254
|
requirement: !ruby/object:Gem::Requirement
|
@@ -263,6 +263,34 @@ dependencies:
|
|
263
263
|
- - '>='
|
264
264
|
- !ruby/object:Gem::Version
|
265
265
|
version: '0'
|
266
|
+
- !ruby/object:Gem::Dependency
|
267
|
+
name: cucumber-api
|
268
|
+
requirement: !ruby/object:Gem::Requirement
|
269
|
+
requirements:
|
270
|
+
- - '>='
|
271
|
+
- !ruby/object:Gem::Version
|
272
|
+
version: '0'
|
273
|
+
type: :development
|
274
|
+
prerelease: false
|
275
|
+
version_requirements: !ruby/object:Gem::Requirement
|
276
|
+
requirements:
|
277
|
+
- - '>='
|
278
|
+
- !ruby/object:Gem::Version
|
279
|
+
version: '0'
|
280
|
+
- !ruby/object:Gem::Dependency
|
281
|
+
name: addressable
|
282
|
+
requirement: !ruby/object:Gem::Requirement
|
283
|
+
requirements:
|
284
|
+
- - '>='
|
285
|
+
- !ruby/object:Gem::Version
|
286
|
+
version: '0'
|
287
|
+
type: :development
|
288
|
+
prerelease: false
|
289
|
+
version_requirements: !ruby/object:Gem::Requirement
|
290
|
+
requirements:
|
291
|
+
- - '>='
|
292
|
+
- !ruby/object:Gem::Version
|
293
|
+
version: '0'
|
266
294
|
description:
|
267
295
|
email:
|
268
296
|
- rafal@conjur.net
|
@@ -347,10 +375,13 @@ files:
|
|
347
375
|
- acceptance-features/pubkeys/show.feature
|
348
376
|
- acceptance-features/step_definitions/cli_steps.rb
|
349
377
|
- acceptance-features/step_definitions/graph_steps.rb
|
378
|
+
- acceptance-features/step_definitions/http_steps.rb
|
379
|
+
- acceptance-features/step_definitions/trusted_proxy_steps.rb
|
350
380
|
- acceptance-features/step_definitions/user_steps.rb
|
351
381
|
- acceptance-features/support/env.rb
|
352
382
|
- acceptance-features/support/hooks.rb
|
353
383
|
- acceptance-features/support/world.rb
|
384
|
+
- acceptance-features/trusted_proxies.feature
|
354
385
|
- bin/_conjur
|
355
386
|
- bin/conjur
|
356
387
|
- bin/conjurize
|