conjur-api 4.31.0 → 5.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +22 -3
- data/Dockerfile +12 -3
- data/Gemfile +3 -3
- data/Jenkinsfile +69 -0
- data/LICENSE.md +195 -0
- data/README.md +16 -0
- data/Rakefile +34 -18
- data/ci/wait_for_server.sh +10 -0
- data/conjur-api.gemspec +6 -14
- data/dev/docker-compose.yml +23 -0
- data/dev/empty.yml +2 -0
- data/dev/start.sh +15 -0
- data/dev/stop.sh +6 -0
- data/docker-compose.yml +27 -0
- data/features/exists.feature +37 -0
- data/features/group.feature +11 -0
- data/features/host.feature +20 -0
- data/features/host_factory_create_host.feature +28 -0
- data/features/host_factory_token.feature +63 -0
- data/features/load_policy.feature +61 -0
- data/features/members.feature +51 -0
- data/features/new_api.feature +36 -0
- data/features/permitted.feature +43 -0
- data/features/permitted_roles.feature +30 -0
- data/features/public_keys.feature +11 -0
- data/features/resource_fields.feature +53 -0
- data/features/role_fields.feature +15 -0
- data/features/rotate_api_key.feature +13 -0
- data/features/step_definitions/api_steps.rb +4 -54
- data/features/step_definitions/policy_steps.rb +35 -0
- data/features/step_definitions/result_steps.rb +7 -0
- data/features/support/env.rb +14 -5
- data/features/support/hooks.rb +3 -0
- data/features/support/world.rb +5 -6
- data/features/update_password.feature +14 -0
- data/features/user.feature +17 -0
- data/features/variable_fields.feature +20 -0
- data/features/variable_value.feature +67 -0
- data/lib/conjur/acts_as_resource.rb +95 -65
- data/lib/conjur/acts_as_role.rb +102 -51
- data/lib/conjur/{audit-api.rb → acts_as_rolsource.rb} +10 -14
- data/lib/conjur/acts_as_user.rb +13 -22
- data/lib/conjur/api/authn.rb +37 -72
- data/lib/conjur/api/host_factories.rb +35 -55
- data/lib/conjur/api/policies.rb +56 -0
- data/lib/conjur/api/pubkeys.rb +36 -160
- data/lib/conjur/api/resources.rb +32 -116
- data/lib/conjur/api/roles.rb +28 -105
- data/lib/conjur/api/variables.rb +22 -91
- data/lib/conjur/api.rb +19 -46
- data/lib/conjur/base.rb +21 -132
- data/lib/conjur/base_object.rb +57 -0
- data/lib/conjur/{authn-api.rb → build_object.rb} +23 -11
- data/lib/conjur/cast.rb +12 -17
- data/lib/conjur/cert_utils.rb +1 -1
- data/lib/conjur/cidr.rb +1 -1
- data/lib/conjur/configuration.rb +13 -91
- data/lib/conjur/escape.rb +1 -2
- data/lib/conjur/group.rb +9 -65
- data/lib/conjur/has_attributes.rb +22 -59
- data/lib/conjur/host.rb +5 -35
- data/lib/conjur/host_factory.rb +40 -40
- data/lib/conjur/host_factory_token.rb +38 -23
- data/lib/conjur/id.rb +63 -0
- data/lib/conjur/layer.rb +5 -80
- data/lib/conjur/log.rb +1 -1
- data/lib/conjur/log_source.rb +1 -1
- data/lib/conjur/{secret.rb → policy.rb} +11 -14
- data/lib/conjur/{api/secrets.rb → policy_load_result.rb} +35 -22
- data/lib/conjur/query_string.rb +2 -1
- data/lib/conjur/resource.rb +5 -299
- data/lib/conjur/role.rb +5 -317
- data/lib/conjur/role_grant.rb +20 -28
- data/lib/conjur/user.rb +5 -63
- data/lib/conjur/variable.rb +31 -76
- data/lib/conjur/{authz-api.rb → webservice.rb} +8 -16
- data/lib/conjur-api/version.rb +2 -2
- data/publish.sh +7 -0
- data/spec/api_spec.rb +208 -0
- data/spec/cast_spec.rb +21 -0
- data/spec/{lib/cert_utils_spec.rb → cert_utils_spec.rb} +0 -0
- data/spec/{lib/cidr_spec.rb → cidr_spec.rb} +0 -0
- data/spec/{lib/configuration_spec.rb → configuration_spec.rb} +40 -140
- data/spec/{lib/has_attributes_spec.rb → has_attributes_spec.rb} +6 -2
- data/spec/{lib/log_source_spec.rb → log_source_spec.rb} +0 -0
- data/spec/{lib/log_spec.rb → log_spec.rb} +0 -0
- data/spec/roles_spec.rb +24 -0
- data/spec/spec_helper.rb +63 -78
- data/spec/ssl_spec.rb +3 -5
- data/spec/vendor/rest_client_spec.rb +0 -54
- data/test.sh +40 -0
- metadata +122 -281
- data/.kateproject +0 -5
- data/LICENSE +0 -22
- data/ci/test.sh +0 -9
- data/features/audit_resources.feature +0 -15
- data/features/audit_roles.feature +0 -15
- data/features/bootstrap.feature +0 -31
- data/features/step_definitions/cli_steps.rb +0 -5
- data/jenkins.sh +0 -27
- data/lib/conjur/acts_as_asset.rb +0 -88
- data/lib/conjur/annotations.rb +0 -186
- data/lib/conjur/api/audit.rb +0 -138
- data/lib/conjur/api/deputies.rb +0 -57
- data/lib/conjur/api/groups.rb +0 -111
- data/lib/conjur/api/hosts.rb +0 -109
- data/lib/conjur/api/info.rb +0 -126
- data/lib/conjur/api/layers.rb +0 -62
- data/lib/conjur/api/ldapsync.rb +0 -115
- data/lib/conjur/api/users.rb +0 -106
- data/lib/conjur/bootstrap.rb +0 -161
- data/lib/conjur/build_from_response.rb +0 -49
- data/lib/conjur/core-api.rb +0 -74
- data/lib/conjur/deputy.rb +0 -55
- data/lib/conjur/env.rb +0 -54
- data/lib/conjur/event_source.rb +0 -101
- data/lib/conjur/exists.rb +0 -60
- data/lib/conjur/graph.rb +0 -295
- data/lib/conjur/has_id.rb +0 -43
- data/lib/conjur/has_identifier.rb +0 -36
- data/lib/conjur/has_owner.rb +0 -51
- data/lib/conjur/host-factory-api.rb +0 -38
- data/lib/conjur/layer-api.rb +0 -13
- data/lib/conjur/ldap_sync_job.rb +0 -89
- data/lib/conjur/path_based.rb +0 -86
- data/lib/conjur/pubkeys-api.rb +0 -50
- data/lib/conjur/standard_methods.rb +0 -91
- data/reqspeed.rb +0 -20
- data/spec/api/authn_spec.rb +0 -81
- data/spec/api/graph_spec.rb +0 -117
- data/spec/api/groups_spec.rb +0 -40
- data/spec/api/hosts_spec.rb +0 -36
- data/spec/api/info_spec.rb +0 -89
- data/spec/api/layer_spec.rb +0 -18
- data/spec/api/ldapsync_spec.rb +0 -44
- data/spec/api/pubkeys_spec.rb +0 -66
- data/spec/api/resources_spec.rb +0 -92
- data/spec/api/roles_spec.rb +0 -100
- data/spec/api/secrets_spec.rb +0 -16
- data/spec/api/users_spec.rb +0 -71
- data/spec/api/variables_spec.rb +0 -112
- data/spec/cas_rest_client.rb +0 -17
- data/spec/cidr_helper.rb +0 -24
- data/spec/lib/acts_as_user_spec.rb +0 -27
- data/spec/lib/annotations_spec.rb +0 -109
- data/spec/lib/api_spec.rb +0 -480
- data/spec/lib/asset_spec.rb +0 -80
- data/spec/lib/audit_spec.rb +0 -155
- data/spec/lib/build_from_response_spec.rb +0 -49
- data/spec/lib/deputy_spec.rb +0 -25
- data/spec/lib/exists_spec.rb +0 -24
- data/spec/lib/group_spec.rb +0 -18
- data/spec/lib/host_spec.rb +0 -31
- data/spec/lib/resource_spec.rb +0 -240
- data/spec/lib/role_grant_spec.rb +0 -13
- data/spec/lib/role_spec.rb +0 -231
- data/spec/lib/standard_methods_spec.rb +0 -66
- data/spec/lib/user_spec.rb +0 -77
- data/spec/standard_methods_helper.rb +0 -41
- data/spec/variable_spec.rb +0 -101
- data/spec/vcr_cassettes/Conjur_Resource/_create/with_path-like_identifier.yml +0 -87
- data/spec/vcr_cassettes/Conjur_Resource/_create/with_un-encoded_path-like_identifier.yml +0 -87
- data/spec/vcr_cassettes/Conjur_Resource/_create/with_uuid_identifier.yml +0 -87
data/lib/conjur/variable.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright
|
2
|
+
# Copyright 2013-2017 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
|
@@ -20,69 +20,37 @@
|
|
20
20
|
#
|
21
21
|
module Conjur
|
22
22
|
|
23
|
-
#
|
23
|
+
# Protected (secret) data stored in Conjur.
|
24
|
+
#
|
24
25
|
# The code responsible for the actual encryption of variables is open source as part of the
|
25
26
|
# {https://github.com/conjurinc/slosilo Slosilo} library.
|
26
27
|
#
|
27
|
-
#
|
28
|
-
# {Conjur::API} methods such as {Conjur::API#create_variable} and {Conjur::API#variable}.
|
29
|
-
#
|
30
|
-
# Conjur variables store metadata (mime-type and secret kind) with each secret.
|
28
|
+
# Each variables has some standard metadata (`mime-type` and secret `kind`).
|
31
29
|
#
|
32
30
|
# Variables are *versioned*. Storing secrets in multiple places is a bad security practice, but
|
33
31
|
# overwriting a secret accidentally can create a major problem for development and ops teams. Conjur
|
34
|
-
# discourages bad security practices while avoiding ops disasters by storing
|
35
|
-
# a secret.
|
32
|
+
# discourages bad security practices while avoiding ops disasters by storing previous versions of
|
33
|
+
# a secret (up to a fixed limit, to avoid unbounded database growth).
|
36
34
|
#
|
37
35
|
# ### Important
|
38
36
|
# A common pitfall when trying to access older versions of a variable is to assume that `0` is the oldest
|
39
|
-
# version.
|
40
|
-
#
|
37
|
+
# version. Variable versions are `1`-based, with `1` being the oldest.
|
41
38
|
#
|
42
39
|
# ### Permissions
|
43
40
|
#
|
44
|
-
# * To *
|
41
|
+
# * To *fetch* the value of a `variable`, you must have permission to `'execute'` the variable.
|
45
42
|
# * To *add* a value to a `variable`, you must have permission to `'update'` the variable.
|
46
43
|
# * To *show* metadata associated with a variable, but *not* the value of the secret, you must have `'read'`
|
47
44
|
# permission on the variable.
|
48
45
|
#
|
49
|
-
# When you create a secret, the creator role is granted all three of the above permissions.
|
50
|
-
#
|
51
46
|
# @example Get a variable and access its metadata and the latest value
|
52
|
-
# variable = api.
|
47
|
+
# variable = api.resource 'myorg:variable:example'
|
53
48
|
# puts variable.kind # "example-secret"
|
54
49
|
# puts variable.mime_type # "text/plain"
|
55
50
|
# puts variable.value # "supahsecret"
|
56
|
-
|
57
|
-
# @example Variable permissions
|
58
|
-
# # use our 'admin' api to create a variable 'permissions-example
|
59
|
-
# admin_var = admin_api.create_variable 'text/plain', 'example', 'permissions-example'
|
60
|
-
#
|
61
|
-
# # get a 'view' to it from user 'alice'
|
62
|
-
# alice_var = alice_api.variable admin_var.id
|
63
|
-
#
|
64
|
-
# # Initilally, all of the following raise a RestClient::Forbidden exception
|
65
|
-
# alice_var.attributes
|
66
|
-
# alice_var.value
|
67
|
-
# alice_var.add_value 'hi'
|
68
|
-
#
|
69
|
-
# # Allow alice to see the variables attributes
|
70
|
-
# admin_var.permit 'read', alice
|
71
|
-
# alice_var.attributes # OK
|
72
|
-
#
|
73
|
-
# # Allow alice to update the variable
|
74
|
-
# admin_var.permit 'update', alice
|
75
|
-
# alice_var.add_value 'hello'
|
76
|
-
#
|
77
|
-
# # Notice that alice still can't see the variable's value:
|
78
|
-
# alice_var.value # raises RestClient::Forbidden
|
79
|
-
#
|
80
|
-
# # Finally, we let alice execute the variable
|
81
|
-
# admin_var.permit 'execute', alice
|
82
|
-
# alice_var.value # 'hello'
|
83
|
-
#
|
51
|
+
|
84
52
|
# @example Variables are versioned
|
85
|
-
#
|
53
|
+
# variable = api.resource 'myorg:variable:example'
|
86
54
|
# # Unless you set a variables value when you create it, the variable starts out without a value and version_count
|
87
55
|
# # is 0.
|
88
56
|
# var.version_count # => 0
|
@@ -106,9 +74,16 @@ module Conjur
|
|
106
74
|
# # Notice that version 0 of a variable is always the most recent:
|
107
75
|
# var.value 0 # => 'value 2'
|
108
76
|
#
|
109
|
-
class Variable <
|
110
|
-
include
|
77
|
+
class Variable < BaseObject
|
78
|
+
include ActsAsResource
|
111
79
|
|
80
|
+
def as_json options={}
|
81
|
+
result = super(options)
|
82
|
+
result["mime_type"] = mime_type
|
83
|
+
result["kind"] = kind
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
112
87
|
# The kind of secret represented by this variable, for example, `'postgres-url'` or
|
113
88
|
# `'aws-secret-access-key'`.
|
114
89
|
#
|
@@ -120,7 +95,7 @@ module Conjur
|
|
120
95
|
# @note this is **not** the same as the `kind` part of a qualified Conjur id.
|
121
96
|
# @return [String] a string representing the kind of secret.
|
122
97
|
def kind
|
123
|
-
|
98
|
+
annotation_value 'conjur/kind' || "secret"
|
124
99
|
end
|
125
100
|
|
126
101
|
# The MIME Type of the variable's value.
|
@@ -134,7 +109,7 @@ module Conjur
|
|
134
109
|
#
|
135
110
|
# @return [String] a MIME type, such as `'text/plain'` or `'application/octet-stream'`.
|
136
111
|
def mime_type
|
137
|
-
|
112
|
+
annotation_value 'conjur/mime_type' || "text/plain"
|
138
113
|
end
|
139
114
|
|
140
115
|
# Add a new value to the variable.
|
@@ -155,7 +130,7 @@ module Conjur
|
|
155
130
|
logger << "Adding a value to variable #{id}"
|
156
131
|
end
|
157
132
|
invalidate do
|
158
|
-
|
133
|
+
core_resource['secrets'][id.to_url_path].post value
|
159
134
|
end
|
160
135
|
end
|
161
136
|
|
@@ -170,7 +145,12 @@ module Conjur
|
|
170
145
|
#
|
171
146
|
# @return [Integer] the number of versions
|
172
147
|
def version_count
|
173
|
-
|
148
|
+
secrets = attributes['secrets']
|
149
|
+
if secrets.empty?
|
150
|
+
0
|
151
|
+
else
|
152
|
+
secrets.last['version']
|
153
|
+
end
|
174
154
|
end
|
175
155
|
|
176
156
|
# Return the version of a variable.
|
@@ -205,34 +185,9 @@ module Conjur
|
|
205
185
|
# @param options [Hash]
|
206
186
|
# @option options [Boolean, false] :show_expired show value even if variable has expired
|
207
187
|
# @return [String] the value of the variable
|
208
|
-
def value
|
209
|
-
url = 'value'
|
188
|
+
def value version = nil, options = {}
|
210
189
|
options['version'] = version if version
|
211
|
-
|
212
|
-
self[url].get.body
|
190
|
+
core_resource['secrets'][id.to_url_path][options_querystring options].get.body
|
213
191
|
end
|
214
|
-
|
215
|
-
# Set the variable to expire after the given interval. The
|
216
|
-
# interval can either be an ISO8601 duration or it can the number
|
217
|
-
# of seconds for which the variable should be valid. Once a
|
218
|
-
# variable has expired, its value will no longer be retrievable.
|
219
|
-
#
|
220
|
-
# You must have the **`'update'`** permission on a variable to call this method.
|
221
|
-
#
|
222
|
-
# @example Use an ISO8601 duration to set the expiration for a variable to tomorrow
|
223
|
-
# var = api.variable 'my-secret'
|
224
|
-
# var.expires_in "P1D"
|
225
|
-
#
|
226
|
-
# @example Use ActiveSupport to set the expiration for a variable to tomorrow
|
227
|
-
# require 'active_support/all'
|
228
|
-
# var = api.variable 'my-secret'
|
229
|
-
# var.expires_in 1.day
|
230
|
-
# @param interval a String containing an ISO8601 duration, otherwise the number of seconds before the variable xpires
|
231
|
-
# @return [Hash] description of the variable's expiration, including the (Conjur server) time when it expires
|
232
|
-
def expires_in interval
|
233
|
-
duration = interval.respond_to?(:to_str) ? interval : "PT#{interval.to_i}S"
|
234
|
-
JSON::parse(self['expiration'].post(duration: duration).body)
|
235
|
-
end
|
236
|
-
|
237
192
|
end
|
238
193
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright
|
2
|
+
# Copyright 2013-2017 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
|
@@ -19,20 +19,12 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def host
|
30
|
-
Conjur.configuration.authz_url
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
22
|
+
# A Conjur Webservice, which protects access to service code.
|
23
|
+
#
|
24
|
+
# Permissions on webservices can be granted and interpreted in a free-form way
|
25
|
+
# which is appropriate to the domain. For example, for a Docker registry
|
26
|
+
# which is guarded by a Webservice, the likely privileges would be `pull` and `push`.
|
27
|
+
class Webservice < BaseObject
|
28
|
+
include ActsAsResource
|
34
29
|
end
|
35
30
|
end
|
36
|
-
|
37
|
-
require 'conjur/api/roles'
|
38
|
-
require 'conjur/api/resources'
|
data/lib/conjur-api/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2013-2017 Conjur Inc.
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
4
|
# this software and associated documentation files (the "Software"), to deal in
|
@@ -19,6 +19,6 @@
|
|
19
19
|
|
20
20
|
module Conjur
|
21
21
|
class API
|
22
|
-
VERSION = "
|
22
|
+
VERSION = "5.0.0.rc1"
|
23
23
|
end
|
24
24
|
end
|
data/publish.sh
ADDED
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fakefs/spec_helpers'
|
3
|
+
|
4
|
+
describe Conjur::API do
|
5
|
+
|
6
|
+
let(:account) { 'api-spec-acount' }
|
7
|
+
before { allow(Conjur.configuration).to receive_messages account: account }
|
8
|
+
|
9
|
+
shared_context "logged in", logged_in: true do
|
10
|
+
let(:login) { "bob" }
|
11
|
+
let(:token) { { 'data' => login, 'timestamp' => Time.now.to_s } }
|
12
|
+
let(:remote_ip) { nil }
|
13
|
+
let(:api_args) { [ token, { remote_ip: remote_ip } ] }
|
14
|
+
subject(:api) { Conjur::API.new_from_token(*api_args) }
|
15
|
+
end
|
16
|
+
|
17
|
+
shared_context "logged in with an API key", logged_in: :api_key do
|
18
|
+
include_context "logged in"
|
19
|
+
let(:api_key) { "theapikey" }
|
20
|
+
let(:api_args) { [ login, api_key, { remote_ip: remote_ip, account: account } ] }
|
21
|
+
subject(:api) { Conjur::API.new_from_key(*api_args) }
|
22
|
+
end
|
23
|
+
|
24
|
+
shared_context "logged in with a token file", logged_in: :token_file do
|
25
|
+
include FakeFS::SpecHelpers
|
26
|
+
include_context "logged in"
|
27
|
+
let(:token_file) { "token_file" }
|
28
|
+
let(:api_args) { [ token_file, { remote_ip: remote_ip } ] }
|
29
|
+
subject(:api) { Conjur::API.new_from_token_file(*api_args) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def time_travel delta
|
33
|
+
allow(api.authenticator).to receive(:gettime).and_wrap_original do |m|
|
34
|
+
m[] + delta
|
35
|
+
end
|
36
|
+
allow(api.authenticator).to receive(:monotonic_time).and_wrap_original do |m|
|
37
|
+
m[] + delta
|
38
|
+
end
|
39
|
+
allow(Time).to receive(:now).and_wrap_original do |m|
|
40
|
+
m[] + delta
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#token' do
|
45
|
+
context 'with token file available', logged_in: :token_file do
|
46
|
+
def write_token token
|
47
|
+
File.write token_file, JSON.generate(token)
|
48
|
+
end
|
49
|
+
|
50
|
+
before do
|
51
|
+
write_token token
|
52
|
+
end
|
53
|
+
|
54
|
+
it "reads the file to get a token" do
|
55
|
+
expect(api.instance_variable_get("@token")).to eq(nil)
|
56
|
+
expect(api.token).to eq(token)
|
57
|
+
expect(api.credentials).to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login })
|
58
|
+
end
|
59
|
+
|
60
|
+
context "after expiration" do
|
61
|
+
it 'it reads a new token' do
|
62
|
+
expect(Time.parse(api.token['timestamp'])).to be_within(5.seconds).of(Time.now)
|
63
|
+
|
64
|
+
time_travel 6.minutes
|
65
|
+
new_token = token.merge "timestamp" => Time.now.to_s
|
66
|
+
write_token new_token
|
67
|
+
|
68
|
+
expect(api.token).to eq(new_token)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with API key available', logged_in: :api_key do
|
74
|
+
it "authenticates to get a token" do
|
75
|
+
expect(Conjur::API).to receive(:authenticate).with(login, api_key, account: account).and_return token
|
76
|
+
|
77
|
+
expect(api.instance_variable_get("@token")).to eq(nil)
|
78
|
+
expect(api.token).to eq(token)
|
79
|
+
expect(api.credentials).to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login })
|
80
|
+
end
|
81
|
+
|
82
|
+
context "after expiration" do
|
83
|
+
|
84
|
+
shared_examples "it gets a new token" do
|
85
|
+
it 'by refreshing' do
|
86
|
+
allow(Conjur::API).to receive(:authenticate).with(login, api_key, account: account).and_return token
|
87
|
+
expect(Time.parse(api.token['timestamp'])).to be_within(5.seconds).of(Time.now)
|
88
|
+
|
89
|
+
time_travel 6.minutes
|
90
|
+
new_token = token.merge "timestamp" => Time.now.to_s
|
91
|
+
|
92
|
+
expect(Conjur::API).to receive(:authenticate).with(login, api_key, account: account).and_return new_token
|
93
|
+
expect(api.token).to eq(new_token)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it_should_behave_like "it gets a new token"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with no API key available', logged_in: true do
|
102
|
+
it "returns the token used to create it" do
|
103
|
+
expect(api.token).to eq token
|
104
|
+
end
|
105
|
+
|
106
|
+
it "doesn't try to refresh an old token" do
|
107
|
+
expect(Conjur::API).not_to receive :authenticate
|
108
|
+
api.token # vivify
|
109
|
+
time_travel 6.minutes
|
110
|
+
expect { api.token }.not_to raise_error
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "credential handling", logged_in: true do
|
116
|
+
context "from token" do
|
117
|
+
describe '#credentials' do
|
118
|
+
subject { super().credentials }
|
119
|
+
it { is_expected.to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"" }, username: login }) }
|
120
|
+
end
|
121
|
+
|
122
|
+
context "with remote_ip" do
|
123
|
+
let(:remote_ip) { "66.0.0.1" }
|
124
|
+
describe '#credentials' do
|
125
|
+
subject { super().credentials }
|
126
|
+
it { is_expected.to eq({ headers: { authorization: "Token token=\"#{Base64.strict_encode64(token.to_json)}\"", :x_forwarded_for=>"66.0.0.1" }, username: login }) }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "from logged-in RestClient::Resource" do
|
132
|
+
let (:authz_header) { %Q{Token token="#{token_encoded}"} }
|
133
|
+
let (:priv_header) { nil }
|
134
|
+
let (:forwarded_for_header) { nil }
|
135
|
+
let (:audit_roles_header) { nil }
|
136
|
+
let (:audit_resources_header) { nil }
|
137
|
+
let (:username) { 'bob' }
|
138
|
+
subject { resource.conjur_api }
|
139
|
+
|
140
|
+
shared_examples "it can clone itself" do
|
141
|
+
it "has the authz header" do
|
142
|
+
expect(subject.credentials[:headers][:authorization]).to eq(authz_header)
|
143
|
+
end
|
144
|
+
it "has the username" do
|
145
|
+
expect(subject.credentials[:username]).to eq(username)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
let(:token_encoded) { Base64.strict_encode64(token.to_json) }
|
150
|
+
let(:base_headers) { { authorization: authz_header } }
|
151
|
+
let(:headers) { base_headers }
|
152
|
+
let(:resource) { RestClient::Resource.new("http://example.com", { headers: headers })}
|
153
|
+
context 'basic functioning' do
|
154
|
+
it_behaves_like 'it can clone itself'
|
155
|
+
end
|
156
|
+
|
157
|
+
context "forwarded for" do
|
158
|
+
let(:forwarded_for_header) { "66.0.0.1" }
|
159
|
+
let(:headers) { base_headers.merge(x_forwarded_for: forwarded_for_header) }
|
160
|
+
it_behaves_like 'it can clone itself'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "#role_from_username", logged_in: true do
|
166
|
+
it "returns a user role when username is plain" do
|
167
|
+
expect(Conjur::API.role_from_username(api, "plain-username", account).id).to eq("#{account}:user:plain-username")
|
168
|
+
end
|
169
|
+
|
170
|
+
it "returns an appropriate role kind when username is qualified" do
|
171
|
+
expect(Conjur::API.role_from_username(api, "host/foo/bar", account).id).to eq("#{account}:host:foo/bar")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "#current_role", logged_in: true do
|
176
|
+
context "when logged in as user" do
|
177
|
+
let(:login) { 'joerandom' }
|
178
|
+
it "returns a user role" do
|
179
|
+
expect(api.current_role(account).id).to eq("#{account}:user:joerandom")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "when logged in as host" do
|
184
|
+
let(:host) { "somehost" }
|
185
|
+
let(:login) { "host/#{host}" }
|
186
|
+
it "returns a host role" do
|
187
|
+
expect(api.current_role(account).id).to eq("#{account}:host:somehost")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe 'url escapes' do
|
193
|
+
let(:urls){[
|
194
|
+
'foo/bar@baz',
|
195
|
+
'/test/some group with spaces'
|
196
|
+
]}
|
197
|
+
|
198
|
+
describe '#fully_escape' do
|
199
|
+
let(:expected){[
|
200
|
+
'foo%2Fbar%40baz',
|
201
|
+
'%2Ftest%2Fsome%20group%20with%20spaces'
|
202
|
+
]}
|
203
|
+
it 'escapes the urls correctly' do
|
204
|
+
expect(urls.map{|u| Conjur::API.fully_escape u}).to eq(expected)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
data/spec/cast_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Conjur::Cast do
|
4
|
+
let!(:object) {
|
5
|
+
Object.new.tap do |obj|
|
6
|
+
class << obj
|
7
|
+
include Conjur::Cast
|
8
|
+
end
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
it 'String casts to itself' do
|
13
|
+
expect(object.send(:cast_to_id, "foo")).to eq("foo")
|
14
|
+
end
|
15
|
+
it 'Id casts to to_s' do
|
16
|
+
expect(object.send(:cast_to_id, "foo")).to eq("foo")
|
17
|
+
end
|
18
|
+
it 'Array casts via #join' do
|
19
|
+
expect(object.send(:cast_to_id, [ "foo", "bar" ])).to eq("foo:bar")
|
20
|
+
end
|
21
|
+
end
|
File without changes
|
File without changes
|