aspera-cli 4.2.2 → 4.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.
@@ -21,11 +21,12 @@ module Aspera
21
21
  ACCESS_KEY_TRANSFER_USER='xfer'
22
22
  # executes a local "ascp", connects mgt port, equivalent of "Fasp Manager"
23
23
  class Local < Manager
24
- # options for initialize
24
+ # options for initialize (same as values in option transfer_info)
25
25
  DEFAULT_OPTIONS = {
26
26
  :spawn_timeout_sec => 3,
27
27
  :spawn_delay_sec => 2,
28
28
  :wss => false,
29
+ :multi_incr_udp => true,
29
30
  :resume => {}
30
31
  }
31
32
  DEFAULT_UDP_PORT=33001
@@ -64,21 +65,27 @@ module Aspera
64
65
  transfer_spec['EX_ssh_key_paths'] = Installation.instance.bypass_keys
65
66
  end
66
67
 
67
- # TODO: check if changing fasp(UDP) port is really necessary, not clear from doc
68
- # compute this before using transfer spec, even if the var is not used in single session
69
- multi_session_udp_port_base=DEFAULT_UDP_PORT
70
- multi_session_number=0
68
+ # Compute this before using transfer spec because it potentially modifies the transfer spec
69
+ # (even if the var is not used in single session)
70
+ multi_session_info=nil
71
71
  if transfer_spec.has_key?('multi_session')
72
- multi_session_number=transfer_spec['multi_session'].to_i
73
- if multi_session_number < 0
72
+ multi_session_info={
73
+ count: transfer_spec['multi_session'].to_i,
74
+ }
75
+ # Managed by multi-session, so delete from transfer spec
76
+ transfer_spec.delete('multi_session')
77
+ if multi_session_info[:count] < 0
74
78
  Log.log.error("multi_session(#{transfer_spec['multi_session']}) shall be integer >= 0")
75
- multi_session_number = 0
76
- end
77
- if multi_session_number > 0
78
- # managed here, so delete from transfer spec
79
- transfer_spec.delete('multi_session')
80
- if transfer_spec.has_key?('fasp_port')
81
- multi_session_udp_port_base=transfer_spec['fasp_port']
79
+ multi_session_info = nil
80
+ elsif multi_session_info[:count].eql?(0)
81
+ Log.log.debug("multi_session count is zero: no multisession")
82
+ multi_session_info = nil
83
+ else # multi_session_info[:count] > 0
84
+ # if option not true: keep default udp port for all sessions
85
+ if @options[:multi_incr_udp]
86
+ # override if specified, else use default value
87
+ multi_session_info[:udp_base]=transfer_spec.has_key?('fasp_port') ? transfer_spec['fasp_port'] : DEFAULT_UDP_PORT
88
+ # delete from original transfer spec, as we will increment values
82
89
  transfer_spec.delete('fasp_port')
83
90
  end
84
91
  end
@@ -111,22 +118,23 @@ module Aspera
111
118
  :options => job_options # [Hash]
112
119
  }
113
120
 
114
- if multi_session_number <= 1
121
+ if multi_session_info.nil?
115
122
  Log.log.debug('Starting single session thread')
116
123
  # single session for transfer : simple
117
124
  session[:thread] = Thread.new(session) {|s|transfer_thread_entry(s)}
118
125
  xfer_job[:sessions].push(session)
119
126
  else
120
127
  Log.log.debug('Starting multi session threads')
121
- 1.upto(multi_session_number) do |i|
128
+ 1.upto(multi_session_info[:count]) do |i|
129
+ # do not delay the first session
122
130
  sleep(@options[:spawn_delay_sec]) unless i.eql?(1)
123
131
  # do deep copy (each thread has its own copy because it is modified here below and in thread)
124
132
  this_session=session.clone()
125
133
  this_session[:env_args]=this_session[:env_args].clone()
126
134
  this_session[:env_args][:args]=this_session[:env_args][:args].clone()
127
- this_session[:env_args][:args].unshift("-C#{i}:#{multi_session_number}")
128
- # necessary only if server is not linux, i.e. server does not support port re-use
129
- this_session[:env_args][:args].unshift('-O',"#{multi_session_udp_port_base+i-1}")
135
+ this_session[:env_args][:args].unshift("-C#{i}:#{multi_session_info[:count]}")
136
+ # option: increment (default as per ascp manual) or not (cluster on other side ?)
137
+ this_session[:env_args][:args].unshift('-O',"#{multi_session_info[:udp_base]+i-1}") if @options[:multi_incr_udp]
130
138
  this_session[:thread] = Thread.new(this_session) {|s|transfer_thread_entry(s)}
131
139
  xfer_job[:sessions].push(this_session)
132
140
  end
@@ -260,6 +268,7 @@ module Aspera
260
268
  Log.log.error('need to regenerate token'.red)
261
269
  if session[:options].is_a?(Hash) and session[:options].has_key?(:regenerate_token)
262
270
  # regenerate token here, expired, or error on it
271
+ # Note: in multi-session, each session will have a different one.
263
272
  env_args[:env]['ASPERA_SCP_TOKEN']=session[:options][:regenerate_token].call(true)
264
273
  end
265
274
  end
@@ -323,7 +332,7 @@ module Aspera
323
332
 
324
333
  private
325
334
 
326
- # @param options : keys(symbol): wss, resume
335
+ # @param options : keys(symbol): see DEFAULT_OPTIONS
327
336
  def initialize(options=nil)
328
337
  super()
329
338
  # by default no interactive progress bar
@@ -332,7 +341,7 @@ module Aspera
332
341
  @jobs={}
333
342
  # mutex protects global data accessed by threads
334
343
  @mutex=Mutex.new
335
- # manage options
344
+ # set default options and override if specified
336
345
  @options=DEFAULT_OPTIONS.clone
337
346
  if !options.nil?
338
347
  raise "expecting Hash (or nil), but have #{options.class}" unless options.is_a?(Hash)
@@ -340,7 +349,7 @@ module Aspera
340
349
  if DEFAULT_OPTIONS.has_key?(k)
341
350
  @options[k]=v
342
351
  else
343
- raise "unknown local agent parameter: #{k}, expect one of #{DEFAULT_OPTIONS.keys.map{|i|i.to_s}.join(",")}"
352
+ raise "Unknown local agent parameter: #{k}, expect one of #{DEFAULT_OPTIONS.keys.map{|i|i.to_s}.join(",")}"
344
353
  end
345
354
  end
346
355
  end
@@ -7,9 +7,12 @@ module Aspera
7
7
  # this singleton class is used by the CLI to provide a common interface to start a transfer
8
8
  # before using it, the use must set the `node_api` member.
9
9
  class Node < Manager
10
- def initialize(node_api)
10
+ # option include: root_id if the node is an access key
11
+ attr_writer :options
12
+ def initialize(node_api,options={})
11
13
  super()
12
14
  @node_api=node_api
15
+ @options=options
13
16
  # TODO: currently only supports one transfer. This is bad shortcut. but ok for CLI.
14
17
  @transfer_id=nil
15
18
  end
@@ -32,6 +35,25 @@ module Aspera
32
35
 
33
36
  # generic method
34
37
  def start_transfer(transfer_spec,options=nil)
38
+ # add root id if access key
39
+ if @options.has_key?(:root_id)
40
+ case transfer_spec['direction']
41
+ when 'send';transfer_spec['source_root_id']=@options[:root_id]
42
+ when 'receive';transfer_spec['destination_root_id']=@options[:root_id]
43
+ else raise "unexpected direction in ts: #{transfer_spec['direction']}"
44
+ end
45
+ end
46
+ # manage special additional parameter
47
+ if transfer_spec.has_key?('EX_ssh_key_paths') and transfer_spec['EX_ssh_key_paths'].is_a?(Array) and !transfer_spec['EX_ssh_key_paths'].empty?
48
+ # not standard, so place standard field
49
+ if transfer_spec.has_key?('ssh_private_key')
50
+ Log.log.warn('Both ssh_private_key and EX_ssh_key_paths are present, using ssh_private_key')
51
+ else
52
+ Log.log.warn('EX_ssh_key_paths has multiple keys, using first one only') unless transfer_spec['EX_ssh_key_paths'].length.eql?(1)
53
+ transfer_spec['ssh_private_key']=File.read(transfer_spec['EX_ssh_key_paths'].first)
54
+ transfer_spec.delete('EX_ssh_key_paths')
55
+ end
56
+ end
35
57
  if transfer_spec['tags'].is_a?(Hash) and transfer_spec['tags']['aspera'].is_a?(Hash)
36
58
  transfer_spec['tags']['aspera']['xfer_retry']||=150
37
59
  end
@@ -0,0 +1,22 @@
1
+ require 'uri'
2
+
3
+ module Aspera
4
+ class IdGenerator
5
+ ID_SEPARATOR='_'
6
+ WINDOWS_PROTECTED_CHAR=%r{[/:"<>\\\*\?]}
7
+ PROTECTED_CHAR_REPLACE='_'
8
+ private_constant :ID_SEPARATOR,:PROTECTED_CHAR_REPLACE,:WINDOWS_PROTECTED_CHAR
9
+ def self.from_list(object_id)
10
+ if object_id.is_a?(Array)
11
+ object_id=object_id.select{|i|!i.nil?}.map do |i|
12
+ (i.is_a?(String) and i.start_with?('https://')) ? URI.parse(i).host : i.to_s
13
+ end.join(ID_SEPARATOR)
14
+ end
15
+ raise "id must be a String" unless object_id.is_a?(String)
16
+ return object_id.
17
+ gsub(WINDOWS_PROTECTED_CHAR,PROTECTED_CHAR_REPLACE). # remove windows forbidden chars
18
+ gsub('.',PROTECTED_CHAR_REPLACE). # keep dot for extension only (nicer)
19
+ downcase
20
+ end
21
+ end
22
+ end
data/lib/aspera/node.rb CHANGED
@@ -10,10 +10,8 @@ module Aspera
10
10
  ACCESS_LEVELS=['delete','list','mkdir','preview','read','rename','write']
11
11
  MATCH_EXEC_PREFIX='exec:'
12
12
 
13
- # for information only
14
- def self.decode_bearer_token(token)
15
- return JSON.parse(Zlib::Inflate.inflate(Base64.decode64(token)).partition('==SIGNATURE==').first)
16
- end
13
+ # register node special token decoder
14
+ Oauth.register_decoder(lambda{|token|JSON.parse(Zlib::Inflate.inflate(Base64.decode64(token)).partition('==SIGNATURE==').first)})
17
15
 
18
16
  # for access keys: provide expression to match entry in folder
19
17
  # if no prefix: regex
data/lib/aspera/oauth.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'aspera/open_application'
2
2
  require 'aspera/web_auth'
3
+ require 'aspera/id_generator'
3
4
  require 'base64'
4
5
  require 'date'
5
6
  require 'socket'
@@ -9,8 +10,14 @@ module Aspera
9
10
  # Implement OAuth 2 for the REST client and generate a bearer token
10
11
  # call get_authorization() to get a token.
11
12
  # bearer tokens are kept in memory and also in a file cache for later re-use
12
- # if a token is expired (api returns 4xx), call again get_authorization({:refresh=>true})
13
+ # if a token is expired (api returns 4xx), call again get_authorization({refresh: true})
13
14
  class Oauth
15
+ # used for code exchange
16
+ DEFAULT_PATH_AUTHORIZE='authorize'
17
+ # to generate token
18
+ DEFAULT_PATH_TOKEN='token'
19
+ # field with token in result
20
+ DEFAULT_TOKEN_FIELD='access_token'
14
21
  private
15
22
  # remove 5 minutes to account for time offset (TODO: configurable?)
16
23
  JWT_NOTBEFORE_OFFSET_SEC=300
@@ -20,7 +27,9 @@ module Aspera
20
27
  TOKEN_CACHE_EXPIRY_SEC=1800
21
28
  # a prefix for persistency of tokens (garbage collect)
22
29
  PERSIST_CATEGORY_TOKEN='token'
23
- private_constant :JWT_NOTBEFORE_OFFSET_SEC,:JWT_EXPIRY_OFFSET_SEC,:PERSIST_CATEGORY_TOKEN,:TOKEN_CACHE_EXPIRY_SEC
30
+ ONE_HOUR_AS_DAY_FRACTION=Rational(1,24)
31
+
32
+ private_constant :JWT_NOTBEFORE_OFFSET_SEC,:JWT_EXPIRY_OFFSET_SEC,:PERSIST_CATEGORY_TOKEN,:TOKEN_CACHE_EXPIRY_SEC,:ONE_HOUR_AS_DAY_FRACTION
24
33
  class << self
25
34
  # OAuth methods supported
26
35
  def auth_types
@@ -45,8 +54,25 @@ module Aspera
45
54
  def flush_tokens
46
55
  persist_mgr.garbage_collect(PERSIST_CATEGORY_TOKEN,nil)
47
56
  end
57
+
58
+ def register_decoder(method)
59
+ @decoders||=[]
60
+ @decoders.push(method)
61
+ end
62
+
63
+ def decode_token(token)
64
+ Log.log.debug(">>>> #{token} : #{@decoders.length}")
65
+ @decoders.each do |decoder|
66
+ result=decoder.call(token) rescue nil
67
+ return result unless result.nil?
68
+ end
69
+ return nil
70
+ end
48
71
  end
49
72
 
73
+ # seems to be quite standard token encoding (RFC?)
74
+ self.register_decoder lambda { |token| parts=token.split('.'); raise "not aoc token" unless parts.length.eql?(3); JSON.parse(Base64.decode64(parts[1]))}
75
+
50
76
  # for supported parameters, look in the code for @params
51
77
  # parameters are provided all with oauth_ prefix :
52
78
  # :base_url
@@ -56,8 +82,8 @@ module Aspera
56
82
  # :jwt_audience
57
83
  # :jwt_private_key_obj
58
84
  # :jwt_subject
59
- # :path_authorize (default: 'authorize')
60
- # :path_token (default: 'token')
85
+ # :path_authorize (default: DEFAULT_PATH_AUTHORIZE)
86
+ # :path_token (default: DEFAULT_PATH_TOKEN)
61
87
  # :scope (optional)
62
88
  # :grant (one of returned by self.auth_types)
63
89
  # :url_token
@@ -65,21 +91,21 @@ module Aspera
65
91
  # :user_pass
66
92
  # :token_type
67
93
  def initialize(auth_params)
68
- Log.log.debug "auth=#{auth_params}"
94
+ Log.log.debug("auth=#{auth_params}")
69
95
  @params=auth_params.clone
70
96
  # default values
71
97
  # name of field to take as token from result of call to /token
72
- @params[:token_field]||='access_token'
98
+ @params[:token_field]||=DEFAULT_TOKEN_FIELD
73
99
  # default endpoint for /token
74
- @params[:path_token]||='token'
100
+ @params[:path_token]||=DEFAULT_PATH_TOKEN
75
101
  # default endpoint for /authorize
76
- @params[:path_authorize]||='authorize'
77
- rest_params={:base_url => @params[:base_url]}
102
+ @params[:path_authorize]||=DEFAULT_PATH_AUTHORIZE
103
+ rest_params={base_url: @params[:base_url]}
78
104
  if @params.has_key?(:client_id)
79
- rest_params.merge!({:auth => {
80
- :type => :basic,
81
- :username => @params[:client_id],
82
- :password => @params[:client_secret]
105
+ rest_params.merge!({auth: {
106
+ type: :basic,
107
+ username: @params[:client_id],
108
+ password: @params[:client_secret]
83
109
  }})
84
110
  end
85
111
  @token_auth_api=Rest.new(rest_params)
@@ -107,28 +133,20 @@ module Aspera
107
133
  return code
108
134
  end
109
135
 
110
- def create_token_advanced(rest_params)
136
+ def create_token(rest_params)
111
137
  return @token_auth_api.call({
112
- :operation => 'POST',
113
- :subpath => @params[:path_token],
114
- :headers => {'Accept'=>'application/json'}}.merge(rest_params))
115
- end
116
-
117
- # shortcut for create_token_advanced
118
- def create_token_www_body(creation_params)
119
- return create_token_advanced({:www_body_params=>creation_params})
138
+ operation: 'POST',
139
+ subpath: @params[:path_token],
140
+ headers: {'Accept'=>'application/json'}}.merge(rest_params))
120
141
  end
121
142
 
122
- # @return Array list of unique identifiers of token
123
- def token_cache_ids(api_scope)
143
+ # @return unique identifier of token
144
+ def token_cache_id(api_scope)
124
145
  oauth_uri=URI.parse(@params[:base_url])
125
- parts=[PERSIST_CATEGORY_TOKEN,oauth_uri.host.downcase.gsub(/[^a-z]+/,'_'),oauth_uri.path.downcase.gsub(/[^a-z]+/,'_'),@params[:grant]]
126
- parts.push(api_scope) unless api_scope.nil?
127
- parts.push(@params[:jwt_subject]) if @params.has_key?(:jwt_subject)
128
- parts.push(@params[:user_name]) if @params.has_key?(:user_name)
129
- parts.push(@params[:url_token]) if @params.has_key?(:url_token)
130
- parts.push(@params[:api_key]) if @params.has_key?(:api_key)
131
- return parts
146
+ parts=[PERSIST_CATEGORY_TOKEN,api_scope,oauth_uri.host,oauth_uri.path]
147
+ # add some of the parameters that uniquely define the token
148
+ [:grant,:jwt_subject,:user_name,:url_token,:api_key].inject(parts){|p,i|p.push(@params[i])}
149
+ return IdGenerator.from_list(parts)
132
150
  end
133
151
 
134
152
  public
@@ -148,22 +166,23 @@ module Aspera
148
166
  use_refresh_token=options[:refresh]
149
167
 
150
168
  # generate token identifier to use with cache
151
- token_ids=token_cache_ids(api_scope)
169
+ token_id=token_cache_id(api_scope)
152
170
 
153
171
  # get token_data from cache (or nil), token_data is what is returned by /token
154
- token_data=self.class.persist_mgr.get(token_ids)
172
+ token_data=self.class.persist_mgr.get(token_id)
155
173
  token_data=JSON.parse(token_data) unless token_data.nil?
156
-
157
174
  # Optional optimization: check if node token is expired, then force refresh
158
175
  # in case the transfer agent cannot refresh himself
159
176
  # else, anyway, faspmanager is equipped with refresh code
160
177
  if !token_data.nil?
161
- decoded_node_token = Node.decode_bearer_token(token_data['access_token']) rescue nil
178
+ # TODO: use @params[:token_field] ?
179
+ decoded_node_token = self.class.decode_token(token_data['access_token'])
180
+ Log.dump('decoded_node_token',decoded_node_token) unless decoded_node_token.nil?
162
181
  if decoded_node_token.is_a?(Hash) and decoded_node_token['expires_at'].is_a?(String)
163
- Log.dump('decoded_node_token',decoded_node_token)
164
182
  expires_at=DateTime.parse(decoded_node_token['expires_at'])
165
- one_hour_as_day_fraction=Rational(1,24)
166
- use_refresh_token=true if DateTime.now > (expires_at-one_hour_as_day_fraction)
183
+ # Time.at(decoded_node_token['exp'])
184
+ # does it seem expired, with one hour of security
185
+ use_refresh_token=true if DateTime.now > (expires_at-ONE_HOUR_AS_DAY_FRACTION)
167
186
  end
168
187
  end
169
188
 
@@ -174,7 +193,7 @@ module Aspera
174
193
  refresh_token=token_data['refresh_token']
175
194
  end
176
195
  # delete caches
177
- self.class.persist_mgr.delete(token_ids)
196
+ self.class.persist_mgr.delete(token_id)
178
197
  token_data=nil
179
198
  # lets try the existing refresh token
180
199
  if !refresh_token.nil?
@@ -182,14 +201,14 @@ module Aspera
182
201
  # try to refresh
183
202
  # note: admin token has no refresh, and lives by default 1800secs
184
203
  # Note: scope is mandatory in Files, and we can either provide basic auth, or client_Secret in data
185
- resp=create_token_www_body(p_client_id_and_scope.merge({
186
- :grant_type =>'refresh_token',
187
- :refresh_token=>refresh_token}))
204
+ resp=create_token(www_body_params: p_client_id_and_scope.merge({
205
+ grant_type: 'refresh_token',
206
+ refresh_token: refresh_token}))
188
207
  if resp[:http].code.start_with?('2') then
189
- # save only if success ?
208
+ # save only if success
190
209
  json_data=resp[:http].body
191
210
  token_data=JSON.parse(json_data)
192
- self.class.persist_mgr.put(token_ids,json_data)
211
+ self.class.persist_mgr.put(token_id,json_data)
193
212
  else
194
213
  Log.log.debug("refresh failed: #{resp[:http].body}".bg_red)
195
214
  end
@@ -204,19 +223,19 @@ module Aspera
204
223
  # AoC Web based Auth
205
224
  check_code=SecureRandom.uuid
206
225
  auth_params=p_client_id_and_scope.merge({
207
- :response_type => 'code',
208
- :redirect_uri => @params[:redirect_uri],
209
- :state => check_code
226
+ response_type: 'code',
227
+ redirect_uri: @params[:redirect_uri],
228
+ state: check_code
210
229
  })
211
230
  auth_params[:client_secret]=@params[:client_secret] if @params.has_key?(:client_secret)
212
231
  login_page_url=Rest.build_uri("#{@params[:base_url]}/#{@params[:path_authorize]}",auth_params)
213
232
  # here, we need a human to authorize on a web page
214
233
  code=goto_page_and_get_code(login_page_url,check_code)
215
234
  # exchange code for token
216
- resp=create_token_www_body(p_client_id_and_scope.merge({
217
- :grant_type => 'authorization_code',
218
- :code => code,
219
- :redirect_uri => @params[:redirect_uri]
235
+ resp=create_token(www_body_params: p_client_id_and_scope.merge({
236
+ grant_type: 'authorization_code',
237
+ code: code,
238
+ redirect_uri: @params[:redirect_uri]
220
239
  }))
221
240
  when :jwt
222
241
  # https://tools.ietf.org/html/rfc7519
@@ -226,18 +245,18 @@ module Aspera
226
245
  Log.log.info("seconds=#{seconds_since_epoch}")
227
246
 
228
247
  payload = {
229
- :iss => @params[:client_id], # issuer
230
- :sub => @params[:jwt_subject], # subject
231
- :aud => @params[:jwt_audience], # audience
232
- :nbf => seconds_since_epoch-JWT_NOTBEFORE_OFFSET_SEC, # not before
233
- :exp => seconds_since_epoch+JWT_EXPIRY_OFFSET_SEC # expiration
248
+ iss: @params[:client_id], # issuer
249
+ sub: @params[:jwt_subject], # subject
250
+ aud: @params[:jwt_audience], # audience
251
+ nbf: seconds_since_epoch-JWT_NOTBEFORE_OFFSET_SEC, # not before
252
+ exp: seconds_since_epoch+JWT_EXPIRY_OFFSET_SEC # expiration
234
253
  }
235
254
  # Hum.. compliant ? TODO: remove when Faspex5 API is clarified
236
255
  if @params.has_key?(:f5_username)
237
256
  payload[:jti] = SecureRandom.uuid # JWT id
238
257
  payload[:iat] = seconds_since_epoch # issued at
239
- payload.delete(:nbf)
240
- p_scope[:redirect_uri]="https://127.0.0.1:5000/token"
258
+ payload.delete(:nbf) # not used in f5
259
+ p_scope[:redirect_uri]="https://127.0.0.1:5000/token" # used ?
241
260
  p_scope[:state]=SecureRandom.uuid
242
261
  p_scope[:client_id]=@params[:client_id]
243
262
  @token_auth_api.params[:auth]={type: :basic,username: @params[:f5_username], password: @params[:f5_password]}
@@ -245,65 +264,62 @@ module Aspera
245
264
 
246
265
  # non standard, only for global ids
247
266
  payload.merge!(@params[:jwt_add]) if @params.has_key?(:jwt_add)
267
+ Log.log.debug("JWT payload=[#{payload}]")
248
268
 
249
269
  rsa_private=@params[:jwt_private_key_obj] # type: OpenSSL::PKey::RSA
250
-
251
270
  Log.log.debug("private=[#{rsa_private}]")
252
271
 
253
- Log.log.debug("JWT payload=[#{payload}]")
254
- assertion = JWT.encode(payload, rsa_private, 'RS256',@params[:jwt_headers]||{})
255
-
272
+ assertion = JWT.encode(payload, rsa_private, 'RS256', @params[:jwt_headers]||{})
256
273
  Log.log.debug("assertion=[#{assertion}]")
257
274
 
258
- resp=create_token_www_body(p_scope.merge({
259
- :grant_type => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
260
- :assertion => assertion
275
+ resp=create_token(www_body_params: p_scope.merge({
276
+ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
277
+ assertion: assertion
261
278
  }))
262
279
  when :url_token
263
280
  # AoC Public Link
264
- params={:url_token=>@params[:url_token]}
281
+ params={url_token: @params[:url_token]}
265
282
  params[:password]=@params[:password] if @params.has_key?(:password)
266
- resp=create_token_advanced({
267
- :json_params => params,
268
- :url_params => p_scope.merge({
269
- :grant_type => 'url_token'
270
- })})
283
+ resp=create_token({
284
+ json_params: params,
285
+ url_params: p_scope.merge({grant_type: 'url_token'})
286
+ })
271
287
  when :ibm_apikey
272
288
  # ATS
273
- resp=create_token_www_body({
274
- 'grant_type' => 'urn:ibm:params:oauth:grant-type:apikey',
275
- 'response_type' => 'cloud_iam',
276
- 'apikey' => @params[:api_key]
289
+ resp=create_token(www_body_params: {
290
+ grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
291
+ response_type: 'cloud_iam',
292
+ apikey: @params[:api_key]
277
293
  })
278
294
  when :delegated_refresh
279
295
  # COS
280
- resp=create_token_www_body({
281
- 'grant_type' => 'urn:ibm:params:oauth:grant-type:apikey',
282
- 'response_type' => 'delegated_refresh_token',
283
- 'apikey' => @params[:api_key],
284
- 'receiver_client_ids' => 'aspera_ats'
296
+ resp=create_token(www_body_params: {
297
+ grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
298
+ response_type: 'delegated_refresh_token',
299
+ apikey: @params[:api_key],
300
+ receiver_client_ids: 'aspera_ats'
285
301
  })
286
302
  when :header_userpass
287
303
  # used in Faspex apiv4 and shares2
288
- resp=create_token_advanced({
289
- :auth => {
290
- :type => :basic,
291
- :username => @params[:user_name],
292
- :password => @params[:user_pass]},
293
- :json_params => p_client_id_and_scope.merge({:grant_type => 'password'}), #:www_body_params also works
294
- })
304
+ resp=create_token(
305
+ json_params: p_client_id_and_scope.merge({grant_type: 'password'}), #:www_body_params also works
306
+ auth: {
307
+ type: :basic,
308
+ username: @params[:user_name],
309
+ password: @params[:user_pass]}
310
+ )
295
311
  when :body_userpass
296
312
  # legacy, not used
297
- resp=create_token_www_body(p_client_id_and_scope.merge({
298
- :grant_type => 'password',
299
- :username => @params[:user_name],
300
- :password => @params[:user_pass]
313
+ resp=create_token(www_body_params: p_client_id_and_scope.merge({
314
+ grant_type: 'password',
315
+ username: @params[:user_name],
316
+ password: @params[:user_pass]
301
317
  }))
302
318
  when :body_data
303
319
  # used in Faspex apiv5
304
- resp=create_token_advanced({
305
- :auth => {:type => :none},
306
- :json_params => @params[:userpass_body],
320
+ resp=create_token({
321
+ auth: {type: :none},
322
+ json_params: @params[:userpass_body],
307
323
  })
308
324
  else
309
325
  raise "auth grant type unknown: #{@params[:grant]}"
@@ -311,9 +327,9 @@ module Aspera
311
327
  # TODO: test return code ?
312
328
  json_data=resp[:http].body
313
329
  token_data=JSON.parse(json_data)
314
- self.class.persist_mgr.put(token_ids,json_data)
330
+ self.class.persist_mgr.put(token_id,json_data)
315
331
  end # if ! in_cache
316
-
332
+ raise "API error: No such field in answer: #{@params[:token_field]}" unless token_data.has_key?(@params[:token_field])
317
333
  # ok we shall have a token here
318
334
  return 'Bearer '+token_data[@params[:token_field]]
319
335
  end
@@ -6,7 +6,7 @@ module Aspera
6
6
  class PersistencyActionOnce
7
7
  # @param :manager Mandatory Database
8
8
  # @param :data Mandatory object to persist, must be same object from begin to end (assume array by default)
9
- # @param :ids Mandatory identifiers
9
+ # @param :id Mandatory identifiers
10
10
  # @param :delete Optional delete persistency condition
11
11
  # @param :parse Optional parse method (default to JSON)
12
12
  # @param :format Optional dump method (default to JSON)
@@ -16,27 +16,31 @@ module Aspera
16
16
  raise "options shall be Hash" unless options.is_a?(Hash)
17
17
  raise "mandatory :manager" if options[:manager].nil?
18
18
  raise "mandatory :data" if options[:data].nil?
19
- raise "mandatory :ids (Array)" unless options[:ids].is_a?(Array)
20
- raise "mandatory 1 element in :ids" unless options[:ids].length >= 1
19
+ raise "mandatory :id (String)" unless options[:id].is_a?(String)
20
+ raise "mandatory 1 element in :id" unless options[:id].length >= 1
21
21
  @manager=options[:manager]
22
22
  @persisted_object=options[:data]
23
- @object_ids=options[:ids]
23
+ @object_id=options[:id]
24
24
  # by default , at save time, file is deleted if data is nil
25
25
  @delete_condition=options[:delete] || lambda{|d|d.empty?}
26
26
  @persist_format=options[:format] || lambda {|h| JSON.generate(h)}
27
27
  persist_parse=options[:parse] || lambda {|t| JSON.parse(t)}
28
28
  persist_merge=options[:merge] || lambda {|current,file| current.concat(file).uniq rescue current}
29
- value=@manager.get(@object_ids)
29
+ value=@manager.get(@object_id)
30
30
  persist_merge.call(@persisted_object,persist_parse.call(value)) unless value.nil?
31
31
  end
32
32
 
33
33
  def save
34
34
  if @delete_condition.call(@persisted_object)
35
- @manager.delete(@object_ids)
35
+ @manager.delete(@object_id)
36
36
  else
37
- @manager.put(@object_ids,@persist_format.call(@persisted_object))
37
+ @manager.put(@object_id,@persist_format.call(@persisted_object))
38
38
  end
39
39
  end
40
40
 
41
+ def data
42
+ return @persisted_object
43
+ end
44
+
41
45
  end
42
46
  end