aws-sessionstore-dynamodb 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.yardopts +3 -0
- data/Gemfile +28 -0
- data/LICENSE.txt +12 -0
- data/README.md +171 -0
- data/Rakefile +15 -0
- data/aws-sessionstore-dynamodb.gemspec +18 -0
- data/lib/aws-sessionstore-dynamodb.rb +34 -0
- data/lib/aws/session_store/dynamo_db/configuration.rb +298 -0
- data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +45 -0
- data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +57 -0
- data/lib/aws/session_store/dynamo_db/garbage_collection.rb +128 -0
- data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +21 -0
- data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +21 -0
- data/lib/aws/session_store/dynamo_db/locking/base.rb +162 -0
- data/lib/aws/session_store/dynamo_db/locking/null.rb +40 -0
- data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +160 -0
- data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +21 -0
- data/lib/aws/session_store/dynamo_db/rack_middleware.rb +130 -0
- data/lib/aws/session_store/dynamo_db/railtie.rb +28 -0
- data/lib/aws/session_store/dynamo_db/table.rb +98 -0
- data/lib/aws/session_store/dynamo_db/tasks/session_table.rake +21 -0
- data/lib/aws/session_store/dynamo_db/version.rb +21 -0
- data/lib/rails/generators/sessionstore/dynamodb/dynamodb_generator.rb +55 -0
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/USAGE +13 -0
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/dynamodb.yml +71 -0
- data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb +10 -0
- data/spec/aws/session_store/dynamo_db/app_config.yml +19 -0
- data/spec/aws/session_store/dynamo_db/config/dynamo_db_session.yml +24 -0
- data/spec/aws/session_store/dynamo_db/configuration_spec.rb +101 -0
- data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +62 -0
- data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +156 -0
- data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +95 -0
- data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +129 -0
- data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +149 -0
- data/spec/aws/session_store/dynamo_db/rails_app_config.yml +24 -0
- data/spec/aws/session_store/dynamo_db/table_spec.rb +46 -0
- data/spec/spec_helper.rb +61 -0
- data/tasks/test.rake +29 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1395af7cb7211af4f4cb72dcd4037ee046627a64
|
4
|
+
data.tar.gz: 55d5c7eb166a8571b05c883fb05baa53d293152f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a9f754fabdd1af66c5853249a946b39b76eca01db99ee569ba9f63b11eec8ba2be7f93d94f6e8055af7013371dde889d6af3c3e093967aeaa24dd56c9b4b52f3
|
7
|
+
data.tar.gz: 3d276410f121bdf18acc8217a14c4cc6967a0cd84863e562aa4dd17e1ce38765d4ee42da3472cc3a9ca75d10cbf20ec6cdac15877e2d7d01d84eac39072dca63
|
data/.gitignore
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
source 'https://rubygems.org'
|
15
|
+
|
16
|
+
gemspec
|
17
|
+
|
18
|
+
gem 'rake', '~> 10.0'
|
19
|
+
|
20
|
+
group :documentation do
|
21
|
+
gem 'yard', '~> 0.0'
|
22
|
+
end
|
23
|
+
|
24
|
+
group :test do
|
25
|
+
gem 'rspec', '~> 2.0'
|
26
|
+
gem 'simplecov', '~> 0.0', :require => false
|
27
|
+
gem 'rack-test', '~> 0.0'
|
28
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
may not use this file except in compliance with the License. A copy of
|
5
|
+
the License is located at
|
6
|
+
|
7
|
+
http://aws.amazon.com/apache2.0/
|
8
|
+
|
9
|
+
or in the "license" file accompanying this file. This file is
|
10
|
+
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
ANY KIND, either express or implied. See the License for the specific
|
12
|
+
language governing permissions and limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# Amazon DynamoDB Session Store
|
2
|
+
|
3
|
+
The **Amazon DynamoDB Session Store** handles sessions for Ruby web applications
|
4
|
+
using a DynamoDB backend. The session store is compatible with Rails and other
|
5
|
+
Rack based frameworks.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
#### Rails Installation
|
10
|
+
|
11
|
+
Install the session store gem by placing the following command into your
|
12
|
+
Gemfile:
|
13
|
+
|
14
|
+
gem 'aws-sessionstore-dynamodb'
|
15
|
+
|
16
|
+
You will need to have an existing Amazon DynamoDB session table in order for the
|
17
|
+
application to work. You can generate a migration file for the session table
|
18
|
+
with the following command:
|
19
|
+
|
20
|
+
rails generate sessionstore:dynamodb
|
21
|
+
|
22
|
+
To create the table, run migrations as normal with:
|
23
|
+
|
24
|
+
rake db:migrate
|
25
|
+
|
26
|
+
Change the session store to `:dynamodb_store` by editing
|
27
|
+
`config/initializers/session_store.rb` to contain the following:
|
28
|
+
|
29
|
+
YourAppName::Application.config.session_store :dynamodb_store
|
30
|
+
|
31
|
+
You can now start your Rails application with session support.
|
32
|
+
|
33
|
+
#### Basic Rack Application Installation
|
34
|
+
|
35
|
+
For non-Rails applications, you can create the Amazon DynamoDB table in a
|
36
|
+
Ruby file using the following method:
|
37
|
+
|
38
|
+
require 'aws-sessionstore-dynamodb'
|
39
|
+
|
40
|
+
AWS::SessionStore::DynamoDB::Table.create_table
|
41
|
+
|
42
|
+
Run the session store as a Rack middleware in the following way:
|
43
|
+
|
44
|
+
require 'aws-sessionstore-dynamodb'
|
45
|
+
require 'some_rack_app'
|
46
|
+
|
47
|
+
options = { :secret_key => 'SECRET_KEY' }
|
48
|
+
|
49
|
+
use AWS::SessionStore::DynamoDB::RackMiddleware.new(options)
|
50
|
+
run SomeRackApp
|
51
|
+
|
52
|
+
Note that `:secret_key` is a mandatory configuration option that must be set.
|
53
|
+
|
54
|
+
## Detailed Usage
|
55
|
+
|
56
|
+
The session store is a Rack Middleware, meaning that it will implement the Rack
|
57
|
+
interface for dealing with HTTP request/responses.
|
58
|
+
|
59
|
+
This session store uses a DynamoDB backend in order to provide scaling and
|
60
|
+
centralized data benefits for session storage with more ease than other
|
61
|
+
containers, like local servers or cookies. Once an application scales beyond
|
62
|
+
a single web server, session data will need to be shared across the servers.
|
63
|
+
DynamoDB takes care of this burden for you by scaling with your application.
|
64
|
+
Cookie storage places all session data on the client side,
|
65
|
+
discouraging sensitive data storage. It also forces strict data size
|
66
|
+
limitations. DynamoDB takes care of these concerns by allowing for a safe and
|
67
|
+
scalable storage container with a much larger data size limit for session data.
|
68
|
+
|
69
|
+
Full API documentation of the library can be found on [RubyDoc.info][1].
|
70
|
+
|
71
|
+
### Configuration Options
|
72
|
+
|
73
|
+
A number of options are available to be set in
|
74
|
+
`AWS::SessionStore::DynamoDB::Configuration`, which is used by the
|
75
|
+
`RackMiddleware` class. These options can be set in the YAML configuration
|
76
|
+
file in a Rails application (located in `config/sessionstore/dynamodb.yml`),
|
77
|
+
directly by Ruby code, or through environment variables.
|
78
|
+
|
79
|
+
The full set of options along with defaults can be found in the
|
80
|
+
[Configuration class documentation][2].
|
81
|
+
|
82
|
+
#### Environment Options
|
83
|
+
|
84
|
+
Certain configuration options can be loaded from the environment. These
|
85
|
+
options must be specified in the following format:
|
86
|
+
|
87
|
+
DYNAMO_DB_SESSION_NAME-OF-CONFIGURATION-OPTION
|
88
|
+
|
89
|
+
The example below would be a valid way to set the session table name:
|
90
|
+
|
91
|
+
export DYNAMO_DB_SESSION_TABLE_NAME='sessions'
|
92
|
+
|
93
|
+
### Rails Generator Details
|
94
|
+
|
95
|
+
The generator command specified in the installation section will generate two
|
96
|
+
files: a migration file, `db/migration/VERSION_migration_name.rb`, and a
|
97
|
+
configuration YAML file, `config/sessionstore/dynamodb.yml`.
|
98
|
+
|
99
|
+
You can run the command with an argument that will define the name of the
|
100
|
+
migration file. Once the YAML file is created, you can uncomment any of the
|
101
|
+
lines to set configuration options to your liking. The session store will pull
|
102
|
+
options from `config/sessionstore/dynamodb.yml` by default if the file exists.
|
103
|
+
If you do not wish to place the configuration YAML file in that location,
|
104
|
+
you can also pass in a different file path to pull options from.
|
105
|
+
|
106
|
+
### Garbage Collection
|
107
|
+
|
108
|
+
You may want to delete old sessions from your session table. The
|
109
|
+
following examples show how to clear old sessions from your table.
|
110
|
+
|
111
|
+
#### Rails
|
112
|
+
|
113
|
+
A Rake task for garbage collection is provided for Rails applications.
|
114
|
+
By default sessions do not expire. See `config/sessionstore/dynamodb.yml` to
|
115
|
+
configure the max age or stale period of a session. Once you have configured
|
116
|
+
those values you can clear the old sessions with:
|
117
|
+
|
118
|
+
rake dynamo_db:collect_garbage
|
119
|
+
|
120
|
+
#### Outside of Rails
|
121
|
+
|
122
|
+
You can create your own Rake task for garbage collection similar to below:
|
123
|
+
|
124
|
+
require "aws-sessionstore-dynamodb"
|
125
|
+
|
126
|
+
desc 'Perform Garbage Collection'
|
127
|
+
task :garbage_collect do |t|
|
128
|
+
options = {:max_age => 3600*24, max_stale => 5*3600 }
|
129
|
+
AWS::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
|
130
|
+
end
|
131
|
+
|
132
|
+
The above example will clear sessions older than one day or that have been
|
133
|
+
stale for longer than an hour.
|
134
|
+
|
135
|
+
### Locking Strategy
|
136
|
+
|
137
|
+
You may want the Session Store to implement the provided pessimistic locking
|
138
|
+
strategy if you are concerned about concurrency issues with session accesses.
|
139
|
+
By default, locking is not implemented for the session store. You must trigger
|
140
|
+
the locking strategy through the configuration of the session store. Pessimistic
|
141
|
+
locking, in this case, means that only one read can be made on a session at
|
142
|
+
once. While the session is being read by the process with the lock, other
|
143
|
+
processes may try to obtain a lock on the same session but will be blocked.
|
144
|
+
|
145
|
+
Locking is expensive and will drive up costs depending on how it is used.
|
146
|
+
Without locking, one read and one write are performed per request for session
|
147
|
+
data manipulation. If a locking strategy is implemented, as many as the total
|
148
|
+
maximum wait time divided by the lock retry delay writes to the database.
|
149
|
+
Keep these considerations in mind if you plan to enable locking.
|
150
|
+
|
151
|
+
#### Configuration for Locking
|
152
|
+
|
153
|
+
The following configuration options will allow you to configure the pessimistic
|
154
|
+
locking strategy according to your needs:
|
155
|
+
|
156
|
+
options = {
|
157
|
+
:enable_locking => true,
|
158
|
+
:lock_expiry_time => 500,
|
159
|
+
:lock_retry_delay => 500,
|
160
|
+
:lock_max_wait_time => 1
|
161
|
+
}
|
162
|
+
|
163
|
+
### Error Handling
|
164
|
+
|
165
|
+
You can pass in your own error handler for raised exceptions or you can allow
|
166
|
+
the default error handler to them for you. See the API documentation
|
167
|
+
on the {AWS::SessionStore::DynamoDB::Errors::BaseHandler} class for more
|
168
|
+
details.
|
169
|
+
|
170
|
+
[1]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/frames
|
171
|
+
[2]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/AWS/SessionStore/DynamoDB/Configuration#initialize-instance_method
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
Dir.glob(File.dirname(__FILE__) + '/tasks/*.rake').each {|file| load file }
|
15
|
+
task :default => 'test:unit'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/lib/aws/session_store/dynamo_db/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "aws-sessionstore-dynamodb"
|
5
|
+
spec.version = AWS::SessionStore::DynamoDB::VERSION
|
6
|
+
spec.authors = ["Ruby Robinson"]
|
7
|
+
spec.summary = "The Amazon DynamoDB Session Store handles sessions " +
|
8
|
+
"for Ruby web applications using a DynamoDB backend."
|
9
|
+
spec.homepage = "http://github.com/aws/aws-sessionstore-dynamodb-ruby"
|
10
|
+
spec.license = "Apache License 2.0"
|
11
|
+
|
12
|
+
spec.files = `git ls-files`.split($/)
|
13
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
14
|
+
spec.require_paths = ["lib"]
|
15
|
+
|
16
|
+
spec.add_dependency 'aws-sdk', '~> 1.0'
|
17
|
+
spec.add_dependency 'rack', '~> 1.0'
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
|
15
|
+
module AWS
|
16
|
+
module SessionStore
|
17
|
+
module DynamoDB; end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'aws/session_store/dynamo_db/configuration'
|
22
|
+
require 'aws/session_store/dynamo_db/invalid_id_error'
|
23
|
+
require 'aws/session_store/dynamo_db/missing_secret_key_error'
|
24
|
+
require 'aws/session_store/dynamo_db/lock_wait_timeout_error'
|
25
|
+
require 'aws/session_store/dynamo_db/errors/base_handler'
|
26
|
+
require 'aws/session_store/dynamo_db/errors/default_handler'
|
27
|
+
require 'aws/session_store/dynamo_db/garbage_collection'
|
28
|
+
require 'aws/session_store/dynamo_db/locking/base'
|
29
|
+
require 'aws/session_store/dynamo_db/locking/null'
|
30
|
+
require 'aws/session_store/dynamo_db/locking/pessimistic'
|
31
|
+
require 'aws/session_store/dynamo_db/rack_middleware'
|
32
|
+
require 'aws/session_store/dynamo_db/table'
|
33
|
+
require 'aws/session_store/dynamo_db/version'
|
34
|
+
require 'aws/session_store/dynamo_db/railtie' if defined?(Rails)
|
@@ -0,0 +1,298 @@
|
|
1
|
+
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require 'yaml'
|
15
|
+
require 'aws-sdk'
|
16
|
+
|
17
|
+
module AWS::SessionStore::DynamoDB
|
18
|
+
# This class provides a Configuration object for all DynamoDB transactions
|
19
|
+
# by pulling configuration options from Runtime, a YAML file, the ENV and
|
20
|
+
# default settings.
|
21
|
+
#
|
22
|
+
# == Environment Variables
|
23
|
+
# The Configuration object can load default values from your environment. An example
|
24
|
+
# of setting and environment variable is below:
|
25
|
+
#
|
26
|
+
# export DYNAMO_DB_SESSION_TABLE_NAME='Sessions'
|
27
|
+
#
|
28
|
+
# == Handling Errors
|
29
|
+
# There are two configurable options for error handling: :raise_errors and :error_handler.
|
30
|
+
#
|
31
|
+
# If you would like to use the Default Error Handler, you can decide to set :raise_errors
|
32
|
+
# to true or false depending on whether you want all errors, regadless of class, to be raised
|
33
|
+
# up the stack and essentially throw a 500.
|
34
|
+
#
|
35
|
+
# If you decide to use your own Error Handler. You may pass it in for the value of the key
|
36
|
+
# :error_handler as a cofniguration object. You must implement the BaseErrorHandler class.
|
37
|
+
# @see BaseHandler Interface for Error Handling for DynamoDB Session Store.
|
38
|
+
#
|
39
|
+
# == Locking Strategy
|
40
|
+
# By default, locking is not implemented for the session store. You must trigger the
|
41
|
+
# locking strategy through the configuration of the session store. Pessimistic locking,
|
42
|
+
# in this case, means that only one read can be made on a session at once. While the session
|
43
|
+
# is being read by the process with the lock, other processes may try to obtain a lock on
|
44
|
+
# the same session but will be blocked. See the accessors with lock in their name for
|
45
|
+
# how to configure the pessimistic locking strategy to your needs.
|
46
|
+
#
|
47
|
+
# == DynamoDB Specific Options
|
48
|
+
# You may configure the table name and table hash key value of your session table with
|
49
|
+
# the :table_name and :table_key options. You may also configure performance options for
|
50
|
+
# your table with the :consistent_read, :read_capacity, write_capacity. For more information
|
51
|
+
# about these configurations see CreateTable method for Amazon DynamoDB.
|
52
|
+
#
|
53
|
+
class Configuration
|
54
|
+
|
55
|
+
# Default configuration options
|
56
|
+
DEFAULTS = {
|
57
|
+
:table_name => "sessions",
|
58
|
+
:table_key => "session_id",
|
59
|
+
:consistent_read => true,
|
60
|
+
:read_capacity => 10,
|
61
|
+
:write_capacity => 5,
|
62
|
+
:raise_errors => false,
|
63
|
+
# :max_age => 7*3600*24,
|
64
|
+
# :max_stale => 3600*5,
|
65
|
+
:enable_locking => false,
|
66
|
+
:lock_expiry_time => 500,
|
67
|
+
:lock_retry_delay => 500,
|
68
|
+
:lock_max_wait_time => 1,
|
69
|
+
:secret_key => nil,
|
70
|
+
:api_version => '2012-08-10'
|
71
|
+
}
|
72
|
+
|
73
|
+
# @return [String] Session table name.
|
74
|
+
attr_reader :table_name
|
75
|
+
|
76
|
+
# @return [String] Session table hash key name.
|
77
|
+
attr_reader :table_key
|
78
|
+
|
79
|
+
# @return [true] If a strongly consistent read is used
|
80
|
+
# @return [false] If an eventually consistent read is used.
|
81
|
+
# See AWS DynamoDB documentation for table consistent_read for more
|
82
|
+
# information on this setting.
|
83
|
+
attr_reader :consistent_read
|
84
|
+
|
85
|
+
# @return [Integer] Maximum number of reads consumed per second before
|
86
|
+
# DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
|
87
|
+
# for table read_capacity for more information on this setting.
|
88
|
+
attr_reader :read_capacity
|
89
|
+
|
90
|
+
# @return [Integer] Maximum number of writes consumed per second before
|
91
|
+
# DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
|
92
|
+
# for table write_capacity for more information on this setting.
|
93
|
+
attr_reader :write_capacity
|
94
|
+
|
95
|
+
# @return [true] All errors are raised up the stack when default ErrorHandler
|
96
|
+
# is used.
|
97
|
+
# @return [false] Only specified errors are raised up the stack when default
|
98
|
+
# ErrorHandler is used.
|
99
|
+
attr_reader :raise_errors
|
100
|
+
|
101
|
+
# @return [DynamoDB Client] DynamoDB client.
|
102
|
+
attr_reader :dynamo_db_client
|
103
|
+
|
104
|
+
# @return [Error Handler] An error handling object that handles all exceptions
|
105
|
+
# thrown during execution of the AWS DynamoDB Session Store Rack Middleware.
|
106
|
+
# For more information see the Handling Errors Section.
|
107
|
+
attr_reader :error_handler
|
108
|
+
|
109
|
+
# @return [Integer] Maximum number of seconds earlier
|
110
|
+
# from the current time that a session was created.
|
111
|
+
attr_reader :max_age
|
112
|
+
|
113
|
+
# @return [Integer] Maximum number of seconds
|
114
|
+
# before the current time that the session was last accessed.
|
115
|
+
attr_reader :max_stale
|
116
|
+
|
117
|
+
# @return [String] The secret key for HMAC encryption.
|
118
|
+
attr_reader :secret_key
|
119
|
+
|
120
|
+
# @return [true] Pessimistic locking strategy will be implemented for
|
121
|
+
# all session accesses.
|
122
|
+
# @return [false] No locking strategy will be implemented for
|
123
|
+
# all session accesses.
|
124
|
+
attr_reader :enable_locking
|
125
|
+
|
126
|
+
# @return [Integer] Time in milleseconds after which lock will expire.
|
127
|
+
attr_reader :lock_expiry_time
|
128
|
+
|
129
|
+
# @return [Integer] Time in milleseconds to wait before retrying to obtain
|
130
|
+
# lock once an attempt to obtain lock has been made and has failed.
|
131
|
+
attr_reader :lock_retry_delay
|
132
|
+
|
133
|
+
# @return [Integer] Maximum time in seconds to wait to acquire lock
|
134
|
+
# before giving up.
|
135
|
+
attr_reader :lock_max_wait_time
|
136
|
+
|
137
|
+
|
138
|
+
# Provides configuration object that allows access to options defined
|
139
|
+
# during Runtime, in a YAML file, in the ENV and by default.
|
140
|
+
#
|
141
|
+
# @option options [String] :table_name ("Sessions") Name of the session
|
142
|
+
# table.
|
143
|
+
# @option options [String] :table_key ("id") The hash key of the sesison
|
144
|
+
# table.
|
145
|
+
# @option options [Boolean] :consistent_read (true) If true, a strongly
|
146
|
+
# consistent read is used. If false, an eventually consistent read is
|
147
|
+
# used.
|
148
|
+
# @option options [Integer] :read_capacity (10) The maximum number of
|
149
|
+
# strongly consistent reads consumed per second before
|
150
|
+
# DynamoDB raises a ThrottlingException. See AWS DynamoDB documentation
|
151
|
+
# for table read_capacity for more information on this setting.
|
152
|
+
# @option options [Integer] :write_capacity (5) The maximum number of writes
|
153
|
+
# consumed per second before DynamoDB returns a ThrottlingException.
|
154
|
+
# See AWS DynamoDB documentation for table write_capacity for more
|
155
|
+
# information on this setting.
|
156
|
+
# @option options [DynamoDB Client] :dynamo_db_client
|
157
|
+
# (AWS::DynamoDB::ClientV2) DynamoDB client used to perform database
|
158
|
+
# operations inside of middleware application.
|
159
|
+
# @option options [Boolean] :raise_errors (false) If true, all errors are
|
160
|
+
# raised up the stack when default ErrorHandler. If false, Only specified
|
161
|
+
# errors are raised up the stack when default ErrorHandler is used.
|
162
|
+
# @option options [Error Handler] :error_handler (DefaultErrorHandler)
|
163
|
+
# An error handling object that handles all exceptions thrown during
|
164
|
+
# execution of the AWS DynamoDB Session Store Rack Middleware.
|
165
|
+
# For more information see the Handling Errors Section.
|
166
|
+
# @option options [Integer] :max_age (nil) Maximum number of seconds earlier
|
167
|
+
# from the current time that a session was created.
|
168
|
+
# @option options [Integer] :max_stale (nil) Maximum number of seconds
|
169
|
+
# before current time that session was last accessed.
|
170
|
+
# @option options [String] :secret_key (nil) Secret key for HMAC encription.
|
171
|
+
# @option options [Integer] :enable_locking (false) If true, a pessimistic
|
172
|
+
# locking strategy will be implemented for all session accesses.
|
173
|
+
# If false, no locking strategy will be implemented for all session
|
174
|
+
# accesses.
|
175
|
+
# @option options [Integer] :lock_expiry_time (500) Time in milliseconds
|
176
|
+
# after which lock expires on session.
|
177
|
+
# @option options [Integer] :lock_retry_delay (500) Time in milleseconds to
|
178
|
+
# wait before retrying to obtain lock once an attempt to obtain lock
|
179
|
+
# has been made and has failed.
|
180
|
+
# @option options [Integer] :lock_max_wait_time (500) Maximum time in seconds
|
181
|
+
# to wait to acquire lock before giving up.
|
182
|
+
# @option options [String] :secret_key (SecureRandom.hex(64))
|
183
|
+
# Secret key for HMAC encription.
|
184
|
+
def initialize(options = {})
|
185
|
+
@options = default_options.merge(
|
186
|
+
env_options.merge(
|
187
|
+
file_options(options).merge(
|
188
|
+
symbolize_keys(options)
|
189
|
+
)
|
190
|
+
)
|
191
|
+
)
|
192
|
+
@options = client_error.merge(@options)
|
193
|
+
set_attributes(@options)
|
194
|
+
end
|
195
|
+
|
196
|
+
# @return [Hash] The merged configuration hash.
|
197
|
+
def to_hash
|
198
|
+
@options.dup
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
# @return [Hash] DDB client.
|
204
|
+
def gen_dynamo_db_client
|
205
|
+
client_opts = client_subset(@options)
|
206
|
+
client = AWS::DynamoDB::Client
|
207
|
+
dynamo_db_client = @options[:dynamo_db_client] || client.new(client_opts)
|
208
|
+
{:dynamo_db_client => dynamo_db_client}
|
209
|
+
end
|
210
|
+
|
211
|
+
# @return [Hash] Default Error Handler
|
212
|
+
def gen_error_handler
|
213
|
+
default_handler = AWS::SessionStore::DynamoDB::Errors::DefaultHandler
|
214
|
+
error_handler = @options[:error_handler] ||
|
215
|
+
default_handler.new(@options[:raise_errors])
|
216
|
+
{:error_handler => error_handler}
|
217
|
+
end
|
218
|
+
|
219
|
+
# @return [Hash] Client and error objects in hash.
|
220
|
+
def client_error
|
221
|
+
gen_error_handler.merge(gen_dynamo_db_client)
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [Hash] Default Session table options.
|
225
|
+
def default_options
|
226
|
+
DEFAULTS
|
227
|
+
end
|
228
|
+
|
229
|
+
# @return [Hash] Environment options that are useful for Session Handler.
|
230
|
+
def env_options
|
231
|
+
default_options.keys.inject({}) do |opts, opt_name|
|
232
|
+
env_var = "DYNAMO_DB_SESSION_#{opt_name.to_s.upcase}"
|
233
|
+
opts[opt_name] = ENV[env_var] if ENV.key?(env_var)
|
234
|
+
opts
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# @return [Hash] File options.
|
239
|
+
def file_options(options = {})
|
240
|
+
file_path = config_file_path(options)
|
241
|
+
if file_path
|
242
|
+
load_from_file(file_path)
|
243
|
+
elsif rails_defined && File.exists?(rails_config_file_path)
|
244
|
+
load_from_file(rails_config_file_path)
|
245
|
+
else
|
246
|
+
{}
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# @return [Boolean] Necessary Rails variables defined.
|
251
|
+
def rails_defined
|
252
|
+
defined?(Rails) && defined?(Rails.root) && defined?(Rails.env)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Load options from YAML file depending on existence of Rails
|
256
|
+
# and possible development stage defined.
|
257
|
+
def load_from_file(file_path)
|
258
|
+
require "erb"
|
259
|
+
opts = YAML.load(ERB.new(File.read(file_path)).result) || {}
|
260
|
+
opts = opts[Rails.env] if rails_defined && opts.key?(Rails.env)
|
261
|
+
symbolize_keys(opts)
|
262
|
+
end
|
263
|
+
|
264
|
+
# @return [String] Configuration path found in environment or YAML file.
|
265
|
+
def config_file_path(options)
|
266
|
+
options[:config_file] || ENV["DYNAMO_DB_SESSION_CONFIG_FILE"]
|
267
|
+
end
|
268
|
+
|
269
|
+
# @return [String] Rails configuraton path to YAML file default.
|
270
|
+
def rails_config_file_path
|
271
|
+
File.join(Rails.root, "config", "sessionstore/dynamodb.yml")
|
272
|
+
end
|
273
|
+
|
274
|
+
# Set accessible attributes after merged options.
|
275
|
+
def set_attributes(options)
|
276
|
+
@options.keys.each do |opt_name|
|
277
|
+
instance_variable_set("@#{opt_name}", options[opt_name])
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# @return [Hash] Hash with all symbolized keys.
|
282
|
+
def symbolize_keys(options)
|
283
|
+
options.inject({}) do |opts, (opt_name, opt_value)|
|
284
|
+
opts[opt_name.to_sym] = opt_value
|
285
|
+
opts
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# @return [Hash] Client subset options hash.
|
290
|
+
def client_subset(options = {})
|
291
|
+
client_keys = [:aws_secret_key, :aws_region, :aws_access_key, :api_version]
|
292
|
+
options.inject({}) do |opts, (opt_name, opt_value)|
|
293
|
+
opts[opt_name.to_sym] = opt_value if client_keys.include?(opt_name.to_sym)
|
294
|
+
opts
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|