conjur-api 4.23.0 → 4.24.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/conjur-api.gemspec +0 -1
- data/lib/conjur-api/version.rb +1 -1
- data/lib/conjur/api.rb +6 -5
- data/lib/conjur/api/ldapsync.rb +51 -0
- data/lib/conjur/base.rb +31 -32
- data/lib/conjur/escape.rb +2 -1
- data/lib/conjur/user.rb +0 -3
- data/spec/api/ldapsync_spec.rb +54 -0
- data/spec/lib/api_spec.rb +51 -47
- metadata +5 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6a400415b1a2ace3c70bfa63befe1155411e689
|
4
|
+
data.tar.gz: da597b98f100670f494de01da0c7ec3e14f23164
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cd91330ebb3ca97d512e639ee35256dd79723b55528fef64290e4d2c5c863048d4667598604e61145de22316045fe6a13a2a7bc5ba156819f7c440b52c0d3c1
|
7
|
+
data.tar.gz: beb95a4206bf8ffed5d1bd8bee7a799d0d9984d7f7dffb729b3e29bb1832ed576e77c083e00988e0e6bb5e0e77e4e39a381cd360090946ba478fab9f7c12a579
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# v4.24.0
|
2
|
+
|
3
|
+
* Add `Conjur::API#ldap_sync_now` (requires Conjur 4.7 or later).
|
4
|
+
* Don't trust the system clock and don't check token validity. Rely on the
|
5
|
+
server to verify the token instead, and only try to refresh if enough time
|
6
|
+
has passed locally (using monotonic clock for reference where available).
|
7
|
+
* Don't try refreshing the token if the required credentials are not available.
|
8
|
+
|
1
9
|
# v4.23.0
|
2
10
|
|
3
11
|
* Add `with_audit_roles` and `with_audit_resources` to `Conjur::API`
|
data/conjur-api.gemspec
CHANGED
@@ -38,7 +38,6 @@ Gem::Specification.new do |gem|
|
|
38
38
|
gem.add_development_dependency 'rdoc'
|
39
39
|
gem.add_development_dependency 'yard'
|
40
40
|
gem.add_development_dependency 'redcarpet'
|
41
|
-
gem.add_development_dependency 'timecop'
|
42
41
|
gem.add_development_dependency 'tins', '~> 1.6', '< 1.7.0'
|
43
42
|
gem.add_development_dependency 'inch'
|
44
43
|
end
|
data/lib/conjur-api/version.rb
CHANGED
data/lib/conjur/api.rb
CHANGED
@@ -45,6 +45,7 @@ require 'conjur/host-factory-api'
|
|
45
45
|
require 'conjur/bootstrap'
|
46
46
|
require 'conjur-api/version'
|
47
47
|
require 'conjur/api/info'
|
48
|
+
require 'conjur/api/ldapsync'
|
48
49
|
|
49
50
|
# Monkey patch RestClient::Request so it always uses
|
50
51
|
# :ssl_cert_store. (RestClient::Resource uses Request to send
|
@@ -57,14 +58,14 @@ class RestClient::Request
|
|
57
58
|
ssl_cert_store: OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
|
58
59
|
}
|
59
60
|
end
|
60
|
-
|
61
|
+
|
61
62
|
def initialize args
|
62
63
|
initialize_without_defaults default_args.merge(args)
|
63
64
|
end
|
64
|
-
|
65
|
+
|
65
66
|
end
|
66
67
|
|
67
|
-
|
68
|
+
|
68
69
|
class RestClient::Resource
|
69
70
|
include Conjur::Escape
|
70
71
|
include Conjur::LogSource
|
@@ -119,11 +120,11 @@ class RestClient::Resource
|
|
119
120
|
raise AuthorizationError.new("Authorization missing")
|
120
121
|
end
|
121
122
|
end
|
122
|
-
|
123
|
+
|
123
124
|
def remote_ip
|
124
125
|
options[:headers][:x_forwarded_for]
|
125
126
|
end
|
126
|
-
|
127
|
+
|
127
128
|
def conjur_privilege
|
128
129
|
options[:headers][:x_conjur_privilege]
|
129
130
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2016 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
|
+
module Conjur
|
23
|
+
class API
|
24
|
+
# @!group LDAP Sync Service
|
25
|
+
|
26
|
+
# Trigger a LDAP sync with a given profile.
|
27
|
+
|
28
|
+
# @param [String] config_name Saved profile to run sync with
|
29
|
+
# @param [Boolean] dry_run Don't actually run sync, instead just report the state of the upstream LDAP.
|
30
|
+
# @param [String] format Requested MIME type of the response, either 'text/yaml' or 'application/json'
|
31
|
+
# @return [Hash] a hash mapping with keys 'ok' and 'result[:actions]'
|
32
|
+
def ldap_sync_now(config_name, format, dry_run)
|
33
|
+
opts = credentials.dup.tap{ |h|
|
34
|
+
h[:headers][:accept] = format
|
35
|
+
}
|
36
|
+
|
37
|
+
resp = RestClient::Resource.new(Conjur.configuration.appliance_url, opts)['ldap-sync']['sync'].post({
|
38
|
+
config_name: config_name,
|
39
|
+
dry_run: dry_run
|
40
|
+
})
|
41
|
+
|
42
|
+
if format == 'text/yaml'
|
43
|
+
resp.body
|
44
|
+
elsif format == 'application/json'
|
45
|
+
JSON.parse(resp.body)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @!endgroup
|
50
|
+
end
|
51
|
+
end
|
data/lib/conjur/base.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (C) 2013-
|
2
|
+
# Copyright (C) 2013-2016 Conjur Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
5
|
# this software and associated documentation files (the "Software"), to deal in
|
@@ -222,22 +222,14 @@ module Conjur
|
|
222
222
|
self.class.host
|
223
223
|
end
|
224
224
|
|
225
|
-
# The token used to authenticate requests made with the api. The token will be fetched
|
226
|
-
# if
|
227
|
-
# exception if the credentials are invalid.
|
228
|
-
#
|
229
|
-
# @note calling this method on an {Conjur::API} instance created with {Conjur::API.new_from_token} will have
|
230
|
-
# undefined behavior if the token is expired.
|
225
|
+
# The token used to authenticate requests made with the api. The token will be fetched,
|
226
|
+
# if possible, when not present or about to expire. Accordingly, this
|
227
|
+
# method may raise a RestClient::Unauthorized exception if the credentials are invalid.
|
231
228
|
#
|
232
229
|
# @return [Hash] the authentication token as a Hash
|
233
230
|
# @raise [RestClient::Unauthorized] if the username and api key are invalid.
|
234
231
|
def token
|
235
|
-
|
236
|
-
|
237
|
-
@token ||= Conjur::API.authenticate(@username, @api_key)
|
238
|
-
|
239
|
-
validate_token
|
240
|
-
|
232
|
+
refresh_token if needs_token_refresh?
|
241
233
|
return @token
|
242
234
|
end
|
243
235
|
|
@@ -285,28 +277,35 @@ module Conjur
|
|
285
277
|
|
286
278
|
private
|
287
279
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
280
|
+
|
281
|
+
# Tries to refresh the token if possible.
|
282
|
+
#
|
283
|
+
# @return [Hash, false] false if the token couldn't be refreshed due to
|
284
|
+
# unavailable API key; otherwise, the new token.
|
285
|
+
def refresh_token
|
286
|
+
return false unless @api_key
|
287
|
+
@token_born = gettime
|
288
|
+
@token = Conjur::API.authenticate(@username, @api_key)
|
295
289
|
end
|
296
290
|
|
297
|
-
|
291
|
+
TOKEN_STALE = 5.minutes
|
292
|
+
|
293
|
+
# Checks if the token is old (or not present).
|
298
294
|
#
|
299
|
-
# @
|
300
|
-
def
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
295
|
+
# @return [Boolean]
|
296
|
+
def needs_token_refresh?
|
297
|
+
!@token || ((token_age || 0) > TOKEN_STALE)
|
298
|
+
end
|
299
|
+
|
300
|
+
def gettime
|
301
|
+
Process.clock_gettime Process::CLOCK_MONOTONIC
|
302
|
+
rescue
|
303
|
+
# fall back to normal clock if there's no CLOCK_MONOTONIC
|
304
|
+
Time.now.to_f
|
305
|
+
end
|
306
|
+
|
307
|
+
def token_age
|
308
|
+
@token_born && (gettime - @token_born)
|
310
309
|
end
|
311
310
|
end
|
312
311
|
end
|
data/lib/conjur/escape.rb
CHANGED
@@ -25,7 +25,8 @@ module Conjur
|
|
25
25
|
# The helpers are added as both class and isntance methods.
|
26
26
|
module Escape
|
27
27
|
module ClassMethods
|
28
|
-
# URL escape the entire string. This is essentially the same as calling `CGI.escape str
|
28
|
+
# URL escape the entire string. This is essentially the same as calling `CGI.escape str`,
|
29
|
+
# and then substituting `%20` for `+`.
|
29
30
|
#
|
30
31
|
# @example
|
31
32
|
# fully_escape 'foo/bar@baz'
|
data/lib/conjur/user.rb
CHANGED
@@ -19,9 +19,6 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
-
class InvalidToken < Exception
|
23
|
-
end
|
24
|
-
|
25
22
|
# This class represents a {http://developer.conjur.net/reference/services/directory/user Conjur User}.
|
26
23
|
class User < RestClient::Resource
|
27
24
|
include ActsAsAsset
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2016 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
|
+
require 'spec_helper'
|
22
|
+
|
23
|
+
describe Conjur::API, api: :dummy do
|
24
|
+
let(:appliance_url){ "http://example.com/api" }
|
25
|
+
let(:ldapsync_url){ "#{appliance_url}/ldap-sync/sync" }
|
26
|
+
let(:response_json){
|
27
|
+
{
|
28
|
+
:okay => true,
|
29
|
+
:result => {
|
30
|
+
:actions => [
|
31
|
+
"Create user 'Guest'\n Set annotation 'ldap-sync/source'\n Set annotation 'ldap-sync/upstream-dn'"
|
32
|
+
]
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
let(:response){ double('response', body: response_json.to_json) }
|
37
|
+
|
38
|
+
before do
|
39
|
+
allow(Conjur.configuration).to receive(:appliance_url).and_return appliance_url
|
40
|
+
allow(Conjur::API).to receive_messages(ldap_sync_now: ldapsync_url)
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#ldap_sync_now" do
|
44
|
+
it "POSTs /sync" do
|
45
|
+
expect_request(
|
46
|
+
url: ldapsync_url,
|
47
|
+
method: :post,
|
48
|
+
headers: credentials[:headers],
|
49
|
+
payload: {config_name: 'default', dry_run: true}
|
50
|
+
).and_return response
|
51
|
+
api.ldap_sync_now('default', 'application/json', true)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/lib/api_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'timecop'
|
3
2
|
|
4
3
|
shared_examples_for "API endpoint" do
|
5
4
|
before { Conjur.configuration = Conjur::Configuration.new }
|
@@ -222,24 +221,67 @@ describe Conjur::API do
|
|
222
221
|
end
|
223
222
|
end
|
224
223
|
|
225
|
-
shared_context logged_in: true do
|
224
|
+
shared_context "logged in", logged_in: true do
|
226
225
|
let(:login) { "bob" }
|
227
226
|
let(:token) { { 'data' => login, 'timestamp' => Time.now.to_s } }
|
228
|
-
subject { api }
|
229
227
|
let(:remote_ip) { nil }
|
230
228
|
let(:api_args) { [ token, remote_ip ].compact }
|
231
|
-
|
229
|
+
subject(:api) { Conjur::API.new_from_token(*api_args) }
|
232
230
|
let(:account) { 'some-account' }
|
233
231
|
before { allow(Conjur::Core::API).to receive_messages conjur_account: account }
|
234
232
|
end
|
235
233
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
234
|
+
shared_context "logged in with an API key", logged_in: :api_key do
|
235
|
+
include_context "logged in"
|
236
|
+
let(:api_key) { "theapikey" }
|
237
|
+
let(:api_args) { [ login, api_key, remote_ip ].compact }
|
238
|
+
subject(:api) { Conjur::API.new_from_key(*api_args) }
|
239
|
+
end
|
240
|
+
|
241
|
+
def time_travel delta
|
242
|
+
allow(api).to receive(:gettime).and_wrap_original do |m|
|
243
|
+
m[] + delta
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe '#token' do
|
248
|
+
context 'with API key available', logged_in: :api_key do
|
249
|
+
it "authenticates to get a token" do
|
250
|
+
expect(Conjur::API).to receive(:authenticate).with(login, api_key).and_return token
|
251
|
+
|
252
|
+
expect(api.instance_variable_get("@token")).to eq(nil)
|
253
|
+
expect(api.token).to eq(token)
|
254
|
+
expect(api.credentials).to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login })
|
241
255
|
end
|
242
256
|
|
257
|
+
it "fetches a new token if old" do
|
258
|
+
allow(Conjur::API).to receive(:authenticate).with(login, api_key).and_return token
|
259
|
+
expect(Time.parse(api.token['timestamp'])).to be_within(5.seconds).of(Time.now)
|
260
|
+
|
261
|
+
time_travel 6.minutes
|
262
|
+
new_token = token.merge "timestamp" => Time.now.to_s
|
263
|
+
|
264
|
+
expect(Conjur::API).to receive(:authenticate).with(login, api_key).and_return new_token
|
265
|
+
expect(api.token).to eq(new_token)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
context 'with no API key available', logged_in: true do
|
270
|
+
it "returns the token used to create it" do
|
271
|
+
expect(api.token).to eq token
|
272
|
+
end
|
273
|
+
|
274
|
+
it "doesn't try to refresh an old token" do
|
275
|
+
expect(Conjur::API).not_to receive :authenticate
|
276
|
+
api.token # vivify
|
277
|
+
time_travel 6.minutes
|
278
|
+
expect { api.token }.not_to raise_error
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
context "credential handling", logged_in: true do
|
284
|
+
context "from token" do
|
243
285
|
describe '#credentials' do
|
244
286
|
subject { super().credentials }
|
245
287
|
it { is_expected.to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login }) }
|
@@ -260,44 +302,6 @@ describe Conjur::API do
|
|
260
302
|
end
|
261
303
|
end
|
262
304
|
end
|
263
|
-
|
264
|
-
|
265
|
-
context "from api key", logged_in: true do
|
266
|
-
let(:api_key) { "theapikey" }
|
267
|
-
let(:api_args) { [ login, api_key, remote_ip ].compact }
|
268
|
-
let(:api) { Conjur::API.new_from_key(*api_args) }
|
269
|
-
let(:remote_ip) { nil }
|
270
|
-
subject { api }
|
271
|
-
|
272
|
-
it("should authenticate to get a token") do
|
273
|
-
expect(Conjur::API).to receive(:authenticate).with(login, api_key).and_return token
|
274
|
-
|
275
|
-
expect(api.instance_variable_get("@token")).to eq(nil)
|
276
|
-
expect(api.token).to eq(token)
|
277
|
-
expect(api.credentials).to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login })
|
278
|
-
end
|
279
|
-
|
280
|
-
it("checks if the token is fresh") do
|
281
|
-
expired_token = token.merge 'timestamp' => 10.minutes.ago.to_s
|
282
|
-
expect(Conjur::API).to receive(:authenticate).with(login, api_key).and_return expired_token
|
283
|
-
|
284
|
-
expect(api.instance_variable_get("@token")).to eq(nil)
|
285
|
-
expect { api.token }.to raise_error /obtained token is invalid/
|
286
|
-
end
|
287
|
-
|
288
|
-
context "with an expired token" do
|
289
|
-
it "fetches a new one" do
|
290
|
-
allow(Conjur::API).to receive(:authenticate).with(login, api_key).and_return token
|
291
|
-
expect(Time.parse(api.token['timestamp'])).to be_within(5.seconds).of(Time.now)
|
292
|
-
|
293
|
-
Timecop.travel Time.now + 6.minutes
|
294
|
-
new_token = token.merge "timestamp" => Time.now.to_s
|
295
|
-
|
296
|
-
expect(Conjur::API).to receive(:authenticate).with(login, api_key).and_return new_token
|
297
|
-
expect(api.token).to eq(new_token)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
end
|
301
305
|
|
302
306
|
context "from logged-in RestClient::Resource" do
|
303
307
|
let (:authz_header) { %Q{Token token="#{token_encoded}"} }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conjur-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.24.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-05-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -269,20 +269,6 @@ dependencies:
|
|
269
269
|
- - '>='
|
270
270
|
- !ruby/object:Gem::Version
|
271
271
|
version: '0'
|
272
|
-
- !ruby/object:Gem::Dependency
|
273
|
-
name: timecop
|
274
|
-
requirement: !ruby/object:Gem::Requirement
|
275
|
-
requirements:
|
276
|
-
- - '>='
|
277
|
-
- !ruby/object:Gem::Version
|
278
|
-
version: '0'
|
279
|
-
type: :development
|
280
|
-
prerelease: false
|
281
|
-
version_requirements: !ruby/object:Gem::Requirement
|
282
|
-
requirements:
|
283
|
-
- - '>='
|
284
|
-
- !ruby/object:Gem::Version
|
285
|
-
version: '0'
|
286
272
|
- !ruby/object:Gem::Dependency
|
287
273
|
name: tins
|
288
274
|
requirement: !ruby/object:Gem::Requirement
|
@@ -361,6 +347,7 @@ files:
|
|
361
347
|
- lib/conjur/api/hosts.rb
|
362
348
|
- lib/conjur/api/info.rb
|
363
349
|
- lib/conjur/api/layers.rb
|
350
|
+
- lib/conjur/api/ldapsync.rb
|
364
351
|
- lib/conjur/api/pubkeys.rb
|
365
352
|
- lib/conjur/api/resources.rb
|
366
353
|
- lib/conjur/api/roles.rb
|
@@ -414,6 +401,7 @@ files:
|
|
414
401
|
- spec/api/hosts_spec.rb
|
415
402
|
- spec/api/info_spec.rb
|
416
403
|
- spec/api/layer_spec.rb
|
404
|
+
- spec/api/ldapsync_spec.rb
|
417
405
|
- spec/api/pubkeys_spec.rb
|
418
406
|
- spec/api/resources_spec.rb
|
419
407
|
- spec/api/roles_spec.rb
|
@@ -490,6 +478,7 @@ test_files:
|
|
490
478
|
- spec/api/hosts_spec.rb
|
491
479
|
- spec/api/info_spec.rb
|
492
480
|
- spec/api/layer_spec.rb
|
481
|
+
- spec/api/ldapsync_spec.rb
|
493
482
|
- spec/api/pubkeys_spec.rb
|
494
483
|
- spec/api/resources_spec.rb
|
495
484
|
- spec/api/roles_spec.rb
|