azure-signature 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGES +2 -0
- data/MANIFEST +6 -0
- data/README +46 -0
- data/Rakefile +27 -0
- data/azure-signature.gemspec +23 -0
- data/lib/azure/signature.rb +131 -0
- data/test/test_signature.rb +90 -0
- metadata +71 -0
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
data/MANIFEST
ADDED
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
|