simplest_auth 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +107 -0
- data/Rakefile +51 -0
- data/lib/simplest_auth/controller.rb +69 -0
- data/lib/simplest_auth/model.rb +79 -0
- data/lib/simplest_auth/version.rb +13 -0
- data/lib/simplest_auth.rb +13 -0
- data/test/unit/simplest_auth/ar_model_test.rb +46 -0
- data/test/unit/simplest_auth/controller_test.rb +144 -0
- data/test/unit/simplest_auth/dm_model_test.rb +47 -0
- data/test/unit/simplest_auth/model_test.rb +79 -0
- metadata +75 -0
data/README.textile
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
h1. SimplestAuth
|
2
|
+
|
3
|
+
simplest_auth is a gem to be used with Rails applications where RESTful Authentication is overkill - it handles authentication and nothing else (e.g. password resets, etc...)
|
4
|
+
|
5
|
+
simplest_auth is now compatible with both ActiveRecord and DataMapper (the README displays examples for AR)
|
6
|
+
|
7
|
+
h2. Installation
|
8
|
+
|
9
|
+
SimplestAuth depends (for now) on the BCrypt gem, so install that first:
|
10
|
+
|
11
|
+
<pre><code>$ sudo gem install bcrypt-ruby</code></pre>
|
12
|
+
|
13
|
+
Configure for the gem:
|
14
|
+
|
15
|
+
<pre><code>config.gem 'vigetlabs-simplest_auth', :lib => 'simplest_auth'</code></pre>
|
16
|
+
|
17
|
+
h2. Usage
|
18
|
+
|
19
|
+
SimplestAuth is an extension to the existing models and controllers in your Rails application. It makes some decisions about how you structure your models, but will give you flexibility with naming and any ActiveRecord validations that you want to use.
|
20
|
+
|
21
|
+
h3. Model Integration
|
22
|
+
|
23
|
+
If you're starting out with a fresh User model, you just need an identifier such as @email@ and @crypted_password@ columns in your database:
|
24
|
+
|
25
|
+
<pre><code>$ ./script/generate model User email:string crypted_password:string</code></pre>
|
26
|
+
|
27
|
+
To get started, just use the @SimplestAuth::Model@ mix-in, and tell it how you want to identify, in your User class:
|
28
|
+
|
29
|
+
<pre><code>
|
30
|
+
class User < ActiveRecord::Base
|
31
|
+
include SimplestAuth::Model
|
32
|
+
|
33
|
+
authenticate_by :email
|
34
|
+
end
|
35
|
+
</code></pre>
|
36
|
+
|
37
|
+
The module provides accessors for both @password@ and @password_confirmation@, but you will need to provide the validations required for your application. A @password_required?@ method is defined, as well. Some sane defaults:
|
38
|
+
|
39
|
+
<pre><code>
|
40
|
+
validates_presence_of :email
|
41
|
+
validates_uniqueness_of :email
|
42
|
+
|
43
|
+
validates_presence_of :password, :on => :create
|
44
|
+
validates_confirmation_of :password, :if => :password_required?
|
45
|
+
</code></pre>
|
46
|
+
|
47
|
+
Before creating new records, the password is crypted before storing the User in the database.
|
48
|
+
|
49
|
+
The full model class:
|
50
|
+
|
51
|
+
<pre><code>
|
52
|
+
class User < ActiveRecord::Base
|
53
|
+
include SimplestAuth::Model
|
54
|
+
|
55
|
+
validates_presence_of :email
|
56
|
+
validates_uniqueness_of :email
|
57
|
+
|
58
|
+
validates_presence_of :password, :on => :create
|
59
|
+
validates_confirmation_of :password, :if => :password_required?
|
60
|
+
end
|
61
|
+
</code></pre>
|
62
|
+
|
63
|
+
h3. Controller
|
64
|
+
|
65
|
+
To initialize the Controller functionality for use in your application, you need to include it in your @ApplicationController@:
|
66
|
+
|
67
|
+
<pre><code>
|
68
|
+
class ApplicationController < ActionController::Base
|
69
|
+
include SimplestAuth::Controller
|
70
|
+
end
|
71
|
+
</code></pre>
|
72
|
+
|
73
|
+
The plugin defines the @user_class@ method so that it can find the appropriate object in your application, it defaults to User but can be Account or anything else. Once that is included, you can use the controller methods in your application - logging in, for example:
|
74
|
+
|
75
|
+
<pre><code>
|
76
|
+
class SessionsController < ApplicationController
|
77
|
+
|
78
|
+
def new; end
|
79
|
+
|
80
|
+
def create
|
81
|
+
if user = User.authenticate(params[:email], params[:password])
|
82
|
+
self.current_user = user
|
83
|
+
flash[:notice] = 'Welcome!'
|
84
|
+
redirect_to root_path
|
85
|
+
else
|
86
|
+
flash.now[:error] = "Couldn't locate a user with those credentials"
|
87
|
+
render :action => :new
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
</code></pre>
|
92
|
+
|
93
|
+
h3. Helpers
|
94
|
+
|
95
|
+
The plug-in also defines some convenient helpers to use in your views:
|
96
|
+
|
97
|
+
* *@current_user@*: The user object of the currently logged-in user (or nil if the user isn't logged-in)
|
98
|
+
* *@logged_in?@*: Is there a user logged in?
|
99
|
+
* *@authorized?@*: Is this user authorized? Defaults to simply checking for logged_in? Override for your authorization scheme.
|
100
|
+
|
101
|
+
h2. TODO
|
102
|
+
|
103
|
+
* Document the usage of helper methods (e.g. :logged_in? / :authorized?) in the controller
|
104
|
+
|
105
|
+
h2. Credits
|
106
|
+
|
107
|
+
Tony Pitale and Matt Swasey of Viget Labs (http://www.viget.com)
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'lib/simplest_auth/version'
|
6
|
+
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'simplest_auth'
|
11
|
+
s.version = SimplestAuth::Version.to_s
|
12
|
+
s.summary = "Simple implementation of authentication for Rails"
|
13
|
+
s.author = 'Tony Pitale'
|
14
|
+
s.email = 'tony.pitale@viget.com'
|
15
|
+
s.homepage = 'http://viget.com/extend'
|
16
|
+
s.files = %w(README.textile Rakefile) + Dir.glob("lib/**/*")
|
17
|
+
s.test_files = Dir.glob("test/**/*_test.rb")
|
18
|
+
|
19
|
+
s.add_dependency('bcrypt-ruby', '~> 2.0.5')
|
20
|
+
end
|
21
|
+
|
22
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
23
|
+
pkg.gem_spec = spec
|
24
|
+
end
|
25
|
+
|
26
|
+
Rake::TestTask.new do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Generate the gemspec to serve this Gem from Github'
|
33
|
+
task :github do
|
34
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
35
|
+
File.open(file, 'w') {|f| f << spec.to_ruby }
|
36
|
+
puts "Created gemspec: #{file}"
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
require 'rcov/rcovtask'
|
41
|
+
|
42
|
+
desc "Generate RCov coverage report"
|
43
|
+
Rcov::RcovTask.new(:rcov) do |t|
|
44
|
+
t.test_files = FileList['test/**/*_test.rb']
|
45
|
+
t.rcov_opts << "-x lib/simplest_auth.rb -x lib/simplest_auth/version.rb"
|
46
|
+
end
|
47
|
+
rescue LoadError
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
task :default => 'test'
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SimplestAuth
|
2
|
+
class UndefinedMethodError < StandardError; end
|
3
|
+
|
4
|
+
module Controller
|
5
|
+
def user_class
|
6
|
+
User
|
7
|
+
end
|
8
|
+
|
9
|
+
def authorized?
|
10
|
+
logged_in?
|
11
|
+
end
|
12
|
+
|
13
|
+
def access_denied
|
14
|
+
store_location
|
15
|
+
flash[:error] = login_message
|
16
|
+
redirect_to new_session_url
|
17
|
+
end
|
18
|
+
|
19
|
+
def login_message
|
20
|
+
"Login or Registration Required"
|
21
|
+
end
|
22
|
+
|
23
|
+
def store_location
|
24
|
+
session[:return_to] = request.request_uri
|
25
|
+
end
|
26
|
+
|
27
|
+
def redirect_back_or_default(default)
|
28
|
+
redirect_to(session[:return_to] || default)
|
29
|
+
session[:return_to] = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def login_required
|
33
|
+
authorized? || access_denied
|
34
|
+
end
|
35
|
+
|
36
|
+
def logged_in?
|
37
|
+
!current_user_id.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def current_user
|
41
|
+
if @current_user.nil?
|
42
|
+
begin
|
43
|
+
@current_user = user_class.find(current_user_id)
|
44
|
+
rescue user_class::RecordNotFound
|
45
|
+
clear_session
|
46
|
+
@current_user = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@current_user
|
50
|
+
end
|
51
|
+
|
52
|
+
def current_user=(user)
|
53
|
+
session[:user_id] = user ? user.id : nil
|
54
|
+
@current_user = user || false
|
55
|
+
end
|
56
|
+
|
57
|
+
def current_user_id
|
58
|
+
session[:user_id]
|
59
|
+
end
|
60
|
+
|
61
|
+
def clear_session
|
62
|
+
session[:user_id] = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.included(base)
|
66
|
+
base.send :helper_method, :current_user, :logged_in?, :authorized? if base.respond_to? :helper_method
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SimplestAuth
|
2
|
+
module Model
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.send(:include, InstanceMethods)
|
6
|
+
|
7
|
+
base.class_eval do
|
8
|
+
attr_accessor :password, :password_confirmation
|
9
|
+
end
|
10
|
+
|
11
|
+
if base.active_record?
|
12
|
+
base.class_eval do
|
13
|
+
before_save :hash_password, :if => :password_required?
|
14
|
+
end
|
15
|
+
elsif base.data_mapper?
|
16
|
+
base.class_eval do
|
17
|
+
before :save, :hash_password, :if => :password_required?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def active_record?
|
24
|
+
defined?(ActiveRecord)
|
25
|
+
end
|
26
|
+
|
27
|
+
def data_mapper?
|
28
|
+
defined?(DataMapper)
|
29
|
+
end
|
30
|
+
|
31
|
+
def authenticate(email, password)
|
32
|
+
if active_record?
|
33
|
+
klass = find_by_email(email)
|
34
|
+
elsif data_mapper?
|
35
|
+
klass = first(:email => email)
|
36
|
+
end
|
37
|
+
|
38
|
+
(klass && klass.authentic?(password)) ? klass : nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def authenticate_by(ident)
|
42
|
+
if active_record?
|
43
|
+
instance_eval <<-EOM
|
44
|
+
def authenticate(#{ident}, password)
|
45
|
+
klass = find_by_#{ident}(#{ident})
|
46
|
+
(klass && klass.authentic?(password)) ? klass : nil
|
47
|
+
end
|
48
|
+
EOM
|
49
|
+
elsif data_mapper?
|
50
|
+
instance_eval <<-EOM
|
51
|
+
def authenticate(#{ident}, password)
|
52
|
+
klass = first(:#{ident} => #{ident})
|
53
|
+
(klass && klass.authentic?(password)) ? klass : nil
|
54
|
+
end
|
55
|
+
EOM
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
include BCrypt
|
62
|
+
|
63
|
+
RecordNotFound = Class.new(StandardError)
|
64
|
+
|
65
|
+
def authentic?(password)
|
66
|
+
Password.new(self.crypted_password) == password
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def hash_password
|
71
|
+
self.crypted_password = Password.create(self.password) if password_required?
|
72
|
+
end
|
73
|
+
|
74
|
+
def password_required?
|
75
|
+
self.crypted_password.blank? || !self.password.blank?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
ARUser = Class.new
|
4
|
+
|
5
|
+
class ARUserTest < Test::Unit::TestCase
|
6
|
+
include BCrypt
|
7
|
+
|
8
|
+
context "with ActiveRecord" do
|
9
|
+
setup do
|
10
|
+
ARUser.stubs(:active_record?).returns(true)
|
11
|
+
ARUser.expects(:before_save).with(:hash_password, :if => :password_required?)
|
12
|
+
ARUser.send(:include, SimplestAuth::Model)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "the ARUser class" do
|
16
|
+
should "redefine authenticate for AR" do
|
17
|
+
ARUser.expects(:instance_eval).with(kind_of(String))
|
18
|
+
ARUser.authenticate_by :email
|
19
|
+
end
|
20
|
+
|
21
|
+
should "have a default authenticate to email" do
|
22
|
+
user = mock do |m|
|
23
|
+
m.expects(:authentic?).with('password').returns(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
ARUser.expects(:find_by_email).with('joe@schmoe.com').returns(user)
|
27
|
+
assert_equal user, ARUser.authenticate('joe@schmoe.com', 'password')
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with authenticate_by set to username" do
|
31
|
+
setup do
|
32
|
+
ARUser.authenticate_by :username
|
33
|
+
end
|
34
|
+
|
35
|
+
should "find a user with email for authentication" do
|
36
|
+
user = mock do |m|
|
37
|
+
m.expects(:authentic?).with('password').returns(true)
|
38
|
+
end
|
39
|
+
|
40
|
+
ARUser.expects(:find_by_username).with('joeschmoe').returns(user)
|
41
|
+
assert_equal user, ARUser.authenticate('joeschmoe', 'password')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class User
|
4
|
+
class RecordNotFound < StandardError; end
|
5
|
+
end
|
6
|
+
|
7
|
+
class ControllerTest < Test::Unit::TestCase
|
8
|
+
include SimplestAuth::Controller
|
9
|
+
|
10
|
+
context "the Controller module" do
|
11
|
+
should "know if a user is authorized" do
|
12
|
+
stubs(:logged_in?).returns(true)
|
13
|
+
assert authorized?
|
14
|
+
end
|
15
|
+
|
16
|
+
should "redirect to a new session if access is denied" do
|
17
|
+
stubs(:store_location)
|
18
|
+
expects(:redirect_to).with("")
|
19
|
+
stubs(:new_session_url).returns("")
|
20
|
+
stubs(:flash).returns({})
|
21
|
+
access_denied
|
22
|
+
end
|
23
|
+
|
24
|
+
should "set the error flash if access is denied" do
|
25
|
+
stubs(:store_location)
|
26
|
+
stubs(:redirect_to).with("")
|
27
|
+
stubs(:new_session_url).returns("")
|
28
|
+
stubs(:login_message).returns("blah")
|
29
|
+
flash_stub = {}
|
30
|
+
stubs(:flash).returns(flash_stub)
|
31
|
+
access_denied
|
32
|
+
assert_equal "blah", flash_stub[:error]
|
33
|
+
end
|
34
|
+
|
35
|
+
should "store the location of the desired page before redirecting" do
|
36
|
+
expects(:store_location)
|
37
|
+
stubs(:redirect_to)
|
38
|
+
stubs(:new_session_url)
|
39
|
+
stubs(:flash).returns({})
|
40
|
+
access_denied
|
41
|
+
end
|
42
|
+
|
43
|
+
should "store the location of the current request to session" do
|
44
|
+
expects(:session).returns({})
|
45
|
+
stubs(:request).returns(stub(:request_uri => ''))
|
46
|
+
store_location
|
47
|
+
end
|
48
|
+
|
49
|
+
should "redirect back to the stored uri" do
|
50
|
+
stubs(:session).returns({:return_to => 'somewhere'})
|
51
|
+
expects(:redirect_to).with('somewhere')
|
52
|
+
redirect_back_or_default('')
|
53
|
+
end
|
54
|
+
|
55
|
+
should "redirect to a default location if the session url is nil" do
|
56
|
+
stubs(:session).returns({:return_to => nil})
|
57
|
+
expects(:redirect_to).with('default')
|
58
|
+
redirect_back_or_default('default')
|
59
|
+
end
|
60
|
+
|
61
|
+
should "clear the session stored url after redirect" do
|
62
|
+
session = {:return_to => 'somewhere'}
|
63
|
+
stubs(:session).returns(session)
|
64
|
+
stubs(:redirect_to)
|
65
|
+
redirect_back_or_default('')
|
66
|
+
assert_nil session[:return_to]
|
67
|
+
end
|
68
|
+
|
69
|
+
should "know if login is required from authorized method" do
|
70
|
+
stubs(:authorized?).returns(true)
|
71
|
+
assert login_required
|
72
|
+
end
|
73
|
+
|
74
|
+
should "consider access denied if login is required and not authorized" do
|
75
|
+
stubs(:authorized?).returns(false)
|
76
|
+
expects(:access_denied)
|
77
|
+
login_required
|
78
|
+
end
|
79
|
+
|
80
|
+
should "know if a user is logged in" do
|
81
|
+
stubs(:current_user_id).returns(1)
|
82
|
+
assert logged_in?
|
83
|
+
end
|
84
|
+
|
85
|
+
should "know if a user is not logged in" do
|
86
|
+
stubs(:current_user_id).returns(nil)
|
87
|
+
assert_equal false, logged_in?
|
88
|
+
end
|
89
|
+
|
90
|
+
should "find the current user" do
|
91
|
+
user_stub = stub()
|
92
|
+
user_stub.stubs(:find).with(1).returns("user")
|
93
|
+
|
94
|
+
stubs(:current_user_id).returns(1)
|
95
|
+
stubs(:user_class).returns(user_stub)
|
96
|
+
|
97
|
+
assert_equal "user", current_user
|
98
|
+
end
|
99
|
+
|
100
|
+
should "return nil for the current user if it doesn't exist" do
|
101
|
+
User.stubs(:find).with('1').raises(User::RecordNotFound)
|
102
|
+
stubs(:current_user_id).with().returns('1')
|
103
|
+
stubs(:clear_session)
|
104
|
+
|
105
|
+
assert_nil current_user
|
106
|
+
end
|
107
|
+
|
108
|
+
should "be able to clear its session variables" do
|
109
|
+
expects(:session).with().returns(mock() {|m| m.expects(:[]=).with(:user_id, nil) })
|
110
|
+
clear_session
|
111
|
+
end
|
112
|
+
|
113
|
+
should "clear the :user_id from session if the user cannot be found" do
|
114
|
+
User.stubs(:find).with('1').raises(User::RecordNotFound)
|
115
|
+
stubs(:current_user_id).with().returns('1')
|
116
|
+
expects(:clear_session).with()
|
117
|
+
|
118
|
+
current_user
|
119
|
+
end
|
120
|
+
|
121
|
+
should "allow assigning to the current user" do
|
122
|
+
stubs(:session).returns({})
|
123
|
+
user = mock(:id => 1)
|
124
|
+
self.current_user = user
|
125
|
+
end
|
126
|
+
|
127
|
+
should "save the current user to avoid lookup" do
|
128
|
+
stubs(:session).returns({})
|
129
|
+
user = stub(:id => 1)
|
130
|
+
self.current_user = user
|
131
|
+
assert_equal user, current_user
|
132
|
+
end
|
133
|
+
|
134
|
+
should "know the current user id from session" do
|
135
|
+
stubs(:session).returns({:user_id => 1})
|
136
|
+
assert_equal 1, current_user_id
|
137
|
+
end
|
138
|
+
|
139
|
+
should "have a default login error message" do
|
140
|
+
assert_equal "Login or Registration Required", login_message
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
DMUser = Class.new
|
4
|
+
|
5
|
+
class DMUserTest < Test::Unit::TestCase
|
6
|
+
include BCrypt
|
7
|
+
|
8
|
+
context "with DataMapper" do
|
9
|
+
setup do
|
10
|
+
DMUser.stubs(:active_record?).returns(false)
|
11
|
+
DMUser.stubs(:data_mapper?).returns(true)
|
12
|
+
DMUser.expects(:before).with(:save, :hash_password, :if => :password_required?)
|
13
|
+
DMUser.send(:include, SimplestAuth::Model)
|
14
|
+
end
|
15
|
+
|
16
|
+
context "the DMUser class" do
|
17
|
+
should "redefine authenticate for DM" do
|
18
|
+
DMUser.expects(:instance_eval).with(kind_of(String))
|
19
|
+
DMUser.authenticate_by :email
|
20
|
+
end
|
21
|
+
|
22
|
+
should "have a default authenticate to email" do
|
23
|
+
user = mock do |m|
|
24
|
+
m.expects(:authentic?).with('password').returns(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
DMUser.expects(:first).with(:email => 'joe@schmoe.com').returns(user)
|
28
|
+
assert_equal user, DMUser.authenticate('joe@schmoe.com', 'password')
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with authenticate_by set to username" do
|
32
|
+
setup do
|
33
|
+
DMUser.authenticate_by :username
|
34
|
+
end
|
35
|
+
|
36
|
+
should "find a user with email for authentication" do
|
37
|
+
user = mock do |m|
|
38
|
+
m.expects(:authentic?).with('password').returns(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
DMUser.expects(:first).with(:username => 'joeschmoe').returns(user)
|
42
|
+
assert_equal user, DMUser.authenticate('joeschmoe', 'password')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class User; end
|
4
|
+
|
5
|
+
class UserTest < Test::Unit::TestCase
|
6
|
+
include BCrypt
|
7
|
+
|
8
|
+
context "with no ORM" do
|
9
|
+
setup do
|
10
|
+
User.stubs(:active_record?).returns(false)
|
11
|
+
User.stubs(:data_mapper?).returns(false)
|
12
|
+
User.send(:include, SimplestAuth::Model)
|
13
|
+
end
|
14
|
+
|
15
|
+
should "return nil for authenticate" do
|
16
|
+
assert_equal nil, User.authenticate('email', 'password')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "an instance of the User class" do
|
21
|
+
setup do
|
22
|
+
User.send(:include, SimplestAuth::Model)
|
23
|
+
@user = User.new
|
24
|
+
@user.stubs(:crypted_password).returns('abcdefg')
|
25
|
+
end
|
26
|
+
|
27
|
+
should "determine if a password is authentic" do
|
28
|
+
password_stub = stub
|
29
|
+
password_stub.stubs(:==).with('password').returns(true)
|
30
|
+
Password.stubs(:new).with('abcdefg').returns(password_stub)
|
31
|
+
|
32
|
+
assert @user.authentic?('password')
|
33
|
+
end
|
34
|
+
|
35
|
+
should "determine when a password is not authentic" do
|
36
|
+
password_stub = stub
|
37
|
+
password_stub.stubs(:==).with('password').returns(false)
|
38
|
+
Password.stubs(:new).with('abcdefg').returns(password_stub)
|
39
|
+
|
40
|
+
assert_equal false, @user.authentic?('password')
|
41
|
+
end
|
42
|
+
|
43
|
+
should "use the Password class == method for comparison" do
|
44
|
+
password_stub = mock
|
45
|
+
password_stub.expects(:==).with('password').returns(true)
|
46
|
+
Password.stubs(:new).with('abcdefg').returns(password_stub)
|
47
|
+
|
48
|
+
@user.authentic?('password')
|
49
|
+
end
|
50
|
+
|
51
|
+
should "use a new Password made from crypted_password" do
|
52
|
+
password_stub = stub
|
53
|
+
password_stub.stubs(:==).with('password').returns(true)
|
54
|
+
Password.expects(:new).with('abcdefg').returns(password_stub)
|
55
|
+
|
56
|
+
@user.authentic?('password')
|
57
|
+
end
|
58
|
+
|
59
|
+
should "hash a password using bcrypt" do
|
60
|
+
@user.stubs(:password_required?).returns(true)
|
61
|
+
@user.expects(:crypted_password=).with('abcdefg')
|
62
|
+
@user.password = 'password'
|
63
|
+
Password.expects(:create).with('password').returns('abcdefg')
|
64
|
+
|
65
|
+
@user.send(:hash_password)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "require a password if crypted password is blank" do
|
69
|
+
@user.stubs(:crypted_password).returns(stub(:blank? => true))
|
70
|
+
assert_equal true, @user.send(:password_required?)
|
71
|
+
end
|
72
|
+
|
73
|
+
should "require a password if a password has been set" do
|
74
|
+
@user.stubs(:crypted_password).returns(stub(:blank? => false))
|
75
|
+
@user.stubs(:password).returns(stub(:blank? => false))
|
76
|
+
assert_equal true, @user.send(:password_required?)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simplest_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tony Pitale
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-03 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bcrypt-ruby
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.5
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: tony.pitale@viget.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README.textile
|
35
|
+
- Rakefile
|
36
|
+
- lib/simplest_auth
|
37
|
+
- lib/simplest_auth/controller.rb
|
38
|
+
- lib/simplest_auth/model.rb
|
39
|
+
- lib/simplest_auth/version.rb
|
40
|
+
- lib/simplest_auth.rb
|
41
|
+
- test/unit/simplest_auth/ar_model_test.rb
|
42
|
+
- test/unit/simplest_auth/controller_test.rb
|
43
|
+
- test/unit/simplest_auth/dm_model_test.rb
|
44
|
+
- test/unit/simplest_auth/model_test.rb
|
45
|
+
has_rdoc: false
|
46
|
+
homepage: http://viget.com/extend
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: Simple implementation of authentication for Rails
|
71
|
+
test_files:
|
72
|
+
- test/unit/simplest_auth/ar_model_test.rb
|
73
|
+
- test/unit/simplest_auth/controller_test.rb
|
74
|
+
- test/unit/simplest_auth/dm_model_test.rb
|
75
|
+
- test/unit/simplest_auth/model_test.rb
|