Module WAZ::Storage::SharedKeyCoreService
In: lib/waz/storage/core_service.rb

This module is imported by the specific services that use Shared Key authentication profile. On the current implementation this module is imported from WAZ::Queues::Service and WAZ::Blobs::Service.

Methods

Attributes

access_key  [RW] 
account_name  [RW] 
base_url  [RW] 
sharedaccesssignature  [RW] 
type_of_service  [RW] 
use_devenv  [RW] 
use_sas_auth_only  [RW] 
use_ssl  [RW] 

Public Class methods

Creates an instance of the implementor service (internally used by the API).

[Source]

    # File lib/waz/storage/core_service.rb, line 9
 9:       def initialize(options = {})
10:         # Flag to define the use of shared access signature only
11:         self.use_sas_auth_only = options[:use_sas_auth_only] or false
12:         self.sharedaccesssignature = options[:sharedaccesssignature] 
13: 
14:         self.account_name = options[:account_name]
15:         self.access_key = options[:access_key]
16:         self.type_of_service = options[:type_of_service]        
17:         self.use_ssl = options[:use_ssl] or false
18:         self.use_devenv = !!options[:use_devenv]
19:         self.base_url = "#{options[:type_of_service] or "blobs"}.#{options[:base_url] or "core.windows.net"}" unless self.use_devenv
20:         self.base_url ||= (options[:base_url] or "core.windows.net") 
21:       end

Public Instance methods

Canonicalizes the request headers by following Microsoft‘s specification on how those headers have to be sorted and which of the given headers apply to be canonicalized.

[Source]

    # File lib/waz/storage/core_service.rb, line 53
53:       def canonicalize_headers(headers)
54:         cannonicalized_headers = headers.keys.select {|h| h.to_s.start_with? 'x-ms'}.map{ |h| "#{h.downcase.strip}:#{headers[h].strip}" }.sort{ |a, b| a <=> b }.join("\x0A")
55:         return cannonicalized_headers
56:       end

Creates a canonical representation of the message by combining account_name/resource_path.

[Source]

    # File lib/waz/storage/core_service.rb, line 59
59:       def canonicalize_message(url)
60:         uri_component = url.gsub(/https?:\/\/[^\/]+\//i, '').gsub(/\?.*/i, '')
61:         comp_component = url.scan(/comp=[^&]+/i).first()
62:         uri_component << "?#{comp_component}" if comp_component
63:         canonicalized_message = "/#{self.account_name}/#{uri_component}"
64:         return canonicalized_message
65:       end

[Source]

     # File lib/waz/storage/core_service.rb, line 104
104:       def canonicalize_message20090919(url)
105:         uri_component = url.gsub(/https?:\/\/[^\/]+\//i, '').gsub(/\?.*/i, '')
106:         query_component = (url.scan(/\?(.*)/i).first() or []).first()
107:         query_component = query_component.split('&').sort{|a, b| a <=> b}.map{ |p| CGI::unescape(p.split('=').join(':')) }.join("\n") if query_component
108:         canonicalized_message = "/#{self.account_name}/#{uri_component}"
109:         canonicalized_message << "\n#{query_component}" if query_component
110:         return canonicalized_message
111:       end

Generates a Windows Azure Storage call, it internally calls url generation method and the request generation message.

[Source]

     # File lib/waz/storage/core_service.rb, line 115
115:       def execute(verb, path, query = {}, headers = {}, payload = nil)
116:         url = generate_request_uri(path, query)
117:         request = generate_request(verb, url, headers, payload)
118:         request.execute()
119:       end

Generates a request based on Adam Wiggings’ rest-client, including all the required headers for interacting with Windows Azure Storage API (except for Tables). This methods embeds the authorization key signature on the request based on the given access_key.

[Source]

    # File lib/waz/storage/core_service.rb, line 26
26:       def generate_request(verb, url, headers = {}, payload = nil)
27:         http_headers = {}
28:         headers.each{ |k, v| http_headers[k.to_s.gsub(/_/, '-')] = v} unless headers.nil?
29:         http_headers.merge!("x-ms-Date" => Time.new.httpdate)
30:         http_headers.merge!("Content-Length" => (payload or "").size)
31:         request = {:headers => http_headers, :method => verb.to_s.downcase.to_sym, :url => url, :payload => payload}
32:         request[:headers].merge!("Authorization" => "SharedKey #{account_name}:#{generate_signature(request)}") unless self.use_sas_auth_only 
33:         return RestClient::Request.new(request)
34:       end

Generates the request uri based on the resource path, the protocol, the account name and the parameters passed on the options hash.

[Source]

    # File lib/waz/storage/core_service.rb, line 38
38:       def generate_request_uri(path = nil, options = {})
39:         protocol = use_ssl ? "https" : "http"
40:         query_params = options.keys.sort{ |a, b| a.to_s <=> b.to_s}.map{ |k| "#{k.to_s.gsub(/_/, '')}=#{CGI.escape(options[k].to_s)}"}.join("&") unless options.nil? or options.empty?
41:         uri = "#{protocol}://#{base_url}/#{path.start_with?(account_name) ? "" : account_name }#{((path or "").start_with?("/") or path.start_with?(account_name)) ? "" : "/"}#{(path or "")}" if !self.use_devenv.nil? and self.use_devenv
42:         uri ||= "#{protocol}://#{account_name}.#{base_url}#{(path or "").start_with?("/") ? "" : "/"}#{(path or "")}" 
43:         if self.use_sas_auth_only 
44:           uri << "?#{self.sharedaccesssignature.gsub(/\?/,'')}" 
45:         else
46:           uri << "?#{query_params}" if query_params
47:         end        
48:         return uri
49:       end

Generates the signature based on Micosoft specs for the REST API. It includes some special headers, the canonicalized header line and the canonical form of the message, all of the joined by \n character. Encoded with Base64 and encrypted with SHA256 using the access_key as the seed.

[Source]

    # File lib/waz/storage/core_service.rb, line 70
70:       def generate_signature(options = {})
71:         return generate_signature20090919(options) if options[:headers]["x-ms-version"] == "2009-09-19"
72: 
73:         signature = options[:method].to_s.upcase + "\x0A" +
74:                      (options[:headers]["Content-MD5"] or "") + "\x0A" +
75:                      (options[:headers]["Content-Type"] or "") + "\x0A" +
76:                      (options[:headers]["Date"] or "")+ "\x0A"
77: 
78:         signature += canonicalize_headers(options[:headers]) + "\x0A" unless self.type_of_service == 'table'
79:         signature += canonicalize_message(options[:url])
80:         signature = signature.toutf8 if(signature.respond_to? :toutf8)
81:         Base64.encode64(HMAC::SHA256.new(Base64.decode64(self.access_key)).update(signature).digest)
82:       end

[Source]

     # File lib/waz/storage/core_service.rb, line 84
 84:       def generate_signature20090919(options = {})
 85:         signature = options[:method].to_s.upcase + "\x0A" +
 86:                     (options[:headers]["Content-Encoding"] or "") + "\x0A" +
 87:                     (options[:headers]["Content-Language"] or "") + "\x0A" +
 88:                     (options[:headers]["Content-Length"] or "").to_s + "\x0A" +                    
 89:                     (options[:headers]["Content-MD5"] or "") + "\x0A" +
 90:                     (options[:headers]["Content-Type"] or "") + "\x0A" +
 91:                     (options[:headers]["Date"] or "")+ "\x0A" +
 92:                     (options[:headers]["If-Modified-Since"] or "")+ "\x0A" +
 93:                     (options[:headers]["If-Match"] or "")+ "\x0A" +
 94:                     (options[:headers]["If-None-Match"] or "")+ "\x0A" +                    
 95:                     (options[:headers]["If-Unmodified-Since"] or "")+ "\x0A" +
 96:                     (options[:headers]["Range"] or "")+ "\x0A" +                    
 97:                     canonicalize_headers(options[:headers]) + "\x0A" +
 98:                     canonicalize_message20090919(options[:url])
 99: 
100:         signature = signature.toutf8 if(signature.respond_to? :toutf8)
101:         Base64.encode64(HMAC::SHA256.new(Base64.decode64(self.access_key)).update(signature).digest)
102:       end

[Validate]