occi-api 4.3.5 → 4.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -25
- data/lib/occi/api/client/client_http.rb +2 -2
- data/lib/occi/api/client/http/authn_plugins/keystone.rb +177 -13
- data/lib/occi/api/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5e457c71d021773fd57e1632882d438166cf935
|
4
|
+
data.tar.gz: 9afa187517fd7ef0facc4295085a10a7b9bf1f97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d531511b8d1fa3d5d2c3658ad9fbb1d29c3c08430779d36ae3b471179443f8afe8b5fc2fd11df0e52df52707a6d09c08dfe9e4919ac86b94759798c855c5bb8
|
7
|
+
data.tar.gz: 2ab2461149750834ea980da58f36892366d5872cd55c35809cf873231d86fb24ce81e9ccb0be9bf778b049d09cc440960709a635ec88d19f5b36a60efcfd97e1
|
data/.travis.yml
CHANGED
@@ -4,36 +4,14 @@ rvm:
|
|
4
4
|
- 1.9.3
|
5
5
|
- 2.0.0
|
6
6
|
- 2.1
|
7
|
+
- 2.2
|
8
|
+
- 2.3
|
7
9
|
- ruby-head
|
8
|
-
- jruby-19mode
|
9
|
-
- jruby-head
|
10
|
-
|
11
|
-
jdk:
|
12
|
-
- openjdk7
|
13
|
-
- oraclejdk7
|
14
|
-
- openjdk6
|
15
10
|
|
16
11
|
matrix:
|
17
12
|
allow_failures:
|
13
|
+
- rvm: 2.3
|
18
14
|
- rvm: ruby-head
|
19
|
-
- rvm: jruby-head
|
20
|
-
exclude:
|
21
|
-
- rvm: 1.9.3
|
22
|
-
jdk: openjdk7
|
23
|
-
- rvm: 1.9.3
|
24
|
-
jdk: oraclejdk7
|
25
|
-
- rvm: 2.0.0
|
26
|
-
jdk: openjdk7
|
27
|
-
- rvm: 2.0.0
|
28
|
-
jdk: oraclejdk7
|
29
|
-
- rvm: 2.1
|
30
|
-
jdk: openjdk7
|
31
|
-
- rvm: 2.1
|
32
|
-
jdk: oraclejdk7
|
33
|
-
- rvm: ruby-head
|
34
|
-
jdk: openjdk7
|
35
|
-
- rvm: ruby-head
|
36
|
-
jdk: oraclejdk7
|
37
15
|
fast_finish: true
|
38
16
|
|
39
17
|
branches:
|
@@ -43,3 +21,10 @@ branches:
|
|
43
21
|
- 4.1.x
|
44
22
|
- 4.2.x
|
45
23
|
- 4.3.x
|
24
|
+
|
25
|
+
install: 'gem install bundler -v ">= 1.7.12" && bundle install --retry=10'
|
26
|
+
|
27
|
+
env:
|
28
|
+
- ON_TRAVIS_CI=yes
|
29
|
+
|
30
|
+
sudo: false
|
@@ -78,10 +78,10 @@ module Occi::Api::Client
|
|
78
78
|
)
|
79
79
|
|
80
80
|
response_msg = response_message(response)
|
81
|
-
raise "HTTP GET failed! #{response_msg}" unless response.code
|
81
|
+
raise "HTTP GET failed! #{response_msg}" unless [200, 204].include?(response.code)
|
82
82
|
|
83
83
|
# TODO: remove the gsub OCCI-OS hack as soon as they stop using 'uri:'
|
84
|
-
response.body.gsub(/\# uri:\/(compute|storage|network)\/[\n]?/, '').split("\n").compact
|
84
|
+
(response.body || '').gsub(/\# uri:\/(compute|storage|network)\/[\n]?/, '').split("\n").compact
|
85
85
|
end
|
86
86
|
|
87
87
|
# @see Occi::Api::Client::ClientBase
|
@@ -5,20 +5,14 @@ module Occi::Api::Client
|
|
5
5
|
class Keystone < Base
|
6
6
|
|
7
7
|
KEYSTONE_URI_REGEXP = /^(Keystone|snf-auth) uri='(.+)'$/
|
8
|
+
KEYSTONE_VERSION_REGEXP = /^v([0-9]).*$/
|
8
9
|
|
9
10
|
def setup(options = {})
|
10
11
|
# get Keystone URL if possible
|
11
12
|
set_keystone_base_url
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
set_auth_token ENV['ROCCI_CLIENT_KEYSTONE_TENANT']
|
16
|
-
else
|
17
|
-
# get an unscoped token, use the unscoped token
|
18
|
-
# for tenant discovery and get a scoped token
|
19
|
-
set_auth_token
|
20
|
-
get_first_working_tenant
|
21
|
-
end
|
14
|
+
# discover Keystone API version
|
15
|
+
set_auth_token ENV['ROCCI_CLIENT_KEYSTONE_TENANT']
|
22
16
|
|
23
17
|
raise ::Occi::Api::Client::Errors::AuthnError,
|
24
18
|
"Unable to get a tenant from Keystone, fallback failed!" if @env_ref.class.headers['X-Auth-Token'].blank?
|
@@ -56,12 +50,73 @@ module Occi::Api::Client
|
|
56
50
|
raise ::Occi::Api::Client::Errors::AuthnError,
|
57
51
|
"Unable to get Keystone's URL from the response, fallback failed!" unless match && match[2]
|
58
52
|
|
59
|
-
@keystone_url = match[2]
|
53
|
+
@keystone_url = match[2]
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_auth_token(tenant = nil)
|
57
|
+
response = @env_ref.class.get @keystone_url
|
58
|
+
Occi::Api::Log.debug response.inspect
|
59
|
+
|
60
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
61
|
+
"Unable to get Keystone API version from the response, fallback failed!" if (400..599).include?(response.code)
|
62
|
+
|
63
|
+
# multiple choices, sort them by version id
|
64
|
+
if response.code == 300
|
65
|
+
versions = response['versions']['values'].sort_by { |v| v['id']}
|
66
|
+
else
|
67
|
+
# assume a single version
|
68
|
+
versions = [response['version']]
|
69
|
+
end
|
70
|
+
|
71
|
+
versions.each do |v|
|
72
|
+
match = KEYSTONE_VERSION_REGEXP.match(v['id'])
|
73
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
74
|
+
"Unable to get Keystone API version from the response, fallback failed!" unless match && match[1]
|
75
|
+
if match[1] == '2'
|
76
|
+
handler_class = KeystoneV2
|
77
|
+
elsif match[1] == '3'
|
78
|
+
handler_class = KeystoneV3
|
79
|
+
end
|
80
|
+
v['links'].each do |link|
|
81
|
+
begin
|
82
|
+
if link['rel'] == 'self'
|
83
|
+
keystone_url = link['href'].chomp('/')
|
84
|
+
keystone_handler = handler_class.new(keystone_url, @env_ref, @options)
|
85
|
+
token = keystone_handler.set_auth_token(tenant)
|
86
|
+
# found a working keystone, stop looking
|
87
|
+
return
|
88
|
+
end
|
89
|
+
rescue ::Occi::Api::Client::Errors::AuthnError
|
90
|
+
# ignore and try with next link
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class KeystoneV2
|
99
|
+
def initialize(base_url, env_ref, options = {})
|
100
|
+
@base_url = base_url
|
101
|
+
@env_ref = env_ref
|
102
|
+
@options = options
|
60
103
|
end
|
61
104
|
|
62
105
|
def set_auth_token(tenant = nil)
|
106
|
+
if !tenant.blank?
|
107
|
+
# get a scoped token for the specified tenant directly
|
108
|
+
authenticate ENV['ROCCI_CLIENT_KEYSTONE_TENANT']
|
109
|
+
else
|
110
|
+
# get an unscoped token, use the unscoped token
|
111
|
+
# for tenant discovery and get a scoped token
|
112
|
+
authenticate
|
113
|
+
get_first_working_tenant
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def authenticate(tenant = nil)
|
63
118
|
response = @env_ref.class.post(
|
64
|
-
"#{@
|
119
|
+
"#{@base_url}/tokens",
|
65
120
|
:body => get_keystone_req(tenant),
|
66
121
|
:headers => get_req_headers
|
67
122
|
)
|
@@ -99,7 +154,7 @@ module Occi::Api::Client
|
|
99
154
|
|
100
155
|
def get_first_working_tenant
|
101
156
|
response = @env_ref.class.get(
|
102
|
-
"#{@
|
157
|
+
"#{@base_url}/tenants",
|
103
158
|
:headers => get_req_headers
|
104
159
|
)
|
105
160
|
Occi::Api::Log.debug response.inspect
|
@@ -110,7 +165,7 @@ module Occi::Api::Client
|
|
110
165
|
response['tenants'].each do |tenant|
|
111
166
|
begin
|
112
167
|
Occi::Api::Log.debug "Authenticating for tenant #{tenant['name'].inspect}"
|
113
|
-
|
168
|
+
authenticate(tenant['name'])
|
114
169
|
|
115
170
|
# found a working tenant, stop looking
|
116
171
|
break
|
@@ -120,6 +175,115 @@ module Occi::Api::Client
|
|
120
175
|
end
|
121
176
|
end
|
122
177
|
|
178
|
+
def get_req_headers
|
179
|
+
headers = @env_ref.class.headers.clone
|
180
|
+
headers['Content-Type'] = "application/json"
|
181
|
+
headers['Accept'] = headers['Content-Type']
|
182
|
+
|
183
|
+
headers
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class KeystoneV3
|
188
|
+
def initialize(base_url, env_ref, options = {})
|
189
|
+
@base_url = base_url
|
190
|
+
@env_ref = env_ref
|
191
|
+
@options = options
|
192
|
+
end
|
193
|
+
|
194
|
+
def set_auth_token(tenant = nil)
|
195
|
+
if @options[:original_type] == "x509"
|
196
|
+
voms_authenticate(tenant)
|
197
|
+
elsif @options[:username] && @options[:password]
|
198
|
+
passwd_authenticate(tenant)
|
199
|
+
else
|
200
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
201
|
+
"Unable to request a token from Keystone! Chosen " \
|
202
|
+
"AuthN is not supported, fallback failed!"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def passwd_authenticate(tenant = nil)
|
207
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
208
|
+
"Needs to be implemented, check http://developer.openstack.org/api-ref-identity-v3.html#authenticatePasswordUnscoped"
|
209
|
+
end
|
210
|
+
|
211
|
+
def voms_authenticate(tenant = nil)
|
212
|
+
set_voms_unscoped_token
|
213
|
+
|
214
|
+
if !tenant.blank?
|
215
|
+
set_scoped_token(tenant)
|
216
|
+
else
|
217
|
+
get_first_working_project
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def set_voms_unscoped_token
|
222
|
+
response = @env_ref.class.post(
|
223
|
+
# egi.eu and voms below should be configurable
|
224
|
+
"#{@base_url}/OS-FEDERATION/identity_providers/egi.eu/protocols/mapped/voms",
|
225
|
+
)
|
226
|
+
Occi::Api::Log.debug response.inspect
|
227
|
+
|
228
|
+
if response.success?
|
229
|
+
@env_ref.class.headers['X-Auth-Token'] = response.headers['x-subject-token']
|
230
|
+
else
|
231
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
232
|
+
"Unable to get a token from Keystone, fallback failed!"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def get_first_working_project
|
237
|
+
response = @env_ref.class.get(
|
238
|
+
"#{@base_url}/projects",
|
239
|
+
:headers => get_req_headers
|
240
|
+
)
|
241
|
+
Occi::Api::Log.debug response.inspect
|
242
|
+
|
243
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
244
|
+
"Keystone didn't return any projects, fallback failed!" if response['projects'].blank?
|
245
|
+
|
246
|
+
response['projects'].each do |project|
|
247
|
+
begin
|
248
|
+
Occi::Api::Log.debug "Authenticating for project #{project['name'].inspect}"
|
249
|
+
set_scoped_token(project['id'])
|
250
|
+
|
251
|
+
# found a working project, stop looking
|
252
|
+
break
|
253
|
+
rescue ::Occi::Api::Client::Errors::AuthnError
|
254
|
+
# ignoring and trying the next tenant
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def set_scoped_token(project)
|
260
|
+
body = {
|
261
|
+
"auth" => {
|
262
|
+
"identity" => {
|
263
|
+
"methods" => ["token"],
|
264
|
+
"token" => {"id" => @env_ref.class.headers['X-Auth-Token'] }
|
265
|
+
},
|
266
|
+
"scope" => {
|
267
|
+
"project" => {"id" => project}
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
response = @env_ref.class.post(
|
272
|
+
"#{@base_url}/auth/tokens",
|
273
|
+
:body => body,
|
274
|
+
:headers => get_req_headers
|
275
|
+
)
|
276
|
+
|
277
|
+
Occi::Api::Log.debug response.inspect
|
278
|
+
|
279
|
+
if response.success?
|
280
|
+
@env_ref.class.headers['X-Auth-Token'] = response.headers['x-subject-token']
|
281
|
+
else
|
282
|
+
raise ::Occi::Api::Client::Errors::AuthnError,
|
283
|
+
"Unable to get a token from Keystone, fallback failed!"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
123
287
|
def get_req_headers
|
124
288
|
headers = @env_ref.class.headers.clone
|
125
289
|
headers['Content-Type'] = "application/json"
|
data/lib/occi/api/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: occi-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.3.
|
4
|
+
version: 4.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Feldhaus
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-06-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: occi-core
|