class Azure::Storage::Common::Core::Auth::SharedAccessSignature

Constants

ACCOUNT_KEY_MAPPINGS
ACCOUNT_OPTIONAL_QUERY_PARAMS
BLOB_KEY_MAPPINGS
DEFAULTS
FILE_KEY_MAPPINGS
SERVICE_KEY_MAPPINGS
SERVICE_OPTIONAL_QUERY_PARAMS
SERVICE_TYPE_MAPPING
TABLE_KEY_MAPPINGS
USER_DELEGATION_KEY_MAPPINGS

Attributes

account_name[R]

Public Class Methods

new(account_name = "", access_key = "", user_delegation_key = nil) click to toggle source

Public: Initialize the SharedAccessSignature generator

@param account_name [String] The account name. Defaults to the one in the global configuration. @param access_key [String] The access_key encoded in Base64. Defaults to the one in the global configuration. @param user_delegation_key [Azure::Storage::Common::UserDelegationKey] The user delegation key obtained from 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.

# File lib/azure/storage/common/core/auth/shared_access_signature_generator.rb, line 119
def initialize(account_name = "", access_key = "", user_delegation_key = nil)
  if access_key.empty? && !user_delegation_key.nil?
    access_key = user_delegation_key.value
  end
  if account_name.empty? || access_key.empty?
    client = Azure::Storage::Common::Client.create_from_env
    account_name = client.storage_account_name if account_name.empty?
    access_key = client.storage_access_key if access_key.empty?
  end
  @account_name = account_name
  @user_delegation_key = user_delegation_key
  @signer = Azure::Core::Auth::Signer.new(access_key)
end

Public Instance Methods

canonicalize_time(options) click to toggle source
# 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) click to toggle source

Return the cononicalized resource representation of the blob resource @return [String]

# File lib/azure/storage/common/core/auth/shared_access_signature_generator.rb, line 327
def canonicalized_resource(service_type, path)
  "/#{service_type}/#{account_name}#{path.start_with?('/') ? '' : '/'}#{path}"
end
generate_account_sas_token(options = {}) click to toggle source

Account Shared Access Signature Token for the given options @param account_name [String] storage account name @param options [Hash]

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.
# File lib/azure/storage/common/core/auth/shared_access_signature_generator.rb, line 288
def generate_account_sas_token(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(signable_string_for_account(options)))

  URI.encode_www_form(query_hash)
end
generate_service_sas_token(path, options = {}) click to toggle source

Service Shared Access Signature Token for the given path and options @param path [String] Path of the URI or the table name @param options [Hash]

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.

# 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) click to toggle source

Construct the plaintext to the spec required for signatures @return [String]

# File lib/azure/storage/common/core/auth/shared_access_signature_generator.rb, line 308
def signable_string_for_account(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) click to toggle source

Construct the plaintext to the spec required for signatures @return [String]

# 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) click to toggle source

A customised URI reflecting options for the resource signed with Shared Access Signature @param uri [URI] uri to resource including query options @param use_account_sas [Boolean] Whether uses account SAS @param options [Hash]

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.

# File lib/azure/storage/common/core/auth/shared_access_signature_generator.rb, line 381
def signed_uri(uri, use_account_sas, 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 use_account_sas
    generate_account_sas_token(options)
               else
                 generate_service_sas_token(uri.path, options)
               end

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