Class: Azure::Storage::Common::Core::Auth::SharedAccessSignature

Inherits:
Object
  • Object
show all
Defined in:
lib/azure/storage/common/core/auth/shared_access_signature_generator.rb

Constant Summary collapse

DEFAULTS =
{
  permissions: "r",
  version: Azure::Storage::Common::Default::STG_VERSION
}
SERVICE_TYPE_MAPPING =
{
  b: Azure::Storage::Common::ServiceType::BLOB,
  t: Azure::Storage::Common::ServiceType::TABLE,
  q: Azure::Storage::Common::ServiceType::QUEUE,
  f: Azure::Storage::Common::ServiceType::FILE
}
ACCOUNT_KEY_MAPPINGS =
{
  version:              :sv,
  service:              :ss,
  resource:             :srt,
  permissions:          :sp,
  start:                :st,
  expiry:               :se,
  protocol:             :spr,
  ip_range:             :sip
}
SERVICE_KEY_MAPPINGS =
{
  version:              :sv,
  permissions:          :sp,
  start:                :st,
  expiry:               :se,
  identifier:           :si,
  protocol:             :spr,
  ip_range:             :sip
}
USER_DELEGATION_KEY_MAPPINGS =
{
  signed_oid:           :skoid,
  signed_tid:           :sktid,
  signed_start:         :skt,
  signed_expiry:        :ske,
  signed_service:       :sks,
  signed_version:       :skv
}
BLOB_KEY_MAPPINGS =
{
  resource:             :sr,
  timestamp:            :snapshot,
  cache_control:        :rscc,
  content_disposition:  :rscd,
  content_encoding:     :rsce,
  content_language:     :rscl,
  content_type:         :rsct
}
TABLE_KEY_MAPPINGS =
{
  table_name:           :tn,
  startpk:              :spk,
  endpk:                :epk,
  startrk:              :srk,
  endrk:                :erk
}
FILE_KEY_MAPPINGS =
{
  resource:             :sr,
  cache_control:        :rscc,
  content_disposition:  :rscd,
  content_encoding:     :rsce,
  content_language:     :rscl,
  content_type:         :rsct
}
SERVICE_OPTIONAL_QUERY_PARAMS =
[:sp, :si, :sip, :spr, :rscc, :rscd, :rsce, :rscl, :rsct, :spk, :srk, :epk, :erk]
ACCOUNT_OPTIONAL_QUERY_PARAMS =
[:st, :sip, :spr]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(account_name = "", access_key = "", user_delegation_key = nil) ⇒ SharedAccessSignature

Public: Initialize the SharedAccessSignature generator

calling get_user_delegation_key after authenticating with an Azure Active Directory entity. If present, the SAS is signed with the user delegation key instead of the access key.

Parameters:

  • account_name (String) (defaults to: "")

    The account name. Defaults to the one in the global configuration.

  • access_key (String) (defaults to: "")

    The access_key encoded in Base64. Defaults to the one in the global configuration.

  • user_delegation_key (Azure::Storage::Common::UserDelegationKey) (defaults to: nil)

    The user delegation key obtained from



119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 119

def initialize( = "", access_key = "", user_delegation_key = nil)
  if access_key.empty? && !user_delegation_key.nil?
    access_key = user_delegation_key.value
  end
  if .empty? || access_key.empty?
    client = Azure::Storage::Common::Client.create_from_env
     = client. if .empty?
    access_key = client.storage_access_key if access_key.empty?
  end
  @account_name = 
  @user_delegation_key = user_delegation_key
  @signer = Azure::Core::Auth::Signer.new(access_key)
end

Instance Attribute Details

#account_nameObject (readonly)

Returns the value of attribute account_name.



110
111
112
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 110

def 
  @account_name
end

Instance Method Details

#canonicalize_time(options) ⇒ Object



331
332
333
334
335
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 331

def canonicalize_time(options)
  options[:start] = Time.parse(options[:start]).utc.iso8601 if options[:start]
  options[:expiry] = Time.parse(options[:expiry]).utc.iso8601 if options[:expiry]
  options[:expiry] ||= (Time.now + 60 * 30).utc.iso8601
end

#canonicalized_resource(service_type, path) ⇒ String

Return the cononicalized resource representation of the blob resource

Returns:



327
328
329
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 327

def canonicalized_resource(service_type, path)
  "/#{service_type}/#{}#{path.start_with?('/') ? '' : '/'}#{path}"
end

#generate_account_sas_token(options = {}) ⇒ Object

Account Shared Access Signature Token for the given options

Options

  • :service - String. Required. Accessible services. Combination of ‘b’ (blob), ‘q’ (queue), ‘t’ (table), ‘f’ (file).

  • :resource - String. Required. Accessible resource types. Combination of ‘s’ (service), ‘c’ (container-level), ‘o’(object-level).

  • :permissions - String. Required. Permissions. Combination of ‘r’ (read), ‘w’ (write), ‘d’(delete), ‘l’(list), ‘a’(add),

    'c'(create), 'u'(update), 'p'(process). Permissions are only valid if they match
    the specified signed resource type; otherwise they are ignored.
    
  • :start - String. Optional. UTC Date/Time in ISO8601 format.

  • :expiry - String. Optional. UTC Date/Time in ISO8601 format. Default now + 30 minutes.

  • :protocol - String. Optional. Permitted protocols.

  • :ip_range - String. Optional. An IP address or a range of IP addresses from which to accept requests.

    When specifying a range, note that the range is inclusive.
    

Parameters:

  • account_name (String)

    storage account name

  • options (Hash) (defaults to: {})

Raises:



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 288

def (options = {})
  raise Azure::Storage::Common::InvalidOptionsError, "SAS version cannot be set" if options[:version]

  options = DEFAULTS.merge(options)
  valid_mappings = ACCOUNT_KEY_MAPPINGS

  invalid_options = options.reject { |k, _| valid_mappings.key?(k) }
  raise Azure::Storage::Common::InvalidOptionsError, "invalid options #{invalid_options} provided for SAS token generate" if invalid_options.length > 0

  canonicalize_time(options)

  query_hash = Hash[options.map { |k, v| [ACCOUNT_KEY_MAPPINGS[k], v] }]
  .reject { |k, v| ACCOUNT_OPTIONAL_QUERY_PARAMS.include?(k) && v.to_s == "" }
  .merge(sig: @signer.sign((options)))

  URI.encode_www_form(query_hash)
end

#generate_service_sas_token(path, options = {}) ⇒ Object

Service Shared Access Signature Token for the given path and options

Options

  • :service - String. Required. Service type. ‘b’ (blob) or ‘q’ (queue) or ‘t’ (table) or ‘f’ (file).

  • :resource - String. Required. Resource type, ‘b’ (blob) or ‘c’ (container) or ‘f’ (file) or ‘s’ (share).

  • :permissions - String. Optional. Combination of ‘r’, ‘a’, ‘c’, w’,‘d’,‘l’ in this order for a container.

    Combination of 'r', 'a', 'c', 'w', 'd' in this order for a blob.
    Combination of 'r', 'c', 'w', 'd', 'l' in this order for a share.
    Combination of 'r', 'c', 'w', 'd' in this order for a file.
    Combination of 'r', 'a', 'u', 'p' in this order for a queue.
    Combination of 'r', 'a', 'u', 'd' in this order for a table.
    This option must be omitted if it has been specified in an associated stored access policy.
    
  • :start - String. Optional. UTC Date/Time in ISO8601 format.

  • :expiry - String. Optional. UTC Date/Time in ISO8601 format. Default now + 30 minutes.

  • :identifier - String. Optional. Identifier for stored access policy.

    This option must be omitted if a user delegation key has been provided.
    
  • :protocol - String. Optional. Permitted protocols.

  • :ip_range - String. Optional. An IP address or a range of IP addresses from which to accept requests.

Below options for blob serivce only

  • :snapshot - String. Optional. UTC Date/Time in ISO8601 format. The blob snapshot to grant permission.

  • :cache_control - String. Optional. Response header override.

  • :content_disposition - String. Optional. Response header override.

  • :content_encoding - String. Optional. Response header override.

  • :content_language - String. Optional. Response header override.

  • :content_type - String. Optional. Response header override.

Below options for table service only

  • :startpk - String. Optional but must accompany startrk. The start partition key of a specified partition key range.

  • :endpk - String. Optional but must accompany endrk. The end partition key of a specified partition key range.

  • :startrk - String. Optional. The start row key of a specified row key range.

  • :endrk - String. Optional. The end row key of a specified row key range.

Parameters:

  • path (String)

    Path of the URI or the table name

  • options (Hash) (defaults to: {})

Raises:



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 168

def generate_service_sas_token(path, options = {})
  if options.key?(:service)
    service_type = SERVICE_TYPE_MAPPING[options[:service].to_sym]
    options.delete(:service)
  end

  raise Azure::Storage::Common::InvalidOptionsError, "SAS version cannot be set" if options[:version]

  options = DEFAULTS.merge(options)
  valid_mappings = SERVICE_KEY_MAPPINGS
  if service_type == Azure::Storage::Common::ServiceType::BLOB
    if options[:resource]
      options.merge!(resource: options[:resource])
    else
      options.merge!(resource: "b")
    end
    valid_mappings.merge!(BLOB_KEY_MAPPINGS)
  elsif service_type == Azure::Storage::Common::ServiceType::TABLE
    options.merge!(table_name: path)
    valid_mappings.merge!(TABLE_KEY_MAPPINGS)
  elsif service_type == Azure::Storage::Common::ServiceType::FILE
    if options[:resource]
      options.merge!(resource: options[:resource])
    else
      options.merge!(resource: "f")
    end
    valid_mappings.merge!(FILE_KEY_MAPPINGS)
  end

  service_key_mappings = SERVICE_KEY_MAPPINGS
  unless @user_delegation_key.nil?
    valid_mappings.delete(:identifier)
    USER_DELEGATION_KEY_MAPPINGS.each { |k, _| options[k] = @user_delegation_key.send(k) }
    valid_mappings.merge!(USER_DELEGATION_KEY_MAPPINGS)
    service_key_mappings = service_key_mappings.merge(USER_DELEGATION_KEY_MAPPINGS)
  end

  invalid_options = options.reject { |k, _| valid_mappings.key?(k) }
  raise Azure::Storage::Common::InvalidOptionsError, "invalid options #{invalid_options} provided for SAS token generate" if invalid_options.length > 0

  canonicalize_time(options)

  query_hash = Hash[options.map { |k, v| [service_key_mappings[k], v] }]
  .reject { |k, v| SERVICE_OPTIONAL_QUERY_PARAMS.include?(k) && v.to_s == "" }
  .merge(sig: @signer.sign(signable_string_for_service(service_type, path, options)))

  URI.encode_www_form(query_hash)
end

#signable_string_for_account(options) ⇒ String

Construct the plaintext to the spec required for signatures

Returns:



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 308

def (options)
  # Order is significant
  # The newlines from empty strings here are required
  [
    @account_name,
    options[:permissions],
    options[:service],
    options[:resource],
    options[:start],
    options[:expiry],
    options[:ip_range],
    options[:protocol],
    Azure::Storage::Common::Default::STG_VERSION,
    ""
  ].join("\n")
end

#signable_string_for_service(service_type, path, options) ⇒ String

Construct the plaintext to the spec required for signatures

Returns:



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 219

def signable_string_for_service(service_type, path, options)
  # Order is significant
  # The newlines from empty strings here are required
  signable_fields =
  [
    options[:permissions],
    options[:start],
    options[:expiry],
    canonicalized_resource(service_type, path)
  ]

  if @user_delegation_key.nil?
    signable_fields.push(options[:identifier])
  else
    signable_fields.concat [
      @user_delegation_key.signed_oid,
      @user_delegation_key.signed_tid,
      @user_delegation_key.signed_start,
      @user_delegation_key.signed_expiry,
      @user_delegation_key.signed_service,
      @user_delegation_key.signed_version
    ]
  end

  signable_fields.concat [
    options[:ip_range],
    options[:protocol],
    Azure::Storage::Common::Default::STG_VERSION
  ]

  signable_fields.concat [
    options[:resource],
    options[:timestamp]
  ] if service_type == Azure::Storage::Common::ServiceType::BLOB

  signable_fields.concat [
    options[:cache_control],
    options[:content_disposition],
    options[:content_encoding],
    options[:content_language],
    options[:content_type]
  ] if service_type == Azure::Storage::Common::ServiceType::BLOB || service_type == Azure::Storage::Common::ServiceType::FILE

  signable_fields.concat [
    options[:startpk],
    options[:startrk],
    options[:endpk],
    options[:endrk]
  ] if service_type == Azure::Storage::Common::ServiceType::TABLE

  signable_fields.join "\n"
end

#signed_uri(uri, use_account_sas, options) ⇒ Object

A customised URI reflecting options for the resource signed with Shared Access Signature

Options

  • :start - String. Optional. UTC Date/Time in ISO8601 format.

  • :expiry - String. Optional. UTC Date/Time in ISO8601 format. Default now + 30 minutes.

  • :protocol - String. Optional. Permitted protocols.

  • :ip_range - String. Optional. An IP address or a range of IP addresses from which to accept requests.

    When specifying a range, note that the range is inclusive.
    

Below options for account SAS only

  • :service - String. Required. Accessible services. Combination of ‘b’ (blob), ‘q’ (queue), ‘t’ (table), ‘f’ (file).

  • :resource - String. Required. Accessible resource types. Combination of ‘s’ (service), ‘c’ (container-level), ‘o’(object-level).

  • :permissions - String. Required. Permissions. Combination of ‘r’ (read), ‘w’ (write), ‘d’(delete), ‘l’(list), ‘a’(add),

    'c'(create), 'u'(update), 'p'(process). Permissions are only valid if they match
    the specified signed resource type; otherwise they are ignored.
    

Below options for service SAS only

  • :service - String. Required. Service type. ‘b’ (blob) or ‘q’ (queue) or ‘t’ (table) or ‘f’ (file).

  • :resource - String. Required. Resource type, ‘b’ (blob) or ‘c’ (container) or ‘f’ (file) or ‘s’ (share).

  • :identifier - String. Optional. Identifier for stored access policy.

  • :permissions - String. Optional. Combination of ‘r’, ‘a’, ‘c’, w’,‘d’,‘l’ in this order for a container.

    Combination of 'r', 'a', 'c', 'w', 'd' in this order for a blob.
    Combination of 'r', 'c', 'w', 'd', 'l' in this order for a share.
    Combination of 'r', 'c', 'w', 'd' in this order for a file.
    Combination of 'r', 'a', 'u', 'p' in this order for a queue.
    Combination of 'r', 'a', 'u', 'd' in this order for a table.
    

Below options for Blob service only

  • :cache_control - String. Optional. Response header override.

  • :content_disposition - String. Optional. Response header override.

  • :content_encoding - String. Optional. Response header override.

  • :content_language - String. Optional. Response header override.

  • :content_type - String. Optional. Response header override.

Below options for Table service only

  • :table_name - String. Required. Table name for SAS.

  • :startpk - String. Optional but must accompany startrk. The start partition key of a specified partition key range.

  • :endpk - String. Optional but must accompany endrk. The end partition key of a specified partition key range.

  • :startrk - String. Optional. The start row key of a specified row key range.

  • :endrk - String. Optional. The end row key of a specified row key range.

Parameters:

  • uri (URI)

    uri to resource including query options

  • use_account_sas (Boolean)

    Whether uses account SAS

  • options (Hash)


381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/azure/storage/common/core/auth/shared_access_signature_generator.rb', line 381

def signed_uri(uri, , options)
  CGI::parse(uri.query || "").inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }

  if options[:service] == (nil) && uri.host != (nil)
    host_splits = uri.host.split(".")
    options[:service] = host_splits[1].chr if host_splits.length > 1 && host_splits[0] == @account_name
  end

  sas_params = if 
    (options)
               else
                 generate_service_sas_token(uri.path, options)
               end

  URI.parse(uri.to_s + (uri.query.nil? ? "?" : "&") + sas_params)
end