azure-signature 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a3e4bf37dea120788f3e4b8b1f1f4ba2cac0da67
4
+ data.tar.gz: 804102d0275a2c4a7bb01dfda9636a85e32529dc
5
+ SHA512:
6
+ metadata.gz: 3593818f612766c12b61de678db9f4766866855e17f936dd88e2fa3367cf7ba33b49557dc4f6b9925e7607bb4ae04e565d3053f4828a6f7e2814b0e79d16688d
7
+ data.tar.gz: ad442a9a682c1d1a921a37bd5c1baf073b1555c00bcd6df310d0d44236e4b351e703b3d057c7a19361fe21d7e59398ba3f792fa374f9baf8363d2d7f5fa5dc67
data/CHANGES ADDED
@@ -0,0 +1,2 @@
1
+ = 0.1.0 - 25-Sep-2015
2
+ * Initial release
data/MANIFEST ADDED
@@ -0,0 +1,6 @@
1
+ CHANGES
2
+ MANIFEST
3
+ Rakefile
4
+ README
5
+ lib/azure/signature.rb
6
+ test/test_signature.rb
data/README ADDED
@@ -0,0 +1,46 @@
1
+ = Description
2
+ A Ruby library for generating an authentication signature for Azure storage services.
3
+
4
+ = Installation
5
+ gem install azure-signature
6
+
7
+ = Synopis
8
+ require 'azure/signature'
9
+
10
+ key = "SGVsbG8gV29ybGQ="
11
+ url = "http://testsnapshots.blob.core.windows.net/Tables"
12
+
13
+ sig = Azure::Signature.new(url, key)
14
+
15
+ # Look at canonical URL
16
+ p sig.canonical_url # => "/testsnapshots/Tables"
17
+
18
+ # Get a signature with the defaults
19
+ p sig.signature(:table)
20
+
21
+ # Or pass some options
22
+ p sig.signature(:table, :auth_string => true, :date => some_date, :verb => 'PUT')
23
+
24
+ = Caveats
25
+ For the first release only table signatures are supported (because that's
26
+ what I happened to need). I'll add blob, file and queue in the future.
27
+
28
+ = Acknowledgements
29
+ I borrowed the code to canonicalize resources and headers from the
30
+ azure-sdk-for-ruby project.
31
+
32
+ = Copyright
33
+ Copyright (c) 2015, Daniel J. Berger.
34
+ All rights reserved.
35
+
36
+ = License
37
+ Apache 2.0
38
+ http://www.apache.org/licenses/LICENSE-2.0
39
+
40
+ = Warranty
41
+ This package is provided "as is" and without any express or
42
+ implied warranties, including, without limitation, the implied
43
+ warranties of merchantability and fitness for a particular purpose.
44
+
45
+ = Author
46
+ Daniel Berger
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+
5
+ CLEAN.include("**/*.gem", "**/*.rbc")
6
+
7
+ namespace :gem do
8
+ desc 'Create the azure-signature gem'
9
+ task :create => [:clean] do
10
+ require 'rubygems/package'
11
+ spec = eval(IO.read('azure-signature.gemspec'))
12
+ Gem::Package.build(spec)
13
+ end
14
+
15
+ desc "Install the azure-signature library as a gem"
16
+ task :install => [:create] do
17
+ file = Dir["*.gem"].first
18
+ sh "gem install -l #{file}"
19
+ end
20
+ end
21
+
22
+ Rake::TestTask.new do |t|
23
+ t.warning = true
24
+ t.verbose = true
25
+ end
26
+
27
+ task :default => :test
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'azure-signature'
5
+ gem.version = '0.1.0'
6
+ gem.author = 'Daniel J. Berger'
7
+ gem.license = 'Apache 2.0'
8
+ gem.email = 'djberg96@gmail.com'
9
+ gem.homepage = 'http://github.com/djberg96/azure-signature'
10
+ gem.summary = 'Generate authentication signatures for Azure'
11
+ gem.test_file = 'test/test_signature.rb'
12
+ gem.files = Dir['**/*'].reject{ |f| f.include?('git') }
13
+
14
+ gem.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
15
+
16
+ gem.add_development_dependency('test-unit')
17
+
18
+ gem.description = <<-EOF
19
+ The azure-signature library generates storage signatures for
20
+ Microsoft Azure's cloud platform. You can use this to access
21
+ Azure storage services - tables, blobs, queues and files.
22
+ EOF
23
+ end
@@ -0,0 +1,131 @@
1
+ require 'uri'
2
+ require 'openssl'
3
+ require 'base64'
4
+ require 'cgi'
5
+ require 'time'
6
+
7
+ # The Azure module serves as a namespace.
8
+ module Azure
9
+ # The Signature class encapsulates an canonicalized resource string.
10
+ class Signature
11
+ # The version of the azure-signature library.
12
+ VERSION = '0.1.0'
13
+
14
+ # The resource (URL) passed to the constructor.
15
+ attr_reader :resource
16
+
17
+ # The canonical version of the resource.
18
+ attr_reader :canonical_resource
19
+
20
+ # The base64-decoded account key passed to the constructor.
21
+ attr_reader :key
22
+
23
+ # The name of the storage account, based on the resource.
24
+ attr_reader :account_name
25
+
26
+ # A URI object that encapsulates the resource.
27
+ attr_reader :uri
28
+
29
+ alias url resource
30
+ alias canonical_url canonical_resource
31
+
32
+ # Creates and returns an Azure::Signature object taking a +resource+ (URL)
33
+ # as an argument and a storage account key. The +resource+ will typically
34
+ # be an Azure storage account endpoint.
35
+ #
36
+ def initialize(resource, key)
37
+ @resource = resource
38
+ @uri = URI.parse(resource)
39
+ @account_name = @uri.host.split(".").first.split("-").first
40
+ @key = Base64.strict_decode64(key)
41
+ @canonical_resource = canonicalize_resource(resource)
42
+ end
43
+
44
+ # Generate a signature for use with the table service. Use the +options+
45
+ # hash to pass optional information. The following keys are supported:
46
+ #
47
+ # - :auth_type. Either 'SharedKey' (the default) or 'SharedKeyLight'.
48
+ # - :verb. The http verb used for SharedKey auth. The default is 'GET'.
49
+ # - :date. The date (or x-ms-date) used. The default is Time.now.httpdate.
50
+ # - :content_md5. The Content-MD5 if desired. The default is nil.
51
+ # - :content_type. The Content-Type if desired. The default is nil.
52
+ # - :auth_string. If true, prepends the auth_type + account name to the
53
+ # result and returns a string. The default is false.
54
+ #
55
+ # The result is a digest string that you can use as an authorization header
56
+ # for future http requests to (presumably) Azure storage endpoints.
57
+ #
58
+ def table_signature(options = {})
59
+ auth_type = options[:auth_type] || 'SharedKey'
60
+ verb = options[:verb] || 'GET'
61
+ date = options[:date] || Time.now.httpdate
62
+ auth_string = options[:auth_string] || false
63
+ content_md5 = options[:content_md5]
64
+ content_type = options[:content_type]
65
+
66
+ unless ['SharedKey', 'SharedKeyLight'].include?(auth_type)
67
+ raise ArgumentError, "auth type must be SharedKey or SharedKeyLight"
68
+ end
69
+
70
+ if auth_type == 'SharedKey'
71
+ body = [verb, content_md5, content_type, date, canonical_resource].join("\n")
72
+ else
73
+ body = [date, canonical_resource].join("\n")
74
+ end
75
+
76
+ if auth_string
77
+ "Authorization: #{auth_type} #{account_name}:" + sign(body)
78
+ else
79
+ sign(body)
80
+ end
81
+ end
82
+
83
+ # Generic wrapper method for getting a signature, where +type+ can be
84
+ # :table, :blob, :queue, or :file.
85
+ #
86
+ # At the moment only :table is supported.
87
+ #--
88
+ # TODO: Add support for other types.
89
+ #
90
+ def signature(type, args = {})
91
+ case type.to_s.downcase
92
+ when 'table'
93
+ table_signature(args)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ # Generate a canonical URL from an endpoint.
100
+ #--
101
+ # Borrowed from azure-sdk-for-ruby. I had my own, but this was nicer.
102
+ #
103
+ def canonicalize_resource(url)
104
+ resource = '/' + account_name + (uri.path.empty? ? '/' : uri.path)
105
+ params = CGI.parse(uri.query.to_s).map { |k,v| [k.downcase, v] }
106
+ params.sort_by! { |k,v| k }
107
+ params.map! { |k,v| '%s:%s' % [k, v.map(&:strip).sort.join(',')] }
108
+ [resource, *params].join("\n")
109
+ end
110
+
111
+ # Generate canonical headers.
112
+ #--
113
+ # Borrowed from azure-sdk-for-ruby.
114
+ #
115
+ def canonicalized_headers(headers)
116
+ headers = headers.map { |k,v| [k.to_s.downcase, v] }
117
+ headers.select! { |k,v| k =~ /^x-ms-/ }
118
+ headers.sort_by! { |k,v| k }
119
+ headers.map! { |k,v| '%s:%s' % [k, v] }
120
+ headers.map! { |h| h.gsub(/\s+/, ' ') }.join("\n")
121
+ end
122
+
123
+ # Generate a digest based on the +data+ argument, using the key
124
+ # passed to constructor.
125
+ #
126
+ def sign(body)
127
+ signed = OpenSSL::HMAC.digest('sha256', key, body)
128
+ Base64.strict_encode64(signed)
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,90 @@
1
+ require 'test-unit'
2
+ require 'azure/signature'
3
+
4
+ class TC_Azure_Signature < Test::Unit::TestCase
5
+ def setup
6
+ @key = "SGVsbG8gV29ybGQ="
7
+ @url = 'http://testsnapshots.blob.core.windows.net/?comp=list'
8
+ @sig = Azure::Signature.new(@url, @key)
9
+ end
10
+
11
+ test "version constant is set to expected value" do
12
+ assert_equal("0.1.0", Azure::Signature::VERSION)
13
+ end
14
+
15
+ test "key method basic functionality" do
16
+ assert_respond_to(@sig, :key)
17
+ assert_kind_of(String, @sig.key)
18
+ end
19
+
20
+ test "account_name basic functionality" do
21
+ assert_respond_to(@sig, :account_name)
22
+ assert_equal('testsnapshots', @sig.account_name)
23
+ end
24
+
25
+ test "resource method basic functionality" do
26
+ assert_respond_to(@sig, :resource)
27
+ assert_equal(@url, @sig.resource)
28
+ end
29
+
30
+ test "url is an alias for the resource method" do
31
+ assert_respond_to(@sig, :url)
32
+ assert_alias_method(@sig, :url, :resource)
33
+ end
34
+
35
+ test "uri method basic functionality" do
36
+ assert_respond_to(@sig, :uri)
37
+ assert_kind_of(URI, @sig.uri)
38
+ end
39
+
40
+ test "canonical_resource method basic functionality" do
41
+ assert_respond_to(@sig, :canonical_resource)
42
+ assert_kind_of(String, @sig.canonical_resource)
43
+ end
44
+
45
+ test "canonical_url is an alias for the canonical_resource method" do
46
+ assert_respond_to(@sig, :canonical_url)
47
+ assert_alias_method(@sig, :canonical_url, :canonical_resource)
48
+ end
49
+
50
+ test "canonical_resource returns the expected value for basic url" do
51
+ @url = "http://myaccount.blob.core.windows.net/Tables"
52
+ @sig = Azure::Signature.new(@url, @key)
53
+ expected = "/myaccount/Tables"
54
+ assert_equal(expected, @sig.canonical_resource)
55
+ end
56
+
57
+ test "canonical_resource returns the expected value for url with query" do
58
+ @url = "http://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=metadata"
59
+ @sig = Azure::Signature.new(@url, @key)
60
+ expected = "/myaccount/mycontainer\ncomp:metadata\nrestype:container"
61
+ assert_equal(expected, @sig.canonical_resource)
62
+ end
63
+
64
+ test "canonical_resource returns the expected value for url with multiple, identical query params" do
65
+ @url = "http://myaccount.blob.core.windows.net/mycontainer?restype=container"
66
+ @url << "&comp=list&include=snapshots&include=metadata&include=uncommittedblobs"
67
+ @sig = Azure::Signature.new(@url, @key)
68
+ expected = "/myaccount/mycontainer\ncomp:list\ninclude:metadata,snapshots,"
69
+ expected << "uncommittedblobs\nrestype:container"
70
+ assert_equal(expected, @sig.canonical_resource)
71
+ end
72
+
73
+ test "canonical_resource returns the expected value for secondary account" do
74
+ @url = "https://myaccount-secondary.blob.core.windows.net/mycontainer/myblob"
75
+ @sig = Azure::Signature.new(@url, @key)
76
+ expected = "/myaccount/mycontainer/myblob"
77
+ assert_equal(expected, @sig.canonical_resource)
78
+ end
79
+
80
+ test "constructor requires two arguments" do
81
+ assert_raise(ArgumentError){ Azure::Signature.new }
82
+ assert_raise(ArgumentError){ Azure::Signature.new('http://foo/bar') }
83
+ end
84
+
85
+ def teardown
86
+ @key = nil
87
+ @url = nil
88
+ @sig = nil
89
+ end
90
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: azure-signature
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel J. Berger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: test-unit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: |2
28
+ The azure-signature library generates storage signatures for
29
+ Microsoft Azure's cloud platform. You can use this to access
30
+ Azure storage services - tables, blobs, queues and files.
31
+ email: djberg96@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files:
35
+ - README
36
+ - CHANGES
37
+ - MANIFEST
38
+ files:
39
+ - CHANGES
40
+ - MANIFEST
41
+ - README
42
+ - Rakefile
43
+ - azure-signature.gemspec
44
+ - lib/azure/signature.rb
45
+ - test/test_signature.rb
46
+ homepage: http://github.com/djberg96/azure-signature
47
+ licenses:
48
+ - Apache 2.0
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.4.5
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: Generate authentication signatures for Azure
70
+ test_files:
71
+ - test/test_signature.rb