shuber-authentication 1.0.0 → 1.0.1

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/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ 2009-01-09 - Sean Huber (shuber@huberry.com)
2
+ * Add authentication_options cattr_accessor
3
+ * Update README
4
+ * Add authentication_options cattr_accessor to models as well
5
+
1
6
  2009-01-08 - Sean Huber (shuber@huberry.com)
2
7
  * Clean up CHANGELOG
3
8
  * Convert to soft tabs
data/README.markdown CHANGED
@@ -12,8 +12,12 @@ Installation
12
12
  script/plugin install git://github.com/shuber/authentication.git
13
13
 
14
14
 
15
- Example
16
- -------
15
+ Usage
16
+ -----
17
+
18
+ ### Model ###
19
+
20
+ Simply call `uses_authentication` in your model like so:
17
21
 
18
22
  class User < ActiveRecord::Base
19
23
  # Accepts an optional hash of options
@@ -23,59 +27,83 @@ Example
23
27
  # :salt_field - (defaults to :salt)
24
28
  uses_authentication :login_field => :username
25
29
  end
30
+
31
+ A few helpful methods will now be available for your model:
32
+
33
+ # Class method that authenticates a user based on a login and password - returns a user instance or false
34
+ User.authenticate(login, password)
26
35
 
27
- class ApplicationController < ActionController::Base
28
- # Set optional authentication options here
29
- # self.authentication_model = The model that uses authentication (defaults to 'User')
30
- # self.unauthenticated_message = The error flash message to set when unauthenticated (defaults to 'Login to continue')
31
- # self.unauthenticated_redirect_path = The path to redirect to when unauthenticated (can be a symbol of a method) (defaults to '/')
32
- end
36
+ # Checks if the password passed to it matches the current user instance's password
37
+ authenticated?(password)
33
38
 
39
+ # Checks if the current user instance's password has just been changed
40
+ password_changed?
41
+
42
+ # Resets the password - will generate a new random password if one is not specified
43
+ reset_password(new_password = nil)
44
+
45
+ # Resets the password and saves - will generate a new random password if one is not specified
46
+ reset_password!(new_password = nil)
47
+
48
+
49
+ ### Controller ###
50
+
51
+ Simply add `before_filter :authentication_required` for any actions that require authentication. The `:model` will then be searched
52
+ for a record with the id found in the `session[options[:session_field]`. The result of that query is stored in a controller instance
53
+ method called `current_user`. If a record could not be found, the controller's `unauthenticated` instance method is called which simply
54
+ redirects with a flash message. You can overwrite this method to change this behavior.
55
+
34
56
  class UsersController < ApplicationController
35
57
  before_filter :authentication_required, :only => [:index]
36
-
58
+
37
59
  def index
38
- render :text => 'test'
60
+ render :text => current_user.id.to_s
39
61
  end
40
- end
41
-
62
+ end
42
63
 
43
- Controller Methods
44
- ------------------
64
+ A few helpful instance methods are available for your controller:
45
65
 
46
66
  # Returns the current user or nil if a user is not logged in
47
67
  current_user
48
68
 
49
- # Checks if the current user is authenticated (optionaly accepts a block that is yielded when true)
69
+ # Checks if the current user is authenticated
50
70
  logged_in?
51
71
 
52
72
  # Login a user
53
73
  login(user)
54
74
 
55
- # A before filter to require authentication - redirects to the controller class's authentication_redirect_path if unauthenticated
56
- authentication_required
57
-
58
75
  # Logout the current user
59
76
  logout
60
77
 
78
+ `current_user` and `logged_in?` are also helper methods so you can use them in your views.
61
79
 
62
- Model Methods
63
- -------------
64
80
 
65
- # Class method that authenticates a user based on a login and password - returns a user instance or false
66
- User.authenticate(login, password)
81
+ ### Controller options ###
82
+
83
+ Your controller has a class method called `authentication_options` which contains a hash with default options. You can change
84
+ these like so:
85
+
86
+ class ApplicationController < ActionController::Base
87
+ self.authentication_options.merge!{ :message => 'You are not authenticated', :redirect_to => :new_session_path }
88
+ end
89
+
90
+ The default controller authentication\_options are:
91
+
92
+ # The type of flash message to use when authentication fails. Defaults to :error.
93
+ :flash_type
67
94
 
68
- # Checks if the password passed to it matches the current user instance's password
69
- authenticated?(password)
95
+ # The flash message to use when authentication fails. If set to false, no flash is set. Defaults to 'Login to continue'.
96
+ :message
70
97
 
71
- # Checks if the current user instance's password has just been changed
72
- password_changed?
98
+ # The model to authenticate with. Defaults to 'User'
99
+ :model
73
100
 
74
- # Resets the password - will generate a new random password if one is not specified
75
- reset_password(new_password = nil)
101
+ # The session field name to store the current_user's id. Defaults to "#{options[:model].to_s.underscore}_id".to_sym (e.g. :user_id)
102
+ :session_field
76
103
 
77
- # Resets the password and saves - will generate a new random password if one is not specified
78
- reset_password!(new_password = nil)
104
+ # The path to redirect to if authentication fails. Accepts a string or a symbol representing an instance method to call.
105
+ # Defaults to '/'
106
+ :redirect_to
79
107
 
80
108
 
81
109
  Contact
@@ -5,10 +5,13 @@ module Huberry
5
5
  base.class_eval do
6
6
  include InstanceMethods
7
7
 
8
- cattr_accessor :authentication_model, :unauthenticated_message, :unauthenticated_redirect_path
9
- self.authentication_model = 'User'
10
- self.unauthenticated_message = 'Login to continue'
11
- self.unauthenticated_redirect_path = '/'
8
+ cattr_accessor :authentication_options
9
+ self.authentication_options = {
10
+ :flash_type => :error,
11
+ :model => 'User',
12
+ :message => 'Login to continue',
13
+ :redirect_to => '/'
14
+ }
12
15
 
13
16
  attr_accessor :current_user
14
17
  helper_method :current_user, :logged_in?
@@ -25,35 +28,33 @@ module Huberry
25
28
  def find_current_user(force_query = false)
26
29
  if @queried_for_current_user.nil? || force_query
27
30
  @queried_for_current_user = true
28
- self.current_user = self.class.authentication_model.to_s.constantize.find(session[:user_id]) rescue nil
31
+ self.current_user = self.class.authentication_options[:model].to_s.constantize.find(session[authentication_session_field]) rescue nil
29
32
  end
30
33
  self.current_user
31
34
  end
32
35
 
33
36
  def logged_in?
34
- find_current_user if self.current_user.nil?
35
- if self.current_user.nil?
36
- block_given? ? nil : false
37
- else
38
- block_given? ? yield : true
39
- end
37
+ !find_current_user.nil?
40
38
  end
41
39
 
42
40
  def login(user)
43
41
  self.current_user = user
44
- session[:user_id] = user.id
42
+ session[authentication_session_field] = user.id
45
43
  end
46
44
 
47
45
  def logout
48
46
  self.current_user = nil
49
- session[:user_id] = nil
47
+ session[authentication_session_field] = nil
48
+ end
49
+
50
+ def authentication_session_field
51
+ self.class.authentication_options[:session_field] || "#{self.class.authentication_options[:model].to_s.underscore}_id".to_sym
50
52
  end
51
53
 
52
54
  def unauthenticated
53
55
  session[:return_to] = request.request_uri
54
- flash[:error] = self.class.unauthenticated_message.to_s
55
- redirect_to respond_to?(self.class.unauthenticated_redirect_path) ? send(self.class.unauthenticated_redirect_path) : self.class.unauthenticated_redirect_path.to_s
56
- false
56
+ flash[self.class.authentication_options[:flash_type]] = self.class.authentication_options[:message] if self.class.authentication_options[:message]
57
+ redirect_to respond_to?(self.class.authentication_options[:redirect_to]) ? send(self.class.authentication_options[:redirect_to]) : self.class.authentication_options[:redirect_to].to_s
57
58
  end
58
59
  end
59
60
  end
@@ -7,17 +7,19 @@ module Huberry
7
7
  extend ClassMethods
8
8
  include InstanceMethods
9
9
 
10
- cattr_accessor :hashed_password_field, :login_field, :password_field, :salt_field
11
- self.hashed_password_field = options[:hashed_password_field] || :hashed_password
12
- self.login_field = options[:login_field] || :email
13
- self.password_field = options[:password_field] || :password
14
- self.salt_field = options[:salt_field] || :salt
10
+ cattr_accessor :authentication_options
11
+ self.authentication_options = {
12
+ :hashed_password_field => :hashed_password,
13
+ :login_field => :email,
14
+ :password_field => :password,
15
+ :salt_field => :salt
16
+ }.merge(options)
15
17
 
16
- attr_accessor self.password_field, "#{self.password_field}_confirmation".to_sym
18
+ attr_accessor self.authentication_options[:password_field], "#{self.authentication_options[:password_field]}_confirmation".to_sym
17
19
 
18
- validates_presence_of self.login_field
19
- validates_presence_of self.password_field, :if => :password_required?
20
- validates_confirmation_of self.password_field, :if => :password_required?
20
+ validates_presence_of self.authentication_options[:login_field]
21
+ validates_presence_of self.authentication_options[:password_field], :if => :password_required?
22
+ validates_confirmation_of self.authentication_options[:password_field], :if => :password_required?
21
23
 
22
24
  before_save :hash_password
23
25
 
@@ -27,7 +29,7 @@ module Huberry
27
29
 
28
30
  module ClassMethods
29
31
  def authenticate(login, password)
30
- user = send("find_by_#{self.login_field}", login)
32
+ user = send("find_by_#{self.authentication_options[:login_field]}", login)
31
33
  user && user.authenticated?(password) ? user : false
32
34
  end
33
35
 
@@ -38,7 +40,7 @@ module Huberry
38
40
 
39
41
  module InstanceMethods
40
42
  def authenticated?(password)
41
- send(self.class.hashed_password_field) == self.class.digest(password.to_s + send(self.class.salt_field).to_s)
43
+ send(self.class.authentication_options[:hashed_password_field]) == self.class.digest(password.to_s + send(self.class.authentication_options[:salt_field]).to_s)
42
44
  end
43
45
 
44
46
  def password_changed?
@@ -52,9 +54,9 @@ module Huberry
52
54
 
53
55
  def reset_password(new_password = nil)
54
56
  new_password = generate_salt[0..7] if new_password.blank?
55
- send("#{self.class.salt_field}=", nil)
56
- send("#{self.class.password_field}=", new_password)
57
- send("#{self.class.password_field}_confirmation=", new_password)
57
+ send("#{self.class.authentication_options[:salt_field]}=", nil)
58
+ send("#{self.class.authentication_options[:password_field]}=", new_password)
59
+ send("#{self.class.authentication_options[:password_field]}_confirmation=", new_password)
58
60
  @password_changed = true
59
61
  end
60
62
 
@@ -71,13 +73,13 @@ module Huberry
71
73
 
72
74
  def hash_password
73
75
  if password_changed? || password_required?
74
- send("#{self.class.salt_field}=", generate_salt) if send("#{self.class.salt_field}").blank?
75
- send("#{self.class.hashed_password_field}=", self.class.digest(send(self.class.password_field).to_s + send(self.class.salt_field).to_s))
76
+ send("#{self.class.authentication_options[:salt_field]}=", generate_salt) if send("#{self.class.authentication_options[:salt_field]}").blank?
77
+ send("#{self.class.authentication_options[:hashed_password_field]}=", self.class.digest(send(self.class.authentication_options[:password_field]).to_s + send(self.class.authentication_options[:salt_field]).to_s))
76
78
  end
77
79
  end
78
80
 
79
81
  def password_required?
80
- send(self.class.hashed_password_field).blank? || !send(self.class.password_field).blank?
82
+ send(self.class.authentication_options[:hashed_password_field]).blank? || !send(self.class.authentication_options[:password_field]).blank?
81
83
  end
82
84
  end
83
85
  end
@@ -31,7 +31,10 @@ class ControllerTest < Test::Unit::TestCase
31
31
  @request = ActionController::TestRequest.new
32
32
  @response = ActionController::TestResponse.new
33
33
 
34
+ @controller.instance_variable_set('@_request', @request)
34
35
  @controller.instance_variable_set('@_session', @request.session)
36
+
37
+ @controller.class.authentication_options.merge!(:session_field => nil, :message => 'Login to continue')
35
38
  end
36
39
 
37
40
  def teardown
@@ -48,13 +51,6 @@ class ControllerTest < Test::Unit::TestCase
48
51
  assert !@controller.send(:logged_in?)
49
52
  end
50
53
 
51
- def test_logged_in_yields_block_on_true
52
- assert_equal nil, @controller.send(:logged_in?) { 'some_value' }
53
-
54
- @controller.send :login, @user
55
- assert_equal 'some_value', @controller.send(:logged_in?) { 'some_value' }
56
- end
57
-
58
54
  def test_current_user
59
55
  assert_nil @controller.send(:current_user)
60
56
 
@@ -68,9 +64,6 @@ class ControllerTest < Test::Unit::TestCase
68
64
  def test_should_require_login
69
65
  get :login_required
70
66
  assert_response :redirect
71
- assert flash.has_key?(:error)
72
- assert_equal @controller.unauthenticated_message, flash[:error]
73
- assert_redirected_to '/'
74
67
  end
75
68
 
76
69
  def test_should_not_require_login
@@ -111,4 +104,26 @@ class ControllerTest < Test::Unit::TestCase
111
104
  assert_equal @controller.session[:return_to], '/login_required'
112
105
  end
113
106
 
107
+ def test_should_set_a_flash_message_when_unauthenticated
108
+ get :login_required
109
+ assert_equal @controller.class.authentication_options[:message], flash[@controller.class.authentication_options[:flash_type]]
110
+ end
111
+
112
+ def test_not_should_set_a_flash_message_when_unauthenticated_if_message_is_false
113
+ @controller.class.authentication_options[:message] = false
114
+ get :login_required
115
+ assert_nil flash[@controller.class.authentication_options[:flash_type]]
116
+ end
117
+
118
+ def test_should_redirect_when_unauthenticated
119
+ get :login_required
120
+ assert_redirected_to @controller.class.authentication_options[:redirect_to]
121
+ end
122
+
123
+ def test_should_use_custom_session_field
124
+ @controller.class.authentication_options[:session_field] = :test
125
+ @request.session[:test] = @user.id
126
+ assert @controller.send(:logged_in?)
127
+ end
128
+
114
129
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shuber-authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Huber
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-08 00:00:00 -08:00
12
+ date: 2009-01-09 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15