Skip to content

Instantly share code, notes, and snippets.

@rahim
Last active August 29, 2015 14:16
Show Gist options
  • Save rahim/dbed644be94fc18933d9 to your computer and use it in GitHub Desktop.
Save rahim/dbed644be94fc18933d9 to your computer and use it in GitHub Desktop.
Manually testing Azure Shared Access Signatures in Ruby
# see http://stackoverflow.com/questions/21994466/signature-did-not-match-on-azure-sas-url
# see https://msdn.microsoft.com/library/azure/dn140255.aspx
# see https://msdn.microsoft.com/en-us/library/azure/dn140256.aspx
# see https://github.com/Azure/azure-sdk-for-ruby/issues/162
# This assumes the Azure Ruby SDK is already loaded and initialized with appropriate config
# Note we need the empty strings as the empty lines are required in the signed string
DEFAULTS = {
path: '/',
resource: 'b',
permissions: 'r',
start: '',
expiry: '',
identifier: '',
version: '2013-08-15',
cache_control: '',
content_disposition: '',
content_encoding: '',
content_language: '',
content_type: ''
}
def prepared_string(options = {}, account_name = Azure.config.storage_account_name)
options = DEFAULTS.merge(options)
s = []
s << options[:permissions]
s << options[:start]
s << options[:expiry]
s << canonicalized_resource(options[:path], options[:resource])
s << options[:identifier]
s << options[:version]
s << options[:cache_control]
s << options[:content_disposition]
s << options[:content_encoding]
s << options[:content_language]
s << options[:content_type]
puts
puts s.join("\n")
puts
s.join("\n")
end
def canonicalized_resource(path, resource = 'b', account_name = Azure.config.storage_account_name)
# If resource is a container, remove the last part (which is the filename)
path = path.split('/').reverse.drop(1).reverse.join('/') if resource == 'c'
"/#{account_name}/#{path}"
end
# We should be able to reuse much of Azure::Core::Auth::SharedKey if implementing properly within the SDK
def create_signature(string_to_sign, access_key = Azure.config.storage_access_key)
signature = OpenSSL::HMAC.digest('sha256', Base64.strict_decode64(access_key), string_to_sign.encode(Encoding::UTF_8))
Base64.strict_encode64(signature)
end
def create_signed_query_string(options = {}, account_name = Azure.config.storage_account_name)
options = DEFAULTS.merge(options)
base = "https://#{account_name}.blob.core.windows.net"
uri = Addressable::URI.new
# Parts
parts = {}
parts[:st] = URI.unescape(options[:start]) unless options[:start] == ''
parts[:se] = URI.unescape(options[:expiry])
parts[:sr] = URI.unescape(options[:resource])
parts[:sp] = URI.unescape(options[:permissions])
parts[:si] = URI.unescape(options[:identifier]) unless options[:identifier] == ''
parts[:sv] = URI.unescape(options[:version])
parts[:rscc] = URI.unescape(options[:cache_control]) unless options[:cache_control] == ''
parts[:rscd] = URI.unescape(options[:content_disposition]) unless options[:content_disposition] == ''
parts[:rsce] = URI.unescape(options[:content_encoding]) unless options[:content_encoding] == ''
parts[:rscl] = URI.unescape(options[:content_language]) unless options[:content_language] == ''
parts[:rsct] = URI.unescape(options[:content_type]) unless options[:content_type] == ''
parts[:sig] = URI.unescape(create_signature(prepared_string(options)))
uri.query_values = parts
return "#{base}/#{options[:path]}?#{uri.query}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment