aws-sessionstore-dynamodb 2.2.0 → 3.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/CHANGELOG.md +15 -0
- data/LICENSE.txt +202 -0
- data/VERSION +1 -1
- data/lib/aws/session_store/dynamo_db/configuration.rb +119 -204
- data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +2 -0
- data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +13 -12
- data/lib/aws/session_store/dynamo_db/errors.rb +27 -0
- data/lib/aws/session_store/dynamo_db/garbage_collection.rb +84 -93
- data/lib/aws/session_store/dynamo_db/locking/base.rb +31 -32
- data/lib/aws/session_store/dynamo_db/locking/null.rb +4 -3
- data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +32 -20
- data/lib/aws/session_store/dynamo_db/rack_middleware.rb +45 -49
- data/lib/aws/session_store/dynamo_db/table.rb +64 -67
- data/lib/aws-sessionstore-dynamodb.rb +14 -14
- metadata +18 -64
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -6
- data/.github/workflows/ci.yml +0 -39
- data/.gitignore +0 -12
- data/.gitmodules +0 -3
- data/.yardopts +0 -4
- data/CODE_OF_CONDUCT.md +0 -4
- data/CONTRIBUTING.md +0 -61
- data/Gemfile +0 -24
- data/LICENSE +0 -12
- data/README.md +0 -125
- data/Rakefile +0 -35
- data/aws-sessionstore-dynamodb.gemspec +0 -24
- data/doc-src/templates/default/layout/html/footer.erb +0 -6
- data/doc-src/templates/default/layout/html/layout.erb +0 -31
- data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/version.rb +0 -7
- data/spec/aws/session_store/dynamo_db/app_config.yml +0 -16
- data/spec/aws/session_store/dynamo_db/configuration_spec.rb +0 -81
- data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +0 -64
- data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +0 -158
- data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +0 -96
- data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +0 -130
- data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +0 -148
- data/spec/aws/session_store/dynamo_db/table_spec.rb +0 -48
- data/spec/spec_helper.rb +0 -65
@@ -1,130 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'spec_helper'
|
17
|
-
|
18
|
-
module Aws
|
19
|
-
module SessionStore
|
20
|
-
module DynamoDB
|
21
|
-
describe RackMiddleware do
|
22
|
-
include Rack::Test::Methods
|
23
|
-
|
24
|
-
instance_exec(&ConstantHelpers)
|
25
|
-
|
26
|
-
before do
|
27
|
-
@options = { secret_key: 'watermelon_cherries' }
|
28
|
-
end
|
29
|
-
|
30
|
-
# Table options for client
|
31
|
-
def table_opts(sid)
|
32
|
-
{
|
33
|
-
table_name: Configuration::DEFAULTS[:table_name],
|
34
|
-
key: { Configuration::DEFAULTS[:table_key] => sid }
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
# Attributes to be retrieved via client
|
39
|
-
def attr_opts
|
40
|
-
{
|
41
|
-
attributes_to_get: %w[data created_at locked_at],
|
42
|
-
consistent_read: true
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
def extract_time(sid)
|
47
|
-
options = table_opts(sid).merge(attr_opts)
|
48
|
-
Time.at((client.get_item(options)[:item]['created_at']).to_f)
|
49
|
-
end
|
50
|
-
|
51
|
-
let(:base_app) { MultiplierApplication.new }
|
52
|
-
let(:app) { RackMiddleware.new(base_app, @options) }
|
53
|
-
let(:config) { Configuration.new }
|
54
|
-
let(:client) { config.dynamo_db_client }
|
55
|
-
|
56
|
-
context 'Testing best case session storage', integration: true do
|
57
|
-
it 'stores session data in session object' do
|
58
|
-
get '/'
|
59
|
-
expect(last_request.session[:multiplier]).to eq(1)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'creates a new HTTP cookie when Cookie not supplied' do
|
63
|
-
get '/'
|
64
|
-
expect(last_response.body).to eq('All good!')
|
65
|
-
expect(last_response['Set-Cookie']).to be_truthy
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'does not rewrite Cookie if cookie previously/accuarately set' do
|
69
|
-
get '/'
|
70
|
-
expect(last_response['Set-Cookie']).not_to be_nil
|
71
|
-
|
72
|
-
get '/'
|
73
|
-
expect(last_response['Set-Cookie']).to be_nil
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'does not set cookie when defer option is specified' do
|
77
|
-
@options[:defer] = true
|
78
|
-
get '/'
|
79
|
-
expect(last_response['Set-Cookie']).to be_nil
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'creates new session with false/nonexistant http-cookie id' do
|
83
|
-
get '/', {}, invalid_cookie.merge(invalid_session_data)
|
84
|
-
expect(last_response['Set-Cookie']).not_to eq('rack.session=ApplePieBlueberries')
|
85
|
-
expect(last_response['Set-Cookie']).not_to be_nil
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'expires after specified time and sets date for cookie to expire' do
|
89
|
-
@options[:expire_after] = 1
|
90
|
-
get '/'
|
91
|
-
session_cookie = last_response['Set-Cookie']
|
92
|
-
sleep(1.2)
|
93
|
-
|
94
|
-
get '/'
|
95
|
-
expect(last_response['Set-Cookie']).not_to be_nil
|
96
|
-
expect(last_response['Set-Cookie']).not_to eq(session_cookie)
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'will not set a session cookie when defer is true' do
|
100
|
-
@options[:defer] = true
|
101
|
-
get '/'
|
102
|
-
expect(last_response['Set-Cookie']).to be_nil
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'adds the created at attribute for a new session' do
|
106
|
-
get '/'
|
107
|
-
expect(last_request.env['dynamo_db.new_session']).to eq('true')
|
108
|
-
sid = last_response['Set-Cookie'].split(/[;\=]/)[1]
|
109
|
-
time = extract_time(sid)
|
110
|
-
expect(time).to be_within(2).of(Time.now)
|
111
|
-
|
112
|
-
get '/'
|
113
|
-
expect(last_request.env['dynamo_db.new_session']).to be_nil
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'releases pessimistic lock at finish of transaction' do
|
117
|
-
@options[:enable_locking] = true
|
118
|
-
get '/'
|
119
|
-
expect(last_request.env['dynamo_db.new_session']).to eq('true')
|
120
|
-
sid = last_response['Set-Cookie'].split(/[;\=]/)[1]
|
121
|
-
|
122
|
-
get '/'
|
123
|
-
options = table_opts(sid).merge(attr_opts)
|
124
|
-
expect(client.get_item(options)[:item]['locked_at']).to be_nil
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
@@ -1,148 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'spec_helper'
|
17
|
-
|
18
|
-
module Aws
|
19
|
-
module SessionStore
|
20
|
-
module DynamoDB
|
21
|
-
describe RackMiddleware do
|
22
|
-
include Rack::Test::Methods
|
23
|
-
|
24
|
-
before { @options = {} }
|
25
|
-
|
26
|
-
def ensure_data_updated(mutated_data)
|
27
|
-
expect(dynamo_db_client).to receive(:update_item) do |options|
|
28
|
-
if mutated_data
|
29
|
-
expect(options[:attribute_updates]['data']).not_to be_nil
|
30
|
-
else
|
31
|
-
expect(options[:attribute_updates]['data']).to be_nil
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
before do
|
37
|
-
@options = {
|
38
|
-
dynamo_db_client: dynamo_db_client,
|
39
|
-
secret_key: 'watermelon_cherries'
|
40
|
-
}
|
41
|
-
end
|
42
|
-
|
43
|
-
let(:base_app) { MultiplierApplication.new }
|
44
|
-
let(:app) { RackMiddleware.new(base_app, @options) }
|
45
|
-
|
46
|
-
let(:sample_packed_data) do
|
47
|
-
[Marshal.dump('multiplier' => 1)].pack('m*')
|
48
|
-
end
|
49
|
-
|
50
|
-
let(:dynamo_db_client) do
|
51
|
-
double(
|
52
|
-
'Aws::DynamoDB::Client',
|
53
|
-
delete_item: 'Deleted',
|
54
|
-
list_tables: { table_names: ['Sessions'] },
|
55
|
-
get_item: { item: { 'data' => sample_packed_data } },
|
56
|
-
update_item: { attributes: { created_at: 'now' } },
|
57
|
-
config: double(user_agent_frameworks: [])
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
context 'Testing best case session storage with mock client' do
|
62
|
-
it 'stores session data in session object' do
|
63
|
-
get '/'
|
64
|
-
expect(last_request.session.to_hash).to eq('multiplier' => 1)
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'creates a new HTTP cookie when Cookie not supplied' do
|
68
|
-
get '/'
|
69
|
-
expect(last_response.body).to eq('All good!')
|
70
|
-
expect(last_response['Set-Cookie']).to be_truthy
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'loads/manipulates a session based on id from HTTP-Cookie' do
|
74
|
-
get '/'
|
75
|
-
expect(last_request.session.to_hash).to eq('multiplier' => 1)
|
76
|
-
|
77
|
-
get '/'
|
78
|
-
expect(last_request.session.to_hash).to eq('multiplier' => 2)
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'does not rewrite Cookie if cookie previously/accuarately set' do
|
82
|
-
get '/'
|
83
|
-
expect(last_response['Set-Cookie']).not_to be_nil
|
84
|
-
|
85
|
-
get '/'
|
86
|
-
expect(last_response['Set-Cookie']).to be_nil
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'does not set cookie when defer option is specifed' do
|
90
|
-
@options[:defer] = true
|
91
|
-
get '/'
|
92
|
-
expect(last_response['Set-Cookie']).to be_nil
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'creates new session with false/nonexistant http-cookie id' do
|
96
|
-
get '/'
|
97
|
-
expect(last_response['Set-Cookie']).not_to eq('1234')
|
98
|
-
expect(last_response['Set-Cookie']).not_to be_nil
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'expires after specified time and sets date for cookie to expire' do
|
102
|
-
@options[:expire_after] = 0
|
103
|
-
get '/'
|
104
|
-
session_cookie = last_response['Set-Cookie']
|
105
|
-
|
106
|
-
get '/'
|
107
|
-
expect(last_response['Set-Cookie']).not_to be_nil
|
108
|
-
expect(last_response['Set-Cookie']).not_to eq(session_cookie)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "doesn't reset Cookie if not outside expire date" do
|
112
|
-
@options[:expire_after] = 3600
|
113
|
-
get '/'
|
114
|
-
session_cookie = last_response['Set-Cookie']
|
115
|
-
get '/'
|
116
|
-
expect(last_response['Set-Cookie']).to eq(session_cookie)
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'will not set a session cookie when defer is true' do
|
120
|
-
@options[:defer] = true
|
121
|
-
get '/'
|
122
|
-
expect(last_response['Set-Cookie']).to be_nil
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'generates sid and migrates data to new sid when renew is selected' do
|
126
|
-
@options[:renew] = true
|
127
|
-
get '/'
|
128
|
-
expect(last_request.session.to_hash).to eq('multiplier' => 1)
|
129
|
-
session_cookie = last_response['Set-Cookie']
|
130
|
-
|
131
|
-
get '/', 'HTTP_Cookie' => session_cookie
|
132
|
-
expect(last_response['Set-Cookie']).not_to eq(session_cookie)
|
133
|
-
expect(last_request.session.to_hash).to eq('multiplier' => 2)
|
134
|
-
end
|
135
|
-
|
136
|
-
it "doesn't resend unmutated data" do
|
137
|
-
ensure_data_updated(true)
|
138
|
-
@options[:renew] = true
|
139
|
-
get '/'
|
140
|
-
|
141
|
-
ensure_data_updated(false)
|
142
|
-
get '/', {}, { 'rack.session' => { 'multiplier' => nil } }
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'spec_helper'
|
17
|
-
require 'stringio'
|
18
|
-
require 'logger'
|
19
|
-
|
20
|
-
module Aws
|
21
|
-
module SessionStore
|
22
|
-
module DynamoDB
|
23
|
-
describe Table do
|
24
|
-
context 'Mock Table Methods Tests', integration: true do
|
25
|
-
let(:table_name) { "sessionstore-integration-test-#{Time.now.to_i}" }
|
26
|
-
let(:options) { { table_name: table_name } }
|
27
|
-
let(:io) { StringIO.new }
|
28
|
-
|
29
|
-
before { allow(Table).to receive(:logger) { Logger.new(io) } }
|
30
|
-
|
31
|
-
it 'Creates and deletes a new table' do
|
32
|
-
Table.create_table(options)
|
33
|
-
|
34
|
-
# second attempt should warn
|
35
|
-
Table.create_table(options)
|
36
|
-
|
37
|
-
expect(io.string).to include("Table #{table_name} created, waiting for activation...\n")
|
38
|
-
expect(io.string).to include("Table #{table_name} is now ready to use.\n")
|
39
|
-
expect(io.string).to include("Table #{table_name} already exists, skipping creation.\n")
|
40
|
-
|
41
|
-
# now delete table
|
42
|
-
Table.delete_table(options)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
6
|
-
# may not use this file except in compliance with the License. A copy of
|
7
|
-
# the License is located at
|
8
|
-
#
|
9
|
-
# http://aws.amazon.com/apache2.0/
|
10
|
-
#
|
11
|
-
# or in the "license" file accompanying this file. This file is
|
12
|
-
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
13
|
-
# ANY KIND, either express or implied. See the License for the specific
|
14
|
-
# language governing permissions and limitations under the License.
|
15
|
-
|
16
|
-
require 'simplecov'
|
17
|
-
SimpleCov.start { add_filter 'spec' }
|
18
|
-
|
19
|
-
$LOAD_PATH << File.join(File.dirname(File.dirname(__FILE__)), 'lib')
|
20
|
-
|
21
|
-
require 'rspec'
|
22
|
-
require 'aws-sessionstore-dynamodb'
|
23
|
-
require 'rack/test'
|
24
|
-
|
25
|
-
# Default Rack application
|
26
|
-
class MultiplierApplication
|
27
|
-
def call(env)
|
28
|
-
if env['rack.session'][:multiplier]
|
29
|
-
env['rack.session'][:multiplier] *= 2
|
30
|
-
else
|
31
|
-
env['rack.session'][:multiplier] = 1
|
32
|
-
end
|
33
|
-
[200, { 'Content-Type' => 'text/plain' }, ['All good!']]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
ConstantHelpers = lambda do
|
38
|
-
let(:token_error_msg) { 'The security token included in the request is invalid' }
|
39
|
-
let(:resource_error) do
|
40
|
-
Aws::DynamoDB::Errors::ResourceNotFoundException.new(double('Seahorse::Client::RequestContext'), resource_error_msg)
|
41
|
-
end
|
42
|
-
let(:resource_error_msg) { 'The Resource is not found.' }
|
43
|
-
let(:key_error) { Aws::DynamoDB::Errors::ValidationException.new(double('Seahorse::Client::RequestContext'), key_error_msg) }
|
44
|
-
let(:key_error_msg) { 'The provided key element does not match the schema' }
|
45
|
-
let(:client_error) do
|
46
|
-
Aws::DynamoDB::Errors::UnrecognizedClientException.new(double('Seahorse::Client::RequestContext'), client_error_msg)
|
47
|
-
end
|
48
|
-
let(:client_error_msg) { 'Unrecognized Client.'}
|
49
|
-
let(:invalid_cookie) { { 'HTTP_COOKIE' => 'rack.session=ApplePieBlueberries' } }
|
50
|
-
let(:invalid_session_data) { { 'rack.session' => { 'multiplier' => 1 } } }
|
51
|
-
let(:rack_default_error_msg) { "Warning! Aws::SessionStore::DynamoDB failed to save session. Content dropped.\n" }
|
52
|
-
let(:missing_key_error) { Aws::SessionStore::DynamoDB::MissingSecretKeyError }
|
53
|
-
end
|
54
|
-
|
55
|
-
RSpec.configure do |c|
|
56
|
-
c.raise_errors_for_deprecations!
|
57
|
-
c.before(:each, integration: true) do
|
58
|
-
opts = { table_name: 'sessionstore-integration-test' }
|
59
|
-
|
60
|
-
defaults = Aws::SessionStore::DynamoDB::Configuration::DEFAULTS
|
61
|
-
defaults = defaults.merge(opts)
|
62
|
-
stub_const('Aws::SessionStore::DynamoDB::Configuration::DEFAULTS', defaults)
|
63
|
-
Aws::SessionStore::DynamoDB::Table.create_table(opts)
|
64
|
-
end
|
65
|
-
end
|