clearance 1.0.1 → 1.1.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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/Appraisals +1 -1
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +2 -4
- data/Gemfile.lock +13 -19
- data/NEWS.md +14 -0
- data/README.md +69 -9
- data/app/controllers/clearance/sessions_controller.rb +7 -6
- data/app/views/users/new.html.erb +1 -1
- data/config/locales/clearance.en.yml +2 -0
- data/lib/clearance.rb +1 -0
- data/lib/clearance/authentication.rb +4 -2
- data/lib/clearance/configuration.rb +7 -2
- data/lib/clearance/default_sign_in_guard.rb +19 -0
- data/lib/clearance/session.rb +66 -16
- data/lib/clearance/session_status.rb +19 -0
- data/lib/clearance/sign_in_guard.rb +36 -0
- data/lib/clearance/testing/application.rb +2 -1
- data/lib/clearance/user.rb +1 -1
- data/lib/clearance/version.rb +1 -1
- data/spec/clearance/session_spec.rb +207 -35
- data/spec/clearance/sign_in_guard_spec.rb +29 -0
- data/spec/configuration_spec.rb +51 -27
- data/spec/controllers/apis_controller_spec.rb +0 -6
- data/spec/controllers/permissions_controller_spec.rb +70 -0
- data/spec/controllers/sessions_controller_spec.rb +1 -1
- data/spec/models/user_spec.rb +2 -0
- metadata +10 -5
- data/spec/controllers/denies_controller_spec.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0e5c1ad076dc7b6d2437299cd7888a0112eb892
|
4
|
+
data.tar.gz: fbe33eb3eca23b455dd535d7d6c7df5af9e85d53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c34b9bb7f111bc599149e006fbee5e3a98e6c7bbf00797469781585b9a846ae4900d1deed564795ef3da81f62dfe7a691f69f14b574c17091a2e158f2fa3956
|
7
|
+
data.tar.gz: 66f14e544e08dbf94d16ca3066750abe3d444280ff2dae2dc6782e90790efc6ce066234bc2592bffb0e5c4c01f1c3578c69d9529afc75411eca24fe2f95291dc
|
data/.travis.yml
CHANGED
data/Appraisals
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -9,8 +9,8 @@ We love pull requests. Here's a quick guide:
|
|
9
9
|
to know that you have a clean slate: `rake`
|
10
10
|
|
11
11
|
4. Add a test for your change. Only refactoring and documentation changes
|
12
|
-
require no new tests. If you are adding functionality or fixing a
|
13
|
-
a test!
|
12
|
+
require no new tests. If you are adding functionality or fixing a
|
13
|
+
bug, we need a test!
|
14
14
|
|
15
15
|
5. Make the test pass.
|
16
16
|
|
data/Gemfile
CHANGED
@@ -7,14 +7,12 @@ gem 'aruba', '~> 0.5'
|
|
7
7
|
gem 'bourne', '~> 1.4'
|
8
8
|
gem 'bundler', '~> 1.3'
|
9
9
|
gem 'capybara', '~> 2.0.3'
|
10
|
-
gem 'cucumber-rails', '~> 1.3'
|
10
|
+
gem 'cucumber-rails', '~> 1.3', require: false
|
11
11
|
gem 'database_cleaner', '~> 1.0'
|
12
12
|
gem 'factory_girl_rails', '~> 4.2'
|
13
13
|
gem 'jbuilder', '~> 1.2'
|
14
14
|
gem 'rspec-rails', '~> 2.13'
|
15
15
|
gem 'sdoc'
|
16
|
-
gem 'shoulda-matchers',
|
17
|
-
github: 'thoughtbot/shoulda-matchers',
|
18
|
-
branch: 'dp-rails-four'
|
16
|
+
gem 'shoulda-matchers', '~> 2.4'
|
19
17
|
gem 'sqlite3', '~> 1.3'
|
20
18
|
gem 'timecop', '~> 0.6'
|
data/Gemfile.lock
CHANGED
@@ -1,15 +1,7 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git://github.com/thoughtbot/shoulda-matchers.git
|
3
|
-
revision: 2b452d5d3970e7319d0d4ea82942960616e05453
|
4
|
-
branch: dp-rails-four
|
5
|
-
specs:
|
6
|
-
shoulda-matchers (2.2.0)
|
7
|
-
activesupport (>= 3.0.0)
|
8
|
-
|
9
1
|
PATH
|
10
2
|
remote: .
|
11
3
|
specs:
|
12
|
-
clearance (1.0
|
4
|
+
clearance (1.1.0)
|
13
5
|
bcrypt-ruby
|
14
6
|
email_validator (~> 1.4)
|
15
7
|
rails (>= 3.1)
|
@@ -44,13 +36,13 @@ GEM
|
|
44
36
|
appraisal (0.5.2)
|
45
37
|
bundler
|
46
38
|
rake
|
47
|
-
arel (4.0.
|
39
|
+
arel (4.0.1)
|
48
40
|
aruba (0.5.3)
|
49
41
|
childprocess (>= 0.3.6)
|
50
42
|
cucumber (>= 1.1.1)
|
51
43
|
rspec-expectations (>= 2.7.0)
|
52
|
-
atomic (1.1.
|
53
|
-
bcrypt-ruby (3.1.
|
44
|
+
atomic (1.1.14)
|
45
|
+
bcrypt-ruby (3.1.2)
|
54
46
|
bourne (1.5.0)
|
55
47
|
mocha (>= 0.13.2, < 0.15)
|
56
48
|
builder (3.1.4)
|
@@ -87,7 +79,7 @@ GEM
|
|
87
79
|
gherkin (2.12.0)
|
88
80
|
multi_json (~> 1.3)
|
89
81
|
hike (1.2.3)
|
90
|
-
i18n (0.6.
|
82
|
+
i18n (0.6.5)
|
91
83
|
jbuilder (1.5.0)
|
92
84
|
activesupport (>= 3.0.0)
|
93
85
|
multi_json (>= 1.2.0)
|
@@ -101,7 +93,7 @@ GEM
|
|
101
93
|
minitest (4.7.5)
|
102
94
|
mocha (0.14.0)
|
103
95
|
metaclass (~> 0.0.1)
|
104
|
-
multi_json (1.7.
|
96
|
+
multi_json (1.7.9)
|
105
97
|
multi_test (0.0.2)
|
106
98
|
nokogiri (1.6.0)
|
107
99
|
mini_portile (~> 0.5.0)
|
@@ -145,25 +137,27 @@ GEM
|
|
145
137
|
multi_json (~> 1.0)
|
146
138
|
rubyzip
|
147
139
|
websocket (~> 1.0.4)
|
140
|
+
shoulda-matchers (2.4.0)
|
141
|
+
activesupport (>= 3.0.0)
|
148
142
|
sprockets (2.10.0)
|
149
143
|
hike (~> 1.2)
|
150
144
|
multi_json (~> 1.0)
|
151
145
|
rack (~> 1.0)
|
152
146
|
tilt (~> 1.1, != 1.3.0)
|
153
|
-
sprockets-rails (2.0.
|
147
|
+
sprockets-rails (2.0.1)
|
154
148
|
actionpack (>= 3.0)
|
155
149
|
activesupport (>= 3.0)
|
156
150
|
sprockets (~> 2.8)
|
157
151
|
sqlite3 (1.3.7)
|
158
152
|
thor (0.18.1)
|
159
|
-
thread_safe (0.1.
|
153
|
+
thread_safe (0.1.3)
|
160
154
|
atomic
|
161
155
|
tilt (1.4.1)
|
162
156
|
timecop (0.6.2.2)
|
163
|
-
treetop (1.4.
|
157
|
+
treetop (1.4.15)
|
164
158
|
polyglot
|
165
159
|
polyglot (>= 0.3.1)
|
166
|
-
tzinfo (0.3.
|
160
|
+
tzinfo (0.3.38)
|
167
161
|
websocket (1.0.7)
|
168
162
|
xpath (1.0.0)
|
169
163
|
nokogiri (~> 1.3)
|
@@ -184,6 +178,6 @@ DEPENDENCIES
|
|
184
178
|
jbuilder (~> 1.2)
|
185
179
|
rspec-rails (~> 2.13)
|
186
180
|
sdoc
|
187
|
-
shoulda-matchers
|
181
|
+
shoulda-matchers (~> 2.4)
|
188
182
|
sqlite3 (~> 1.3)
|
189
183
|
timecop (~> 0.6)
|
data/NEWS.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
Thank you to all the [contributors](https://github.com/thoughtbot/clearance/graphs/contributors)!
|
2
2
|
|
3
|
+
New for 1.1.0 (November 21, 2013):
|
4
|
+
|
5
|
+
* Validate email with `EmailValidator` [strict mode][strict].
|
6
|
+
* The `cookie_expiration` configuration lambda can now be called with a
|
7
|
+
`cookies` parameter. allows the Clearance cookie expiration to be set
|
8
|
+
according to the value of another cookie (such as `remember_me`).
|
9
|
+
* A `cookie_expiration` lambda that does not accept this `cookies`
|
10
|
+
parameter has been deprecated.
|
11
|
+
* Allow cookie domain and path configuration.
|
12
|
+
* Add sign in guards.
|
13
|
+
* Don't allow logins with blank `remember_token`.
|
14
|
+
|
15
|
+
[strict]: https://github.com/balexand/email_validator#strict-mode
|
16
|
+
|
3
17
|
New for 1.0.1 (August 9, 2013):
|
4
18
|
|
5
19
|
* Fix an issue when trying to sign in with `nil`
|
data/README.md
CHANGED
@@ -8,9 +8,10 @@ Clearance
|
|
8
8
|
Rails authentication with email & password.
|
9
9
|
|
10
10
|
Clearance was extracted out of [Airbrake](http://airbrake.io/). It is intended
|
11
|
-
to be small, simple, well-tested
|
11
|
+
to be small, simple, and well-tested. It is intended to be easy to override
|
12
|
+
defaults.
|
12
13
|
|
13
|
-
Use [
|
14
|
+
Use [GitHub Issues](https://github.com/thoughtbot/clearance/issues) for help.
|
14
15
|
|
15
16
|
Read [CONTRIBUTING.md](/CONTRIBUTING.md) to contribute.
|
16
17
|
|
@@ -23,7 +24,7 @@ It works with Rails 4 and Ruby 2.
|
|
23
24
|
Include the gem in your Gemfile:
|
24
25
|
|
25
26
|
```ruby
|
26
|
-
gem 'clearance'
|
27
|
+
gem 'clearance'
|
27
28
|
```
|
28
29
|
|
29
30
|
Bundle:
|
@@ -43,10 +44,11 @@ The generator:
|
|
43
44
|
|
44
45
|
Then, follow the instructions output from the generator.
|
45
46
|
|
46
|
-
Use Clearance [0.8.8](https://github.com/thoughtbot/clearance/tree/v0.8.8)
|
47
|
-
|
47
|
+
Use Clearance [0.8.8](https://github.com/thoughtbot/clearance/tree/v0.8.8) for
|
48
|
+
Rails 2 apps.
|
48
49
|
|
49
|
-
Use [0.16.3](http://rubygems.org/gems/clearance/versions/0.16.3) for
|
50
|
+
Use Clearance [0.16.3](http://rubygems.org/gems/clearance/versions/0.16.3) for
|
51
|
+
Ruby 1.8.7 apps.
|
50
52
|
|
51
53
|
Configure
|
52
54
|
---------
|
@@ -55,12 +57,15 @@ Override any of these defaults in `config/initializers/clearance.rb`:
|
|
55
57
|
|
56
58
|
```ruby
|
57
59
|
Clearance.configure do |config|
|
58
|
-
config.
|
60
|
+
config.cookie_domain = '.example.com'
|
61
|
+
config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc }
|
62
|
+
config.cookie_path = '/'
|
59
63
|
config.httponly = false
|
60
64
|
config.mailer_sender = 'reply@example.com'
|
61
65
|
config.password_strategy = Clearance::PasswordStrategies::BCrypt
|
62
66
|
config.redirect_url = '/'
|
63
67
|
config.secure_cookie = false
|
68
|
+
config.sign_in_guards = []
|
64
69
|
config.user_model = User
|
65
70
|
end
|
66
71
|
```
|
@@ -314,15 +319,25 @@ class AddSaltToUsers < ActiveRecord::Migration
|
|
314
319
|
end
|
315
320
|
```
|
316
321
|
|
317
|
-
You can write a custom password strategy that has two instance methods
|
322
|
+
You can write a custom password strategy that has two instance methods.
|
323
|
+
In your `authenticated?` method, encrypt the password with your desired
|
324
|
+
strategy, and then compare it to the `encrypted_password` that is provided by
|
325
|
+
Clearance.
|
318
326
|
|
319
327
|
```ruby
|
320
328
|
module CustomPasswordStrategy
|
321
|
-
def authenticated?
|
329
|
+
def authenticated?(password)
|
330
|
+
encrypted_password == encrypt(password)
|
322
331
|
end
|
323
332
|
|
324
333
|
def password=(new_password)
|
325
334
|
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
def encrypt
|
339
|
+
# your encryption strategy
|
340
|
+
end
|
326
341
|
end
|
327
342
|
|
328
343
|
Clearance.configure do |config|
|
@@ -354,6 +369,51 @@ Then, override the route:
|
|
354
369
|
resources :passwords, only: [:create]
|
355
370
|
```
|
356
371
|
|
372
|
+
Using the SignInGuard stack
|
373
|
+
-------------------
|
374
|
+
|
375
|
+
`SignInGuard`s offer fine-grained control over the process of
|
376
|
+
signing in a user. Each guard is run in order and hands the session off to
|
377
|
+
the next guard in the stack.
|
378
|
+
|
379
|
+
A `SignInGuard` is an object that responds to `call`. It is initialized with a
|
380
|
+
session and the current stack.
|
381
|
+
|
382
|
+
On success, a guard should call the next guard or return `SuccessStatus.new` if
|
383
|
+
you don't want any subsequent guards to run.
|
384
|
+
|
385
|
+
On failure, a guard should call `FailureStatus.new(failure_message)`. It can
|
386
|
+
provide a message explaining the failure.
|
387
|
+
|
388
|
+
For convenience, a [SignInGuard](lib/clearance/sign_in_guard.rb) class has been
|
389
|
+
provided and can be inherited from. The convenience class provides a few methods
|
390
|
+
to help make writing guards simple: `success`, `failure`, `next_guard`,
|
391
|
+
`signed_in?`, and `current_user`.
|
392
|
+
|
393
|
+
Here's an example custom guard to handle email confirmation:
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
Clearance.configure do |config|
|
397
|
+
config.sign_in_guards = [EmailConfirmationGuard]
|
398
|
+
end
|
399
|
+
```
|
400
|
+
|
401
|
+
```ruby
|
402
|
+
class EmailConfirmationGuard < Clearance::SignInGuard
|
403
|
+
def call
|
404
|
+
if unconfirmed?
|
405
|
+
failure("You must confirm your email address.")
|
406
|
+
else
|
407
|
+
next_guard
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
def unconfirmed?
|
412
|
+
signed_in? && !current_user.confirmed_at
|
413
|
+
end
|
414
|
+
end
|
415
|
+
```
|
416
|
+
|
357
417
|
Optional feature specs
|
358
418
|
----------------------
|
359
419
|
|
@@ -5,12 +5,13 @@ class Clearance::SessionsController < ApplicationController
|
|
5
5
|
def create
|
6
6
|
@user = authenticate(params)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
sign_in(@user) do |status|
|
9
|
+
if status.success?
|
10
|
+
redirect_back_or url_after_create
|
11
|
+
else
|
12
|
+
flash.now.notice = status.failure_message
|
13
|
+
render :template => 'sessions/new', :status => :unauthorized
|
14
|
+
end
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
data/lib/clearance.rb
CHANGED
@@ -25,11 +25,13 @@ module Clearance
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def current_user=(user)
|
28
|
+
warn 'DEPRECATION WARNING: Assigning the current_user this way has been' +
|
29
|
+
' deprecated. You should instead use the sign_in method.'
|
28
30
|
clearance_session.sign_in user
|
29
31
|
end
|
30
32
|
|
31
|
-
def sign_in(user)
|
32
|
-
clearance_session.sign_in user
|
33
|
+
def sign_in(user, &block)
|
34
|
+
clearance_session.sign_in user, &block
|
33
35
|
end
|
34
36
|
|
35
37
|
def sign_out
|
@@ -1,20 +1,25 @@
|
|
1
1
|
module Clearance
|
2
2
|
class Configuration
|
3
3
|
attr_accessor \
|
4
|
+
:cookie_domain,
|
4
5
|
:cookie_expiration,
|
6
|
+
:cookie_path,
|
5
7
|
:httponly,
|
6
8
|
:mailer_sender,
|
7
9
|
:password_strategy,
|
8
10
|
:redirect_url,
|
9
11
|
:secure_cookie,
|
12
|
+
:sign_in_guards,
|
10
13
|
:user_model
|
11
14
|
|
12
15
|
def initialize
|
13
|
-
@cookie_expiration =
|
16
|
+
@cookie_expiration = ->(cookies) { 1.year.from_now.utc }
|
17
|
+
@cookie_path = '/'
|
14
18
|
@httponly = false
|
15
19
|
@mailer_sender = 'reply@example.com'
|
16
|
-
@secure_cookie = false
|
17
20
|
@redirect_url = '/'
|
21
|
+
@secure_cookie = false
|
22
|
+
@sign_in_guards = []
|
18
23
|
end
|
19
24
|
|
20
25
|
def user_model
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Clearance
|
2
|
+
class DefaultSignInGuard < SignInGuard
|
3
|
+
def call
|
4
|
+
if session.signed_in?
|
5
|
+
success
|
6
|
+
else
|
7
|
+
failure default_failure_message.html_safe
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_failure_message
|
12
|
+
I18n.t("flashes.failure_after_create", :sign_up_path => sign_up_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def sign_up_path
|
16
|
+
Rails.application.routes.url_helpers.sign_up_path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/clearance/session.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'clearance/default_sign_in_guard'
|
2
|
+
|
1
3
|
module Clearance
|
2
4
|
class Session
|
3
5
|
REMEMBER_TOKEN_COOKIE = 'remember_token'.freeze
|
@@ -7,26 +9,30 @@ module Clearance
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def add_cookie_to_headers(headers)
|
10
|
-
Rack::Utils.set_cookie_header!(
|
11
|
-
headers,
|
12
|
-
REMEMBER_TOKEN_COOKIE,
|
13
|
-
:value => remember_token,
|
14
|
-
:expires => Clearance.configuration.cookie_expiration.call,
|
15
|
-
:secure => Clearance.configuration.secure_cookie,
|
16
|
-
:httponly => Clearance.configuration.httponly,
|
17
|
-
:path => '/'
|
18
|
-
)
|
12
|
+
Rack::Utils.set_cookie_header!(headers, REMEMBER_TOKEN_COOKIE, cookie_value)
|
19
13
|
end
|
20
14
|
|
21
15
|
def current_user
|
22
|
-
|
23
|
-
|
16
|
+
if remember_token.present?
|
17
|
+
@current_user ||= user_from_remember_token(remember_token)
|
24
18
|
end
|
19
|
+
|
20
|
+
@current_user
|
25
21
|
end
|
26
22
|
|
27
|
-
def sign_in(user)
|
28
|
-
cookies[REMEMBER_TOKEN_COOKIE] = user && user.remember_token
|
23
|
+
def sign_in(user, &block)
|
29
24
|
@current_user = user
|
25
|
+
status = run_sign_in_stack
|
26
|
+
|
27
|
+
if status.success?
|
28
|
+
cookies[REMEMBER_TOKEN_COOKIE] = user && user.remember_token
|
29
|
+
else
|
30
|
+
@current_user = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
if block_given?
|
34
|
+
block.call(status)
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
def sign_out
|
@@ -56,10 +62,54 @@ module Clearance
|
|
56
62
|
cookies[REMEMBER_TOKEN_COOKIE]
|
57
63
|
end
|
58
64
|
|
59
|
-
def
|
60
|
-
if
|
61
|
-
|
65
|
+
def remember_token_expires
|
66
|
+
if expires_configuration.arity == 1
|
67
|
+
expires_configuration.call(cookies)
|
68
|
+
else
|
69
|
+
warn 'DEPRECATION WARNING: Clearance.configuration.cookie_expiration' +
|
70
|
+
'lambda with no parameters has been deprecated and will be removed' +
|
71
|
+
' from a future release. The lambda should accept the collection' +
|
72
|
+
' of previously set cookies.'
|
73
|
+
expires_configuration.call
|
62
74
|
end
|
63
75
|
end
|
76
|
+
|
77
|
+
def expires_configuration
|
78
|
+
Clearance.configuration.cookie_expiration
|
79
|
+
end
|
80
|
+
|
81
|
+
def user_from_remember_token(token)
|
82
|
+
Clearance.configuration.user_model.where(remember_token: token).first
|
83
|
+
end
|
84
|
+
|
85
|
+
def run_sign_in_stack
|
86
|
+
@stack ||= initialize_sign_in_guard_stack
|
87
|
+
@stack.call
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize_sign_in_guard_stack
|
91
|
+
default_guard = DefaultSignInGuard.new(self)
|
92
|
+
guards = Clearance.configuration.sign_in_guards
|
93
|
+
|
94
|
+
guards.inject(default_guard) do |stack, guard_class|
|
95
|
+
guard_class.new(self, stack)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def cookie_value
|
100
|
+
value = {
|
101
|
+
:expires => remember_token_expires,
|
102
|
+
:httponly => Clearance.configuration.httponly,
|
103
|
+
:path => Clearance.configuration.cookie_path,
|
104
|
+
:secure => Clearance.configuration.secure_cookie,
|
105
|
+
:value => remember_token
|
106
|
+
}
|
107
|
+
|
108
|
+
if Clearance.configuration.cookie_domain.present?
|
109
|
+
value[:domain] = Clearance.configuration.cookie_domain
|
110
|
+
end
|
111
|
+
|
112
|
+
value
|
113
|
+
end
|
64
114
|
end
|
65
115
|
end
|