frikandel 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c72cb658721f8dedcdc8981612407748dcd1c3bb
4
- data.tar.gz: ce5f11294df1af510cf1c8d95b948217e81b98a7
3
+ metadata.gz: 0eb78e7fc8890e920f675060d65d1305ab310caa
4
+ data.tar.gz: dfe7532de11f1b0e4deacd6b5d9476256a6cfb22
5
5
  SHA512:
6
- metadata.gz: 69bd74f1fdce25360acd89e299cbe245c85a2689d42852023a2bbd5da6bdad711feffe21364b0a53e0498263aa347ef34be7e106cd22152382b4762e57f7383a
7
- data.tar.gz: 89c73e22308498ead5d605ad9dd6382b8ef0b463030f7a2a00a600c4debc1908f11d6f12830237b5507bc42b6d7560b2d22d0051a50c6a6055e1546c813ae419
6
+ metadata.gz: c9f94142388dd71adff1c529b0b43c6216f4f4819afca102cedbc523693ddd253b54dad9642c44229ea25ba730b44c08b1769a560eefdd6ae08aa5cd81c8f54c
7
+ data.tar.gz: 5723a7adfe0d66d77e4a9a37749f337536a21a8c5bb24109c51b4bb1089ff6e58766b8c51d8f9f07586a8caf88a5c37106c6ba6210ebfc40c6cd7dda34b8d98e
data/.gitignore CHANGED
@@ -4,7 +4,7 @@
4
4
  .config
5
5
  .ruby-*
6
6
  .yardoc
7
- Gemfile.lock
7
+ Gemfile*.lock
8
8
  InstalledFiles
9
9
  _yardoc
10
10
  coverage
@@ -1,7 +1,16 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.0
3
+ - "1.9.3"
4
+ - "2.0.0"
5
+ - "2.1.1"
6
+ - ruby-head
6
7
  - jruby-19mode
7
-
8
+ gemfile:
9
+ - Gemfile.rails-3.2.x
10
+ - Gemfile.rails-4.0.x
11
+ - Gemfile.rails-4.1.x
12
+ - Gemfile.rails-head
13
+ matrix:
14
+ allow_failures:
15
+ - rvm: ruby-head
16
+ - gemfile: Gemfile.rails-head
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in frikandel.gemspec
4
+ gemspec
5
+
6
+ gem 'rails', '~> 3.2.0'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in frikandel.gemspec
4
+ gemspec
5
+
6
+ gem 'rails', '~> 4.0.0'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in frikandel.gemspec
4
+ gemspec
5
+
6
+ gem 'rails', '~> 4.1.0'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in frikandel.gemspec
4
+ gemspec
5
+
6
+ gem 'rails', 'github' => 'rails/rails'
data/Guardfile CHANGED
@@ -3,8 +3,7 @@
3
3
 
4
4
  guard :rspec do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
- watch('spec/spec_helper.rb') { "spec" }
8
-
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| ["spec/lib/#{m[1]}_spec.rb", "spec/controllers"] }
7
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
9
  end
10
-
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Frikandel
2
2
  [![Gem Version](https://badge.fury.io/rb/frikandel.png)](http://badge.fury.io/rb/frikandel)
3
3
  [![Build Status](https://api.travis-ci.org/taktsoft/frikandel.png)](https://travis-ci.org/taktsoft/frikandel)
4
+ [![Code Climate](https://codeclimate.com/github/taktsoft/frikandel.png)](https://codeclimate.com/github/taktsoft/frikandel)
4
5
 
5
6
  This gem aims to improve the security of your rails application. It allows you to add a TTL (Time To Live) to the session cookie and allows you to bind the session to an IP address.
6
7
 
@@ -71,7 +72,7 @@ The default values are `24.hours` for `max_ttl` and `2.hours` for `ttl`. If you
71
72
 
72
73
  ### Customize on_invalid_session behavior
73
74
 
74
- You can also overwrite what should happen when a cookie times out on the controller-level. The default behaviour is to do a `reset_session` and `redirect_to root_path`. For example, if you want to overwrite the default behavior when a user is on the `PublicController`, you want to overwrite the `on_expired_session`-method in your controller:
75
+ You can also overwrite what should happen when a cookie times out on the controller-level. The default behaviour is to do a `reset_session` and `redirect_to root_path`. For example, if you want to overwrite the default behavior when a user is on the `PublicController`, you want to overwrite the `on_invalid_session`-method in your controller:
75
76
 
76
77
  ```ruby
77
78
  class PublicController < ApplicationController
@@ -91,7 +92,16 @@ end
91
92
 
92
93
  ## Changes
93
94
 
94
- 2.0.0 Added IP address binding. Renamed callback from 'on_expired_session' to 'on_invalid_session'.
95
+ 2.1.0 -- Reset session only once if using the combination of TTL and IP address binding.
96
+ 2.0.0 -- Added IP address binding. Renamed callback from 'on_expired_session' to 'on_invalid_session'.
97
+
98
+ ## Test
99
+
100
+ To run the test suite with different rails version by selecting the corresponding gemfile. You can use this one liners:
101
+
102
+ $ BUNDLE_GEMFILE=Gemfile.rails-3.2.x bundle update && bundle exec rake spec
103
+ $ BUNDLE_GEMFILE=Gemfile.rails-4.0.x bundle update && bundle exec rake spec
104
+ $ BUNDLE_GEMFILE=Gemfile.rails-4.1.x bundle update && bundle exec rake spec
95
105
 
96
106
  ## Contributing
97
107
  1. Fork it
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "guard-rspec"
28
28
  spec.add_development_dependency "pry"
29
29
 
30
- spec.add_dependency "rails", ['>= 3.2.0', '< 5.0']
30
+ spec.add_dependency "rails", [">= 3.2.0", "< 5.0"]
31
31
  end
@@ -4,16 +4,17 @@ module Frikandel
4
4
 
5
5
  included do
6
6
  append_before_filter :validate_session_ip_address
7
- append_after_filter :persist_session_ip_address
8
7
  end
9
8
 
10
9
  private
11
10
 
12
11
  def validate_session_ip_address
13
- if session.key?(:ip_address) && !ip_address_match_with_current?(session[:ip_address])
12
+ if session.key?(:ip_address) && !ip_address_match_with_current?
14
13
  on_invalid_session
15
14
  elsif !session.key?(:ip_address)
16
15
  reset_session
16
+ else # session ip address is valid
17
+ persist_session_ip_address
17
18
  end
18
19
  end
19
20
 
@@ -25,9 +26,13 @@ module Frikandel
25
26
  request.remote_ip
26
27
  end
27
28
 
28
- def ip_address_match_with_current?(ip_address)
29
- current_ip_address == ip_address
29
+ def ip_address_match_with_current?
30
+ session[:ip_address] == current_ip_address
30
31
  end
31
32
 
33
+ def reset_session
34
+ super
35
+ persist_session_ip_address
36
+ end
32
37
  end
33
38
  end
@@ -1,7 +1,9 @@
1
+ require 'singleton'
2
+
1
3
  module Frikandel
2
4
  class Configuration
3
- include Singleton
4
- extend SingleForwardable
5
+ include ::Singleton
6
+ extend ::SingleForwardable
5
7
 
6
8
  attr_accessor :ttl, :max_ttl
7
9
 
@@ -5,22 +5,36 @@ module Frikandel
5
5
 
6
6
  included do
7
7
  append_before_filter :validate_session_timestamp
8
- append_after_filter :persist_session_timestamp
9
8
  end
10
9
 
11
10
  private
12
11
 
13
12
  def validate_session_timestamp
14
- if session.key?(:ttl) && session.key?(:max_ttl) && (session[:ttl] < Frikandel::Configuration.ttl.ago || session[:max_ttl] < Time.now)
13
+ if session.key?(:ttl) && session.key?(:max_ttl) && (reached_ttl? || reached_max_ttl?)
15
14
  on_invalid_session
16
- elsif !session.key?(:ttl) && !session.key?(:max_ttl)
15
+ elsif !session.key?(:ttl) || !session.key?(:max_ttl)
17
16
  reset_session
17
+ else # session timestamp is valid
18
+ persist_session_timestamp
18
19
  end
19
20
  end
20
21
 
22
+ def reached_ttl?
23
+ session[:ttl] < Frikandel::Configuration.ttl.ago
24
+ end
25
+
26
+ def reached_max_ttl?
27
+ session[:max_ttl] < Time.now
28
+ end
29
+
21
30
  def persist_session_timestamp
22
31
  session[:ttl] = Time.now
23
- session[:max_ttl] ||= Frikandel::Configuration.max_ttl.from_now
32
+ session[:max_ttl] ||= Frikandel::Configuration.max_ttl.since
33
+ end
34
+
35
+ def reset_session
36
+ super
37
+ persist_session_timestamp
24
38
  end
25
39
  end
26
40
  end
@@ -1,3 +1,3 @@
1
1
  module Frikandel
2
- VERSION = "2.0.0"
2
+ VERSION = "2.1.0"
3
3
  end
@@ -1,41 +1,154 @@
1
1
  require "spec_helper"
2
2
  require "support/application_controller"
3
3
 
4
+
4
5
  class BindSessionToIpAddressController < ApplicationController
5
6
  include Frikandel::BindSessionToIpAddress
6
7
 
8
+ before_filter :flash_alert_and_redirect_home, only: [:redirect_home]
9
+
7
10
  def home
8
11
  render text: "bind test"
9
12
  end
10
- end
11
13
 
12
- describe BindSessionToIpAddressController do
13
- it "writes current ip address to session" do
14
- expect(session[:ip_address]).to be_nil
15
- get :home
16
- expect(session[:ip_address]).to eql("0.0.0.0")
14
+ def redirect_home
17
15
  end
18
16
 
19
- it "raises an exception if session address and current ip address don't match" do
20
- session[:ip_address] = "1.2.3.4"
21
- controller.should_receive(:on_invalid_session)
17
+ protected
22
18
 
23
- get :home
19
+ def flash_alert_and_redirect_home
20
+ flash[:alert] = "alert test"
21
+ redirect_to bind_session_to_ip_address_home_url
24
22
  end
23
+ end
24
+
25
25
 
26
+ describe BindSessionToIpAddressController do
27
+ context "requests" do
28
+ it "writes current ip address to session" do
29
+ expect(session[:ip_address]).to be_nil
26
30
 
27
- context "ip address isn't present in session" do
28
- it "resets the session" do
29
- session[:user_id] = 4337
30
31
  get :home
31
32
 
32
- session[:user_id].should be_blank
33
+ expect(session[:ip_address]).to eql("0.0.0.0")
33
34
  end
34
35
 
35
- it "allows the request to be rendered as normal" do
36
+ it "writes current ip address to session even on redirect in another before filter" do
37
+ expect(session[:ip_address]).to be_nil
38
+
39
+ simulate_redirect!(:redirect_home, :home)
40
+
41
+ expect(session[:ip_address]).to eql("0.0.0.0")
42
+
43
+ flash.should_not be_empty
44
+ flash[:alert].should eql("alert test")
45
+ end
46
+
47
+ it "raises an exception if session address and current ip address don't match" do
48
+ session[:ip_address] = "1.2.3.4"
49
+ controller.should_receive(:on_invalid_session)
50
+
36
51
  get :home
52
+ end
53
+
54
+
55
+ context "ip address isn't present in session" do
56
+ it "resets the session and persists the ip address" do
57
+ session[:user_id] = 4337
58
+ session.delete(:ip_address)
59
+ session[:ttl] = "SomeTTL"
60
+ session[:max_ttl] = "SomeMaxTTL"
61
+
62
+ controller.should_receive(:reset_session).and_call_original
63
+ controller.should_receive(:persist_session_ip_address).and_call_original
64
+ get :home
65
+
66
+ session[:user_id].should be_blank
67
+ session[:ip_address].should be_present
68
+ session[:ip_address].should eql("0.0.0.0")
69
+ session[:ttl].should be_blank
70
+ session[:max_ttl].should be_blank
71
+ end
72
+
73
+ it "allows the request to be rendered as normal" do
74
+ get :home
75
+
76
+ response.body.should eql("bind test")
77
+ end
78
+ end
79
+ end
80
+
81
+
82
+ context ".validate_session_ip_address" do
83
+ it "calls on_invalid_session if ip address doesn't match with current" do
84
+ session[:ip_address] = "1.3.3.7"
85
+
86
+ controller.should_receive(:ip_address_match_with_current?).and_return(false)
87
+ controller.should_receive(:on_invalid_session)
88
+
89
+ controller.send(:validate_session_ip_address)
90
+ end
91
+
92
+ it "calls reset_session if ip address isn't persisted in session" do
93
+ session.delete(:ip_address)
94
+
95
+ controller.should_not_receive(:ip_address_match_with_current?)
96
+ controller.should_receive(:reset_session)
97
+
98
+ controller.send(:validate_session_ip_address)
99
+ end
100
+
101
+ it "calls persist_session_ip_address if validation passes" do
102
+ session[:ip_address] = "1.3.3.7"
103
+
104
+ controller.should_receive(:ip_address_match_with_current?).and_return(true)
105
+ controller.should_receive(:persist_session_ip_address)
106
+
107
+ controller.send(:validate_session_ip_address)
108
+ end
109
+ end
110
+
111
+
112
+ context ".persist_session_ip_address" do
113
+ it "sets the current ip address in session on key ip_address" do
114
+ expect {
115
+ controller.should_receive(:current_ip_address).and_return("1.3.3.7")
116
+ controller.send(:persist_session_ip_address)
117
+ }.to change {
118
+ session[:ip_address]
119
+ }.from(nil).to("1.3.3.7")
120
+ end
121
+ end
122
+
123
+
124
+ context ".current_ip_address" do
125
+ it "returns the remote_ip from request" do
126
+ request.should_receive(:remote_ip).and_return(:request_remote_ip)
127
+
128
+ controller.send(:current_ip_address).should eql(:request_remote_ip)
129
+ end
130
+ end
131
+
132
+
133
+ context ".ip_address_match_with_current?" do
134
+ it "compares ip address from session with the current ip address" do
135
+ controller.stub(:current_ip_address).and_return("1.3.3.7")
136
+
137
+ session[:ip_address] = "1.3.3.7"
138
+
139
+ controller.send(:ip_address_match_with_current?).should be_true
140
+
141
+ session[:ip_address] = "7.3.3.1"
142
+
143
+ controller.send(:ip_address_match_with_current?).should be_false
144
+ end
145
+ end
146
+
37
147
 
38
- response.body.should eql("bind test")
148
+ context ".reset_session" do
149
+ it "calls persist_session_ip_address" do
150
+ controller.should_receive(:persist_session_ip_address).and_call_original
151
+ controller.send(:reset_session)
39
152
  end
40
153
  end
41
154
  end
@@ -1,24 +1,40 @@
1
1
  require "spec_helper"
2
2
  require "support/application_controller"
3
3
 
4
+
4
5
  class CombinedController < ApplicationController
5
6
  include Frikandel::LimitSessionLifetime
6
7
  include Frikandel::BindSessionToIpAddress
7
8
 
9
+ before_filter :flash_alert_and_redirect_home, only: [:redirect_home]
10
+
8
11
  def home
9
12
  render text: "combined test"
10
13
  end
14
+
15
+ def redirect_home
16
+ end
17
+
18
+ protected
19
+
20
+ def flash_alert_and_redirect_home
21
+ flash[:alert] = "alert test"
22
+ redirect_to combined_home_url
23
+ end
11
24
  end
12
25
 
26
+
13
27
  describe CombinedController do
14
28
  context "ttl nor ip isn't present in session" do
15
- it "resets the session" do
29
+ it "resets the session and persists ip address, ttl & max_ttl" do
16
30
  session[:user_id] = 4337
31
+
17
32
  get :home
18
33
 
19
34
  session[:user_id].should be_blank
20
- session[:ttl].should be_present
21
35
  session[:ip_address].should be_present
36
+ session[:ttl].should be_present
37
+ session[:max_ttl].should be_present
22
38
  end
23
39
 
24
40
  it "allows the request to be rendered as normal" do
@@ -26,31 +42,68 @@ describe CombinedController do
26
42
 
27
43
  response.body.should eql("combined test")
28
44
  end
45
+
46
+ it "persists ttl, max_ttl and ip even on redirect in another before filter" do
47
+ session[:ip_address].should be_nil
48
+ session[:ttl].should be_nil
49
+ session[:max_ttl].should be_nil
50
+
51
+ simulate_redirect!(:redirect_home, :home)
52
+
53
+ session[:ip_address].should be_present
54
+ session[:ttl].should be_present
55
+ session[:max_ttl].should be_present
56
+
57
+ flash.should_not be_empty
58
+ flash[:alert].should eql("alert test")
59
+ end
29
60
  end
30
61
 
62
+
31
63
  context "ttl or ip isn't present in session" do
32
- it "resets the session if ip address is missing" do
64
+ it "resets the session and persists ip address, ttl & max_ttl if ip address is missing" do
33
65
  session[:user_id] = 4337
34
- session[:ttl] = "Something"
66
+ session[:ttl] = last_ttl = Time.now
67
+ session[:max_ttl] = last_max_ttl = Frikandel::Configuration.max_ttl.from_now
68
+
35
69
  get :home
36
70
 
37
71
  session[:user_id].should be_blank
38
-
39
- session[:ttl].should be_present
40
- session[:ttl].should_not eql("Something")
41
72
  session[:ip_address].should be_present
73
+ session[:ttl].should be_present
74
+ session[:ttl].should_not eql(last_ttl)
75
+ session[:max_ttl].should be_present
76
+ session[:max_ttl].should_not eql(last_max_ttl)
42
77
  end
43
78
 
44
- it "resets the session if ttl is missing" do
79
+ it "resets the session and persists ip address, ttl & max_ttl if ttl is missing" do
45
80
  session[:user_id] = 4337
46
- session[:ip_address] = "Something"
81
+ session[:ip_address] = "0.0.0.0"
82
+ session[:max_ttl] = last_max_ttl = Frikandel::Configuration.max_ttl.from_now
83
+
47
84
  get :home
48
85
 
49
86
  session[:user_id].should be_blank
50
-
87
+ session[:ip_address].should be_present
88
+ session[:ip_address].should eql("0.0.0.0")
51
89
  session[:ttl].should be_present
90
+ session[:max_ttl].should be_present
91
+ session[:max_ttl].should_not eql(last_max_ttl)
92
+ end
93
+
94
+ it "resets the session and persists ip address, ttl & max_ttl if max_ttl is missing" do
95
+ session[:user_id] = 4337
96
+ session[:ip_address] = "0.0.0.0"
97
+ session[:ttl] = last_ttl = Time.now
98
+
99
+ get :home
100
+
101
+ session[:user_id].should be_blank
52
102
  session[:ip_address].should be_present
53
103
  session[:ip_address].should eql("0.0.0.0")
104
+ session[:ttl].should be_present
105
+ session[:ttl].should_not eql(last_ttl)
106
+ session[:max_ttl].should be_present
54
107
  end
55
108
  end
56
109
  end
@@ -1,68 +1,372 @@
1
1
  require "spec_helper"
2
2
  require "support/application_controller"
3
3
 
4
+
4
5
  class LimitSessionLifetimeController < ApplicationController
5
6
  include Frikandel::LimitSessionLifetime
6
7
 
8
+ before_filter :flash_alert_and_redirect_home, only: [:redirect_home]
9
+
7
10
  def home
8
11
  render text: "ttl test"
9
12
  end
13
+
14
+ def redirect_home
15
+ end
16
+
17
+ protected
18
+
19
+ def flash_alert_and_redirect_home
20
+ flash[:alert] = "alert test"
21
+
22
+ redirect_to limit_session_lifetime_home_url
23
+ end
10
24
  end
11
25
 
26
+
12
27
  describe LimitSessionLifetimeController do
13
- it "holds the session for at least .1 seconds" do
14
- get :home
15
- session[:user_id] = 1337
16
- sleep 0.1
17
- get :home
18
-
19
- session[:user_id].should be_present
20
- session[:user_id].should eq 1337
28
+ context "requests" do
29
+ it "writes ttl and max_ttl to session" do
30
+ expect(session[:ttl]).to be_nil
31
+ expect(session[:max_ttl]).to be_nil
32
+
33
+ get :home
34
+
35
+ expect(session[:ttl]).to be_a(Time)
36
+ expect(session[:max_ttl]).to be_a(Time)
37
+ end
38
+
39
+ it "writes ttl and max_ttl to session even on redirect in another before filter" do
40
+ expect(session[:ttl]).to be_nil
41
+ expect(session[:max_ttl]).to be_nil
42
+
43
+ simulate_redirect!(:redirect_home, :home)
44
+
45
+ expect(session[:ttl]).to be_a(Time)
46
+ expect(session[:max_ttl]).to be_a(Time)
47
+
48
+ flash.should_not be_empty
49
+ flash[:alert].should eql("alert test")
50
+ end
51
+
52
+ it "holds the session for at least .1 seconds" do
53
+ get :home
54
+
55
+ session[:user_id] = 1337
56
+ sleep 0.1
57
+
58
+ get :home
59
+
60
+ session[:user_id].should be_present
61
+ session[:user_id].should eq 1337
62
+ end
63
+
64
+ it "destroys the session after SESSION_TTL" do
65
+ get :home
66
+
67
+ session[:user_id] = 2337
68
+ session[:ttl] = (Frikandel::Configuration.ttl + 1.minute).seconds.ago
69
+
70
+ get :home
71
+
72
+ session[:user_id].should be_blank
73
+ end
74
+
75
+ it "destroys the session after SESSION_MAX_TTL" do
76
+ get :home
77
+
78
+ session[:user_id] = 3337
79
+ request.session[:max_ttl] = 1.minute.ago
80
+
81
+ get :home
82
+
83
+ session[:user_id].should be_blank
84
+ end
85
+
86
+ it "is configurable" do
87
+ Frikandel::Configuration.ttl = 1.minute
88
+ get :home
89
+
90
+ session[:ttl] = 30.minutes.ago
91
+ session[:user_id] = 5337
92
+
93
+ get :home
94
+
95
+ session[:user_id].should be_blank
96
+ end
97
+
98
+
99
+ context "ttl isn't present in session" do
100
+ it "resets the session and persists ttl & max_ttl" do
101
+ session[:user_id] = 4337
102
+ session[:ip_address] = "SomeIP"
103
+ session.delete(:ttl)
104
+ session[:max_ttl] = "SomeMaxTTL"
105
+
106
+ controller.should_receive(:reset_session).and_call_original
107
+ controller.should_receive(:persist_session_timestamp).and_call_original
108
+ get :home
109
+
110
+ session[:user_id].should be_blank
111
+ session[:ip_address].should be_blank
112
+ session[:ttl].should be_present
113
+ session[:ttl].should be_a(Time)
114
+ session[:max_ttl].should be_present
115
+ session[:max_ttl].should_not eql("SomeMaxTTL")
116
+ session[:max_ttl].should be_a(Time)
117
+ end
118
+
119
+ it "allows the request to be rendered as normal" do
120
+ session.delete(:ttl)
121
+ session[:max_ttl] = "SomeMaxTTL"
122
+
123
+ get :home
124
+
125
+ response.body.should eql("ttl test")
126
+ end
127
+ end
128
+
129
+
130
+ context "max_ttl isn't present in session" do
131
+ it "resets the session and persists ttl & max_ttl" do
132
+ session[:user_id] = 4337
133
+ session[:ip_address] = "SomeIP"
134
+ session[:ttl] = "SomeTTL"
135
+ session.delete(:max_ttl)
136
+
137
+ controller.should_receive(:reset_session).and_call_original
138
+ controller.should_receive(:persist_session_timestamp).and_call_original
139
+ get :home
140
+
141
+ session[:user_id].should be_blank
142
+ session[:ip_address].should be_blank
143
+ session[:ttl].should be_present
144
+ session[:ttl].should_not eql("SomeTTL")
145
+ session[:ttl].should be_a(Time)
146
+ session[:max_ttl].should be_present
147
+ session[:max_ttl].should be_a(Time)
148
+ end
149
+
150
+ it "allows the request to be rendered as normal" do
151
+ session[:ttl] = "SomeTTL"
152
+ session.delete(:max_ttl)
153
+
154
+ get :home
155
+
156
+ response.body.should eql("ttl test")
157
+ end
158
+ end
159
+
160
+
161
+ context "ttl and max_ttl isn't present in session" do
162
+ it "resets the session and persists ttl & max_ttl" do
163
+ session[:user_id] = 4337
164
+ session[:ip_address] = "SomeIP"
165
+ session.delete(:ttl)
166
+ session.delete(:max_ttl)
167
+
168
+ controller.should_receive(:reset_session).and_call_original
169
+ controller.should_receive(:persist_session_timestamp).and_call_original
170
+ get :home
171
+
172
+ session[:user_id].should be_blank
173
+ session[:ip_address].should be_blank
174
+ session[:ttl].should be_present
175
+ session[:ttl].should be_a(Time)
176
+ session[:max_ttl].should be_present
177
+ session[:max_ttl].should be_a(Time)
178
+ end
179
+
180
+ it "allows the request to be rendered as normal" do
181
+ session.delete(:ttl)
182
+ session.delete(:max_ttl)
183
+
184
+ get :home
185
+
186
+ response.body.should eql("ttl test")
187
+ end
188
+ end
21
189
  end
22
190
 
23
- it "destroys the session after SESSION_TTL" do
24
- get :home
25
- session[:user_id] = 2337
26
- request.session[:ttl] = (Frikandel::Configuration.ttl + 1.minute).seconds.ago
27
- get :home
28
191
 
29
- session[:user_id].should be_blank
192
+ context ".validate_session_timestamp" do
193
+ it "calls on_invalid_session if ttl is reached" do
194
+ session[:ttl] = "SomeTTL"
195
+ session[:max_ttl] = "SomeMaxTTL"
196
+
197
+ controller.should_receive(:reached_ttl?).and_return(true)
198
+ controller.stub(:reached_max_ttl?).and_return(false)
199
+
200
+ controller.should_receive(:on_invalid_session)
201
+
202
+ controller.send(:validate_session_timestamp)
203
+ end
204
+
205
+ it "calls on_invalid_session if max_ttl is reached" do
206
+ session[:ttl] = "SomeTTL"
207
+ session[:max_ttl] = "SomeMaxTTL"
208
+
209
+ controller.stub(:reached_ttl?).and_return(false)
210
+ controller.should_receive(:reached_max_ttl?).and_return(true)
211
+
212
+ controller.should_receive(:on_invalid_session)
213
+
214
+ controller.send(:validate_session_timestamp)
215
+ end
216
+
217
+ it "calls on_invalid_session if ttl and max_ttl are reached" do
218
+ session[:ttl] = "SomeTTL"
219
+ session[:max_ttl] = "SomeMaxTTL"
220
+
221
+ controller.stub(:reached_ttl?).and_return(true)
222
+ controller.stub(:reached_max_ttl?).and_return(true)
223
+
224
+ controller.should_receive(:on_invalid_session)
225
+
226
+ controller.send(:validate_session_timestamp)
227
+ end
228
+
229
+ it "calls reset_session if ttl isn't persisted in session" do
230
+ session.delete(:ttl)
231
+ session[:max_ttl] = "SomeMaxTTL"
232
+
233
+ controller.should_receive(:reset_session)
234
+
235
+ controller.send(:validate_session_timestamp)
236
+ end
237
+
238
+ it "calls reset_session if max_ttl isn't persisted in session" do
239
+ session[:ttl] = "SomeTTL"
240
+ session.delete(:max_ttl)
241
+
242
+ controller.should_receive(:persist_session_timestamp)
243
+
244
+ controller.send(:validate_session_timestamp)
245
+ end
246
+
247
+ it "calls reset_session if ttl and max_ttl aren't persisted in session" do
248
+ session.delete(:ttl)
249
+ session.delete(:max_ttl)
250
+
251
+ controller.should_receive(:persist_session_timestamp)
252
+
253
+ controller.send(:validate_session_timestamp)
254
+ end
255
+
256
+ it "calls persist_session_timestamp if validation passes" do
257
+ session[:ttl] = "SomeTTL"
258
+ session[:max_ttl] = "SomeMaxTTL"
259
+
260
+ controller.stub(:reached_ttl?).and_return(false)
261
+ controller.stub(:reached_max_ttl?).and_return(false)
262
+
263
+ controller.should_receive(:persist_session_timestamp)
264
+
265
+ controller.send(:validate_session_timestamp)
266
+ end
30
267
  end
31
268
 
32
- it "destroys the session after SESSION_MAX_TTL" do
33
- get :home
34
- session[:user_id] = 3337
35
269
 
36
- request.session[:max_ttl] = 1.minute.ago
37
- get :home
270
+ context ".reached_ttl?" do
271
+ it "returns true if persisted ttl is less than configured ttl seconds ago" do
272
+ current_time = Time.now
273
+ Time.stub(:now).and_return(current_time)
274
+
275
+ session[:ttl] = current_time.ago(Frikandel::Configuration.ttl + 1)
276
+
277
+ controller.send(:reached_ttl?).should be_true
278
+ end
279
+
280
+ it "returns false if persisted ttl is equal to configured ttl seconds ago" do
281
+ current_time = Time.now
282
+ Time.stub(:now).and_return(current_time)
283
+
284
+ session[:ttl] = current_time.ago(Frikandel::Configuration.ttl)
285
+
286
+ controller.send(:reached_ttl?).should be_false
287
+ end
38
288
 
39
- session[:user_id].should be_blank
289
+ it "returns false if persisted ttl is greater than configured ttl seconds ago" do
290
+ current_time = Time.now
291
+ Time.stub(:now).and_return(current_time)
292
+
293
+ session[:ttl] = current_time.ago(Frikandel::Configuration.ttl - 1)
294
+
295
+ controller.send(:reached_ttl?).should be_false
296
+ end
40
297
  end
41
- it "is configurable" do
42
- old_value = Frikandel::Configuration.ttl
43
- Frikandel::Configuration.ttl = 1.minute
44
- get :home
45
- session[:ttl] = 30.minutes.ago
46
- session[:user_id] = 5337
47
298
 
48
- get :home
49
- session[:user_id].should be_blank
50
299
 
51
- Frikandel::Configuration.ttl = old_value
300
+ context ".reached_max_ttl?" do
301
+ it "returns true if persisted max_ttl is less than current time" do
302
+ current_time = Time.now
303
+ Time.stub(:now).and_return(current_time)
304
+
305
+ session[:max_ttl] = current_time.ago(1)
306
+
307
+ controller.send(:reached_max_ttl?).should be_true
308
+ end
309
+
310
+ it "returns false if persisted max_ttl is equal to current time" do
311
+ current_time = Time.now
312
+ Time.stub(:now).and_return(current_time)
313
+
314
+ session[:max_ttl] = current_time
315
+
316
+ controller.send(:reached_max_ttl?).should be_false
317
+ end
318
+
319
+ it "returns false if persisted max_ttl is greater than current time" do
320
+ current_time = Time.now
321
+ Time.stub(:now).and_return(current_time)
322
+
323
+ session[:max_ttl] = current_time.since(1)
324
+
325
+ controller.send(:reached_max_ttl?).should be_false
326
+ end
52
327
  end
53
328
 
54
- context "ttl isn't present in session" do
55
- it "resets the session" do
56
- session[:user_id] = 4337
57
- get :home
58
329
 
59
- session[:user_id].should be_blank
330
+ context ".persist_session_timestamp" do
331
+ it "sets ttl to current time" do
332
+ current_time = Time.now
333
+ Time.stub(:now).and_return(current_time)
334
+
335
+ expect {
336
+ controller.send(:persist_session_timestamp)
337
+ }.to change {
338
+ session[:ttl]
339
+ }.from(nil).to(current_time)
60
340
  end
61
341
 
62
- it "allows the request to be rendered as normal" do
63
- get :home
342
+ it "sets max_ttl to configured max_ttl seconds in future if it's blank" do
343
+ current_time = Time.now
344
+ max_ttl_time = current_time.since(Frikandel::Configuration.max_ttl)
345
+ Time.stub(:now).and_return(current_time)
346
+
347
+ expect {
348
+ controller.send(:persist_session_timestamp)
349
+ }.to change {
350
+ session[:max_ttl]
351
+ }.from(nil).to(max_ttl_time)
352
+ end
353
+
354
+ it "doesn't set max_ttl if it's present" do
355
+ session[:max_ttl] = "SomeMaxTTL"
356
+
357
+ expect {
358
+ controller.send(:persist_session_timestamp) # second call, shouldn't change max_ttl
359
+ }.to_not change {
360
+ session[:max_ttl]
361
+ }.from("SomeMaxTTL")
362
+ end
363
+ end
364
+
64
365
 
65
- response.body.should eql("ttl test")
366
+ context ".reset_session" do
367
+ it "calls persist_session_timestamp" do
368
+ controller.should_receive(:persist_session_timestamp).and_call_original
369
+ controller.send(:reset_session)
66
370
  end
67
371
  end
68
372
  end
@@ -5,21 +5,21 @@
5
5
  # gem 'sqlite3'
6
6
  development:
7
7
  adapter: sqlite3
8
- database: db/development.sqlite3
8
+ database: ":memory:"
9
9
  pool: 5
10
- timeout: 5000
10
+ timeout: 500
11
11
 
12
12
  # Warning: The database defined as "test" will be erased and
13
13
  # re-generated from your development database when you run "rake".
14
14
  # Do not set this db to the same as development or production.
15
15
  test:
16
16
  adapter: sqlite3
17
- database: db/test.sqlite3
17
+ database: ":memory:"
18
18
  pool: 5
19
- timeout: 5000
19
+ timeout: 500
20
20
 
21
21
  production:
22
22
  adapter: sqlite3
23
- database: db/production.sqlite3
23
+ database: ":memory:"
24
24
  pool: 5
25
- timeout: 5000
25
+ timeout: 500
@@ -19,3 +19,20 @@ RSpec.configure do |config|
19
19
  Frikandel::Configuration.defaults!
20
20
  end
21
21
  end
22
+
23
+
24
+ # some helper methods
25
+
26
+ def simulate_redirect!(from_action, to_action)
27
+ get from_action.intern
28
+ from_flash = request.flash # HACK for RAILS_VERSION=3.2.0
29
+
30
+ controller.instance_variable_set(:@_frikandel_did_reset_session, nil) # reset state for redirect request
31
+
32
+ get to_action.intern
33
+ request.flash.update(from_flash.to_hash) # HACK for RAILS_VERSION=3.2.0
34
+ end
35
+
36
+ def flash
37
+ request.flash
38
+ end
@@ -1,12 +1,15 @@
1
-
2
1
  Rails.application.routes.draw do
3
2
  root to: "application#home"
4
- get "/limit_session_lifetime_home" => "limit_session_lifetime#home"
5
- get "/customized_controller_home" => "customized_on_invalid_session#home", as: :customized_controller_home
6
- get "/bind_session_to_ip_address_home" => "bind_session_to_ip_address#home"
7
- get "/combined_controller_home" => "combined#home"
3
+ get "/limit_session_lifetime_home" => "limit_session_lifetime#home", :as => :limit_session_lifetime_home
4
+ get "/limit_session_lifetime_redirect_home" => "limit_session_lifetime#redirect_home"
5
+ get "/bind_session_to_ip_address_home" => "bind_session_to_ip_address#home", :as => :bind_session_to_ip_address_home
6
+ get "/bind_session_to_ip_address_redirect_home" => "bind_session_to_ip_address#redirect_home"
7
+ get "/combined_controller_home" => "combined#home", :as => :combined_home
8
+ get "/combined_controller_redirect_home" => "combined#redirect_home"
9
+ get "/customized_controller_home" => "customized_on_invalid_session#home", :as => :customized_controller_home
8
10
  end
9
11
 
12
+
10
13
  class ApplicationController < ActionController::Base
11
14
  protect_from_forgery with: :exception
12
15
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frikandel
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taktsoft
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-24 00:00:00.000000000 Z
11
+ date: 2014-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -125,6 +125,10 @@ files:
125
125
  - ".rspec"
126
126
  - ".travis.yml"
127
127
  - Gemfile
128
+ - Gemfile.rails-3.2.x
129
+ - Gemfile.rails-4.0.x
130
+ - Gemfile.rails-4.1.x
131
+ - Gemfile.rails-head
128
132
  - Guardfile
129
133
  - LICENSE.txt
130
134
  - README.md
@@ -172,7 +176,6 @@ files:
172
176
  - spec/dummy/config/initializers/wrap_parameters.rb
173
177
  - spec/dummy/config/locales/en.yml
174
178
  - spec/dummy/config/routes.rb
175
- - spec/dummy/db/test.sqlite3
176
179
  - spec/dummy/lib/assets/.keep
177
180
  - spec/dummy/log/test.log
178
181
  - spec/dummy/public/404.html
@@ -215,7 +218,6 @@ test_files:
215
218
  - spec/controllers/customized_on_invalid_session_controller_spec.rb
216
219
  - spec/support/application_controller.rb
217
220
  - spec/dummy/README.rdoc
218
- - spec/dummy/db/test.sqlite3
219
221
  - spec/dummy/public/500.html
220
222
  - spec/dummy/public/favicon.ico
221
223
  - spec/dummy/public/422.html
File without changes