clearance 0.13.2 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of clearance might be problematic. Click here for more details.
- data/CHANGELOG.md +10 -0
- data/CONTRIBUTING.md +2 -2
- data/Gemfile.lock +11 -5
- data/README.md +29 -7
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/clearance.gemspec +2 -1
- data/features/support/env.rb +0 -1
- data/gemfiles/3.0.9.gemfile.lock +2 -2
- data/gemfiles/3.1.0.gemfile.lock +3 -3
- data/lib/clearance.rb +3 -1
- data/lib/clearance/authentication.rb +9 -19
- data/lib/clearance/engine.rb +2 -0
- data/lib/clearance/rack_session.rb +15 -0
- data/lib/clearance/session.rb +55 -0
- data/lib/clearance/testing/helpers.rb +5 -0
- data/lib/clearance/user.rb +74 -72
- data/spec/clearance/rack_session_spec.rb +23 -0
- data/spec/clearance/session_spec.rb +109 -0
- data/spec/controllers/flashes_controller_spec.rb +32 -0
- data/spec/controllers/sessions_controller_spec.rb +2 -54
- data/spec/spec_helper.rb +2 -0
- data/spec/support/cookies.rb +30 -26
- metadata +54 -35
data/CHANGELOG.md
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -3,8 +3,8 @@ We love pull requests. Here's a quick guide:
|
|
3
3
|
1. Fork the repo.
|
4
4
|
|
5
5
|
2. Run the tests. We only take pull requests with passing tests, and it's great
|
6
|
-
to know that you have a clean slate: `bundle && rake`
|
7
|
-
|
6
|
+
to know that you have a clean slate: `bundle && rake db:migrate && rake`
|
7
|
+
|
8
8
|
3. Add a test for your change. Only refactoring and documentation changes
|
9
9
|
require no new tests. If you are adding functionality or fixing a bug, we need
|
10
10
|
a test!
|
data/Gemfile.lock
CHANGED
@@ -7,7 +7,7 @@ GIT
|
|
7
7
|
PATH
|
8
8
|
remote: .
|
9
9
|
specs:
|
10
|
-
clearance (0.
|
10
|
+
clearance (0.14.0)
|
11
11
|
diesel (~> 0.1.5)
|
12
12
|
rails (>= 3.0)
|
13
13
|
|
@@ -54,6 +54,8 @@ GEM
|
|
54
54
|
rspec (>= 2.6.0)
|
55
55
|
bcat (0.6.1)
|
56
56
|
rack (~> 1.0)
|
57
|
+
bourne (1.0)
|
58
|
+
mocha (= 0.9.8)
|
57
59
|
builder (2.1.2)
|
58
60
|
capybara (1.0.1)
|
59
61
|
mime-types (>= 1.16)
|
@@ -99,9 +101,10 @@ GEM
|
|
99
101
|
mime-types (~> 1.16)
|
100
102
|
treetop (~> 1.4.8)
|
101
103
|
mime-types (1.16)
|
102
|
-
mocha (0.9.
|
104
|
+
mocha (0.9.8)
|
105
|
+
rake
|
103
106
|
nokogiri (1.5.0)
|
104
|
-
polyglot (0.3.
|
107
|
+
polyglot (0.3.3)
|
105
108
|
rack (1.2.3)
|
106
109
|
rack-mount (0.6.14)
|
107
110
|
rack (>= 1.0.0)
|
@@ -147,7 +150,9 @@ GEM
|
|
147
150
|
sqlite3 (1.3.4)
|
148
151
|
term-ansicolor (1.0.6)
|
149
152
|
thor (0.14.6)
|
150
|
-
|
153
|
+
timecop (0.3.5)
|
154
|
+
treetop (1.4.10)
|
155
|
+
polyglot
|
151
156
|
polyglot (>= 0.3.1)
|
152
157
|
tzinfo (0.3.29)
|
153
158
|
xpath (0.1.4)
|
@@ -159,6 +164,7 @@ PLATFORMS
|
|
159
164
|
DEPENDENCIES
|
160
165
|
appraisal (~> 0.3.8)
|
161
166
|
aruba (~> 0.4.2)
|
167
|
+
bourne
|
162
168
|
bundler (~> 1.0.0)
|
163
169
|
capybara (~> 1.0.0)
|
164
170
|
clearance!
|
@@ -166,7 +172,7 @@ DEPENDENCIES
|
|
166
172
|
database_cleaner
|
167
173
|
factory_girl_rails
|
168
174
|
launchy
|
169
|
-
mocha
|
170
175
|
rspec-rails (~> 2.6.0)
|
171
176
|
shoulda-matchers!
|
172
177
|
sqlite3
|
178
|
+
timecop
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Rails authentication & authorization with email & password.
|
|
5
5
|
|
6
6
|
[We have clearance, Clarence.](http://www.youtube.com/watch?v=fVq4_HhBK8Y)
|
7
7
|
|
8
|
-
Clearance was extracted out of [
|
8
|
+
Clearance was extracted out of [Airbrake](http://airbrakeapp.com/).
|
9
9
|
|
10
10
|
Help
|
11
11
|
----
|
@@ -17,7 +17,7 @@ Help
|
|
17
17
|
Installation
|
18
18
|
------------
|
19
19
|
|
20
|
-
Clearance is a Rails engine for Rails 3. It is currently tested against Rails 3.0.9 and Rails 3.1.0.
|
20
|
+
Clearance is a Rails engine for Rails 3. It is currently tested against Rails 3.0.9 and Rails 3.1.0.
|
21
21
|
|
22
22
|
Include the gem in your Gemfile:
|
23
23
|
|
@@ -86,6 +86,26 @@ Clearance will deliver one email on your app's behalf: when a user resets their
|
|
86
86
|
config.mailer_sender = "me@example.com"
|
87
87
|
end
|
88
88
|
|
89
|
+
Rack
|
90
|
+
----
|
91
|
+
|
92
|
+
Clearance adds its session to the Rack environment hash so middleware and other
|
93
|
+
Rack applications can interact with it:
|
94
|
+
|
95
|
+
class Bubblegum::Middleware
|
96
|
+
def initialize(app)
|
97
|
+
@app = app
|
98
|
+
end
|
99
|
+
|
100
|
+
def call(env)
|
101
|
+
if env[:clearance].signed_in?
|
102
|
+
env[:clearance].current_user.bubble_gum
|
103
|
+
end
|
104
|
+
@app.call(env)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
89
109
|
Overriding defaults
|
90
110
|
-------------------
|
91
111
|
|
@@ -214,16 +234,18 @@ Then run your tests!
|
|
214
234
|
|
215
235
|
rake
|
216
236
|
|
217
|
-
|
218
|
-
|
237
|
+
Testing
|
238
|
+
-------
|
219
239
|
|
220
|
-
|
240
|
+
If you want to write Rails functional tests or controller specs with Clearance,
|
241
|
+
you'll need to require the included test helpers and matchers.
|
221
242
|
|
222
|
-
|
243
|
+
For example, in spec/support/clearance.rb or test/test_helper.rb:
|
223
244
|
|
224
245
|
require 'clearance/testing'
|
225
246
|
|
226
|
-
|
247
|
+
This will make Clearance::Authentication methods work in your controllers
|
248
|
+
during functional tests and provide access to helper methods like:
|
227
249
|
|
228
250
|
sign_in
|
229
251
|
sign_in_as(user)
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.14.0
|
data/clearance.gemspec
CHANGED
@@ -30,7 +30,8 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.add_development_dependency('cucumber-rails', '~> 1.0.2')
|
31
31
|
s.add_development_dependency('rspec-rails', '~> 2.6.0')
|
32
32
|
s.add_development_dependency('sqlite3')
|
33
|
-
s.add_development_dependency('
|
33
|
+
s.add_development_dependency('bourne')
|
34
|
+
s.add_development_dependency('timecop')
|
34
35
|
|
35
36
|
if s.respond_to? :specification_version then
|
36
37
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/features/support/env.rb
CHANGED
data/gemfiles/3.0.9.gemfile.lock
CHANGED
data/gemfiles/3.1.0.gemfile.lock
CHANGED
@@ -5,9 +5,9 @@ GIT
|
|
5
5
|
shoulda-matchers (1.0.0.beta3)
|
6
6
|
|
7
7
|
PATH
|
8
|
-
remote: /Users/
|
8
|
+
remote: /Users/jferris/Source/clearance
|
9
9
|
specs:
|
10
|
-
clearance (0.
|
10
|
+
clearance (0.14.0)
|
11
11
|
diesel (~> 0.1.5)
|
12
12
|
rails (>= 3.0)
|
13
13
|
|
@@ -157,7 +157,7 @@ GEM
|
|
157
157
|
sprockets (2.0.0)
|
158
158
|
hike (~> 1.2)
|
159
159
|
rack (~> 1.0)
|
160
|
-
tilt (
|
160
|
+
tilt (~> 1.1, != 1.3.0)
|
161
161
|
spruz (0.2.13)
|
162
162
|
sqlite3 (1.3.4)
|
163
163
|
term-ansicolor (1.0.6)
|
data/lib/clearance.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'clearance/configuration'
|
2
|
+
require 'clearance/session'
|
3
|
+
require 'clearance/rack_session'
|
2
4
|
require 'clearance/authentication'
|
3
5
|
require 'clearance/user'
|
4
6
|
require 'clearance/engine'
|
5
|
-
require 'clearance/password_strategies'
|
7
|
+
require 'clearance/password_strategies'
|
@@ -10,32 +10,32 @@ module Clearance
|
|
10
10
|
:authorize, :deny_access
|
11
11
|
end
|
12
12
|
|
13
|
-
#
|
13
|
+
# Finds the user from the rack clearance session
|
14
14
|
#
|
15
15
|
# @return [User, nil]
|
16
16
|
def current_user
|
17
|
-
|
17
|
+
clearance_session.current_user
|
18
18
|
end
|
19
19
|
|
20
20
|
# Set the current user
|
21
21
|
#
|
22
22
|
# @param [User]
|
23
23
|
def current_user=(user)
|
24
|
-
|
24
|
+
clearance_session.sign_in user
|
25
25
|
end
|
26
26
|
|
27
27
|
# Is the current user signed in?
|
28
28
|
#
|
29
29
|
# @return [true, false]
|
30
30
|
def signed_in?
|
31
|
-
|
31
|
+
clearance_session.signed_in?
|
32
32
|
end
|
33
33
|
|
34
34
|
# Is the current user signed out?
|
35
35
|
#
|
36
36
|
# @return [true, false]
|
37
37
|
def signed_out?
|
38
|
-
|
38
|
+
!signed_in?
|
39
39
|
end
|
40
40
|
|
41
41
|
# Sign user in to cookie.
|
@@ -45,13 +45,7 @@ module Clearance
|
|
45
45
|
# @example
|
46
46
|
# sign_in(@user)
|
47
47
|
def sign_in(user)
|
48
|
-
|
49
|
-
cookies[:remember_token] = {
|
50
|
-
:value => user.remember_token,
|
51
|
-
:expires => Clearance.configuration.cookie_expiration.call
|
52
|
-
}
|
53
|
-
self.current_user = user
|
54
|
-
end
|
48
|
+
clearance_session.sign_in user
|
55
49
|
end
|
56
50
|
|
57
51
|
# Sign user out of cookie.
|
@@ -59,9 +53,7 @@ module Clearance
|
|
59
53
|
# @example
|
60
54
|
# sign_out
|
61
55
|
def sign_out
|
62
|
-
|
63
|
-
cookies.delete(:remember_token)
|
64
|
-
self.current_user = nil
|
56
|
+
clearance_session.sign_out
|
65
57
|
end
|
66
58
|
|
67
59
|
# Find the user by the given params or return nil.
|
@@ -107,10 +99,8 @@ module Clearance
|
|
107
99
|
|
108
100
|
protected
|
109
101
|
|
110
|
-
def
|
111
|
-
|
112
|
-
::User.find_by_remember_token(token)
|
113
|
-
end
|
102
|
+
def clearance_session
|
103
|
+
request.env[:clearance]
|
114
104
|
end
|
115
105
|
|
116
106
|
def store_location
|
data/lib/clearance/engine.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Clearance
|
2
|
+
class RackSession
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
session = Clearance::Session.new(env)
|
9
|
+
env[:clearance] = session
|
10
|
+
response = @app.call(env)
|
11
|
+
session.add_cookie_to_headers response[1]
|
12
|
+
response
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Clearance
|
2
|
+
class Session
|
3
|
+
REMEMBER_TOKEN_COOKIE = "remember_token".freeze
|
4
|
+
|
5
|
+
def initialize(env)
|
6
|
+
@env = env
|
7
|
+
end
|
8
|
+
|
9
|
+
def signed_in?
|
10
|
+
current_user.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_user
|
14
|
+
@current_user ||= with_remember_token do |token|
|
15
|
+
::User.find_by_remember_token(token)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def sign_in(user)
|
20
|
+
@current_user = user
|
21
|
+
end
|
22
|
+
|
23
|
+
def sign_out
|
24
|
+
current_user.reset_remember_token! if signed_in?
|
25
|
+
@current_user = nil
|
26
|
+
cookies.delete(REMEMBER_TOKEN_COOKIE)
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_cookie_to_headers(headers)
|
30
|
+
if signed_in?
|
31
|
+
Rack::Utils.set_cookie_header!(headers,
|
32
|
+
REMEMBER_TOKEN_COOKIE,
|
33
|
+
:value => current_user.remember_token,
|
34
|
+
:expires => Clearance.configuration.cookie_expiration.call,
|
35
|
+
:path => "/")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def with_remember_token
|
42
|
+
if token = remember_token
|
43
|
+
yield token
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def remember_token
|
48
|
+
cookies[REMEMBER_TOKEN_COOKIE]
|
49
|
+
end
|
50
|
+
|
51
|
+
def cookies
|
52
|
+
@cookies ||= Rack::Request.new(@env).cookies
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/clearance/user.rb
CHANGED
@@ -67,92 +67,94 @@ module Clearance
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
70
|
+
module InstanceMethods
|
71
|
+
# Set the remember token.
|
72
|
+
#
|
73
|
+
# @deprecated Use {#reset_remember_token!} instead
|
74
|
+
def remember_me!
|
75
|
+
warn "[DEPRECATION] remember_me!: use reset_remember_token! instead"
|
76
|
+
reset_remember_token!
|
77
|
+
end
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
# Reset the remember token.
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# user.reset_remember_token!
|
83
|
+
def reset_remember_token!
|
84
|
+
generate_remember_token
|
85
|
+
save(:validate => false)
|
86
|
+
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
# Mark my account as forgotten password.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# user.forgot_password!
|
92
|
+
def forgot_password!
|
93
|
+
generate_confirmation_token
|
94
|
+
save(:validate => false)
|
95
|
+
end
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
97
|
+
# Update my password.
|
98
|
+
#
|
99
|
+
# @return [true, false] password was updated or not
|
100
|
+
# @example
|
101
|
+
# user.update_password('new-password')
|
102
|
+
def update_password(new_password)
|
103
|
+
self.password_changing = true
|
104
|
+
self.password = new_password
|
105
|
+
if valid?
|
106
|
+
self.confirmation_token = nil
|
107
|
+
generate_remember_token
|
108
|
+
end
|
109
|
+
save
|
107
110
|
end
|
108
|
-
save
|
109
|
-
end
|
110
111
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
def password=(unencrypted_password)
|
113
|
+
@password = unencrypted_password
|
114
|
+
encrypt_password
|
115
|
+
end
|
115
116
|
|
116
|
-
|
117
|
+
protected
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
119
|
+
def generate_random_code(length = 20)
|
120
|
+
if RUBY_VERSION >= '1.9'
|
121
|
+
SecureRandom.hex(length).encode('UTF-8')
|
122
|
+
else
|
123
|
+
SecureRandom.hex(length)
|
124
|
+
end
|
123
125
|
end
|
124
|
-
end
|
125
126
|
|
126
|
-
|
127
|
-
|
128
|
-
|
127
|
+
def generate_remember_token
|
128
|
+
self.remember_token = generate_random_code
|
129
|
+
end
|
129
130
|
|
130
|
-
|
131
|
-
|
132
|
-
|
131
|
+
def generate_confirmation_token
|
132
|
+
self.confirmation_token = generate_random_code
|
133
|
+
end
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
135
|
+
# Always false. Override to allow other forms of authentication
|
136
|
+
# (username, facebook, etc).
|
137
|
+
# @return [Boolean] true if the email field be left blank for this user
|
138
|
+
def email_optional?
|
139
|
+
false
|
140
|
+
end
|
140
141
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
142
|
+
# True if the password has been set and the password is not being
|
143
|
+
# updated and we are not updating the password. Override to allow
|
144
|
+
# other forms of authentication (username, facebook, etc).
|
145
|
+
# @return [Boolean] true if the password field can be left blank for this user
|
146
|
+
def password_optional?
|
147
|
+
encrypted_password.present? && password.blank? && password_changing.blank?
|
148
|
+
end
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
150
|
+
def password_required?
|
151
|
+
# warn "[DEPRECATION] password_required?: use !password_optional? instead"
|
152
|
+
!password_optional?
|
153
|
+
end
|
153
154
|
|
154
|
-
|
155
|
-
|
155
|
+
def downcase_email
|
156
|
+
self.email = email.to_s.downcase
|
157
|
+
end
|
156
158
|
end
|
157
159
|
end
|
158
160
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Clearance::RackSession do
|
4
|
+
it "injects a clearance session into the environment" do
|
5
|
+
expected_session = "the session"
|
6
|
+
expected_session.stubs(:add_cookie_to_headers)
|
7
|
+
Clearance::Session.stubs(:new => expected_session)
|
8
|
+
headers = { "X-Roaring-Lobster" => "Red" }
|
9
|
+
|
10
|
+
app = Rack::Builder.new do
|
11
|
+
use Clearance::RackSession
|
12
|
+
run lambda { |env| Rack::Response.new(env[:clearance], 200, headers).finish }
|
13
|
+
end
|
14
|
+
|
15
|
+
env = Rack::MockRequest.env_for("/")
|
16
|
+
|
17
|
+
response = Rack::MockResponse.new(*app.call(env))
|
18
|
+
|
19
|
+
Clearance::Session.should have_received(:new).with(env)
|
20
|
+
response.body.should == expected_session
|
21
|
+
expected_session.should have_received(:add_cookie_to_headers).with(has_entries(headers))
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Clearance::Session do
|
4
|
+
before { Timecop.freeze }
|
5
|
+
after { Timecop.return }
|
6
|
+
|
7
|
+
it "finds a user from a cookie" do
|
8
|
+
user = Factory(:user)
|
9
|
+
env = env_with_remember_token(user.remember_token)
|
10
|
+
|
11
|
+
session = Clearance::Session.new(env)
|
12
|
+
session.should be_signed_in
|
13
|
+
session.current_user.should == user
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns nil for an unknown user" do
|
17
|
+
user = Factory(:user)
|
18
|
+
env = env_with_remember_token("bogus")
|
19
|
+
|
20
|
+
session = Clearance::Session.new(env)
|
21
|
+
session.should_not be_signed_in
|
22
|
+
session.current_user.should be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns nil without a remember token" do
|
26
|
+
env = env_without_remember_token
|
27
|
+
session = Clearance::Session.new(env)
|
28
|
+
session.should_not be_signed_in
|
29
|
+
session.current_user.should be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "signs in a given user" do
|
33
|
+
user = Factory(:user)
|
34
|
+
session = Clearance::Session.new(env_without_remember_token)
|
35
|
+
session.sign_in user
|
36
|
+
session.current_user.should == user
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sets a remember token cookie with a default expiration of 1 year from now" do
|
40
|
+
user = Factory(:user)
|
41
|
+
headers = {}
|
42
|
+
session = Clearance::Session.new(env_without_remember_token)
|
43
|
+
session.sign_in user
|
44
|
+
session.add_cookie_to_headers headers
|
45
|
+
headers.should set_cookie("remember_token", user.remember_token, 1.year.from_now)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "sets a remember token cookie with a custom expiration" do
|
49
|
+
custom_expiration = 1.day.from_now
|
50
|
+
with_custom_expiration 1.day.from_now do
|
51
|
+
user = Factory(:user)
|
52
|
+
headers = {}
|
53
|
+
session = Clearance::Session.new(env_without_remember_token)
|
54
|
+
session.sign_in user
|
55
|
+
session.add_cookie_to_headers headers
|
56
|
+
headers.should set_cookie("remember_token", user.remember_token, 1.day.from_now)
|
57
|
+
Clearance.configuration.cookie_expiration.call.should be_within(100).of(1.year.from_now)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "doesn't set a remember token when signed out" do
|
62
|
+
headers = {}
|
63
|
+
session = Clearance::Session.new(env_without_remember_token)
|
64
|
+
session.add_cookie_to_headers headers
|
65
|
+
headers.should_not set_cookie("remember_token")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "signs out a user" do
|
69
|
+
user = Factory(:user)
|
70
|
+
old_remember_token = user.remember_token
|
71
|
+
env = env_with_remember_token(old_remember_token)
|
72
|
+
|
73
|
+
session = Clearance::Session.new(env)
|
74
|
+
session.sign_out
|
75
|
+
session.current_user.should be_nil
|
76
|
+
user.reload.remember_token.should_not == old_remember_token
|
77
|
+
end
|
78
|
+
|
79
|
+
def env_with_remember_token(token)
|
80
|
+
env_with_cookies("remember_token" => token)
|
81
|
+
end
|
82
|
+
|
83
|
+
def env_without_remember_token
|
84
|
+
env_with_cookies({})
|
85
|
+
end
|
86
|
+
|
87
|
+
def env_with_cookies(cookies)
|
88
|
+
Rack::MockRequest.env_for("/", "HTTP_COOKIE" => serialize_cookies(cookies))
|
89
|
+
end
|
90
|
+
|
91
|
+
def serialize_cookies(hash)
|
92
|
+
header = {}
|
93
|
+
hash.each do |key, value|
|
94
|
+
Rack::Utils.set_cookie_header!(header, key, value)
|
95
|
+
end
|
96
|
+
header['Set-Cookie']
|
97
|
+
end
|
98
|
+
|
99
|
+
def with_custom_expiration(custom_duration)
|
100
|
+
Clearance.configuration.cookie_expiration = lambda { custom_duration }
|
101
|
+
ensure
|
102
|
+
restore_default_config
|
103
|
+
end
|
104
|
+
|
105
|
+
def restore_default_config
|
106
|
+
Clearance.configuration = nil
|
107
|
+
Clearance.configure {}
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class FlashesController < ActionController::Base
|
4
|
+
include Clearance::Authentication
|
5
|
+
|
6
|
+
def set_flash
|
7
|
+
flash[:notice] = params[:message]
|
8
|
+
redirect_to view_flash_url
|
9
|
+
end
|
10
|
+
|
11
|
+
def view_flash
|
12
|
+
render :text => "<html><body>#{flash[:notice]}</body></html>"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe FlashesController do
|
17
|
+
before do
|
18
|
+
Rails.application.routes.draw do
|
19
|
+
match "set_flash" => "flashes#set_flash"
|
20
|
+
match "view_flash" => "flashes#view_flash"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
after do
|
25
|
+
Rails.application.reload_routes!
|
26
|
+
end
|
27
|
+
|
28
|
+
it "sets and views a flash" do
|
29
|
+
visit "/set_flash?message=hello"
|
30
|
+
page.should have_content("hello")
|
31
|
+
end
|
32
|
+
end
|
@@ -20,12 +20,8 @@ describe Clearance::SessionsController do
|
|
20
20
|
|
21
21
|
it { should redirect_to_url_after_create }
|
22
22
|
|
23
|
-
it "sets
|
24
|
-
should
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should have a default of 1 year from now" do
|
28
|
-
Clearance.configuration.cookie_expiration.call.should be_within(100).of(1.year.from_now)
|
23
|
+
it "sets the user in the clearance session" do
|
24
|
+
controller.current_user.should == @user
|
29
25
|
end
|
30
26
|
|
31
27
|
it "should not change the remember token" do
|
@@ -33,50 +29,6 @@ describe Clearance::SessionsController do
|
|
33
29
|
end
|
34
30
|
end
|
35
31
|
|
36
|
-
describe "on POST to #create with good credentials - cookie duration set to 2 weeks" do
|
37
|
-
custom_duration = 2.weeks.from_now.utc
|
38
|
-
|
39
|
-
before do
|
40
|
-
Clearance.configuration.cookie_expiration = lambda { custom_duration }
|
41
|
-
@user = Factory(:user)
|
42
|
-
@user.update_attribute(:remember_token, "old-token2")
|
43
|
-
post :create, :session => {
|
44
|
-
:email => @user.email,
|
45
|
-
:password => @user.password }
|
46
|
-
end
|
47
|
-
|
48
|
-
it "sets a remember token cookie" do
|
49
|
-
should set_cookie("remember_token", "old-token2", custom_duration)
|
50
|
-
end
|
51
|
-
|
52
|
-
after do
|
53
|
-
# restore default Clearance configuration
|
54
|
-
Clearance.configuration = nil
|
55
|
-
Clearance.configure {}
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
describe "on POST to #create with good credentials - cookie expiration set to nil (session cookie)" do
|
60
|
-
before do
|
61
|
-
Clearance.configuration.cookie_expiration = lambda { nil }
|
62
|
-
@user = Factory(:user)
|
63
|
-
@user.update_attribute(:remember_token, "old-token3")
|
64
|
-
post :create, :session => {
|
65
|
-
:email => @user.email,
|
66
|
-
:password => @user.password }
|
67
|
-
end
|
68
|
-
|
69
|
-
it "unsets a remember token cookie" do
|
70
|
-
should set_cookie("remember_token", "old-token3", nil)
|
71
|
-
end
|
72
|
-
|
73
|
-
after do
|
74
|
-
# restore default Clearance configuration
|
75
|
-
Clearance.configuration = nil
|
76
|
-
Clearance.configure {}
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
32
|
describe "on POST to #create with good credentials and a session return url" do
|
81
33
|
before do
|
82
34
|
@user = Factory(:user)
|
@@ -141,10 +93,6 @@ describe Clearance::SessionsController do
|
|
141
93
|
|
142
94
|
it { should redirect_to_url_after_destroy }
|
143
95
|
|
144
|
-
it "should delete the cookie token" do
|
145
|
-
cookies['remember_token'].should be_nil
|
146
|
-
end
|
147
|
-
|
148
96
|
it "should reset the remember token" do
|
149
97
|
@user.reload.remember_token.should_not == "old-token"
|
150
98
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/cookies.rb
CHANGED
@@ -1,27 +1,29 @@
|
|
1
|
-
RSpec::Matchers.define :set_cookie do |name,
|
1
|
+
RSpec::Matchers.define :set_cookie do |name, expected_value, expected_expires_at|
|
2
2
|
match do |subject|
|
3
|
-
@
|
4
|
-
@
|
5
|
-
@
|
3
|
+
@headers = subject
|
4
|
+
@expected_name = name
|
5
|
+
@expected_value = expected_value
|
6
6
|
@expected_expires_at = expected_expires_at
|
7
7
|
|
8
8
|
extract_cookies
|
9
9
|
find_expected_cookie
|
10
10
|
parse_expiration
|
11
|
+
parse_value
|
12
|
+
parse_path
|
11
13
|
|
12
14
|
ensure_cookie_set
|
13
|
-
ensure_value_correct
|
14
15
|
ensure_expiration_correct
|
16
|
+
ensure_path_is_correct
|
15
17
|
end
|
16
18
|
|
17
19
|
def extract_cookies
|
18
|
-
@cookie_headers = @
|
20
|
+
@cookie_headers = @headers['Set-Cookie'] || []
|
19
21
|
@cookie_headers = [@cookie_headers] if @cookie_headers.respond_to?(:to_str)
|
20
22
|
end
|
21
23
|
|
22
24
|
def find_expected_cookie
|
23
25
|
@cookie = @cookie_headers.detect do |header|
|
24
|
-
header =~ /^#{@
|
26
|
+
header =~ /^#{@expected_name}=[^;]*(;|$)/
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
@@ -31,21 +33,29 @@ RSpec::Matchers.define :set_cookie do |name, value, expected_expires_at|
|
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
def
|
35
|
-
@cookie.
|
36
|
+
def parse_value
|
37
|
+
if @cookie && result = @cookie.match(/=(.*?)(?:;|$)/)
|
38
|
+
@value = result[1]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_path
|
43
|
+
if @cookie && result = @cookie.match(/; path=(.*?)(;|$)/)
|
44
|
+
@path = result[1]
|
45
|
+
end
|
36
46
|
end
|
37
47
|
|
38
|
-
def
|
39
|
-
@
|
48
|
+
def ensure_cookie_set
|
49
|
+
@value.should == @expected_value
|
40
50
|
end
|
41
51
|
|
42
52
|
def ensure_expiration_correct
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
@expires_at.should_not be_nil
|
54
|
+
@expires_at.should be_within(100).of(@expected_expires_at)
|
55
|
+
end
|
56
|
+
|
57
|
+
def ensure_path_is_correct
|
58
|
+
@path.should == "/"
|
49
59
|
end
|
50
60
|
|
51
61
|
failure_message do
|
@@ -53,20 +63,14 @@ RSpec::Matchers.define :set_cookie do |name, value, expected_expires_at|
|
|
53
63
|
end
|
54
64
|
|
55
65
|
def expectation
|
56
|
-
|
57
|
-
if @expected_expires_at
|
58
|
-
base << "expiring at #{@expected_expires_at.inspect}"
|
59
|
-
else
|
60
|
-
base << "with no expiration"
|
61
|
-
end
|
62
|
-
base
|
66
|
+
"a cookie named #{@expected_name} with value #{@expected_value.inspect} expiring at #{@expected_expires_at.inspect}"
|
63
67
|
end
|
64
68
|
|
65
69
|
def result
|
66
70
|
if @cookie
|
67
|
-
|
71
|
+
@cookie
|
68
72
|
else
|
69
|
-
|
73
|
+
@cookie_headers.join("; ")
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clearance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 39
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 14
|
9
|
+
- 0
|
10
|
+
version: 0.14.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Dan Croak
|
@@ -27,9 +27,7 @@ cert_chain: []
|
|
27
27
|
date: 2012-01-13 00:00:00 Z
|
28
28
|
dependencies:
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
-
|
31
|
-
prerelease: false
|
32
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
30
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
33
31
|
none: false
|
34
32
|
requirements:
|
35
33
|
- - ">="
|
@@ -39,12 +37,12 @@ dependencies:
|
|
39
37
|
- 3
|
40
38
|
- 0
|
41
39
|
version: "3.0"
|
40
|
+
requirement: *id001
|
42
41
|
type: :runtime
|
43
|
-
version_requirements: *id001
|
44
|
-
- !ruby/object:Gem::Dependency
|
45
|
-
name: diesel
|
46
42
|
prerelease: false
|
47
|
-
|
43
|
+
name: rails
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
48
46
|
none: false
|
49
47
|
requirements:
|
50
48
|
- - ~>
|
@@ -55,12 +53,12 @@ dependencies:
|
|
55
53
|
- 1
|
56
54
|
- 5
|
57
55
|
version: 0.1.5
|
56
|
+
requirement: *id002
|
58
57
|
type: :runtime
|
59
|
-
version_requirements: *id002
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: bundler
|
62
58
|
prerelease: false
|
63
|
-
|
59
|
+
name: diesel
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
64
62
|
none: false
|
65
63
|
requirements:
|
66
64
|
- - ~>
|
@@ -71,12 +69,12 @@ dependencies:
|
|
71
69
|
- 0
|
72
70
|
- 0
|
73
71
|
version: 1.0.0
|
72
|
+
requirement: *id003
|
74
73
|
type: :development
|
75
|
-
version_requirements: *id003
|
76
|
-
- !ruby/object:Gem::Dependency
|
77
|
-
name: appraisal
|
78
74
|
prerelease: false
|
79
|
-
|
75
|
+
name: bundler
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
80
78
|
none: false
|
81
79
|
requirements:
|
82
80
|
- - ~>
|
@@ -87,12 +85,12 @@ dependencies:
|
|
87
85
|
- 3
|
88
86
|
- 8
|
89
87
|
version: 0.3.8
|
88
|
+
requirement: *id004
|
90
89
|
type: :development
|
91
|
-
version_requirements: *id004
|
92
|
-
- !ruby/object:Gem::Dependency
|
93
|
-
name: cucumber-rails
|
94
90
|
prerelease: false
|
95
|
-
|
91
|
+
name: appraisal
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
96
94
|
none: false
|
97
95
|
requirements:
|
98
96
|
- - ~>
|
@@ -103,12 +101,12 @@ dependencies:
|
|
103
101
|
- 0
|
104
102
|
- 2
|
105
103
|
version: 1.0.2
|
104
|
+
requirement: *id005
|
106
105
|
type: :development
|
107
|
-
version_requirements: *id005
|
108
|
-
- !ruby/object:Gem::Dependency
|
109
|
-
name: rspec-rails
|
110
106
|
prerelease: false
|
111
|
-
|
107
|
+
name: cucumber-rails
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
112
110
|
none: false
|
113
111
|
requirements:
|
114
112
|
- - ~>
|
@@ -119,12 +117,12 @@ dependencies:
|
|
119
117
|
- 6
|
120
118
|
- 0
|
121
119
|
version: 2.6.0
|
120
|
+
requirement: *id006
|
122
121
|
type: :development
|
123
|
-
version_requirements: *id006
|
124
|
-
- !ruby/object:Gem::Dependency
|
125
|
-
name: sqlite3
|
126
122
|
prerelease: false
|
127
|
-
|
123
|
+
name: rspec-rails
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
128
126
|
none: false
|
129
127
|
requirements:
|
130
128
|
- - ">="
|
@@ -133,12 +131,26 @@ dependencies:
|
|
133
131
|
segments:
|
134
132
|
- 0
|
135
133
|
version: "0"
|
134
|
+
requirement: *id007
|
136
135
|
type: :development
|
137
|
-
|
136
|
+
prerelease: false
|
137
|
+
name: sqlite3
|
138
138
|
- !ruby/object:Gem::Dependency
|
139
|
-
|
139
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
hash: 3
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
version: "0"
|
148
|
+
requirement: *id008
|
149
|
+
type: :development
|
140
150
|
prerelease: false
|
141
|
-
|
151
|
+
name: bourne
|
152
|
+
- !ruby/object:Gem::Dependency
|
153
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
142
154
|
none: false
|
143
155
|
requirements:
|
144
156
|
- - ">="
|
@@ -147,8 +159,10 @@ dependencies:
|
|
147
159
|
segments:
|
148
160
|
- 0
|
149
161
|
version: "0"
|
162
|
+
requirement: *id009
|
150
163
|
type: :development
|
151
|
-
|
164
|
+
prerelease: false
|
165
|
+
name: timecop
|
152
166
|
description: Rails authentication & authorization with email & password.
|
153
167
|
email: support@thoughtbot.com
|
154
168
|
executables: []
|
@@ -209,6 +223,8 @@ files:
|
|
209
223
|
- lib/clearance/engine.rb
|
210
224
|
- lib/clearance/password_strategies.rb
|
211
225
|
- lib/clearance/password_strategies/sha1.rb
|
226
|
+
- lib/clearance/rack_session.rb
|
227
|
+
- lib/clearance/session.rb
|
212
228
|
- lib/clearance/testing.rb
|
213
229
|
- lib/clearance/testing/assertion_error.rb
|
214
230
|
- lib/clearance/testing/deny_access_matcher.rb
|
@@ -221,7 +237,10 @@ files:
|
|
221
237
|
- lib/generators/clearance/install/templates/db/migrate/upgrade_clearance_to_diesel.rb
|
222
238
|
- lib/generators/clearance/install/templates/user.rb
|
223
239
|
- lib/generators/clearance/views/views_generator.rb
|
240
|
+
- spec/clearance/rack_session_spec.rb
|
241
|
+
- spec/clearance/session_spec.rb
|
224
242
|
- spec/controllers/denies_controller_spec.rb
|
243
|
+
- spec/controllers/flashes_controller_spec.rb
|
225
244
|
- spec/controllers/forgeries_controller_spec.rb
|
226
245
|
- spec/controllers/passwords_controller_spec.rb
|
227
246
|
- spec/controllers/sessions_controller_spec.rb
|