dancroak-clearance 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/README.textile ADDED
@@ -0,0 +1,78 @@
1
+ h1. Clearance
2
+
3
+ Simple, complete Rails authentication.
4
+
5
+ "We have clearance, Clarence.":http://www.youtube.com/v/mNRXJEE3Nz8
6
+
7
+ h2. Features
8
+
9
+ * email & password
10
+ * modules, not a generator
11
+ * gem, not a plugin
12
+ * should & factory_girl tests included
13
+
14
+ h2. Schema
15
+
16
+ Change your User model so it has these attributes.
17
+
18
+ change_table(:users) do |t|
19
+ t.column :email, :string
20
+ t.column :crypted_password, :string, :limit => 40
21
+ t.column :salt, :string, :limit => 40
22
+ t.column :remember_token, :string
23
+ t.column :remember_token_expires_at, :datetime
24
+ end
25
+
26
+ add_index :users, [:email, :password]
27
+
28
+ h2. Model
29
+
30
+ In app/models/user.rb:
31
+
32
+ include Clearance::Model
33
+
34
+ h2. Controllers
35
+
36
+ In app/controllers/application_controller.rb:
37
+
38
+ include Clearance::ApplicationController
39
+
40
+ In app/controllers/sessions_controller.rb:
41
+
42
+ include Clearance::SessionsController
43
+
44
+ In app/controllers/users_controller.rb:
45
+
46
+ include Clearance::UsersController
47
+
48
+ h2. Routes
49
+
50
+ map.login '/login', :controller => 'sessions', :action => 'new'
51
+ map.logout '/logout', :controller => 'sessions', :action => 'destroy'
52
+ map.resource :session
53
+
54
+ h2. Tests
55
+
56
+ The tests use Shoulda and Factory Girl.
57
+
58
+ In test/test_helper.rb:
59
+
60
+ include Clearance::TestHelper
61
+
62
+ In test/unit/user_test.rb:
63
+
64
+ include Clearance::UnitTest
65
+
66
+ In test/functional/sessions_controller_test.rb:
67
+
68
+ include Clearance::SessionsControllerTest
69
+
70
+ In test/functional/users_controller_test.rb:
71
+
72
+ include Clearance::UsersControllerTest
73
+
74
+ h2. Authors
75
+
76
+ * thoughtbot, inc.
77
+ * Dan Croak
78
+ * Josh Nichols
data/clearance.gemspec ADDED
@@ -0,0 +1,11 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "clearance"
3
+ s.version = "0.1"
4
+ s.date = "2008-09-06"
5
+ s.summary = "Simple, complete Rails authentication."
6
+ s.email = "dcroak@thoughtbot.com"
7
+ s.homepage = "http://github.com/dancroak/clearance"
8
+ s.description = "Simple, complete Rails authentication scheme."
9
+ s.authors = ["thoughtbot, inc.", "Dan Croak", "Josh Nichols"]
10
+ s.files = ["README.textile", "clearance.gemspec", "lib/clearance.rb", "lib/clearance/application_controller.rb", "lib/clearance/model.rb", "lib/clearance/sessions_controller.rb", "lib/clearance/sessions_controller_test.rb", "lib/clearance/test_helper.rb", "lib/clearance/unit_test.rb", "lib/clearance/users_controller.rb", "lib/clearance/users_controller_test.rb"]
11
+ end
data/lib/clearance.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'clearance/application_controller'
2
+ require 'clearance/sessions_controller'
3
+ require 'clearance/users_controller'
4
+ require 'clearance/model'
5
+ require 'clearance/test_helper'
6
+ require 'clearance/sessions_controller_test'
7
+ require 'clearance/users_controller_test'
8
+ require 'clearance/unit_test'
@@ -0,0 +1,62 @@
1
+ module Clearance
2
+ module ApplicationController
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ attr_accessor :current_user
7
+ helper_method :current_user
8
+
9
+ include InstanceMethods
10
+
11
+ protected
12
+ include ProtectedInstanceMethods
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+ def current_user
18
+ @current_user ||= (user_from_session || user_from_cookie)
19
+ end
20
+ end
21
+
22
+ module ProtectedInstanceMethods
23
+ def authenticate
24
+ deny_access if current_user.nil?
25
+ end
26
+
27
+ def user_from_session
28
+ User.find_by_id(session[:user_id])
29
+ end
30
+
31
+ def user_from_cookie
32
+ user = User.find_by_remember_token(cookies[:auth_token]) if cookies[:auth_token]
33
+ user && user.remember_token? ? user : nil
34
+ end
35
+
36
+ def login(user)
37
+ create_session_for user
38
+ @current_user = user
39
+ end
40
+
41
+ def create_session_for(user)
42
+ session[:user_id] = user.id if user
43
+ end
44
+
45
+ def redirect_back_or(default)
46
+ session[:return_to] ? redirect_to(session[:return_to]) : redirect_to(default)
47
+ session[:return_to] = nil
48
+ end
49
+
50
+ def store_location
51
+ session[:return_to] = request.request_uri
52
+ end
53
+
54
+ def deny_access(flash_message = nil, opts = {})
55
+ opts[:redirect] ||= login_url
56
+ store_location
57
+ flash[:error] = flash_message if flash_message
58
+ redirect_to opts[:redirect]
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,84 @@
1
+ module Clearance
2
+ module Model
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+
7
+ attr_accessible :email, :password, :password_confirmation
8
+ attr_accessor :password, :password_confirmation
9
+
10
+ validates_presence_of :email
11
+ validates_presence_of :password, :if => :password_required?
12
+ validates_length_of :password, :within => 3..40, :if => :password_required?
13
+ validates_confirmation_of :password, :if => :password_required?
14
+ validates_uniqueness_of :email
15
+
16
+ before_save :initialize_salt, :encrypt_password
17
+
18
+ extend ClassMethods
19
+ include InstanceMethods
20
+
21
+ protected
22
+
23
+ include ProtectedInstanceMethods
24
+
25
+ end
26
+ end
27
+
28
+ module ClassMethods
29
+ def authenticate(email, password)
30
+ user = find_by_email(email) # need to get the salt
31
+ user && user.authenticated?(password) ? user : nil
32
+ end
33
+
34
+ def authenticate_via_auth_token(token)
35
+ return nil if token.blank?
36
+ find_by_auth_token(token)
37
+ end
38
+ end
39
+
40
+ module InstanceMethods
41
+ def authenticated?(password)
42
+ crypted_password == encrypt(password)
43
+ end
44
+
45
+ def encrypt(password)
46
+ Digest::SHA1.hexdigest("--#{salt}--#{password}--")
47
+ end
48
+
49
+ def remember_token?
50
+ remember_token_expires_at && Time.now.utc < remember_token_expires_at
51
+ end
52
+
53
+ def remember_me!
54
+ remember_me_until 2.weeks.from_now.utc
55
+ end
56
+
57
+ def remember_me_until(time)
58
+ self.update_attribute :remember_token_expires_at, time
59
+ self.update_attribute :remember_token, encrypt("#{email}--#{remember_token_expires_at}")
60
+ end
61
+
62
+ def forget_me!
63
+ self.update_attribute :remember_token_expires_at, nil
64
+ self.update_attribute :remember_token, nil
65
+ end
66
+ end
67
+
68
+ module ProtectedInstanceMethods
69
+ def initialize_salt
70
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{email}--") if new_record?
71
+ end
72
+
73
+ def encrypt_password
74
+ return if password.blank?
75
+ self.crypted_password = encrypt(password)
76
+ end
77
+
78
+ def password_required?
79
+ crypted_password.blank? || !password.blank?
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,66 @@
1
+ module Clearance
2
+ module SessionsController
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ skip_before_filter :authenticate
7
+ protect_from_forgery :except => :create
8
+ filter_parameter_logging :password
9
+
10
+ include InstanceMethods
11
+
12
+ protected
13
+ include ProtectedInstanceMethods
14
+ end
15
+ end
16
+
17
+ module InstanceMethods
18
+ def create
19
+ remember_me = params[:session][:remember_me] if params[:session]
20
+ login_via_password(params[:session][:email], params[:session][:password], remember_me)
21
+ end
22
+
23
+ def destroy
24
+ forget current_user
25
+ reset_session
26
+ flash[:notice] = 'You have been logged out.'
27
+ redirect_to login_url
28
+ end
29
+ end
30
+
31
+ module ProtectedInstanceMethods
32
+ def login_via_password(email, password, remember_me)
33
+ user = User.authenticate(email, password)
34
+ if login(user)
35
+ create_session_for(user)
36
+ remember(user) if remember_me == '1'
37
+ login_successful
38
+ else
39
+ login_failure
40
+ end
41
+ end
42
+
43
+ def login_successful
44
+ flash[:notice] = 'Logged in successfully'
45
+ redirect_back_or root_url
46
+ end
47
+
48
+ def login_failure(message = "Bad email or password.")
49
+ flash.now[:notice] = message
50
+ render :action => :new
51
+ end
52
+
53
+ def remember(user)
54
+ user.remember_me!
55
+ cookies[:auth_token] = { :value => user.remember_token,
56
+ :expires => user.remember_token_expires_at }
57
+ end
58
+
59
+ def forget(user)
60
+ user.forget_me! if user
61
+ cookies.delete :auth_token
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,84 @@
1
+ module Clearance
2
+ module SessionsControllerTest
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ context "Given a user" do
7
+ setup do
8
+ @user = Factory(:user)
9
+ end
10
+
11
+ should_filter :password
12
+
13
+ # context "on GET to /sessions/new" do
14
+ # setup { get :new }
15
+ #
16
+ # should_respond_with :success
17
+ # should_render_template :new
18
+ # should_not_set_the_flash
19
+ # should "render a login form" do
20
+ # assert_select "form[action=/session]" do
21
+ # assert_select "input[type=text][name=?]", "session[email]"
22
+ # assert_select "input[type=password][name=?]", "session[password]"
23
+ # assert_select "input[type=checkbox][name=?]", "session[remember_me]"
24
+ # end
25
+ # end
26
+ # end
27
+
28
+ context "a POST to #create with good credentials" do
29
+ setup do
30
+ post :create, :session => { :email => @user.email, :password => @user.password }
31
+ end
32
+
33
+ should_set_the_flash_to /success/i
34
+ should_redirect_to 'root_url'
35
+ end
36
+
37
+ context "a POST to #create with bad credentials" do
38
+ setup do
39
+ post :create, :session => { :email => @user.email, :password => "bad value" }
40
+ end
41
+
42
+ should_set_the_flash_to /bad/i
43
+ should_render_template :new
44
+ end
45
+
46
+ end
47
+
48
+ context "While logged out" do
49
+ setup { logout }
50
+
51
+ context "logging out again" do
52
+ setup { delete :destroy }
53
+ should_redirect_to "login_url"
54
+ end
55
+ end
56
+
57
+ logged_in_user_context do
58
+ context "a DELETE to #destroy without a cookie" do
59
+ setup { delete :destroy }
60
+
61
+ should_set_the_flash_to(/logged out/i)
62
+ should_redirect_to "login_url"
63
+ end
64
+
65
+ context 'a DELETE to #destroy with a cookie' do
66
+ setup do
67
+ cookies['auth_token'] = CGI::Cookie.new 'token', 'value'
68
+ delete :destroy
69
+ end
70
+
71
+ should 'delete the cookie' do
72
+ assert cookies['auth_token'].empty?
73
+ end
74
+
75
+ should 'delete the remember me token in users table' do
76
+ assert_nil @current_user.reload.remember_token
77
+ assert_nil @current_user.reload.remember_token_expires_at
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,75 @@
1
+ module Clearance
2
+ module TestHelper
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+ extend ClassMethods
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ def login_as(user = nil)
13
+ user ||= Factory(:user)
14
+ @request.session[:user_id] = user.id
15
+ return user
16
+ end
17
+
18
+ def logout
19
+ @request.session[:user_id] = nil
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ def should_deny_access_on(command, opts = {})
25
+ opts[:redirect] ||= "login_url"
26
+
27
+ context "on #{command}" do
28
+ setup { eval command }
29
+ should_redirect_to opts[:redirect]
30
+ if opts[:flash]
31
+ should_set_the_flash_to opts[:flash]
32
+ else
33
+ should_not_set_the_flash
34
+ end
35
+ end
36
+ end
37
+
38
+ def should_filter(*keys)
39
+ keys.each do |key|
40
+ should "filter #{key}" do
41
+ assert @controller.respond_to?(:filter_parameters),
42
+ "The key #{key} is not filtered"
43
+ filtered = @controller.send(:filter_parameters, {key.to_s => key.to_s})
44
+ assert_equal '[FILTERED]', filtered[key.to_s],
45
+ "The key #{key} is not filtered"
46
+ end
47
+ end
48
+ end
49
+
50
+ def should_have_user_form
51
+ should "have the user form" do
52
+ assert_select "form" do
53
+ %w(name email openid_url).each do |field|
54
+ assert_select "input[type=text][name=?]", "user[#{field}]"
55
+ end
56
+ %w(password password_confirmation).each do |field|
57
+ assert_select "input[type=password][name=?]", "user[#{field}]"
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def logged_in_user_context(user_name = nil, &blk)
64
+ context "When logged in as a user" do
65
+ setup do
66
+ user = user_name ? instance_variable_get("@#{user_name}") : Factory(:user)
67
+ assert @current_user = login_as(user)
68
+ end
69
+ merge_block(&blk)
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,186 @@
1
+ module Clearance
2
+ module UnitTest
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ should_require_attributes :email, :password
7
+
8
+ should "require password validation on create" do
9
+ user = Factory.build(:user, :password => 'blah', :password_confirmation => 'boogidy')
10
+ assert !user.save
11
+ assert_match(/confirmation/i, user.errors.on(:password))
12
+ end
13
+
14
+ should "create a crypted_password on save" do
15
+ assert_not_nil Factory(:user, :crypted_password => nil).crypted_password
16
+ end
17
+
18
+ context 'updating a password' do
19
+ setup do
20
+ @user = Factory(:user)
21
+ assert_not_nil @user.crypted_password
22
+ @crypt = @user.crypted_password
23
+ assert_not_nil @user.salt
24
+ @salt = @user.salt
25
+ @user.password = 'a_new_password'
26
+ @user.password_confirmation = 'a_new_password'
27
+ assert @user.save
28
+ end
29
+
30
+ should 'update a crypted_password' do
31
+ @user.reload
32
+ assert @user.crypted_password != @crypt
33
+ end
34
+ end
35
+
36
+ context 'A user' do
37
+ setup do
38
+ @password = 'sekrit'
39
+ @salt = 'salt'
40
+ User.any_instance.stubs(:initialize_salt)
41
+ @user = Factory(:user, :password => @password, :salt => @salt)
42
+ end
43
+
44
+ should "require password validation on update" do
45
+ @user.update_attributes(:password => "blah", :password_confirmation => "boogidy")
46
+ assert !@user.save
47
+ assert_match(/confirmation/i, @user.errors.on(:password))
48
+ end
49
+
50
+ should_require_unique_attributes :email
51
+
52
+ context 'authenticating a user' do
53
+ context 'with good credentials' do
54
+ setup do
55
+ @result = User.authenticate @user.email, 'sekrit'
56
+ end
57
+
58
+ should 'return true' do
59
+ assert @result
60
+ end
61
+ end
62
+
63
+ context 'with bad credentials' do
64
+ setup do
65
+ @result = User.authenticate @user.email, 'horribly_wrong_password'
66
+ end
67
+
68
+ should 'return true' do
69
+ assert !@result
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'authenticated?' do
75
+ context 'with good credentials' do
76
+ setup do
77
+ @result = @user.authenticated? @password
78
+ end
79
+
80
+ should 'return true' do
81
+ assert @result
82
+ end
83
+ end
84
+
85
+ context 'with bad credentials' do
86
+ setup do
87
+ @result = @user.authenticated? 'horribly_wrong_password'
88
+ end
89
+
90
+ should 'return true' do
91
+ assert !@result
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'encrypt' do
97
+ setup do
98
+ @crypted = @user.encrypt(@password)
99
+ @expected = Digest::SHA1.hexdigest("--#{@salt}--#{@password}--")
100
+ end
101
+
102
+ should 'create a Hash using SHA1 encryption' do
103
+ assert_equal @expected, @crypted
104
+ assert_not_equal @password, @crypted
105
+ end
106
+ end
107
+
108
+ context 'remember_me!' do
109
+ setup do
110
+ assert_nil @user.remember_token
111
+ assert_nil @user.remember_token_expires_at
112
+ @user.remember_me!
113
+ end
114
+
115
+ should 'set the remember token and expiration date' do
116
+ assert_not_nil @user.remember_token
117
+ assert_not_nil @user.remember_token_expires_at
118
+ end
119
+
120
+ should 'remember_token?' do
121
+ assert @user.remember_token?
122
+ end
123
+
124
+ context 'forget_me!' do
125
+ setup do
126
+ @user.forget_me!
127
+ end
128
+
129
+ should 'unset the remember token and expiration date' do
130
+ assert_nil @user.remember_token
131
+ assert_nil @user.remember_token_expires_at
132
+ end
133
+
134
+ should 'not remember_token?' do
135
+ assert ! @user.remember_token?
136
+ end
137
+ end
138
+ end
139
+
140
+ context 'remember_token?' do
141
+ context 'when token expires in the future' do
142
+ setup do
143
+ @user.update_attribute :remember_token_expires_at, 2.weeks.from_now.utc
144
+ end
145
+
146
+ should 'be true' do
147
+ assert @user.remember_token?
148
+ end
149
+ end
150
+
151
+ context 'when token expired' do
152
+ setup do
153
+ @user.update_attribute :remember_token_expires_at, 2.weeks.ago.utc
154
+ end
155
+
156
+ should 'be false' do
157
+ assert ! @user.remember_token?
158
+ end
159
+ end
160
+ end
161
+
162
+ context "User.authenticate with a valid email and password" do
163
+ setup do
164
+ @found_user = User.authenticate @user.email, @user.password
165
+ end
166
+
167
+ should "find that user" do
168
+ assert_equal @user, @found_user
169
+ end
170
+ end
171
+
172
+ context "When sent authenticate with an invalid email and password" do
173
+ setup do
174
+ @found_user = User.authenticate "not", "valid"
175
+ end
176
+
177
+ should "find nothing" do
178
+ assert_nil @found_user
179
+ end
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,22 @@
1
+ module Clearance
2
+ module UsersController
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ before_filter :authenticate
7
+ before_filter :ensure_user_is_accessing_self, :only => [:edit, :update, :show]
8
+
9
+ filter_parameter_logging :password
10
+ private
11
+ include PrivateInstanceMethods
12
+ end
13
+ end
14
+
15
+ module PrivateInstanceMethods
16
+ def ensure_user_is_accessing_self
17
+ deny_access 'You cannot edit that user.' unless current_user.id.to_i == params[:id].to_i
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,72 @@
1
+ module Clearance
2
+ module UsersControllerTest
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ logged_in_user_context do
7
+
8
+ should_deny_access_on "get :index"
9
+ should_deny_access_on "get :new"
10
+ should_deny_access_on "post :create, :user => {}"
11
+ should_filter :password
12
+
13
+ context "dealing with their own account" do
14
+ context "on GET to /users/:id/show" do
15
+ setup { get :show, :id => @user.to_param }
16
+ should_redirect_to "edit_user_url(@user)"
17
+ should_not_set_the_flash
18
+ end
19
+
20
+ should_deny_access_on "delete :destroy, :id => @user.to_param"
21
+
22
+ context "on GET to /users/:id/edit" do
23
+ setup { get :edit, :id => @user.to_param }
24
+
25
+ should_respond_with :success
26
+ should_render_template :edit
27
+ should_not_set_the_flash
28
+ should_assign_to :user
29
+ should_have_user_form
30
+ end
31
+
32
+ context "on PUT to /users/:id" do
33
+ setup do
34
+ put :update,
35
+ :id => @user.to_param,
36
+ :user => {:email => "none@example.com"}
37
+ end
38
+ should_set_the_flash_to /updated/i
39
+ should_redirect_to "root_url"
40
+ should_assign_to :user
41
+ should "update the user's attributes" do
42
+ assert_equal "none@example.com", assigns(:user).email
43
+ end
44
+ end
45
+
46
+ context "on PUT to /users/:id with invalid attributes" do
47
+ setup { put :update, :id => @user.to_param, :user => {:email => ''} }
48
+ should_not_set_the_flash
49
+ should_assign_to :user
50
+ should_render_template 'edit'
51
+ should "display errors" do
52
+ assert_select '#errorExplanation'
53
+ end
54
+ end
55
+ end
56
+
57
+ context "dealing with another user's account" do
58
+ setup do
59
+ @target_user = Factory(:user, :account => @user.account)
60
+ assert_equal @user.account, @target_user.account
61
+ end
62
+
63
+ should_deny_access_on "get :show, :id => @target_user.to_param", :flash => /cannot edit/i
64
+ should_deny_access_on "get :edit, :id => @target_user.to_param", :flash => /cannot edit/i
65
+ should_deny_access_on "put :update, :id => @target_user.to_param, :user => {}", :flash => /cannot edit/i
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ end
72
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dancroak-clearance
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - thoughtbot, inc.
8
+ - Dan Croak
9
+ - Josh Nichols
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2008-09-06 00:00:00 -07:00
15
+ default_executable:
16
+ dependencies: []
17
+
18
+ description: Simple, complete Rails authentication scheme.
19
+ email: dcroak@thoughtbot.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - README.textile
28
+ - clearance.gemspec
29
+ - lib/clearance.rb
30
+ - lib/clearance/application_controller.rb
31
+ - lib/clearance/model.rb
32
+ - lib/clearance/sessions_controller.rb
33
+ - lib/clearance/sessions_controller_test.rb
34
+ - lib/clearance/test_helper.rb
35
+ - lib/clearance/unit_test.rb
36
+ - lib/clearance/users_controller.rb
37
+ - lib/clearance/users_controller_test.rb
38
+ has_rdoc: false
39
+ homepage: http://github.com/dancroak/clearance
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: Simple, complete Rails authentication.
64
+ test_files: []
65
+