conjur-cli 5.2.5 → 5.3.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 +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
|