aws-sessionstore-dynamodb 0.5.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +15 -0
- data/Gemfile +1 -1
- data/README.md +5 -5
- data/aws-sessionstore-dynamodb.gemspec +3 -3
- data/lib/aws-sessionstore-dynamodb.rb +1 -1
- data/lib/aws/session_store/dynamo_db/configuration.rb +15 -7
- data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +5 -5
- data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +6 -6
- data/lib/aws/session_store/dynamo_db/garbage_collection.rb +4 -4
- data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +1 -1
- data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +1 -1
- data/lib/aws/session_store/dynamo_db/locking/base.rb +6 -6
- data/lib/aws/session_store/dynamo_db/locking/null.rb +4 -4
- data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +10 -10
- data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +1 -1
- data/lib/aws/session_store/dynamo_db/rack_middleware.rb +9 -9
- data/lib/aws/session_store/dynamo_db/railtie.rb +2 -2
- data/lib/aws/session_store/dynamo_db/table.rb +4 -4
- data/lib/aws/session_store/dynamo_db/tasks/session_table.rake +1 -1
- data/lib/aws/session_store/dynamo_db/version.rb +2 -2
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb +2 -2
- data/spec/aws/session_store/dynamo_db/configuration_spec.rb +7 -7
- data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +3 -3
- data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +7 -4
- data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +5 -5
- data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +4 -4
- data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +4 -4
- data/spec/aws/session_store/dynamo_db/table_spec.rb +1 -1
- data/spec/spec_helper.rb +14 -8
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7fc34007a54a256d5ef9749bc952dcbbb9d8c1c
|
4
|
+
data.tar.gz: 31a61f733ce42fe5bf852ae6e7ed07e95a27066a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cec7d8e8ab2bf8135ceace7a4f54647744c2b1e88d69ba20ab44dc5f83236af40cd34cb23d1b1ddc942d4ea787d2e4674ff0e3670a1a3580c0f93850060033da
|
7
|
+
data.tar.gz: 66d01279ddc10ed9e821045356692b73ce9de9597f454787e64c53b8ce6d77b361ca3a5f8fed8447b350aa9cf9a1f42df03668dc8938c45b0c5c38843b440de6
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -37,7 +37,7 @@ Ruby file using the following method:
|
|
37
37
|
|
38
38
|
require 'aws-sessionstore-dynamodb'
|
39
39
|
|
40
|
-
|
40
|
+
Aws::SessionStore::DynamoDB::Table.create_table
|
41
41
|
|
42
42
|
Run the session store as a Rack middleware in the following way:
|
43
43
|
|
@@ -46,7 +46,7 @@ Run the session store as a Rack middleware in the following way:
|
|
46
46
|
|
47
47
|
options = { :secret_key => 'SECRET_KEY' }
|
48
48
|
|
49
|
-
use
|
49
|
+
use Aws::SessionStore::DynamoDB::RackMiddleware.new(options)
|
50
50
|
run SomeRackApp
|
51
51
|
|
52
52
|
Note that `:secret_key` is a mandatory configuration option that must be set.
|
@@ -71,7 +71,7 @@ Full API documentation of the library can be found on [RubyDoc.info][1].
|
|
71
71
|
### Configuration Options
|
72
72
|
|
73
73
|
A number of options are available to be set in
|
74
|
-
`
|
74
|
+
`Aws::SessionStore::DynamoDB::Configuration`, which is used by the
|
75
75
|
`RackMiddleware` class. These options can be set in the YAML configuration
|
76
76
|
file in a Rails application (located in `config/sessionstore/dynamodb.yml`),
|
77
77
|
directly by Ruby code, or through environment variables.
|
@@ -126,7 +126,7 @@ You can create your own Rake task for garbage collection similar to below:
|
|
126
126
|
desc 'Perform Garbage Collection'
|
127
127
|
task :garbage_collect do |t|
|
128
128
|
options = {:max_age => 3600*24, max_stale => 5*3600 }
|
129
|
-
|
129
|
+
Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
|
130
130
|
end
|
131
131
|
|
132
132
|
The above example will clear sessions older than one day or that have been
|
@@ -164,7 +164,7 @@ locking strategy according to your needs:
|
|
164
164
|
|
165
165
|
You can pass in your own error handler for raised exceptions or you can allow
|
166
166
|
the default error handler to them for you. See the API documentation
|
167
|
-
on the {
|
167
|
+
on the {Aws::SessionStore::DynamoDB::Errors::BaseHandler} class for more
|
168
168
|
details.
|
169
169
|
|
170
170
|
[1]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/frames
|
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/lib/aws/session_store/dynamo_db/version'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "aws-sessionstore-dynamodb"
|
5
|
-
spec.version =
|
5
|
+
spec.version = Aws::SessionStore::DynamoDB::VERSION
|
6
6
|
spec.authors = ["Ruby Robinson"]
|
7
7
|
spec.summary = "The Amazon DynamoDB Session Store handles sessions " +
|
8
8
|
"for Ruby web applications using a DynamoDB backend."
|
@@ -13,6 +13,6 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
14
14
|
spec.require_paths = ["lib"]
|
15
15
|
|
16
|
-
spec.add_dependency 'aws-sdk
|
17
|
-
spec.add_dependency 'rack', '
|
16
|
+
spec.add_dependency 'aws-sdk', '~> 2.0'
|
17
|
+
spec.add_dependency 'rack', '>= 1.6.4'
|
18
18
|
end
|
@@ -12,9 +12,9 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
require 'yaml'
|
15
|
-
require 'aws-sdk
|
15
|
+
require 'aws-sdk'
|
16
16
|
|
17
|
-
module
|
17
|
+
module Aws::SessionStore::DynamoDB
|
18
18
|
# This class provides a Configuration object for all DynamoDB transactions
|
19
19
|
# by pulling configuration options from Runtime, a YAML file, the ENV and
|
20
20
|
# default settings.
|
@@ -66,8 +66,7 @@ module AWS::SessionStore::DynamoDB
|
|
66
66
|
:lock_expiry_time => 500,
|
67
67
|
:lock_retry_delay => 500,
|
68
68
|
:lock_max_wait_time => 1,
|
69
|
-
:secret_key => nil
|
70
|
-
:api_version => '2012-08-10'
|
69
|
+
:secret_key => nil
|
71
70
|
}
|
72
71
|
|
73
72
|
# @return [String] Session table name.
|
@@ -154,7 +153,7 @@ module AWS::SessionStore::DynamoDB
|
|
154
153
|
# See AWS DynamoDB documentation for table write_capacity for more
|
155
154
|
# information on this setting.
|
156
155
|
# @option options [DynamoDB Client] :dynamo_db_client
|
157
|
-
# (
|
156
|
+
# (Aws::DynamoDB::Client) DynamoDB client used to perform database
|
158
157
|
# operations inside of middleware application.
|
159
158
|
# @option options [Boolean] :raise_errors (false) If true, all errors are
|
160
159
|
# raised up the stack when default ErrorHandler. If false, Only specified
|
@@ -203,14 +202,15 @@ module AWS::SessionStore::DynamoDB
|
|
203
202
|
# @return [Hash] DDB client.
|
204
203
|
def gen_dynamo_db_client
|
205
204
|
client_opts = client_subset(@options)
|
206
|
-
|
205
|
+
client_opts[:user_agent_suffix] = _user_agent(@options.delete(:user_agent_suffix))
|
206
|
+
client = Aws::DynamoDB::Client
|
207
207
|
dynamo_db_client = @options[:dynamo_db_client] || client.new(client_opts)
|
208
208
|
{:dynamo_db_client => dynamo_db_client}
|
209
209
|
end
|
210
210
|
|
211
211
|
# @return [Hash] Default Error Handler
|
212
212
|
def gen_error_handler
|
213
|
-
default_handler =
|
213
|
+
default_handler = Aws::SessionStore::DynamoDB::Errors::DefaultHandler
|
214
214
|
error_handler = @options[:error_handler] ||
|
215
215
|
default_handler.new(@options[:raise_errors])
|
216
216
|
{:error_handler => error_handler}
|
@@ -294,5 +294,13 @@ module AWS::SessionStore::DynamoDB
|
|
294
294
|
opts
|
295
295
|
end
|
296
296
|
end
|
297
|
+
|
298
|
+
def _user_agent(custom)
|
299
|
+
if custom
|
300
|
+
custom
|
301
|
+
else
|
302
|
+
" aws-sessionstore/#{VERSION}"
|
303
|
+
end
|
304
|
+
end
|
297
305
|
end
|
298
306
|
end
|
@@ -12,9 +12,9 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB::Errors
|
16
16
|
# BaseErrorHandler provides an interface for error handlers
|
17
|
-
# that can be passed in to {
|
17
|
+
# that can be passed in to {Aws::SessionStore::DynamoDB::RackMiddleware}.
|
18
18
|
# Each error handler must implement a handle_error method.
|
19
19
|
#
|
20
20
|
# @example Sample ErrorHandler class
|
@@ -33,11 +33,11 @@ module AWS::SessionStore::DynamoDB::Errors
|
|
33
33
|
# error up the stack.
|
34
34
|
# You may reraise the error passed.
|
35
35
|
#
|
36
|
-
# @param [
|
37
|
-
#
|
36
|
+
# @param [Aws::DynamoDB::Errors::Base] error error passed in from
|
37
|
+
# Aws::SessionStore::DynamoDB::RackMiddleware.
|
38
38
|
# @param [Rack::Request::Environment,nil] env Rack environment
|
39
39
|
# @return [false] If exception was handled and will not reraise exception.
|
40
|
-
# @raise [
|
40
|
+
# @raise [Aws::DynamoDB::Errors] If error has be reraised.
|
41
41
|
def handle_error(error, env = {})
|
42
42
|
raise NotImplementedError
|
43
43
|
end
|
@@ -12,15 +12,15 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB::Errors
|
16
16
|
# This class handles errors raised from DynamoDB.
|
17
|
-
class DefaultHandler <
|
17
|
+
class DefaultHandler < Aws::SessionStore::DynamoDB::Errors::BaseHandler
|
18
18
|
# Array of errors that will always be passed up the Rack stack.
|
19
19
|
HARD_ERRORS = [
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
Aws::DynamoDB::Errors::ResourceNotFoundException,
|
21
|
+
Aws::DynamoDB::Errors::ConditionalCheckFailedException,
|
22
|
+
Aws::SessionStore::DynamoDB::MissingSecretKeyError,
|
23
|
+
Aws::SessionStore::DynamoDB::LockWaitTimeoutError
|
24
24
|
]
|
25
25
|
|
26
26
|
# Determines behavior of DefaultErrorHandler
|
@@ -11,9 +11,9 @@
|
|
11
11
|
# ANY KIND, either express or implied. See the License for the specific
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
|
-
require 'aws-sdk
|
14
|
+
require 'aws-sdk'
|
15
15
|
|
16
|
-
module
|
16
|
+
module Aws::SessionStore::DynamoDB
|
17
17
|
# Collects and deletes unwanted sessions based on
|
18
18
|
# their creation and update dates.
|
19
19
|
module GarbageCollection
|
@@ -34,7 +34,7 @@ module AWS::SessionStore::DynamoDB
|
|
34
34
|
# @option (see Configuration#initialize)
|
35
35
|
# @api private
|
36
36
|
def load_config(options = {})
|
37
|
-
|
37
|
+
Aws::SessionStore::DynamoDB::Configuration.new(options)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Sets scan filter attributes based on attributes specified.
|
@@ -59,7 +59,7 @@ module AWS::SessionStore::DynamoDB
|
|
59
59
|
# @api private
|
60
60
|
def scan(config, last_item = nil)
|
61
61
|
options = scan_opts(config)
|
62
|
-
options.merge(start_key(last_item)) if last_item
|
62
|
+
options = options.merge(start_key(last_item)) if last_item
|
63
63
|
config.dynamo_db_client.scan(options)
|
64
64
|
end
|
65
65
|
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB
|
16
16
|
class LockWaitTimeoutError < RuntimeError
|
17
17
|
def initialize(msg = 'Maximum time spent to acquire lock has been exceeded!')
|
18
18
|
super
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB::Locking
|
16
16
|
# This class provides a framework for implementing
|
17
17
|
# locking strategies.
|
18
18
|
class Base
|
@@ -56,7 +56,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
56
56
|
def handle_error(env = nil, &block)
|
57
57
|
begin
|
58
58
|
yield
|
59
|
-
rescue
|
59
|
+
rescue Aws::DynamoDB::Errors::ServiceError => e
|
60
60
|
@config.error_handler.handle_error(e, env)
|
61
61
|
end
|
62
62
|
end
|
@@ -101,7 +101,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
101
101
|
def table_opts(sid)
|
102
102
|
{
|
103
103
|
:table_name => @config.table_name,
|
104
|
-
:key => {@config.table_key =>
|
104
|
+
:key => { @config.table_key => sid }
|
105
105
|
}
|
106
106
|
end
|
107
107
|
|
@@ -116,7 +116,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
116
116
|
|
117
117
|
# Update client with current time attribute.
|
118
118
|
def updated_at
|
119
|
-
{ :value =>
|
119
|
+
{ :value => "#{(Time.now).to_f}", :action => "PUT" }
|
120
120
|
end
|
121
121
|
|
122
122
|
# Attribute for creation of session.
|
@@ -132,7 +132,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def data_attr(session)
|
135
|
-
{ "data" => {:value =>
|
135
|
+
{ "data" => {:value => session, :action => "PUT"} }
|
136
136
|
end
|
137
137
|
|
138
138
|
# Determine if data has been manipulated
|
@@ -143,7 +143,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
143
143
|
|
144
144
|
# Expected attributes
|
145
145
|
def expected_attributes(sid)
|
146
|
-
{ :expected => {@config.table_key => {:value =>
|
146
|
+
{ :expected => { @config.table_key => {:value => sid, :exists => true} } }
|
147
147
|
end
|
148
148
|
|
149
149
|
# Attributes to be retrieved via client
|
@@ -12,10 +12,10 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB::Locking
|
16
16
|
# This class gets and sets sessions
|
17
17
|
# without a locking strategy.
|
18
|
-
class Null <
|
18
|
+
class Null < Aws::SessionStore::DynamoDB::Locking::Base
|
19
19
|
# Retrieve session if it exists from the database by id.
|
20
20
|
# Unpack the data once retrieved from the database.
|
21
21
|
def get_session_data(env, sid)
|
@@ -32,8 +32,8 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
32
32
|
|
33
33
|
# @return [String] Session data.
|
34
34
|
def extract_data(env, result = nil)
|
35
|
-
env['rack.initial_data'] = result[:item]["data"]
|
36
|
-
unpack_data(result[:item]["data"]
|
35
|
+
env['rack.initial_data'] = result[:item]["data"] if result[:item]
|
36
|
+
unpack_data(result[:item]["data"]) if result[:item]
|
37
37
|
end
|
38
38
|
|
39
39
|
end
|
@@ -12,11 +12,11 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB::Locking
|
16
16
|
# This class implements a pessimistic locking strategy for the
|
17
17
|
# DynamoDB session handler. Sessions obtain an exclusive lock
|
18
18
|
# for reads that is only released when the session is saved.
|
19
|
-
class Pessimistic <
|
19
|
+
class Pessimistic < Aws::SessionStore::DynamoDB::Locking::Base
|
20
20
|
WAIT_ERROR =
|
21
21
|
|
22
22
|
# Saves the session.
|
@@ -43,7 +43,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
43
43
|
exceeded_wait_time?(max_attempt_date)
|
44
44
|
begin
|
45
45
|
result = attempt_set_lock(sid)
|
46
|
-
rescue
|
46
|
+
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
|
47
47
|
expires_at ||= get_expire_date(sid)
|
48
48
|
next if expires_at.nil?
|
49
49
|
result = bust_lock(sid, expires_at)
|
@@ -58,7 +58,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
58
58
|
# @raise [Error] When time for attempting to get lock has
|
59
59
|
# been exceeded.
|
60
60
|
def exceeded_wait_time?(max_attempt_date)
|
61
|
-
lock_error =
|
61
|
+
lock_error = Aws::SessionStore::DynamoDB::LockWaitTimeoutError
|
62
62
|
raise lock_error if Time.now.to_f > max_attempt_date
|
63
63
|
end
|
64
64
|
|
@@ -70,15 +70,15 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
70
70
|
# @return [Time] Time stamp for which the session was locked.
|
71
71
|
def lock_time(sid)
|
72
72
|
result = @config.dynamo_db_client.get_item(get_lock_time_opts(sid))
|
73
|
-
(result[:item]["locked_at"]
|
73
|
+
(result[:item]["locked_at"]).to_f if result[:item]["locked_at"]
|
74
74
|
end
|
75
75
|
|
76
76
|
# @return [String] Session data.
|
77
77
|
def get_data(env, result)
|
78
|
-
lock_time = result[:attributes]["locked_at"]
|
78
|
+
lock_time = result[:attributes]["locked_at"]
|
79
79
|
env["locked_at"] = (lock_time).to_f
|
80
|
-
env['rack.initial_data'] = result[:item]["data"]
|
81
|
-
unpack_data(result[:attributes]["data"]
|
80
|
+
env['rack.initial_data'] = result[:item]["data"] if result.members.include? :item
|
81
|
+
unpack_data(result[:attributes]["data"])
|
82
82
|
end
|
83
83
|
|
84
84
|
# Attempt to bust the lock if the expiration date has expired.
|
@@ -119,7 +119,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
119
119
|
|
120
120
|
# Time in which session was updated.
|
121
121
|
def updated_at
|
122
|
-
{ :value =>
|
122
|
+
{ :value => "#{(Time.now).to_f}", :action => "PUT" }
|
123
123
|
end
|
124
124
|
|
125
125
|
# Attributes for locking.
|
@@ -147,7 +147,7 @@ module AWS::SessionStore::DynamoDB::Locking
|
|
147
147
|
# Expectation of when lock was set.
|
148
148
|
def expect_lock_time(env)
|
149
149
|
{ :expected => {"locked_at" => {
|
150
|
-
:value =>
|
150
|
+
:value => "#{env["locked_at"]}", :exists => true}} }
|
151
151
|
end
|
152
152
|
|
153
153
|
# Attributes to be retrieved via client
|
@@ -13,9 +13,9 @@
|
|
13
13
|
|
14
14
|
require 'rack/session/abstract/id'
|
15
15
|
require 'openssl'
|
16
|
-
require 'aws-sdk
|
16
|
+
require 'aws-sdk'
|
17
17
|
|
18
|
-
module
|
18
|
+
module Aws::SessionStore::DynamoDB
|
19
19
|
# This class is an ID based Session Store Rack Middleware
|
20
20
|
# that uses a DynamoDB backend for session storage.
|
21
21
|
class RackMiddleware < Rack::Session::Abstract::ID
|
@@ -24,9 +24,9 @@ module AWS::SessionStore::DynamoDB
|
|
24
24
|
#
|
25
25
|
# @param app Rack application.
|
26
26
|
# @option (see Configuration#initialize)
|
27
|
-
# @raise [
|
27
|
+
# @raise [Aws::DynamoDB::Errors::ResourceNotFoundException] If valid table
|
28
28
|
# name is not provided.
|
29
|
-
# @raise [
|
29
|
+
# @raise [Aws::SessionStore::DynamoDB::MissingSecretKey] If secret key is
|
30
30
|
# not provided.
|
31
31
|
def initialize(app, options = {})
|
32
32
|
super
|
@@ -42,16 +42,16 @@ module AWS::SessionStore::DynamoDB
|
|
42
42
|
# @return [Locking::Pessimistic] If locking is enabled.
|
43
43
|
def set_locking_strategy
|
44
44
|
if @config.enable_locking
|
45
|
-
@lock =
|
45
|
+
@lock = Aws::SessionStore::DynamoDB::Locking::Pessimistic.new(@config)
|
46
46
|
else
|
47
|
-
@lock =
|
47
|
+
@lock = Aws::SessionStore::DynamoDB::Locking::Null.new(@config)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
# Determines if the correct session table name is being used for
|
52
52
|
# this application. Also tests existence of secret key.
|
53
53
|
#
|
54
|
-
# @raise [
|
54
|
+
# @raise [Aws::DynamoDB::Errors::ResourceNotFoundException] If wrong table
|
55
55
|
# name.
|
56
56
|
def validate_config
|
57
57
|
raise MissingSecretKeyError unless @config.secret_key
|
@@ -99,8 +99,8 @@ module AWS::SessionStore::DynamoDB
|
|
99
99
|
def handle_error(env = nil, &block)
|
100
100
|
begin
|
101
101
|
yield
|
102
|
-
rescue
|
103
|
-
|
102
|
+
rescue Aws::DynamoDB::Errors::Base,
|
103
|
+
Aws::SessionStore::DynamoDB::InvalidIDError => e
|
104
104
|
@config.error_handler.handle_error(e, env)
|
105
105
|
end
|
106
106
|
end
|
@@ -12,10 +12,10 @@
|
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
14
|
|
15
|
-
module
|
15
|
+
module Aws::SessionStore::DynamoDB
|
16
16
|
class Railtie < Rails::Railtie
|
17
17
|
initializer 'aws-sessionstore-dynamodb-rack-middleware' do
|
18
|
-
ActionDispatch::Session::DynamodbStore =
|
18
|
+
ActionDispatch::Session::DynamodbStore = Aws::SessionStore::DynamoDB::RackMiddleware
|
19
19
|
end
|
20
20
|
|
21
21
|
# Load all rake tasks
|
@@ -11,10 +11,10 @@
|
|
11
11
|
# ANY KIND, either express or implied. See the License for the specific
|
12
12
|
# language governing permissions and limitations under the License.
|
13
13
|
|
14
|
-
require 'aws-sdk
|
14
|
+
require 'aws-sdk'
|
15
15
|
require 'logger'
|
16
16
|
|
17
|
-
module
|
17
|
+
module Aws::SessionStore::DynamoDB
|
18
18
|
# This class provides a way to create and delete a session table.
|
19
19
|
module Table
|
20
20
|
module_function
|
@@ -30,7 +30,7 @@ module AWS::SessionStore::DynamoDB
|
|
30
30
|
logger << "Table #{config.table_name} created, waiting for activation...\n"
|
31
31
|
block_until_created(config)
|
32
32
|
logger << "Table #{config.table_name} is now ready to use.\n"
|
33
|
-
rescue
|
33
|
+
rescue Aws::DynamoDB::Errors::ResourceInUseException
|
34
34
|
logger << "Table #{config.table_name} already exists, skipping creation.\n"
|
35
35
|
end
|
36
36
|
|
@@ -50,7 +50,7 @@ module AWS::SessionStore::DynamoDB
|
|
50
50
|
# @option (see Configuration#initialize)
|
51
51
|
# @api private
|
52
52
|
def load_config(options = {})
|
53
|
-
|
53
|
+
Aws::SessionStore::DynamoDB::Configuration.new(options)
|
54
54
|
end
|
55
55
|
|
56
56
|
# @return [Hash] Attribute settings for creating a session table.
|
@@ -15,7 +15,7 @@ namespace "db" do
|
|
15
15
|
namespace "sessions" do
|
16
16
|
desc 'Clean up old sessions in Amazon DynamoDB session store'
|
17
17
|
task :cleanup => :environment do |t|
|
18
|
-
|
18
|
+
Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
class <%= name.camelize %> < ActiveRecord::Migration
|
2
2
|
def up
|
3
|
-
|
3
|
+
Aws::SessionStore::DynamoDB::Table.create_table
|
4
4
|
end
|
5
5
|
|
6
6
|
def down
|
7
|
-
|
7
|
+
Aws::SessionStore::DynamoDB::Table.delete_table
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
require "spec_helper"
|
15
15
|
|
16
|
-
describe
|
16
|
+
describe Aws::SessionStore::DynamoDB::Configuration do
|
17
17
|
|
18
18
|
let(:defaults) do
|
19
19
|
{
|
@@ -45,19 +45,19 @@ describe AWS::SessionStore::DynamoDB::Configuration do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def expected_options(opts)
|
48
|
-
cfg =
|
48
|
+
cfg = Aws::SessionStore::DynamoDB::Configuration.new(opts)
|
49
49
|
expected_opts = defaults.merge(expected_file_opts).merge(opts)
|
50
50
|
cfg.to_hash.should include(expected_opts)
|
51
51
|
end
|
52
52
|
|
53
53
|
context "Configuration Tests" do
|
54
54
|
it "configures option with out runtime,YAML or ENV options" do
|
55
|
-
cfg =
|
55
|
+
cfg = Aws::SessionStore::DynamoDB::Configuration.new
|
56
56
|
cfg.to_hash.should include(defaults)
|
57
57
|
end
|
58
58
|
|
59
59
|
it "configures accurate option hash with runtime options, no YAML or ENV" do
|
60
|
-
cfg =
|
60
|
+
cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
61
61
|
expected_opts = defaults.merge(runtime_options)
|
62
62
|
cfg.to_hash.should include(expected_opts)
|
63
63
|
end
|
@@ -79,7 +79,7 @@ describe AWS::SessionStore::DynamoDB::Configuration do
|
|
79
79
|
it "has rails defiend but no file specified, no error thrown" do
|
80
80
|
rails = double('Rails', {:env => 'test', :root => ''})
|
81
81
|
stub_const("Rails", rails)
|
82
|
-
cfg =
|
82
|
+
cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
83
83
|
expected_opts = defaults.merge(runtime_options)
|
84
84
|
cfg.to_hash.should include(expected_opts)
|
85
85
|
end
|
@@ -87,7 +87,7 @@ describe AWS::SessionStore::DynamoDB::Configuration do
|
|
87
87
|
it "has rails defiend but and default rails YAML file loads" do
|
88
88
|
rails = double('Rails', {:env => 'test', :root => File.dirname(__FILE__)})
|
89
89
|
stub_const("Rails", rails)
|
90
|
-
cfg =
|
90
|
+
cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_options)
|
91
91
|
expected_opts = defaults.merge(runtime_options)
|
92
92
|
cfg.to_hash.should include(expected_opts)
|
93
93
|
end
|
@@ -95,7 +95,7 @@ describe AWS::SessionStore::DynamoDB::Configuration do
|
|
95
95
|
it "throws an exception when wrong path for file" do
|
96
96
|
config_path = 'Wrong path!'
|
97
97
|
runtime_opts = {:config_file => config_path}.merge(runtime_options)
|
98
|
-
expect{cfg =
|
98
|
+
expect{cfg = Aws::SessionStore::DynamoDB::Configuration.new(runtime_opts)}.to raise_error(Errno::ENOENT)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
require 'spec_helper'
|
16
16
|
|
17
|
-
describe
|
17
|
+
describe Aws::SessionStore::DynamoDB do
|
18
18
|
include Rack::Test::Methods
|
19
19
|
|
20
20
|
instance_exec(&ConstantHelpers)
|
@@ -24,8 +24,8 @@ describe AWS::SessionStore::DynamoDB do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
let(:base_app) { MultiplierApplication.new }
|
27
|
-
let(:app) {
|
28
|
-
let(:client) { double('
|
27
|
+
let(:app) { Aws::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) }
|
28
|
+
let(:client) { double('Aws::DynamoDB::Client') }
|
29
29
|
|
30
30
|
context "Error handling for Rack Middleware with default error handler" do
|
31
31
|
it "raises error for missing secret key" do
|
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
require 'spec_helper'
|
15
15
|
|
16
|
-
describe
|
16
|
+
describe Aws::SessionStore::DynamoDB::GarbageCollection do
|
17
17
|
def member(min,max)
|
18
18
|
member = []
|
19
19
|
for i in min..max
|
@@ -36,7 +36,7 @@ describe AWS::SessionStore::DynamoDB::GarbageCollection do
|
|
36
36
|
|
37
37
|
def collect_garbage
|
38
38
|
options = { :dynamo_db_client => dynamo_db_client, :max_age => 100, :max_stale => 100 }
|
39
|
-
|
39
|
+
Aws::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
|
40
40
|
end
|
41
41
|
|
42
42
|
let(:scan_resp1){
|
@@ -97,7 +97,7 @@ describe AWS::SessionStore::DynamoDB::GarbageCollection do
|
|
97
97
|
}
|
98
98
|
}
|
99
99
|
|
100
|
-
let(:dynamo_db_client) {
|
100
|
+
let(:dynamo_db_client) {Aws::DynamoDB::Client.new}
|
101
101
|
|
102
102
|
context "Mock DynamoDB client with garbage collection" do
|
103
103
|
|
@@ -111,7 +111,10 @@ describe AWS::SessionStore::DynamoDB::GarbageCollection do
|
|
111
111
|
|
112
112
|
it "gets scan results then returns last evaluated key and resumes scanning" do
|
113
113
|
dynamo_db_client.should_receive(:scan).
|
114
|
-
exactly(
|
114
|
+
exactly(1).times.and_return(scan_resp2)
|
115
|
+
dynamo_db_client.should_receive(:scan).
|
116
|
+
exactly(1).times.with(hash_including(exclusive_start_key: scan_resp2[:last_evaluated_key])).
|
117
|
+
and_return(scan_resp3)
|
115
118
|
dynamo_db_client.should_receive(:batch_write_item).
|
116
119
|
exactly(3).times.and_return(write_resp1)
|
117
120
|
collect_garbage
|
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
require 'spec_helper'
|
16
16
|
|
17
|
-
describe
|
17
|
+
describe Aws::SessionStore::DynamoDB::RackMiddleware do
|
18
18
|
include Rack::Test::Methods
|
19
19
|
|
20
20
|
def thread(mul_val, time, check)
|
@@ -39,11 +39,11 @@ describe AWS::SessionStore::DynamoDB::RackMiddleware do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
let(:base_app) { MultiplierApplication.new }
|
42
|
-
let(:app) {
|
42
|
+
let(:app) { Aws::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) }
|
43
43
|
|
44
44
|
context "Mock Multiple Threaded Sessions", :integration => true do
|
45
45
|
before do
|
46
|
-
@options =
|
46
|
+
@options = Aws::SessionStore::DynamoDB::Configuration.new.to_hash
|
47
47
|
@options[:enable_locking] = true
|
48
48
|
@options[:secret_key] = 'watermelon_smiles'
|
49
49
|
|
@@ -71,7 +71,7 @@ describe AWS::SessionStore::DynamoDB::RackMiddleware do
|
|
71
71
|
get "/"
|
72
72
|
last_request.session[:multiplier].should eq(1)
|
73
73
|
|
74
|
-
t1 = thread_exception(
|
74
|
+
t1 = thread_exception(Aws::DynamoDB::Errors::ConditionalCheckFailedException)
|
75
75
|
t2 = thread(2, 0.25, true)
|
76
76
|
t1.join
|
77
77
|
t2.join
|
@@ -87,7 +87,7 @@ describe AWS::SessionStore::DynamoDB::RackMiddleware do
|
|
87
87
|
|
88
88
|
t1 = thread(2, 0, false)
|
89
89
|
sleep(0.25)
|
90
|
-
t2 = thread_exception(
|
90
|
+
t2 = thread_exception(Aws::SessionStore::DynamoDB::LockWaitTimeoutError)
|
91
91
|
t1.join
|
92
92
|
t2.join
|
93
93
|
end
|
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
require 'spec_helper'
|
15
15
|
|
16
|
-
module
|
16
|
+
module Aws
|
17
17
|
module SessionStore
|
18
18
|
module DynamoDB
|
19
19
|
describe RackMiddleware do
|
@@ -29,7 +29,7 @@ module AWS
|
|
29
29
|
def table_opts(sid)
|
30
30
|
{
|
31
31
|
:table_name => Configuration::DEFAULTS[:table_name],
|
32
|
-
:key => { Configuration::DEFAULTS[:table_key] =>
|
32
|
+
:key => { Configuration::DEFAULTS[:table_key] => sid }
|
33
33
|
}
|
34
34
|
end
|
35
35
|
|
@@ -43,7 +43,7 @@ module AWS
|
|
43
43
|
|
44
44
|
def extract_time(sid)
|
45
45
|
options = table_opts(sid).merge(attr_opts)
|
46
|
-
Time.at((client.get_item(options)[:item]["created_at"]
|
46
|
+
Time.at((client.get_item(options)[:item]["created_at"]).to_f)
|
47
47
|
end
|
48
48
|
|
49
49
|
let(:base_app) { MultiplierApplication.new }
|
@@ -60,7 +60,7 @@ module AWS
|
|
60
60
|
it "creates a new HTTP cookie when Cookie not supplied" do
|
61
61
|
get "/"
|
62
62
|
last_response.body.should eq('All good!')
|
63
|
-
last_response['Set-Cookie'].should
|
63
|
+
last_response['Set-Cookie'].should be_truthy
|
64
64
|
end
|
65
65
|
|
66
66
|
it "does not rewrite Cookie if cookie previously/accuarately set" do
|
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
require 'spec_helper'
|
15
15
|
|
16
|
-
module
|
16
|
+
module Aws
|
17
17
|
module SessionStore
|
18
18
|
module DynamoDB
|
19
19
|
describe RackMiddleware do
|
@@ -46,11 +46,11 @@ module AWS
|
|
46
46
|
end
|
47
47
|
|
48
48
|
let(:dynamo_db_client) do
|
49
|
-
client = double('
|
49
|
+
client = double('Aws::DynamoDB::Client')
|
50
50
|
client.stub(:delete_item) { 'Deleted' }
|
51
51
|
client.stub(:list_tables) { {:table_names => ['Sessions']} }
|
52
52
|
client.stub(:get_item) do
|
53
|
-
{ :item => { 'data' =>
|
53
|
+
{ :item => { 'data' => sample_packed_data } }
|
54
54
|
end
|
55
55
|
client.stub(:update_item) do
|
56
56
|
{ :attributes => { :created_at => 'now' } }
|
@@ -67,7 +67,7 @@ module AWS
|
|
67
67
|
it "creates a new HTTP cookie when Cookie not supplied" do
|
68
68
|
get "/"
|
69
69
|
last_response.body.should eq('All good!')
|
70
|
-
last_response['Set-Cookie'].should
|
70
|
+
last_response['Set-Cookie'].should be_truthy
|
71
71
|
end
|
72
72
|
|
73
73
|
it "loads/manipulates a session based on id from HTTP-Cookie" do
|
data/spec/spec_helper.rb
CHANGED
@@ -39,23 +39,29 @@ end
|
|
39
39
|
|
40
40
|
ConstantHelpers = lambda do
|
41
41
|
let(:token_error_msg) { 'The security token included in the request is invalid' }
|
42
|
-
let(:resource_error) {
|
43
|
-
|
42
|
+
let(:resource_error) {
|
43
|
+
Aws::DynamoDB::Errors::ResourceNotFoundException.new(double('Seahorse::Client::RequestContext'), resource_error_msg)
|
44
|
+
}
|
45
|
+
let(:resource_error_msg) { 'The Resource is not found.' }
|
46
|
+
let(:key_error) { Aws::DynamoDB::Errors::ValidationException.new(double('Seahorse::Client::RequestContext'), key_error_msg) }
|
44
47
|
let(:key_error_msg) { 'The provided key element does not match the schema' }
|
45
|
-
let(:client_error) {
|
48
|
+
let(:client_error) {
|
49
|
+
Aws::DynamoDB::Errors::UnrecognizedClientException.new(double('Seahorse::Client::RequestContext'), client_error_msg)
|
50
|
+
}
|
51
|
+
let(:client_error_msg) { 'Unrecognized Client.'}
|
46
52
|
let(:invalid_cookie) { {"HTTP_COOKIE" => "rack.session=ApplePieBlueberries"} }
|
47
53
|
let(:invalid_session_data) { {"rack.session"=>{"multiplier" => 1}} }
|
48
|
-
let(:rack_default_error_msg) { "Warning!
|
49
|
-
let(:missing_key_error) {
|
54
|
+
let(:rack_default_error_msg) { "Warning! Aws::SessionStore::DynamoDB failed to save session. Content dropped.\n" }
|
55
|
+
let(:missing_key_error) { Aws::SessionStore::DynamoDB::MissingSecretKeyError }
|
50
56
|
end
|
51
57
|
|
52
58
|
RSpec.configure do |c|
|
53
59
|
c.before(:each, :integration => true) do
|
54
60
|
opts = {:table_name => 'sessionstore-integration-test'}
|
55
61
|
|
56
|
-
defaults =
|
62
|
+
defaults = Aws::SessionStore::DynamoDB::Configuration::DEFAULTS
|
57
63
|
defaults = defaults.merge(opts)
|
58
|
-
stub_const("
|
59
|
-
|
64
|
+
stub_const("Aws::SessionStore::DynamoDB::Configuration::DEFAULTS", defaults)
|
65
|
+
Aws::SessionStore::DynamoDB::Table.create_table(opts)
|
60
66
|
end
|
61
67
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-sessionstore-dynamodb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruby Robinson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: aws-sdk
|
14
|
+
name: aws-sdk
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.6.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.6.4
|
41
41
|
description:
|
42
42
|
email:
|
43
43
|
executables: []
|
@@ -45,6 +45,7 @@ extensions: []
|
|
45
45
|
extra_rdoc_files: []
|
46
46
|
files:
|
47
47
|
- ".gitignore"
|
48
|
+
- ".travis.yml"
|
48
49
|
- ".yardopts"
|
49
50
|
- Gemfile
|
50
51
|
- LICENSE.txt
|
@@ -103,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
104
|
version: '0'
|
104
105
|
requirements: []
|
105
106
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
107
|
+
rubygems_version: 2.5.2
|
107
108
|
signing_key:
|
108
109
|
specification_version: 4
|
109
110
|
summary: The Amazon DynamoDB Session Store handles sessions for Ruby web applications
|
@@ -120,4 +121,3 @@ test_files:
|
|
120
121
|
- spec/aws/session_store/dynamo_db/rails_app_config.yml
|
121
122
|
- spec/aws/session_store/dynamo_db/table_spec.rb
|
122
123
|
- spec/spec_helper.rb
|
123
|
-
has_rdoc:
|