janus 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +65 -29
- data/lib/janus.rb +1 -13
- data/lib/janus/config.rb +9 -5
- data/lib/janus/controllers/confirmations_controller.rb +2 -0
- data/lib/janus/controllers/helpers.rb +17 -0
- data/lib/janus/controllers/internal_helpers.rb +12 -0
- data/lib/janus/controllers/passwords_controller.rb +3 -0
- data/lib/janus/controllers/sessions_controller.rb +58 -21
- data/lib/janus/manager.rb +7 -2
- data/lib/janus/models/database_authenticatable.rb +22 -6
- data/lib/janus/rails.rb +17 -0
- data/lib/janus/routes.rb +1 -2
- data/lib/janus/sinatra.rb +51 -0
- metadata +63 -169
- data/test/functional/home_controller_test.rb +0 -8
- data/test/functional/janus/mailer_test.rb +0 -14
- data/test/functional/janus/manager_test.rb +0 -94
- data/test/functional/users/confirmations_controller_test.rb +0 -59
- data/test/functional/users/passwords_controller_test.rb +0 -101
- data/test/functional/users/registrations_controller_test.rb +0 -112
- data/test/functional/users/sessions_controller_test.rb +0 -100
- data/test/functional/users_controller_test.rb +0 -22
- data/test/integration/users/rememberable_test.rb +0 -32
- data/test/integration/users/remote_test.rb +0 -72
- data/test/integration/users/sessions_test.rb +0 -18
- data/test/integration/users/trackable_test.rb +0 -22
- data/test/rails_app/app/controllers/application_controller.rb +0 -9
- data/test/rails_app/app/controllers/blogs_controller.rb +0 -6
- data/test/rails_app/app/controllers/home_controller.rb +0 -4
- data/test/rails_app/app/controllers/users/confirmations_controller.rb +0 -3
- data/test/rails_app/app/controllers/users/passwords_controller.rb +0 -3
- data/test/rails_app/app/controllers/users/registrations_controller.rb +0 -7
- data/test/rails_app/app/controllers/users/sessions_controller.rb +0 -11
- data/test/rails_app/app/controllers/users_controller.rb +0 -9
- data/test/rails_app/app/helpers/application_helper.rb +0 -2
- data/test/rails_app/app/mailers/janus_mailer.rb +0 -2
- data/test/rails_app/app/models/remote_token.rb +0 -6
- data/test/rails_app/app/models/user.rb +0 -8
- data/test/rails_app/config/application.rb +0 -42
- data/test/rails_app/config/boot.rb +0 -6
- data/test/rails_app/config/environment.rb +0 -5
- data/test/rails_app/config/environments/development.rb +0 -26
- data/test/rails_app/config/environments/production.rb +0 -49
- data/test/rails_app/config/environments/test.rb +0 -36
- data/test/rails_app/config/initializers/janus.rb +0 -11
- data/test/rails_app/config/initializers/secret_token.rb +0 -7
- data/test/rails_app/config/initializers/session_store.rb +0 -8
- data/test/rails_app/config/routes.rb +0 -12
- data/test/rails_app/db/migrate/20110323153820_create_users.rb +0 -34
- data/test/rails_app/db/migrate/20110331153546_create_remote_tokens.rb +0 -15
- data/test/rails_app/db/schema.rb +0 -45
- data/test/rails_app/db/seeds.rb +0 -7
- data/test/test_helper.rb +0 -103
- data/test/unit/confirmable_test.rb +0 -36
- data/test/unit/janus_test.rb +0 -27
- data/test/unit/rememberable_test.rb +0 -50
- data/test/unit/remote_authenticatable_test.rb +0 -37
- data/test/unit/remote_token_test.rb +0 -9
- data/test/unit/reset_password_test.rb +0 -45
- data/test/unit/trackable_test.rb +0 -21
- data/test/unit/user_test.rb +0 -60
data/README.rdoc
CHANGED
@@ -2,48 +2,86 @@
|
|
2
2
|
|
3
3
|
Janus is an authentication engine for Ruby on Rails 3 and is an alternative
|
4
4
|
to the Warden + Devise combo, without the Rack middleware. The whole project
|
5
|
-
is inspired by the Warden and Devise API
|
6
|
-
different since everything happens within ActionDispatch and not
|
7
|
-
level.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
is inspired by the Warden and Devise API (in order to somehow compatible)
|
6
|
+
but is quite different since everything happens within ActionDispatch and not
|
7
|
+
at the Rack level.
|
8
|
+
|
9
|
+
This Rails instead of Rack difference, allows to actually have the main logic
|
10
|
+
within plain Rails controllers. For instance the database authentication is
|
11
|
+
called from SessionsController, and it's not just another strategy operating
|
12
|
+
at the Rack level within Warden (which requires to check that it's being
|
13
|
+
called from the correct URL). There ain't no factory to add strategy modules
|
14
|
+
to your models too. You must manually include the necessary ones.
|
15
|
+
|
16
|
+
Another difference is that you must actually create the necessary controllers,
|
17
|
+
models, mailers and views within your project (extending the default ones).
|
18
|
+
You will eventually need to have those controllers anyway, and having those
|
19
|
+
from the beginning allows to skip some configuration. The burdensome of
|
20
|
+
manually creating all those classes should eventually be leveraged by using
|
21
|
+
some rails generators.
|
22
|
+
|
23
|
+
Janus also provides a finer control over setting and unsetting a user than
|
24
|
+
Warden provides. Janus uses +login+ and +logout+ to actually sign the user
|
25
|
+
in and out, just like Warden, but actually uses +set_user+ and +unset_user+
|
26
|
+
to manually set the session, without dispatching the +after_login+ and
|
27
|
+
+after_logout+ hooks, of course.
|
28
|
+
|
29
|
+
Emails are also sent from the controllers, not from the models, because I
|
30
|
+
believe this is actually the job of controllers, not models.
|
15
31
|
|
16
32
|
== Features
|
17
33
|
|
34
|
+
The main feature is of course having a framework for authenticating users
|
35
|
+
painleslly. Yet a very usefull feature is the cross domain authentication
|
36
|
+
--which allows a user to single sign in and out across top level domains.
|
37
|
+
|
38
|
+
How is the cross domain authentication strategy usefull? Let's imagine you
|
39
|
+
host of blogging website where users may host their blogs on other domains.
|
40
|
+
Since you don't rely on subdomains, it will be a pain to keep the user
|
41
|
+
authentified, because you can't rely on '.' domain cookie trick.
|
42
|
+
|
43
|
+
This is where RemoteAuthentication comes in, and allows you to painlessly
|
44
|
+
keep your users connected across the main website and their blogs. This
|
45
|
+
without actually tracking connections since this strategy takes advantage
|
46
|
+
of the +set_user+ and +unset_user+ methods, because they're not really
|
47
|
+
signing in, they just stay authentified across domains.
|
48
|
+
|
49
|
+
So, Janus provides the following API:
|
50
|
+
|
51
|
+
- full authentication system with strategies and hooks
|
52
|
+
- scoped authentications with parallel authentication (like `users`, `admin_users`, etc.)
|
53
|
+
- database authentication with password encryption (bcrypt) and validation
|
54
|
+
- remote authentication for cross domain single sign in / sign out
|
55
|
+
- abstract controllers for session management, registration, email confirmation and password reset
|
56
|
+
- route generation for the above controllers
|
57
|
+
|
58
|
+
And for the strategies and hooks:
|
59
|
+
|
18
60
|
- DatabaseAuthenticatable
|
19
61
|
- RemoteAuthenticatable
|
20
62
|
- Confirmable
|
21
63
|
- Rememberable
|
22
|
-
- Trackable
|
23
|
-
|
24
|
-
Note: login through Janus::Manager#set_user won't track the user.
|
25
|
-
|
26
|
-
- authentication system with strategies and hooks
|
27
|
-
- scoped authentications with parallel authentication
|
28
|
-
- database authentication with password encryption, validation and remember me strategy
|
29
|
-
- remote authentication for cross domain sign in / sign out
|
30
|
-
- controllers: sessions, registrations, confirmations, passwords and their routes
|
31
|
-
- route generation for above controllers
|
32
|
-
- trackable hook
|
64
|
+
- Trackable (note that login through Janus::Manager#set_user won't track the user).
|
33
65
|
|
34
66
|
== TODO
|
35
67
|
|
36
|
-
-
|
37
|
-
-
|
68
|
+
- Simple configuration to use scrypt instead of bcrypt for password encryption.
|
69
|
+
- Reconfirmable when email changes.
|
70
|
+
- TokenAuthenticatable.
|
71
|
+
- Remember me on remote authenticated domains.
|
72
|
+
- Differenciate mailers per resource, by looking for Users::Mailer class.
|
73
|
+
- Generators: `janus:install` and `janus <scope>`.
|
74
|
+
- Integrate OmniAuth, or shall we let the user do it himself?
|
75
|
+
- Providing an OAuth 2.0 server whould be cool.
|
38
76
|
|
39
77
|
== Install
|
40
78
|
|
41
|
-
There is no automated way to install Janus yet,
|
42
|
-
|
79
|
+
There is no automated way to install Janus yet, because generators are missing.
|
80
|
+
Also remember that Janus is only compatible with Rails 3+.
|
43
81
|
|
44
82
|
First add the gem to your Gemfile:
|
45
83
|
|
46
|
-
$ gem 'janus'
|
84
|
+
$ gem 'janus'
|
47
85
|
|
48
86
|
Configure your user models by including all or a selection of the Janus::Models
|
49
87
|
modules:
|
@@ -60,7 +98,6 @@ modules:
|
|
60
98
|
class Admin < ActiveRecord::Base
|
61
99
|
include Janus::Models::Base
|
62
100
|
include Janus::Models::DatabaseAuthenticatable
|
63
|
-
include Janus::Models::RemoteAuthenticatable
|
64
101
|
end
|
65
102
|
|
66
103
|
Configure your routes:
|
@@ -68,7 +105,6 @@ Configure your routes:
|
|
68
105
|
Name::Application.routes.map do
|
69
106
|
janus :users, :session => true, :registration => true, :password => true, :confirmation => true
|
70
107
|
janus :admins, :session => true
|
71
|
-
|
72
108
|
root :to => "home#index"
|
73
109
|
end
|
74
110
|
|
@@ -86,7 +122,7 @@ Create the required controllers:
|
|
86
122
|
respond_to :html
|
87
123
|
end
|
88
124
|
|
89
|
-
class Users::
|
125
|
+
class Users::ConfirmationsController < Janus::ConfirmationsController
|
90
126
|
respond_to :html
|
91
127
|
end
|
92
128
|
|
data/lib/janus.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
+
require 'active_support/core_ext/class'
|
1
2
|
require 'janus/config'
|
2
3
|
require 'janus/hooks'
|
3
4
|
require 'janus/strategies'
|
4
5
|
require 'janus/manager'
|
5
|
-
require 'janus/routes'
|
6
6
|
|
7
7
|
autoload :JanusHelper, 'janus/helper'
|
8
8
|
|
@@ -16,18 +16,6 @@ module Janus
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
autoload :Mailer, 'janus/mailer'
|
20
|
-
autoload :TestHelper, 'janus/test_helper'
|
21
|
-
|
22
|
-
autoload :Helpers, 'janus/controllers/helpers'
|
23
|
-
autoload :UrlHelpers, 'janus/controllers/url_helpers'
|
24
|
-
autoload :InternalHelpers, 'janus/controllers/internal_helpers'
|
25
|
-
|
26
|
-
autoload :SessionsController, 'janus/controllers/sessions_controller'
|
27
|
-
autoload :RegistrationsController, 'janus/controllers/registrations_controller'
|
28
|
-
autoload :ConfirmationsController, 'janus/controllers/confirmations_controller'
|
29
|
-
autoload :PasswordsController, 'janus/controllers/passwords_controller'
|
30
|
-
|
31
19
|
module Models
|
32
20
|
autoload :Base, 'janus/models/base'
|
33
21
|
autoload :DatabaseAuthenticatable, 'janus/models/database_authenticatable'
|
data/lib/janus/config.rb
CHANGED
@@ -5,17 +5,21 @@ module Janus
|
|
5
5
|
mattr_accessor :contact_email
|
6
6
|
|
7
7
|
# DatabaseAuthenticatable
|
8
|
-
mattr_accessor :authentication_keys, :stretches, :pepper
|
9
|
-
self.authentication_keys = [:email]
|
8
|
+
mattr_accessor :authentication_keys, :encryptor, :stretches, :pepper, :scrypt_options
|
9
|
+
self.authentication_keys = [ :email ]
|
10
|
+
self.encryptor = :bcrypt
|
10
11
|
self.stretches = 10
|
12
|
+
self.pepper = nil
|
13
|
+
self.scrypt_options = { :max_time => 0.25 }
|
11
14
|
|
12
15
|
# Confirmable
|
13
|
-
mattr_accessor :confirmation_key
|
16
|
+
mattr_accessor :confirmation_key #,reconfirmable
|
14
17
|
self.confirmation_key = :confirm_token
|
18
|
+
# self.reconfirmable = true
|
15
19
|
|
16
20
|
# Rememberable
|
17
|
-
mattr_accessor :remember_for, :extend_remember_period
|
18
|
-
self.remember_for =
|
21
|
+
mattr_accessor :remember_for, :extend_remember_period #, :remember_across_browsers
|
22
|
+
self.remember_for = 1.year
|
19
23
|
self.extend_remember_period = false
|
20
24
|
# self.remember_across_browsers = false
|
21
25
|
|
@@ -13,19 +13,36 @@ module Janus
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
# Returns the current instance of Janus::Manager.
|
16
17
|
def janus
|
17
18
|
@janus ||= Janus::Manager.new(request, cookies)
|
18
19
|
end
|
19
20
|
|
21
|
+
# Signs the current user out (from all scopes at once) in case of a CSRF attack.
|
22
|
+
# See ActionController::RequestForgeryProtection for documentation.
|
20
23
|
def handle_unverified_requests
|
21
24
|
janus.logout
|
25
|
+
super
|
22
26
|
end
|
23
27
|
|
28
|
+
# Returns true if a scope user is currently authenticated.
|
24
29
|
def signed_in?(scope)
|
25
30
|
janus.authenticate?(scope)
|
26
31
|
end
|
27
32
|
|
28
33
|
module ClassMethods
|
34
|
+
# Aliases some Janus methods for convenience. For instance calling
|
35
|
+
# `janus(:user, :admin)` will generate the following methods:
|
36
|
+
#
|
37
|
+
# authenticate_user! # => janus.authenticate!(:user)
|
38
|
+
# current_user # => janus.authenticate(:user)
|
39
|
+
# user_signed_in? # => janus.authenticate?(:user)
|
40
|
+
# user_session # => janus.sesssion(:user)
|
41
|
+
#
|
42
|
+
# authenticate_admin! # => janus.authenticate!(:admin)
|
43
|
+
# current_admin # => janus.authenticate(:admin)
|
44
|
+
# admin_signed_in? # => janus.authenticate?(:admin)
|
45
|
+
# admin_session # => janus.sesssion(:admin)
|
29
46
|
def janus(*scopes)
|
30
47
|
scopes.each do |scope|
|
31
48
|
class_eval <<-EOV
|
@@ -1,4 +1,7 @@
|
|
1
1
|
module Janus
|
2
|
+
# A collection of abstraction helper methods used in Janus controllers and views.
|
3
|
+
# This should be of no particular outside of abstract controllers for Janus that
|
4
|
+
# must be working for all scopes at once.
|
2
5
|
module InternalHelpers
|
3
6
|
extend ActiveSupport::Concern
|
4
7
|
|
@@ -6,26 +9,35 @@ module Janus
|
|
6
9
|
helper_method :janus_scope, :resource, :resource_class, :resource_name
|
7
10
|
end
|
8
11
|
|
12
|
+
# Abstract method for the authenticate_scope! before filter, with scope
|
13
|
+
# as detected by janus_scope.
|
9
14
|
def authenticate!
|
10
15
|
send("authenticate_#{janus_scope}!")
|
11
16
|
end
|
12
17
|
|
18
|
+
# Detects the scope from the controller name.
|
13
19
|
def janus_scope
|
14
20
|
@janus_scope ||= self.class.name.split('::', 2).first.underscore.singularize
|
15
21
|
end
|
16
22
|
|
23
|
+
# Returns the `@user` instance variable (or `@admin` or whatever),
|
24
|
+
# as detected by janus_scope.
|
17
25
|
def resource
|
18
26
|
instance_variable_get(:"@#{janus_scope}")
|
19
27
|
end
|
20
28
|
|
29
|
+
# Sets the `@user` instance variable (or `@admin` or whatever),
|
30
|
+
# as detected by janus_scope.
|
21
31
|
def resource=(value)
|
22
32
|
instance_variable_set(:"@#{janus_scope}", value)
|
23
33
|
end
|
24
34
|
|
35
|
+
# Returns the `User` class (or `Admin` or whatever) as detected by janus_scope.
|
25
36
|
def resource_class
|
26
37
|
@resource_class ||= janus_scope.camelize.constantize
|
27
38
|
end
|
28
39
|
|
40
|
+
# Alias for janus_scope.
|
29
41
|
def resource_name
|
30
42
|
janus_scope
|
31
43
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This controller is responsible for resetting a lost password. It sends an
|
2
|
+
# email with an unique token, on demand by the user. Then allows the user to
|
3
|
+
# change its password (as long as the token is valid).
|
1
4
|
class Janus::PasswordsController < ApplicationController
|
2
5
|
include Janus::InternalHelpers
|
3
6
|
|
@@ -1,5 +1,13 @@
|
|
1
1
|
require 'addressable/uri'
|
2
2
|
|
3
|
+
# This controller is responsible for creating and destroying
|
4
|
+
# authenticated user sessions.
|
5
|
+
#
|
6
|
+
# The creation uses the DatabaseAuthenticatable strategy, while the destruction
|
7
|
+
# simply destroys any session, whatever strategy it was created with. Janus
|
8
|
+
# hooks will be called, of course, allowing to destroy any Rememberable cookies
|
9
|
+
# for instance, as well as any user defined behavior.
|
10
|
+
#
|
3
11
|
class Janus::SessionsController < ApplicationController
|
4
12
|
include Janus::InternalHelpers
|
5
13
|
# include Janus::UrlHelpers
|
@@ -34,7 +42,6 @@ class Janus::SessionsController < ApplicationController
|
|
34
42
|
self.resource ||= resource_class.new(params[resource_name])
|
35
43
|
resource.clean_up_passwords
|
36
44
|
resource.errors.add(:base, :not_found)
|
37
|
-
|
38
45
|
render "new", :status => :unauthorized
|
39
46
|
end
|
40
47
|
format.any { head :unauthorized }
|
@@ -51,41 +58,71 @@ class Janus::SessionsController < ApplicationController
|
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
61
|
+
# An overridable method that returns the default path to return the just
|
62
|
+
# signed in user to. Defaults to return the user object, which will be
|
63
|
+
# interpreted by rails as `user_path(user)`.
|
54
64
|
def after_sign_in_url(user)
|
55
65
|
user
|
56
66
|
end
|
57
67
|
|
68
|
+
# An overridable method that returns the default path to return the just
|
69
|
+
# signed out user to. Defaults to `root_url`.
|
58
70
|
def after_sign_out_url(scope)
|
59
71
|
root_url
|
60
72
|
end
|
61
73
|
|
62
|
-
# Returns true if
|
63
|
-
#
|
64
|
-
#
|
74
|
+
# Returns true if host is known and that we allow to redirect the user
|
75
|
+
# with an auth_token.
|
76
|
+
#
|
77
|
+
# Warning: must be overwritten by child classes because it always
|
78
|
+
# returns false by default!
|
65
79
|
def valid_remote_host?(host)
|
66
|
-
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns an Array of URL that we shouldn't automatically return to. It
|
84
|
+
# actually returns URL to prevent infinite loops. We must for instance
|
85
|
+
# never return to new_sesssion_path.
|
86
|
+
#
|
87
|
+
# If you ever needd to override this method, don't forget to call `super`.
|
88
|
+
# For instance:
|
89
|
+
#
|
90
|
+
# def never_return_to(scope)
|
91
|
+
# super + [ my_peculiar_path, another_path ]
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
def never_return_to(scope)
|
95
|
+
scope = Janus.scope_for(scope)
|
96
|
+
[
|
97
|
+
new_session_path(scope),
|
98
|
+
new_password_path(scope),
|
99
|
+
edit_password_path(scope)
|
100
|
+
]
|
67
101
|
end
|
68
102
|
|
69
|
-
# Either redirects the user to after_sign_in_url or to
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
103
|
+
# Either redirects the user to after_sign_in_url or to <tt>params[:return_to]</tt>.
|
104
|
+
#
|
105
|
+
# If <tt>params[:return_to] is an absolute URL, and not just a path,
|
106
|
+
# valid_remote_host? will be invoked to check wether we should redirect
|
107
|
+
# to this URL or not, in order to secure auth tokens for
|
108
|
+
# RemoteAuthenticatable to leak into the wild.
|
74
109
|
def redirect_after_sign_in(user)
|
75
110
|
unless params[:return_to].blank?
|
76
111
|
return_to = Addressable::URI.parse(params[:return_to])
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
112
|
+
|
113
|
+
unless never_return_to(user).include?(return_to.path)
|
114
|
+
if return_to.host.nil? || return_to.host == request.host
|
115
|
+
redirect_to params[:return_to]
|
116
|
+
return
|
117
|
+
elsif valid_remote_host?(return_to.host)
|
118
|
+
if user.class.include?(Janus::Models::RemoteAuthenticatable)
|
119
|
+
query = return_to.query_values || {}
|
120
|
+
return_to.query_values = query.merge(user.class.remote_authentication_key => user.generate_remote_token!)
|
121
|
+
end
|
122
|
+
|
123
|
+
redirect_to return_to.to_s
|
124
|
+
return
|
85
125
|
end
|
86
|
-
|
87
|
-
redirect_to return_to.to_s
|
88
|
-
return
|
89
126
|
end
|
90
127
|
end
|
91
128
|
|
data/lib/janus/manager.rb
CHANGED
@@ -34,7 +34,7 @@ module Janus
|
|
34
34
|
|
35
35
|
# Logs a user in.
|
36
36
|
#
|
37
|
-
# FIXME: what should happen when a user signs in but a user is already signed in?!
|
37
|
+
# FIXME: what should happen when a user signs in but a user is already signed in for the same scope?!
|
38
38
|
def login(user, options = {})
|
39
39
|
options[:scope] ||= Janus.scope_for(user)
|
40
40
|
set_user(user, options)
|
@@ -76,8 +76,13 @@ module Janus
|
|
76
76
|
|
77
77
|
if authenticated?(scope)
|
78
78
|
if @users[scope].nil?
|
79
|
+
begin
|
79
80
|
@users[scope] = session(scope)[:user_class].find(session(scope)[:user_id])
|
80
|
-
|
81
|
+
rescue ActiveRecord::RecordNotFound
|
82
|
+
unset_user(scope)
|
83
|
+
else
|
84
|
+
Janus::Manager.run_callbacks(:fetch, @users[scope], self, :scope => scope)
|
85
|
+
end
|
81
86
|
end
|
82
87
|
|
83
88
|
@users[scope]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'bcrypt'
|
2
|
+
require 'scrypt'
|
2
3
|
|
3
4
|
module Janus
|
4
5
|
module Models
|
@@ -24,13 +25,13 @@ module Janus
|
|
24
25
|
|
25
26
|
included do
|
26
27
|
attr_protected :encrypted_password, :reset_password_token, :reset_password_sent_at
|
27
|
-
attr_reader
|
28
|
-
attr_accessor
|
28
|
+
attr_reader :password
|
29
|
+
attr_accessor :current_password
|
29
30
|
|
30
31
|
validates :password, :presence => true, :confirmation => true, :if => :password_required?
|
31
32
|
validate :validate_current_password, :on => :update, :if => :current_password
|
32
33
|
|
33
|
-
janus_config(:authentication_keys, :stretches, :pepper)
|
34
|
+
janus_config(:authentication_keys, :encryptor, :stretches, :pepper, :scrypt_options)
|
34
35
|
end
|
35
36
|
|
36
37
|
def password=(password)
|
@@ -38,13 +39,28 @@ module Janus
|
|
38
39
|
self.encrypted_password = digest_password(@password) unless @password.blank?
|
39
40
|
end
|
40
41
|
|
41
|
-
# Checks if a given password matches this user password.
|
42
|
+
# Checks if a given password matches this user's password.
|
42
43
|
def valid_password?(password)
|
43
|
-
|
44
|
+
case self.class.encryptor
|
45
|
+
when :bcrypt
|
46
|
+
::BCrypt::Password.new(encrypted_password) == salted_password(password)
|
47
|
+
when :scrypt
|
48
|
+
::SCrypt::Password.new(encrypted_password) == salted_password(password)
|
49
|
+
end
|
44
50
|
end
|
45
51
|
|
52
|
+
# Digests a password using either bcrypt or scrypt (as configured by `config.encryptor`).
|
46
53
|
def digest_password(password)
|
47
|
-
|
54
|
+
case self.class.encryptor
|
55
|
+
when :bcrypt
|
56
|
+
::BCrypt::Password.create(salted_password(password), :cost => self.class.stretches).to_s
|
57
|
+
when :scrypt
|
58
|
+
::SCrypt::Password.create(salted_password(password), self.class.scrypt_options).to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def salted_password(password)
|
63
|
+
"#{password}#{self.class.pepper}"
|
48
64
|
end
|
49
65
|
|
50
66
|
def clean_up_passwords
|