janus 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +77 -154
- data/lib/generators/janus/install_generator.rb +19 -0
- data/lib/generators/janus/resource_generator.rb +64 -0
- data/lib/generators/templates/confirmations/new.html.erb +16 -0
- data/lib/generators/templates/confirmations_controller.erb +3 -0
- data/lib/generators/templates/janus.en.yml +62 -0
- data/lib/generators/templates/janus.rb +25 -0
- data/lib/generators/templates/model.erb +8 -0
- data/lib/generators/templates/passwords/edit.html.erb +21 -0
- data/lib/generators/templates/passwords/new.html.erb +16 -0
- data/lib/generators/templates/passwords_controller.erb +3 -0
- data/lib/generators/templates/registrations/edit.html.erb +31 -0
- data/lib/generators/templates/registrations/new.html.erb +26 -0
- data/lib/generators/templates/registrations_controller.erb +17 -0
- data/lib/generators/templates/sessions/new.html.erb +30 -0
- data/lib/generators/templates/sessions_controller.erb +11 -0
- data/lib/janus.rb +1 -0
- data/lib/janus/config.rb +10 -4
- data/lib/janus/controllers/confirmations_controller.rb +6 -6
- data/lib/janus/controllers/helpers.rb +4 -4
- data/lib/janus/controllers/passwords_controller.rb +3 -3
- data/lib/janus/controllers/registrations_controller.rb +12 -9
- data/lib/janus/controllers/sessions_controller.rb +15 -7
- data/lib/janus/helper.rb +1 -1
- data/lib/janus/hooks.rb +6 -6
- data/lib/janus/hooks/rememberable.rb +2 -2
- data/lib/janus/hooks/remote_authenticatable.rb +1 -1
- data/lib/janus/manager.rb +5 -5
- data/lib/janus/models/base.rb +2 -2
- data/lib/janus/models/confirmable.rb +7 -4
- data/lib/janus/models/database_authenticatable.rb +26 -16
- data/lib/janus/models/rememberable.rb +12 -9
- data/lib/janus/models/remote_authenticatable.rb +21 -18
- data/lib/janus/models/trackable.rb +11 -8
- data/lib/janus/routes.rb +22 -22
- data/lib/janus/strategies.rb +3 -3
- data/lib/janus/strategies/database_authenticatable.rb +1 -1
- data/lib/janus/strategies/rememberable.rb +1 -1
- data/lib/janus/strategies/remote_authenticatable.rb +1 -1
- data/lib/janus/test_helper.rb +6 -2
- metadata +19 -36
@@ -1,7 +1,7 @@
|
|
1
1
|
Janus::Manager.after_login do |user, manager, options|
|
2
2
|
if options[:rememberable] && user.respond_to?(:remember_me!)
|
3
3
|
user.remember_me!
|
4
|
-
|
4
|
+
|
5
5
|
remember_cookie_name = Janus::Strategies::Rememberable.remember_cookie_name(options[:scope])
|
6
6
|
manager.cookies[remember_cookie_name] = {
|
7
7
|
:value => user.remember_token,
|
@@ -13,7 +13,7 @@ end
|
|
13
13
|
Janus::Manager.after_logout do |user, manager, options|
|
14
14
|
if user.respond_to?(:forget_me!)
|
15
15
|
user.forget_me!
|
16
|
-
|
16
|
+
|
17
17
|
remember_cookie_name = Janus::Strategies::Rememberable.remember_cookie_name(options[:scope])
|
18
18
|
manager.cookies.delete(remember_cookie_name)
|
19
19
|
end
|
data/lib/janus/manager.rb
CHANGED
@@ -33,7 +33,7 @@ module Janus
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# Logs a user in.
|
36
|
-
#
|
36
|
+
#
|
37
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)
|
@@ -46,13 +46,13 @@ module Janus
|
|
46
46
|
# whole session will be resetted.
|
47
47
|
def logout(*scopes)
|
48
48
|
scopes = janus_sessions.keys if scopes.empty?
|
49
|
-
|
49
|
+
|
50
50
|
scopes.each do |scope|
|
51
51
|
_user = user(scope)
|
52
52
|
unset_user(scope)
|
53
53
|
Janus::Manager.run_callbacks(:logout, _user, self, :scope => scope)
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
request.reset_session if janus_sessions.empty?
|
57
57
|
end
|
58
58
|
|
@@ -73,7 +73,7 @@ module Janus
|
|
73
73
|
def user(scope)
|
74
74
|
scope = scope.to_sym
|
75
75
|
@users ||= {}
|
76
|
-
|
76
|
+
|
77
77
|
if authenticated?(scope)
|
78
78
|
if @users[scope].nil?
|
79
79
|
begin
|
@@ -84,7 +84,7 @@ module Janus
|
|
84
84
|
Janus::Manager.run_callbacks(:fetch, @users[scope], self, :scope => scope)
|
85
85
|
end
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
@users[scope]
|
89
89
|
end
|
90
90
|
end
|
data/lib/janus/models/base.rb
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
module Janus
|
2
2
|
module Models
|
3
3
|
# = Confirmable
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# Confirms an account's email by sending an email with an unique token.
|
6
6
|
# This is necessary to be sure the user can be contacted on that email.
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# IMPROVE: reconfirm whenever email changes.
|
9
9
|
module Confirmable
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
12
|
included do
|
13
|
-
|
13
|
+
begin
|
14
|
+
attr_protected :confirmation_token, :confirmation_sent_at, :confirmed_at
|
15
|
+
rescue
|
16
|
+
end
|
14
17
|
janus_config(:confirmation_key)
|
15
|
-
|
18
|
+
|
16
19
|
before_create :generate_confirmation_token
|
17
20
|
# before_update :generate_confirmation_token, :if => :email_changed?
|
18
21
|
end
|
@@ -1,36 +1,46 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
begin
|
2
|
+
require 'bcrypt'
|
3
|
+
rescue
|
4
|
+
end
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'scrypt'
|
8
|
+
rescue
|
9
|
+
end
|
3
10
|
|
4
11
|
module Janus
|
5
12
|
module Models
|
6
13
|
# = DatabaseAuthenticatable
|
7
|
-
#
|
14
|
+
#
|
8
15
|
# This is the initial part and is required for email + password registration
|
9
16
|
# and logins. Passwords are automatically encrypted following Devise's
|
10
17
|
# default encryption logic, which relies on bcrypt.
|
11
|
-
#
|
18
|
+
#
|
12
19
|
# == Required columns:
|
13
|
-
#
|
20
|
+
#
|
14
21
|
# - email
|
15
22
|
# - encrypted_password
|
16
|
-
#
|
23
|
+
#
|
17
24
|
# == Configuration
|
18
|
-
#
|
25
|
+
#
|
19
26
|
# - +stretches+
|
20
27
|
# - +pepper+
|
21
28
|
# - +authentication_keys+ - required keys for authenticating a user, defaults to <tt>[:email]</tt>
|
22
|
-
#
|
29
|
+
#
|
23
30
|
module DatabaseAuthenticatable
|
24
31
|
extend ActiveSupport::Concern
|
25
32
|
|
26
33
|
included do
|
27
|
-
|
34
|
+
begin
|
35
|
+
attr_protected :encrypted_password, :reset_password_token, :reset_password_sent_at
|
36
|
+
rescue
|
37
|
+
end
|
28
38
|
attr_reader :password
|
29
39
|
attr_accessor :current_password
|
30
|
-
|
40
|
+
|
31
41
|
validates :password, :presence => true, :confirmation => true, :if => :password_required?
|
32
42
|
validate :validate_current_password, :on => :update, :if => :current_password
|
33
|
-
|
43
|
+
|
34
44
|
janus_config(:authentication_keys, :encryptor, :stretches, :pepper, :scrypt_options)
|
35
45
|
end
|
36
46
|
|
@@ -74,10 +84,10 @@ module Janus
|
|
74
84
|
end
|
75
85
|
|
76
86
|
def reset_password!(params)
|
77
|
-
|
78
|
-
send("#{
|
87
|
+
%w{password password_confirmation}.each do |attr|
|
88
|
+
send("#{attr}=", params[attr]) if params.has_key?(attr)
|
79
89
|
end
|
80
|
-
|
90
|
+
|
81
91
|
self.reset_password_sent_at = self.reset_password_token = nil
|
82
92
|
save
|
83
93
|
end
|
@@ -99,13 +109,13 @@ module Janus
|
|
99
109
|
|
100
110
|
def find_for_password_reset(token)
|
101
111
|
user = find_by_reset_password_token(token) unless token.blank?
|
102
|
-
|
112
|
+
|
103
113
|
if user && user.reset_password_sent_at < 2.days.ago
|
104
114
|
user.reset_password_token = user.reset_password_sent_at = nil
|
105
115
|
user.save
|
106
116
|
user = nil
|
107
117
|
end
|
108
|
-
|
118
|
+
|
109
119
|
user
|
110
120
|
end
|
111
121
|
end
|
@@ -1,26 +1,29 @@
|
|
1
1
|
module Janus
|
2
2
|
module Models
|
3
3
|
# = Rememberable
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# Allows a user to check a remember me check box when she logs in through
|
6
6
|
# DatabaseAuthenticatable. It will set a cookie with a configurable
|
7
7
|
# expiration date.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# == Required columns
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# - remember_token
|
12
12
|
# - remember_created_at
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# == Configuration
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# - remember_for - how long to remember the user, for instance <tt>1.week</tt>.
|
17
17
|
# - :extend_remember_period - set to true to extend the remember cookie every time the user logs in.
|
18
|
-
#
|
18
|
+
#
|
19
19
|
module Rememberable
|
20
20
|
extend ActiveSupport::Concern
|
21
21
|
|
22
22
|
included do
|
23
|
-
|
23
|
+
begin
|
24
|
+
attr_protected :remember_token, :remember_created_at
|
25
|
+
rescue
|
26
|
+
end
|
24
27
|
janus_config :remember_for, :extend_remember_period
|
25
28
|
end
|
26
29
|
|
@@ -40,12 +43,12 @@ module Janus
|
|
40
43
|
module ClassMethods
|
41
44
|
def find_for_remember_authentication(token)
|
42
45
|
user = where(:remember_token => token).first unless token.blank?
|
43
|
-
|
46
|
+
|
44
47
|
if user && user.remember_created_at < remember_for.ago
|
45
48
|
user.forget_me!
|
46
49
|
user = nil
|
47
50
|
end
|
48
|
-
|
51
|
+
|
49
52
|
user
|
50
53
|
end
|
51
54
|
end
|
@@ -3,61 +3,64 @@ require 'janus/hooks/remote_authenticatable'
|
|
3
3
|
module Janus
|
4
4
|
module Models
|
5
5
|
# = RemoteAuthenticatable
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# Keeping a user connected on subdomains is an easy task, all you need to do
|
8
8
|
# is define the session cookie to <tt>.example.com</tt> for instance. But
|
9
9
|
# keeping a user connected on multiple top level domains is a harder task.
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# Hopefully RemoteAuthenticatable takes care of all the hassle.
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# == Single Sign In
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# The authentication must happen on a single domain, for instance
|
16
16
|
# <tt>login.example.com</tt>, then other domains must redirect to that
|
17
17
|
# domain's new session url. For instance:
|
18
|
-
#
|
18
|
+
#
|
19
19
|
# redirect_to new_user_session_url(:host => "login.example.com") unless user_signed_in?
|
20
|
-
#
|
20
|
+
#
|
21
21
|
# And that's it! The user shall be redirected with an unique +remote_token+,
|
22
22
|
# which shall log her in. Actually the user won't be logged in through
|
23
23
|
# Janus::Manager#login but through Janus::Manager#set_user which won't
|
24
24
|
# run the login hooks. This is useful for not tracking the user everytime
|
25
25
|
# it gets authenticated on each remote site.
|
26
|
-
#
|
26
|
+
#
|
27
27
|
# == Single Sign Out
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# Session state is maintained across domains through the session_token
|
30
30
|
# column of your User model. If a session token is invalid the session
|
31
31
|
# is simply resetted, thus logging out the user on remote domains. Actually
|
32
32
|
# the user is logged out using Janus::Manager#unset_user before
|
33
33
|
# resetting the session.
|
34
|
-
#
|
34
|
+
#
|
35
35
|
# == Required columns and models:
|
36
|
-
#
|
36
|
+
#
|
37
37
|
# A +session_token+ column (string) is required, as well as a RemoteToken
|
38
38
|
# model like so:
|
39
|
-
#
|
39
|
+
#
|
40
40
|
# class RemoteToken < ActiveRecord::Base
|
41
41
|
# include Janus::Models::RemoteToken
|
42
|
-
#
|
42
|
+
#
|
43
43
|
# belongs_to :user
|
44
44
|
# validates_presence_of :user
|
45
45
|
# end
|
46
|
-
#
|
46
|
+
#
|
47
47
|
# With the associated table:
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# create_table :remote_tokens do |t|
|
50
50
|
# t.references :user
|
51
51
|
# t.string :token
|
52
52
|
# t.datetime :created_at
|
53
53
|
# end
|
54
|
-
#
|
54
|
+
#
|
55
55
|
# add_index :remote_tokens, :token, :unique => true
|
56
56
|
module RemoteAuthenticatable
|
57
57
|
extend ActiveSupport::Concern
|
58
58
|
|
59
59
|
included do |klass|
|
60
|
-
|
60
|
+
begin
|
61
|
+
attr_protected :session_token
|
62
|
+
rescue
|
63
|
+
end
|
61
64
|
klass.class_eval { has_many :remote_tokens }
|
62
65
|
janus_config :remote_authentication_key
|
63
66
|
end
|
@@ -65,7 +68,7 @@ module Janus
|
|
65
68
|
# Generates an unique session token. This token will be used to validate
|
66
69
|
# the current session, and must be generated whenever a user signs in on
|
67
70
|
# the main site.
|
68
|
-
#
|
71
|
+
#
|
69
72
|
# The token won't be regenerated if it already exists.
|
70
73
|
def generate_session_token!
|
71
74
|
update_attribute(:session_token, self.class.generate_token(:session_token)) unless session_token
|
@@ -87,7 +90,7 @@ module Janus
|
|
87
90
|
module ClassMethods
|
88
91
|
def find_for_remote_authentication(token)
|
89
92
|
remote_token = ::RemoteToken.where(:token => token).first
|
90
|
-
|
93
|
+
|
91
94
|
if remote_token
|
92
95
|
remote_token.destroy
|
93
96
|
remote_token.user unless remote_token.created_at < 30.seconds.ago
|
@@ -3,33 +3,36 @@ require 'janus/hooks/trackable'
|
|
3
3
|
module Janus
|
4
4
|
module Models
|
5
5
|
# = Trackable
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# Simple hook to update some columns of your model whenever a user logs in.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# == Required columns
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# - +sign_in_count+
|
12
12
|
# - +current_sign_in_ip+
|
13
13
|
# - +current_sign_in_at+
|
14
14
|
# - +last_sign_in_ip+
|
15
15
|
# - +last_sign_in_at+
|
16
|
-
#
|
16
|
+
#
|
17
17
|
module Trackable
|
18
18
|
extend ActiveSupport::Concern
|
19
19
|
|
20
20
|
included do
|
21
|
-
|
21
|
+
begin
|
22
|
+
attr_protected :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip
|
23
|
+
rescue
|
24
|
+
end
|
22
25
|
end
|
23
26
|
|
24
27
|
def track!(ip)
|
25
28
|
self.sign_in_count += 1
|
26
|
-
|
29
|
+
|
27
30
|
self.last_sign_in_at = self.current_sign_in_at
|
28
31
|
self.last_sign_in_ip = self.current_sign_in_ip
|
29
|
-
|
32
|
+
|
30
33
|
self.current_sign_in_at = Time.now
|
31
34
|
self.current_sign_in_ip = ip
|
32
|
-
|
35
|
+
|
33
36
|
save(:validate => false)
|
34
37
|
end
|
35
38
|
end
|
data/lib/janus/routes.rb
CHANGED
@@ -2,73 +2,73 @@ module ActionDispatch # :nodoc:
|
|
2
2
|
module Routing # :nodoc:
|
3
3
|
class Mapper
|
4
4
|
# Creates the routes for a Janus capable resource.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# Example:
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# MyApp::Application.routes.draw do
|
9
9
|
# janus :users, :session => true, :registration => false
|
10
10
|
# end
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Options:
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# - +session+ - true to generate session routes
|
15
15
|
# - +registration+ - true to generate registration routes
|
16
16
|
# - +confirmation+ - true to generate confirmation routes
|
17
17
|
# - +password+ - true to generate password reset routes
|
18
|
-
#
|
18
|
+
#
|
19
19
|
# Generated session routes:
|
20
|
-
#
|
20
|
+
#
|
21
21
|
# new_user_session GET /users/sign_in(.:format) {:controller=>"users/sessions", :action=>"new"}
|
22
22
|
# user_session POST /users/sign_in(.:format) {:controller=>"users/sessions", :action=>"create"}
|
23
|
-
# destroy_user_session
|
24
|
-
#
|
23
|
+
# destroy_user_session DELETE /users/sign_out(.:format) {:controller=>"users/sessions", :action=>"destroy"}
|
24
|
+
#
|
25
25
|
# Generated registration routes:
|
26
|
-
#
|
26
|
+
#
|
27
27
|
# new_user_registration GET /users/sign_up(.:format) {:controller=>"users/registrations", :action=>"new"}
|
28
28
|
# user_registration POST /users(.:format) {:controller=>"users/registrations", :action=>"create"}
|
29
29
|
# edit_user_registration GET /users/edit(.:format) {:controller=>"users/registrations", :action=>"edit"}
|
30
30
|
# PUT /users(.:format) {:controller=>"users/registrations", :action=>"update"}
|
31
31
|
# DELETE /users(.:format) {:controller=>"users/registrations", :action=>"destroy"}
|
32
|
-
#
|
32
|
+
#
|
33
33
|
# Generated confirmation routes:
|
34
|
-
#
|
34
|
+
#
|
35
35
|
# user_confirmation POST /users/confirmation(.:format) {:controller=>"users/confirmations", :action=>"create"}
|
36
36
|
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"users/confirmations", :action=>"new"}
|
37
37
|
# GET /users/confirmation(.:format) {:controller=>"users/confirmations", :action=>"show"}
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# Generated password reset routes:
|
40
|
-
#
|
40
|
+
#
|
41
41
|
# user_password POST /users/password(.:format) {:controller=>"users/passwords", :action=>"create"}
|
42
42
|
# new_user_password GET /users/password/new(.:format) {:controller=>"users/passwords", :action=>"new"}
|
43
43
|
# edit_user_password GET /users/password/edit(.:format) {:controller=>"users/passwords", :action=>"edit"}
|
44
44
|
# PUT /users/password(.:format) {:controller=>"users/passwords", :action=>"update"}
|
45
|
-
#
|
45
|
+
#
|
46
46
|
def janus(*resources)
|
47
47
|
ActionController::Base.send(:include, Janus::Helpers) unless ActionController::Base.include?(Janus::Helpers)
|
48
48
|
ActionController::Base.send(:include, Janus::UrlHelpers) unless ActionController::Base.include?(Janus::UrlHelpers)
|
49
49
|
options = resources.extract_options!
|
50
|
-
|
50
|
+
|
51
51
|
resources.each do |plural|
|
52
52
|
singular = plural.to_s.singularize
|
53
|
-
|
53
|
+
|
54
54
|
if options[:session]
|
55
55
|
scope :path => plural, :controller => "#{plural}/sessions" do
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
get "/sign_in(.:format)", :action => "new", :as => "new_#{singular}_session"
|
57
|
+
post "/sign_in(.:format)", :action => "create", :as => "#{singular}_session"
|
58
|
+
delete "/sign_out(.:format)", :action => "destroy", :as => "destroy_#{singular}_session"
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
namespace plural, :as => singular do
|
63
63
|
if options[:registration]
|
64
64
|
resource :registration, :except => [:index, :show], :path => "",
|
65
65
|
:path_names => { :new => 'sign_up' }
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
resource :confirmation, :only => [:show, :new, :create] if options[:confirmation]
|
69
69
|
resource :password, :except => [:index, :show, :destroy] if options[:password]
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
ActionController::Base.janus(singular)
|
73
73
|
end
|
74
74
|
end
|