dynamodb 0.0.2 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +2 -1
- data/README.md +41 -11
- data/dynamodb.gemspec +3 -2
- data/lib/dynamodb.rb +18 -17
- data/lib/dynamodb/connection.rb +34 -70
- data/lib/dynamodb/failure_response.rb +41 -0
- data/lib/dynamodb/http_handler.rb +74 -0
- data/lib/dynamodb/request.rb +107 -0
- data/lib/dynamodb/success_response.rb +51 -0
- data/lib/dynamodb/version.rb +3 -0
- data/lib/net/http/connection_pool.rb +226 -0
- data/lib/net/http/connection_pool/connection.rb +189 -0
- data/lib/net/http/connection_pool/session.rb +126 -0
- data/spec/dynamodb/connection_spec.rb +14 -117
- data/spec/dynamodb/failure_response_spec.rb +27 -0
- data/spec/dynamodb/http_handler_spec.rb +71 -0
- data/spec/dynamodb/request_spec.rb +31 -0
- data/spec/dynamodb/success_response_spec.rb +93 -0
- data/spec/dynamodb_spec.rb +24 -0
- metadata +18 -28
- data/lib/dynamodb/credentials.rb +0 -30
- data/lib/dynamodb/response.rb +0 -33
- data/lib/dynamodb/security_token_service.rb +0 -110
- data/lib/dynamodb/typhoeus/request.rb +0 -27
- data/spec/dynamodb/credentials_spec.rb +0 -22
- data/spec/dynamodb/response_spec.rb +0 -87
- data/spec/dynamodb/security_token_service_spec.rb +0 -97
data/spec/dynamodb_spec.rb
CHANGED
@@ -31,6 +31,20 @@ describe DynamoDB do
|
|
31
31
|
DynamoDB.serialize("foo" => nil).should == {}
|
32
32
|
DynamoDB.serialize("foo" => "").should == {}
|
33
33
|
end
|
34
|
+
|
35
|
+
it "serializes StringSet" do
|
36
|
+
DynamoDB.serialize(["foo", "bar", "foo"]).should == {"SS" => ["foo", "bar"]}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "serializes NumberSet" do
|
40
|
+
DynamoDB.serialize([1, 2, 1]).should == {"NS" => [1,2]}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "raises an error on mixed types" do
|
44
|
+
lambda {
|
45
|
+
DynamoDB.serialize([1, "2", 1])
|
46
|
+
}.should raise_error
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
36
50
|
describe "#deserialize" do
|
@@ -55,5 +69,15 @@ describe DynamoDB do
|
|
55
69
|
deserialized["price"].should == 11.99
|
56
70
|
deserialized["active"].should == 1
|
57
71
|
end
|
72
|
+
|
73
|
+
it "deserializes StringSet and NumberSet" do
|
74
|
+
item = {
|
75
|
+
"turtles" => {"SS" => ["Leonardo", "Michelangelo"]},
|
76
|
+
"powerball" => {"NS" => [1,2]}
|
77
|
+
}
|
78
|
+
deserialized = DynamoDB.deserialize(item)
|
79
|
+
deserialized["turtles"].should == ["Leonardo", "Michelangelo"]
|
80
|
+
deserialized["powerball"].should == [1,2]
|
81
|
+
end
|
58
82
|
end
|
59
83
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamodb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,24 +10,8 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2013-05-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
16
|
-
name: typhoeus
|
17
|
-
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
|
-
requirements:
|
20
|
-
- - '='
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 0.4.2
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
|
-
requirements:
|
28
|
-
- - '='
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: 0.4.2
|
31
15
|
- !ruby/object:Gem::Dependency
|
32
16
|
name: multi_json
|
33
17
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,14 +77,19 @@ files:
|
|
93
77
|
- dynamodb.gemspec
|
94
78
|
- lib/dynamodb.rb
|
95
79
|
- lib/dynamodb/connection.rb
|
96
|
-
- lib/dynamodb/
|
97
|
-
- lib/dynamodb/
|
98
|
-
- lib/dynamodb/
|
99
|
-
- lib/dynamodb/
|
80
|
+
- lib/dynamodb/failure_response.rb
|
81
|
+
- lib/dynamodb/http_handler.rb
|
82
|
+
- lib/dynamodb/request.rb
|
83
|
+
- lib/dynamodb/success_response.rb
|
84
|
+
- lib/dynamodb/version.rb
|
85
|
+
- lib/net/http/connection_pool.rb
|
86
|
+
- lib/net/http/connection_pool/connection.rb
|
87
|
+
- lib/net/http/connection_pool/session.rb
|
100
88
|
- spec/dynamodb/connection_spec.rb
|
101
|
-
- spec/dynamodb/
|
102
|
-
- spec/dynamodb/
|
103
|
-
- spec/dynamodb/
|
89
|
+
- spec/dynamodb/failure_response_spec.rb
|
90
|
+
- spec/dynamodb/http_handler_spec.rb
|
91
|
+
- spec/dynamodb/request_spec.rb
|
92
|
+
- spec/dynamodb/success_response_spec.rb
|
104
93
|
- spec/dynamodb_spec.rb
|
105
94
|
- spec/spec_helper.rb
|
106
95
|
homepage: http://github.com/groupme/dynamodb
|
@@ -129,8 +118,9 @@ specification_version: 3
|
|
129
118
|
summary: Communicate with Amazon DynamoDB.
|
130
119
|
test_files:
|
131
120
|
- spec/dynamodb/connection_spec.rb
|
132
|
-
- spec/dynamodb/
|
133
|
-
- spec/dynamodb/
|
134
|
-
- spec/dynamodb/
|
121
|
+
- spec/dynamodb/failure_response_spec.rb
|
122
|
+
- spec/dynamodb/http_handler_spec.rb
|
123
|
+
- spec/dynamodb/request_spec.rb
|
124
|
+
- spec/dynamodb/success_response_spec.rb
|
135
125
|
- spec/dynamodb_spec.rb
|
136
126
|
- spec/spec_helper.rb
|
data/lib/dynamodb/credentials.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
module DynamoDB
|
2
|
-
class Credentials
|
3
|
-
attr_reader :access_key_id, :secret_access_key, :session_token
|
4
|
-
|
5
|
-
def self.from_hash(hash)
|
6
|
-
new(hash["access_key_id"], hash["secret_access_key"], hash["session_token"])
|
7
|
-
end
|
8
|
-
|
9
|
-
def initialize(access_key_id, secret_access_key, session_token)
|
10
|
-
@access_key_id = access_key_id
|
11
|
-
@secret_access_key = secret_access_key
|
12
|
-
@session_token = session_token
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_hash
|
16
|
-
{
|
17
|
-
"access_key_id" => access_key_id,
|
18
|
-
"secret_access_key" => secret_access_key,
|
19
|
-
"session_token" => session_token
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
def ==(other)
|
24
|
-
self.class == other.class &&
|
25
|
-
access_key_id == other.access_key_id &&
|
26
|
-
secret_access_key == other.secret_access_key &&
|
27
|
-
session_token == other.session_token
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/dynamodb/response.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
module DynamoDB
|
2
|
-
class Response
|
3
|
-
attr_reader :typhoeus_response
|
4
|
-
|
5
|
-
def initialize(typhoeus_response)
|
6
|
-
@typhoeus_response = typhoeus_response
|
7
|
-
end
|
8
|
-
|
9
|
-
def hash_key_element
|
10
|
-
DynamoDB.deserialize(json["LastEvaluatedKey"]["HashKeyElement"])
|
11
|
-
end
|
12
|
-
|
13
|
-
def range_key_element
|
14
|
-
DynamoDB.deserialize(json["LastEvaluatedKey"]["RangeKeyElement"])
|
15
|
-
end
|
16
|
-
|
17
|
-
def item
|
18
|
-
return unless json["Item"]
|
19
|
-
@item ||= DynamoDB.deserialize(json["Item"])
|
20
|
-
end
|
21
|
-
|
22
|
-
def items
|
23
|
-
return unless json["Items"]
|
24
|
-
@items ||= json["Items"].map { |i| DynamoDB.deserialize(i) }
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def json
|
30
|
-
@json ||= MultiJson.load(typhoeus_response.body)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
module DynamoDB
|
2
|
-
attr_writer :access_key_id
|
3
|
-
attr_writer :secret_acces_key
|
4
|
-
attr_writer :session_token
|
5
|
-
|
6
|
-
# SecurityTokenService automatically manages the creation and renewal of
|
7
|
-
# temporary AWS credentials.
|
8
|
-
#
|
9
|
-
# Usage:
|
10
|
-
#
|
11
|
-
# credentials = SecurityTokenService.new "id", "secret key"
|
12
|
-
# credentials.access_key_id # => String
|
13
|
-
# credentials.secret_access_key # => String
|
14
|
-
# credentials.session_token # => String
|
15
|
-
#
|
16
|
-
class SecurityTokenService
|
17
|
-
THIRTY_SIX_HOURS = 129600
|
18
|
-
|
19
|
-
# A SecurityTokenService is initialized for a single AWS user using his
|
20
|
-
# credentials.
|
21
|
-
def initialize(access_key_id, secret_access_key)
|
22
|
-
@_access_key_id = access_key_id
|
23
|
-
@_secret_access_key = secret_access_key
|
24
|
-
@credentials = nil
|
25
|
-
end
|
26
|
-
|
27
|
-
def credentials
|
28
|
-
obtain_credentials
|
29
|
-
@credentials
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def signature(authorization_params)
|
35
|
-
sign(string_to_sign(authorization_params))
|
36
|
-
end
|
37
|
-
|
38
|
-
# The last line needs to be a query string of all parameters
|
39
|
-
# in the request in alphabetical order.
|
40
|
-
def string_to_sign(authorization_params)
|
41
|
-
[
|
42
|
-
"GET",
|
43
|
-
"sts.amazonaws.com",
|
44
|
-
"/",
|
45
|
-
"AWSAccessKeyId=#{@_access_key_id}" +
|
46
|
-
"&Action=GetSessionToken" +
|
47
|
-
"&DurationSeconds=#{THIRTY_SIX_HOURS}" +
|
48
|
-
"&SignatureMethod=HmacSHA256" +
|
49
|
-
"&SignatureVersion=2" +
|
50
|
-
"&Timestamp=#{CGI.escape(authorization_params[:Timestamp])}" +
|
51
|
-
"&Version=2011-06-15"
|
52
|
-
].join("\n")
|
53
|
-
end
|
54
|
-
|
55
|
-
# Extract the contents of a given tag.
|
56
|
-
def get_tag(tag, string)
|
57
|
-
# Considering that the XML string received from STS is sane and always
|
58
|
-
# has the same simple structure, I think a simple regular expression
|
59
|
-
# can do the job (with the benefit of not adding a dependency on
|
60
|
-
# another library just for ONE method). I will switch to Nokogiri if
|
61
|
-
# needed.
|
62
|
-
string.match(/#{tag.to_s}>([^<]*)/)[1]
|
63
|
-
end
|
64
|
-
|
65
|
-
# Obtain temporary credentials, set to expire after 1 hour. If
|
66
|
-
# credentials were previously obtained, no request is made until they
|
67
|
-
# expire.
|
68
|
-
def obtain_credentials
|
69
|
-
return unless credentials_expired?
|
70
|
-
|
71
|
-
authorization_params = {
|
72
|
-
:Action => 'GetSessionToken',
|
73
|
-
:Timestamp => Time.now.utc.iso8601,
|
74
|
-
:Version => '2011-06-15',
|
75
|
-
:DurationSeconds => THIRTY_SIX_HOURS # 36 hour expiration
|
76
|
-
}
|
77
|
-
|
78
|
-
params = {
|
79
|
-
:AWSAccessKeyId => @_access_key_id,
|
80
|
-
:SignatureMethod => 'HmacSHA256',
|
81
|
-
:SignatureVersion => '2',
|
82
|
-
:Signature => signature(authorization_params)
|
83
|
-
}.merge(authorization_params)
|
84
|
-
|
85
|
-
response = Typhoeus::Request.get("https://sts.amazonaws.com", :params => params)
|
86
|
-
if response.success?
|
87
|
-
body = response.body
|
88
|
-
@expiration = Time.parse(get_tag(:Expiration, body))
|
89
|
-
@credentials = Credentials.new(
|
90
|
-
get_tag(:AccessKeyId, body),
|
91
|
-
get_tag(:SecretAccessKey, body),
|
92
|
-
get_tag(:SessionToken, body))
|
93
|
-
else
|
94
|
-
raise AuthenticationError.new(response)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Sign (HMAC-SHA256) a string using the secret key given at
|
99
|
-
# initialization.
|
100
|
-
def sign(string)
|
101
|
-
Base64.encode64(
|
102
|
-
OpenSSL::HMAC.digest('sha256', @_secret_access_key, string)
|
103
|
-
).strip
|
104
|
-
end
|
105
|
-
|
106
|
-
def credentials_expired?
|
107
|
-
@expiration.nil? || @expiration <= Time.now.utc
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module Typhoeus
|
2
|
-
class Request
|
3
|
-
def sign(credentials)
|
4
|
-
headers.merge!('x-amzn-authorization' => "AWS3 AWSAccessKeyId=#{credentials.access_key_id},Algorithm=HmacSHA256,Signature=#{digest(credentials.secret_access_key)}")
|
5
|
-
end
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
def digest(secret_key)
|
10
|
-
Base64.encode64(
|
11
|
-
OpenSSL::HMAC.digest('sha256', secret_key, Digest::SHA256.digest(string_to_sign))
|
12
|
-
).strip
|
13
|
-
end
|
14
|
-
|
15
|
-
def string_to_sign
|
16
|
-
"POST\n/\n\nhost:#{parsed_uri.host}\n#{amz_to_sts}\n#{body}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def amz_to_sts
|
20
|
-
get_amz_headers.sort.map {|key, val| [key, val].join(':') + "\n"}.join
|
21
|
-
end
|
22
|
-
|
23
|
-
def get_amz_headers
|
24
|
-
headers.select {|key, val| key =~ /\Ax-amz-/}
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe DynamoDB::Credentials do
|
4
|
-
describe "#==" do
|
5
|
-
it "is true for identical credentials" do
|
6
|
-
DynamoDB::Credentials.new("abc", "123", "token").should ==
|
7
|
-
DynamoDB::Credentials.new("abc", "123", "token")
|
8
|
-
end
|
9
|
-
|
10
|
-
it "is false otherwise" do
|
11
|
-
DynamoDB::Credentials.new("abc", "123", "token").should_not ==
|
12
|
-
DynamoDB::Credentials.new("abc", "123", "different token")
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "#to_hash" do
|
17
|
-
it "converts to a hash and back" do
|
18
|
-
credentials = DynamoDB::Credentials.new("abc", "123", "token")
|
19
|
-
DynamoDB::Credentials.from_hash(credentials.to_hash).should == credentials
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe DynamoDB::Response do
|
4
|
-
before do
|
5
|
-
body = {
|
6
|
-
"LastEvaluatedKey" => {
|
7
|
-
"HashKeyElement" => {"N"=>"1"},
|
8
|
-
"RangeKeyElement"=>{"N"=>"1501"}
|
9
|
-
},
|
10
|
-
"Items"=>[
|
11
|
-
{
|
12
|
-
"name"=>{"S"=>"John Smith"},
|
13
|
-
"created_at"=>{"N"=>"1321564309.99428"},
|
14
|
-
"disabled"=>{"N"=>"0"},
|
15
|
-
"group_id"=>{"N"=>"1"},
|
16
|
-
"person_id"=>{"N" => "1500"}
|
17
|
-
},
|
18
|
-
{
|
19
|
-
"name"=>{"S"=>"Jane Smith"},
|
20
|
-
"created_at"=>{"N"=>"1321564309.99428"},
|
21
|
-
"disabled"=>{"N"=>"1"},
|
22
|
-
"group_id"=>{"N"=>"1"},
|
23
|
-
"person_id"=>{"N" => "1501"}
|
24
|
-
}
|
25
|
-
],
|
26
|
-
"Count" => 1,
|
27
|
-
"ConsumedCapacityUnits" => 0.5
|
28
|
-
}
|
29
|
-
@typhoeus_response = mock("response", :body => MultiJson.dump(body))
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "#hash_key_element" do
|
33
|
-
it "returns the typecast value of HashKeyElement" do
|
34
|
-
response = DynamoDB::Response.new(@typhoeus_response)
|
35
|
-
response.hash_key_element.should == 1
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe "#range_key_element" do
|
40
|
-
it "returns the typecast value of RangeKeyElement" do
|
41
|
-
response = DynamoDB::Response.new(@typhoeus_response)
|
42
|
-
response.range_key_element.should == 1501
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "Items" do
|
47
|
-
it "type casts response" do
|
48
|
-
response = DynamoDB::Response.new(@typhoeus_response)
|
49
|
-
response.items[0]["name"].should == "John Smith"
|
50
|
-
response.items[0]["created_at"].should == 1321564309.99428
|
51
|
-
response.items[0]["disabled"].should == 0
|
52
|
-
response.items[0]["group_id"].should == 1
|
53
|
-
response.items[0]["person_id"].should == 1500
|
54
|
-
|
55
|
-
response.items[1]["name"].should == "Jane Smith"
|
56
|
-
response.items[1]["created_at"].should == 1321564309.99428
|
57
|
-
response.items[1]["disabled"].should == 1
|
58
|
-
response.items[1]["group_id"].should == 1
|
59
|
-
response.items[1]["person_id"].should == 1501
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context "Item" do
|
64
|
-
before do
|
65
|
-
body = {
|
66
|
-
"Item"=> {
|
67
|
-
"name"=>{"S"=>"John Smith"},
|
68
|
-
"created_at"=>{"N"=>"1321564309.99428"},
|
69
|
-
"disabled"=>{"N"=>"0"},
|
70
|
-
"group_id"=>{"N"=>"1"},
|
71
|
-
"person_id"=>{"N" => "1500"}
|
72
|
-
},
|
73
|
-
"ConsumedCapacityUnits" => 0.5
|
74
|
-
}
|
75
|
-
@typhoeus_response = mock("response", :body => MultiJson.dump(body))
|
76
|
-
end
|
77
|
-
|
78
|
-
it "type casts response" do
|
79
|
-
response = DynamoDB::Response.new(@typhoeus_response)
|
80
|
-
response.item["name"].should == "John Smith"
|
81
|
-
response.item["created_at"].should == 1321564309.99428
|
82
|
-
response.item["disabled"].should == 0
|
83
|
-
response.item["group_id"].should == 1
|
84
|
-
response.item["person_id"].should == 1500
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
|
3
|
-
module DynamoDB
|
4
|
-
describe SecurityTokenService do
|
5
|
-
let(:sts) { SecurityTokenService.new("access_key_id", "secret_access_key") }
|
6
|
-
|
7
|
-
context "success" do
|
8
|
-
before do
|
9
|
-
Time.stub(:now).and_return(Time.parse("2012-03-24T22:10:38Z"))
|
10
|
-
success_body = <<-XML
|
11
|
-
<GetSessionTokenResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
|
12
|
-
<GetSessionTokenResult>
|
13
|
-
<Credentials>
|
14
|
-
<SessionToken>session_token</SessionToken>
|
15
|
-
<SecretAccessKey>secret_access_key</SecretAccessKey>
|
16
|
-
<Expiration>2036-03-19T01:03:22.276Z</Expiration>
|
17
|
-
<AccessKeyId>access_key_id</AccessKeyId>
|
18
|
-
</Credentials>
|
19
|
-
</GetSessionTokenResult>
|
20
|
-
<ResponseMetadata>
|
21
|
-
<RequestId>f0fa5827-7156-11e1-8f1e-a92b58fdc66e</RequestId>
|
22
|
-
</ResponseMetadata>
|
23
|
-
</GetSessionTokenResponse>
|
24
|
-
XML
|
25
|
-
|
26
|
-
@request = stub_request(:get, "https://sts.amazonaws.com/").
|
27
|
-
with(:query => {
|
28
|
-
"AWSAccessKeyId" => "access_key_id",
|
29
|
-
"Action" => "GetSessionToken",
|
30
|
-
"Signature" => "HyF65paDxprCe+zEHx7wxah+hiZ43PhvtmeehDtfuw8=",
|
31
|
-
"SignatureMethod" => "HmacSHA256",
|
32
|
-
"SignatureVersion" => "2",
|
33
|
-
"Timestamp" => "2012-03-24T22:10:38Z",
|
34
|
-
"Version" => "2011-06-15",
|
35
|
-
"DurationSeconds" => "129600"
|
36
|
-
}).to_return(:status => 200, :body => success_body)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "obtains session_token, access_key_id, secret_access_key" do
|
40
|
-
sts = SecurityTokenService.new("access_key_id", "secret_access_key")
|
41
|
-
credentials = sts.credentials
|
42
|
-
credentials.access_key_id.should == "access_key_id"
|
43
|
-
credentials.secret_access_key.should == "secret_access_key"
|
44
|
-
credentials.session_token.should == "session_token"
|
45
|
-
end
|
46
|
-
|
47
|
-
it "does not query STS if the credentials are not expired" do
|
48
|
-
sts = SecurityTokenService.new("access_key_id", "secret_access_key")
|
49
|
-
|
50
|
-
sts.stub(:credentials_expired?).and_return(true)
|
51
|
-
sts.credentials
|
52
|
-
@request.should have_been_requested
|
53
|
-
|
54
|
-
WebMock.reset!
|
55
|
-
|
56
|
-
sts.stub(:credentials_expired?).and_return(false)
|
57
|
-
sts.credentials
|
58
|
-
@request.should_not have_been_requested
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context "failure" do
|
63
|
-
before do
|
64
|
-
Time.stub(:now).and_return(Time.parse("2012-03-24T22:10:38Z"))
|
65
|
-
error_body = <<-XML
|
66
|
-
<ErrorResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
|
67
|
-
<Error>
|
68
|
-
<Type>Sender</Type>
|
69
|
-
<Code>InvalidClientTokenId</Code>
|
70
|
-
<Message>The security token included in the request is invalid</Message>
|
71
|
-
</Error>
|
72
|
-
<RequestId>a9f51cd0-7f5b-11e1-8022-bd0f2fc51c4b</RequestId>
|
73
|
-
</ErrorResponse>
|
74
|
-
XML
|
75
|
-
|
76
|
-
stub_request(:get, "https://sts.amazonaws.com/").
|
77
|
-
with(:query => {
|
78
|
-
"AWSAccessKeyId" => "access_key_id",
|
79
|
-
"Action" => "GetSessionToken",
|
80
|
-
"Signature" => "HyF65paDxprCe+zEHx7wxah+hiZ43PhvtmeehDtfuw8=",
|
81
|
-
"SignatureMethod" => "HmacSHA256",
|
82
|
-
"SignatureVersion" => "2",
|
83
|
-
"Timestamp" => "2012-03-24T22:10:38Z",
|
84
|
-
"Version" => "2011-06-15",
|
85
|
-
"DurationSeconds" => "129600"
|
86
|
-
}).to_return(:status => 403, :body => error_body)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "raises an AuthenticationError" do
|
90
|
-
s = SecurityTokenService.new("access_key_id", "secret_access_key")
|
91
|
-
proc {
|
92
|
-
s.credentials
|
93
|
-
}.should raise_error(DynamoDB::AuthenticationError)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|