blobsterix 0.0.34 → 0.0.35

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: de4c7f26e746a8a411576f67e073d959d8ae48dd
4
- data.tar.gz: 1adb250fcf9cc7546d6e5acd3ad493c6b14e6629
3
+ metadata.gz: 549a1162916756237d9df4372dbce37432d2cbb2
4
+ data.tar.gz: 85b118a8cb57a4140e922dbae3caf6c768b17cd3
5
5
  SHA512:
6
- metadata.gz: 0e9ba6fe49bf8f777f19f2409c1bec4fa434a108ec1886a62975145e639851cf07b6d1af236418aa06700432165061818f1ec517d4d83f508af569b7b30e55c3
7
- data.tar.gz: 48909960b47c5fce517eee45b253fede5eb5583c008017c6293b718da5d68dba0112b15a3e361608a63e476f449679f7de89d57cbd0bc5331c6148b35106ed2f
6
+ metadata.gz: 00f4d1abc5b5b64469090a20b5f6c6d303ba13d361a723961f606e79723fb23eb56755d8f5ee91d548d51f69466beabeab8fd6f01f4042b6ec718f621714a773
7
+ data.tar.gz: c79acbb55211463bb151cc0ed731aa85a7673b8c4936842d839a39a28b8cce7656c3efd8e9b6f829daee35897ecf3d9008260cf964b01eb4fab7aaf988dec342
@@ -3,30 +3,102 @@ module Blobsterix
3
3
  class V4
4
4
  include ::Blobsterix::S3UrlHelper
5
5
  include ::Blobsterix::UrlHelper
6
-
7
6
 
8
7
  V4_REGEX = /AWS4-HMAC-SHA256 Credential=(\w+\/\d+\/.+\/\w+\/aws4_request),.*SignedHeaders=(.+),.*Signature=(\w+)/
9
8
 
10
9
  def self.create(env)
11
- auth_string = env["HTTP_AUTHORIZATION"]
12
- matcher = V4_REGEX.match(auth_string)
10
+ matcher = V4_REGEX.match(env["HTTP_AUTHORIZATION"])
13
11
  matcher ? V4.new(env, matcher[1], matcher[2], matcher[3]) : nil
14
12
  end
15
13
 
16
- attr_reader :env, :credential, :signed_headers, :signature
14
+ attr_reader :env, :credential, :signed_headers, :signature, :access_key, :scope_date, :scope_region, :scope_service
15
+
17
16
  def initialize(env, credential, signed_headers, signature)
18
17
  @env = env
19
18
  @credential = credential
20
19
  @signed_headers = signed_headers
21
20
  @signature = signature
21
+
22
+ @access_key, @scope_date, @scope_region, @scope_service = @credential.split("/")
23
+ end
24
+
25
+ def check(secret_key_store)
26
+ return false if is_expired?
27
+
28
+ secret_key = secret_key_store.get_key(@access_key)
29
+ gen_signature(secret_key) == @signature
30
+ end
31
+
32
+ def gen_signature(secret_key)
33
+ signing_key = hmac256("AWS4"+secret_key, @scope_date)
34
+ signing_key = hmac256(signing_key, @scope_region)
35
+ signing_key = hmac256(signing_key, @scope_service)
36
+ signing_key = hmac256(signing_key, "aws4_request")
37
+
38
+ hmac256(signing_key, string_to_sign).unpack('H*').first
39
+ end
40
+
41
+ def string_to_sign
42
+ [
43
+ "AWS4-HMAC-SHA256",
44
+ header_datetime_iso8601,
45
+ [@scope_date, @scope_region, @scope_service, "aws4_request"].join("/"),
46
+ Digest::SHA256.hexdigest(canonical_request)
47
+ ].join("\n")
48
+ end
49
+
50
+ def canonical_request
51
+ [
52
+ @env["REQUEST_METHOD"].to_s.upcase,
53
+ @env["REQUEST_PATH"],
54
+ canonical_query,
55
+ canonical_headers,
56
+ @signed_headers,
57
+ @env["HTTP_X_AMZ_CONTENT_SHA256"] || Digest::SHA256.hexdigest("")
58
+ ].join("\n")
59
+ end
60
+
61
+ def canonical_query
62
+ @env["QUERY_STRING"].to_s.split("&").sort.map do |param|
63
+ escaped = param.split("=").map { |k_or_v| escape(k_or_v) }.join("=")
64
+ escaped["="] ? escaped : "#{escaped}="
65
+ end.join("&")
66
+ end
67
+
68
+ def canonical_headers
69
+ canonicalized = @env.select { |key,value| key.is_a?(String) }.inject({}) do |memo, (key,value)|
70
+ memo[key.gsub("HTTP_","").downcase.gsub("_","-")] = value.to_s.strip
71
+ memo
72
+ end
73
+
74
+ headers = ""
75
+
76
+ @signed_headers.split(";").each do |key|
77
+ raise StandardError.new("Missing signed header") unless canonicalized.key?(key)
78
+ headers << key + ":" + canonicalized[key] + "\n"
79
+ end
80
+
81
+ headers
82
+ end
83
+
84
+ def hmac256(key, data)
85
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), key, data)
86
+ end
87
+
88
+ def header_datetime
89
+ Time.parse(@env["HTTP_X_AMZ_DATE"] || @env["HTTP_DATE"] || Time.now.to_s)
90
+ end
91
+
92
+ def header_datetime_iso8601
93
+ header_datetime.utc.strftime('%Y%m%dT%H%M%SZ')
94
+ end
95
+
96
+ def is_expired?
97
+ ::Blobsterix::S3Auth.current_time > header_datetime+15*60
22
98
  end
23
- def getSignatureKey(key, dateStamp, regionName, serviceName)
24
- kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + key, dateStamp)
25
- kRegion = OpenSSL::HMAC.digest('sha256', kDate, regionName)
26
- kService = OpenSSL::HMAC.digest('sha256', kRegion, serviceName)
27
- kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
28
99
 
29
- kSigning
100
+ def escape(string)
101
+ string.gsub(/([^a-zA-Z0-9_.\-~]+)/) { "%" + $1.unpack("H2" * $1.bytesize).join("%").upcase }
30
102
  end
31
103
  end
32
104
  end
@@ -1,3 +1,3 @@
1
1
  module Blobsterix
2
- VERSION = "0.0.34"
2
+ VERSION = "0.0.35"
3
3
  end
@@ -63,7 +63,7 @@ describe Blobsterix::S3Auth do
63
63
  :path=>"/photos/puppy.jpg",
64
64
  :query=>"AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D&Expires=1175139620",
65
65
  :head => {
66
- "host"=>"johnsmith.s3.amazonaws.com"
66
+ "host"=>"johnsmith.s3.amazonaws.com"
67
67
  }
68
68
  }
69
69
  }
@@ -97,12 +97,12 @@ describe Blobsterix::S3Auth do
97
97
  "HTTP_PROXY_CONNECTION"=>"Keep-Alive",
98
98
  "HTTP_DATE"=>"Fri, 24 May 2013 00:00:00 GMT",
99
99
  "HTTP_AUTHORIZATION"=>"AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;range;x-amz-content-sha256;x-amz-date,Signature=f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41",
100
- "HTTP_HOST"=>"examplebucket.s3.amazonaws.com:80",
100
+ "HTTP_HOST"=>"examplebucket.s3.amazonaws.com",
101
101
  "HTTP_TE"=>"trailers, deflate, gzip",
102
102
  "HTTP_CONNECTION"=>"TE, close",
103
103
  "CONTENT_LENGTH"=>"0",
104
104
  "REQUEST_METHOD"=>"GET",
105
- "REQUEST_URI"=>"http://examplebucket.s3.amazonaws.com:80/test.txt",
105
+ "REQUEST_URI"=>"http://examplebucket.s3.amazonaws.com/test.txt",
106
106
  "QUERY_STRING"=>nil,
107
107
  "HTTP_VERSION"=>"1.1",
108
108
  "SCRIPT_NAME"=>"",
@@ -117,6 +117,42 @@ describe Blobsterix::S3Auth do
117
117
  }
118
118
  }
119
119
 
120
+ let(:v4_req_env_with_query_param) {
121
+ {
122
+ "HTTP_HOST"=>"firefox.s3.amazonaws.com",
123
+ "HTTP_ACCEPT_ENCODING"=>"identity",
124
+ "HTTP_X_AMZ_CONTENT_SHA256"=>"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
125
+ "HTTP_AUTHORIZATION"=>"AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20160217/US/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=10681a4fd1254dce4d80d7c254ae521dd8031b5ef871d77b7ffb28b260ee8372",
126
+ "HTTP_X_AMZ_DATE"=>"20160217T134245Z",
127
+ "CONTENT_LENGTH"=>"0",
128
+ "REQUEST_METHOD"=>"GET",
129
+ "REQUEST_URI"=>"http://firefox.s3.amazonaws.com/?delimiter=/",
130
+ "QUERY_STRING"=>"delimiter=/",
131
+ "HTTP_VERSION"=>"1.1",
132
+ "SCRIPT_NAME"=>"",
133
+ "REQUEST_PATH"=>"/",
134
+ "PATH_INFO"=>"/"
135
+ }
136
+ }
137
+
138
+ let(:v4_req_env_with_query_param_2) {
139
+ {
140
+ "HTTP_HOST"=>"firefox.s3.amazonaws.com",
141
+ "HTTP_ACCEPT_ENCODING"=>"identity",
142
+ "HTTP_X_AMZ_CONTENT_SHA256"=>"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
143
+ "HTTP_AUTHORIZATION"=>"AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20160217/US/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=d8fe8bcca8ada96996626125bec12258ed4ba0462f7c277d7412a8b9c230430d",
144
+ "HTTP_X_AMZ_DATE"=>"20160217T134245Z",
145
+ "CONTENT_LENGTH"=>"0",
146
+ "REQUEST_METHOD"=>"GET",
147
+ "REQUEST_URI"=>"http://firefox.s3.amazonaws.com/?location",
148
+ "QUERY_STRING"=>"location",
149
+ "HTTP_VERSION"=>"1.1",
150
+ "SCRIPT_NAME"=>"",
151
+ "REQUEST_PATH"=>"/",
152
+ "PATH_INFO"=>"/"
153
+ }
154
+ }
155
+
120
156
  before :all do
121
157
  Blobsterix.secret_key_store = Blobsterix::S3Auth::KeyStore.new(
122
158
  "AKIAIOSFODNN7EXAMPLE" => "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
@@ -174,8 +210,28 @@ describe Blobsterix::S3Auth do
174
210
  auth.class.should eql Blobsterix::S3Auth::V4
175
211
  end
176
212
 
213
+ it "should authenticate v4 request if the signature match and request time is within 15minutes window" do
214
+ Blobsterix::S3Auth.current_time=lambda{Time.parse("Fri, 24 May 2013 00:14:59 GMT")}
215
+ Blobsterix::S3Auth.authenticate(v4_req_env).check(Blobsterix.secret_key_store).should be_true
216
+ end
217
+
218
+ it "should not authenticate v4 request if the signature match but request time is older than 15 minutes" do
219
+ Blobsterix::S3Auth.current_time=lambda{Time.parse("Fri, 24 May 2013 00:15:01 GMT")}
220
+ Blobsterix::S3Auth.authenticate(v4_req_env).check(Blobsterix.secret_key_store).should be_false
221
+ end
222
+
223
+ it "should authenticate v4 request with query params" do
224
+ Blobsterix::S3Auth.current_time=lambda{Time.parse("20160217T135245Z")}
225
+ Blobsterix::S3Auth.authenticate(v4_req_env_with_query_param).check(Blobsterix.secret_key_store).should be_true
226
+ end
227
+
228
+ it "should authenticate v4 request with query param without equal character" do
229
+ Blobsterix::S3Auth.current_time=lambda{Time.parse("20160217T135245Z")}
230
+ Blobsterix::S3Auth.authenticate(v4_req_env_with_query_param_2).check(Blobsterix.secret_key_store).should be_true
231
+ end
232
+
177
233
  it "should at least recognize aws v2" do
178
234
  auth = Blobsterix::S3Auth.authenticate(v2_req_env)
179
235
  auth.class.should eql Blobsterix::S3Auth::V2
180
236
  end
181
- end
237
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blobsterix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.34
4
+ version: 0.0.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Sudmann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-18 00:00:00.000000000 Z
11
+ date: 2016-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -317,7 +317,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
317
317
  version: '0'
318
318
  requirements: []
319
319
  rubyforge_project:
320
- rubygems_version: 2.4.5.1
320
+ rubygems_version: 2.5.1
321
321
  signing_key:
322
322
  specification_version: 4
323
323
  summary: Blobsterix is a transcoding, caching, storage server.