aws-sessionstore-dynamodb 2.2.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/LICENSE +172 -9
  4. data/VERSION +1 -1
  5. data/lib/aws/session_store/dynamo_db/configuration.rb +134 -208
  6. data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +5 -3
  7. data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +13 -12
  8. data/lib/aws/session_store/dynamo_db/errors.rb +27 -0
  9. data/lib/aws/session_store/dynamo_db/garbage_collection.rb +85 -93
  10. data/lib/aws/session_store/dynamo_db/locking/base.rb +31 -32
  11. data/lib/aws/session_store/dynamo_db/locking/null.rb +4 -3
  12. data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +32 -20
  13. data/lib/aws/session_store/dynamo_db/locking.rb +10 -0
  14. data/lib/aws/session_store/dynamo_db/rack_middleware.rb +45 -49
  15. data/lib/aws/session_store/dynamo_db/table.rb +64 -67
  16. data/lib/aws-sessionstore-dynamodb.rb +12 -14
  17. metadata +25 -70
  18. data/.github/PULL_REQUEST_TEMPLATE.md +0 -6
  19. data/.github/workflows/ci.yml +0 -39
  20. data/.gitignore +0 -12
  21. data/.gitmodules +0 -3
  22. data/.yardopts +0 -4
  23. data/CODE_OF_CONDUCT.md +0 -4
  24. data/CONTRIBUTING.md +0 -61
  25. data/Gemfile +0 -24
  26. data/README.md +0 -125
  27. data/Rakefile +0 -35
  28. data/aws-sessionstore-dynamodb.gemspec +0 -24
  29. data/doc-src/templates/default/layout/html/footer.erb +0 -6
  30. data/doc-src/templates/default/layout/html/layout.erb +0 -31
  31. data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +0 -7
  32. data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +0 -7
  33. data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +0 -7
  34. data/lib/aws/session_store/dynamo_db/version.rb +0 -7
  35. data/spec/aws/session_store/dynamo_db/app_config.yml +0 -16
  36. data/spec/aws/session_store/dynamo_db/configuration_spec.rb +0 -81
  37. data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +0 -64
  38. data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +0 -158
  39. data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +0 -96
  40. data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +0 -130
  41. data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +0 -148
  42. data/spec/aws/session_store/dynamo_db/table_spec.rb +0 -48
  43. data/spec/spec_helper.rb +0 -65
@@ -1,96 +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
- describe Aws::SessionStore::DynamoDB::RackMiddleware do
19
- include Rack::Test::Methods
20
-
21
- def thread(mul_val, time, check)
22
- Thread.new do
23
- sleep(time)
24
- get '/'
25
- expect(last_request.session[:multiplier]).to eq(mul_val) if check
26
- end
27
- end
28
-
29
- def thread_exception(error)
30
- Thread.new { expect { get '/' }.to raise_error(error) }
31
- end
32
-
33
- def update_item_mock(options, update_method)
34
- if options[:return_values] == 'UPDATED_NEW' && options.key?(:expected)
35
- sleep(0.50)
36
- update_method.call(options)
37
- else
38
- update_method.call(options)
39
- end
40
- end
41
-
42
- let(:base_app) { MultiplierApplication.new }
43
- let(:app) { Aws::SessionStore::DynamoDB::RackMiddleware.new(base_app, @options) }
44
-
45
- context 'Mock Multiple Threaded Sessions', integration: true do
46
- before do
47
- @options = Aws::SessionStore::DynamoDB::Configuration.new.to_hash
48
- @options[:enable_locking] = true
49
- @options[:secret_key] = 'watermelon_smiles'
50
-
51
- update_method = @options[:dynamo_db_client].method(:update_item)
52
- expect(@options[:dynamo_db_client]).to receive(:update_item).at_least(:once) do |options|
53
- update_item_mock(options, update_method)
54
- end
55
- end
56
-
57
- it 'should wait for lock' do
58
- @options[:lock_expiry_time] = 2000
59
-
60
- get '/'
61
- expect(last_request.session[:multiplier]).to eq(1)
62
-
63
- t1 = thread(2, 0, false)
64
- t2 = thread(4, 0.25, true)
65
- t1.join
66
- t2.join
67
- end
68
-
69
- it 'should bust lock' do
70
- @options[:lock_expiry_time] = 100
71
-
72
- get '/'
73
- expect(last_request.session[:multiplier]).to eq(1)
74
-
75
- t1 = thread_exception(Aws::DynamoDB::Errors::ConditionalCheckFailedException)
76
- t2 = thread(2, 0.25, true)
77
- t1.join
78
- t2.join
79
- end
80
-
81
- it 'should throw exceeded time spent aquiring lock error' do
82
- @options[:lock_expiry_time] = 1000
83
- @options[:lock_retry_delay] = 100
84
- @options[:lock_max_wait_time] = 0.25
85
-
86
- get '/'
87
- expect(last_request.session[:multiplier]).to eq(1)
88
-
89
- t1 = thread(2, 0, false)
90
- sleep(0.25)
91
- t2 = thread_exception(Aws::SessionStore::DynamoDB::LockWaitTimeoutError)
92
- t1.join
93
- t2.join
94
- end
95
- end
96
- end
@@ -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