refinerycms-authentication 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,7 +13,8 @@ module Refinery
13
13
  # Include default devise modules. Others available are:
14
14
  # :token_authenticatable, :confirmable, :lockable and :timeoutable
15
15
  if self.respond_to?(:devise)
16
- devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
16
+ devise :database_authenticatable, :registerable, :recoverable, :rememberable,
17
+ :trackable, :validatable, :authentication_keys => [:login]
17
18
  end
18
19
 
19
20
  # Setup accessible (or protected) attributes for your model
@@ -23,6 +24,7 @@ module Refinery
23
24
  attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :plugins, :login
24
25
 
25
26
  validates :username, :presence => true, :uniqueness => true
27
+ before_validation :downcase_username
26
28
 
27
29
  class << self
28
30
  # Find user by email or username.
@@ -77,7 +79,7 @@ module Refinery
77
79
  save
78
80
  # add refinery role
79
81
  add_role(:refinery)
80
- # add superuser role
82
+ # add superuser role if there are no other users
81
83
  add_role(:superuser) if ::Refinery::Role[:refinery].users.count == 1
82
84
  # add plugins
83
85
  self.plugins = Refinery::Plugins.registered.in_menu.names
@@ -95,5 +97,13 @@ module Refinery
95
97
  to_s.parameterize
96
98
  end
97
99
 
100
+ private
101
+ # To ensure uniqueness without case sensitivity we first downcase the username.
102
+ # We do this here and not in SQL is that it will otherwise bypass indexes using LOWER:
103
+ # SELECT 1 FROM "refinery_users" WHERE LOWER("refinery_users"."username") = LOWER('UsErNAME') LIMIT 1
104
+ def downcase_username
105
+ self.username = self.username.downcase if self.username?
106
+ end
107
+
98
108
  end
99
109
  end
@@ -7,19 +7,48 @@ module Refinery
7
7
  session[:return_to] = request.fullpath.sub("//", "/")
8
8
  end
9
9
 
10
+ # Clear and return the stored location
11
+ def pop_stored_location
12
+ session.delete(:return_to)
13
+ end
14
+
10
15
  # Redirect to the URI stored by the most recent store_location call or
11
16
  # to the passed default.
12
17
  def redirect_back_or_default(default)
13
- redirect_to(session[:return_to] || default)
14
- session[:return_to] = nil
18
+ redirect_to(pop_stored_location || default)
19
+ end
20
+
21
+ # This defines the devise method for refinery routes
22
+ def signed_in_root_path(resource_or_scope)
23
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
24
+ home_path = "#{scope}_root_path"
25
+ if respond_to?(home_path, true)
26
+ refinery.send(home_path)
27
+ elsif respond_to?(:admin_root_path)
28
+ refinery.admin_root_path
29
+ else
30
+ "/"
31
+ end
32
+ end
33
+
34
+ # Pops the stored url, trims the sneaky "//" from it, and returns it.
35
+ #
36
+ # Making sure bad urls aren't stored in the first place should probably be
37
+ # a part of the Devise::FailureApp
38
+ def sanitized_stored_location_for(resource_or_scope)
39
+ # `stored_location_for` is the devise method that pops the
40
+ # scoped `return_to` key
41
+ location = stored_location_for(resource_or_scope)
42
+ location.sub!("//", "/") if location.respond_to?(:sub!)
43
+ location
15
44
  end
16
45
 
17
46
  # This just defines the devise method for after sign in to support
18
47
  # extension namespace isolation...
19
48
  def after_sign_in_path_for(resource_or_scope)
20
- scope = Devise::Mapping.find_scope!(resource_or_scope)
21
- home_path = "#{scope}_root_path"
22
- respond_to?(home_path, true) ? refinery.send(home_path) : refinery.admin_root_path
49
+ pop_stored_location ||
50
+ sanitized_stored_location_for(resource_or_scope) ||
51
+ signed_in_root_path(resource_or_scope)
23
52
  end
24
53
 
25
54
  def after_sign_out_path_for(resource_or_scope)
@@ -30,7 +59,8 @@ module Refinery
30
59
  refinery_user_signed_in? && current_refinery_user.has_role?(:refinery)
31
60
  end
32
61
 
33
- protected :store_location, :redirect_back_or_default, :refinery_user?
62
+ protected :store_location, :pop_stored_location, :redirect_back_or_default,
63
+ :sanitized_stored_location_for, :refinery_user?
34
64
 
35
65
  def self.included(base)
36
66
  if base.respond_to? :helper_method
@@ -68,6 +68,11 @@ module Refinery
68
68
  User.create!(attr)
69
69
  User.new(attr.merge(:email => "another@email.com")).should_not be_valid
70
70
  end
71
+
72
+ it "rejects duplicate usernames regardless of case" do
73
+ User.create!(attr)
74
+ User.new(attr.merge(:username => attr[:username].upcase, :email => "another@email.com")).should_not be_valid
75
+ end
71
76
  end
72
77
 
73
78
  describe ".find_for_database_authentication" do
@@ -2,11 +2,15 @@ require "spec_helper"
2
2
 
3
3
  module Refinery
4
4
  describe "sign in" do
5
+ let(:login_path) { refinery.new_refinery_user_session_path }
6
+ let(:login_retry_path) { refinery.refinery_user_session_path }
7
+ let(:admin_path) { refinery.admin_root_path }
8
+
5
9
  before(:each) do
6
10
  FactoryGirl.create(:refinery_user, :username => "ugisozols",
7
11
  :password => "123456",
8
12
  :password_confirmation => "123456")
9
- visit refinery.new_refinery_user_session_path
13
+ visit login_path
10
14
  end
11
15
 
12
16
  it "shows login form" do
@@ -21,6 +25,7 @@ module Refinery
21
25
  fill_in "Password", :with => "123456"
22
26
  click_button "Sign in"
23
27
  page.should have_content("Signed in successfully.")
28
+ current_path.should == admin_path
24
29
  end
25
30
  end
26
31
 
@@ -30,6 +35,7 @@ module Refinery
30
35
  fill_in "Password", :with => "Hmmm"
31
36
  click_button "Sign in"
32
37
  page.should have_content("Sorry, your login or password was incorrect.")
38
+ current_path.should == login_retry_path
33
39
  end
34
40
  end
35
41
  end
@@ -59,4 +65,39 @@ module Refinery
59
65
  end
60
66
  end
61
67
  end
68
+
69
+ describe 'redirects' do
70
+ let(:protected_path) { refinery.new_admin_user_path }
71
+ let(:login_path) { refinery.new_refinery_user_session_path }
72
+
73
+ before(:each) do
74
+ FactoryGirl.create(:refinery_user,
75
+ :username => "ugisozols",
76
+ :password => "123456",
77
+ :password_confirmation => "123456"
78
+ )
79
+ end
80
+
81
+ context "when visiting a protected path" do
82
+ before(:each) { visit protected_path }
83
+
84
+ it "redirects to the login" do
85
+ current_path.should == login_path
86
+ end
87
+
88
+ it "shows login form" do
89
+ page.should have_content("Hello! Please sign in.")
90
+ page.should have_content("I forgot my password")
91
+ page.should have_selector("a[href*='/refinery/users/password/new']")
92
+ end
93
+
94
+ it "redirects to the protected path on login" do
95
+ fill_in "Login", :with => "ugisozols"
96
+ fill_in "Password", :with => "123456"
97
+ page.click_button "Sign in"
98
+ current_path.should == protected_path
99
+ end
100
+ end
101
+
102
+ end
62
103
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refinerycms-authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2012-05-14 00:00:00.000000000 Z
16
+ date: 2012-06-11 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: refinerycms-core
@@ -22,7 +22,7 @@ dependencies:
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 2.0.4
25
+ version: 2.0.5
26
26
  type: :runtime
27
27
  prerelease: false
28
28
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 2.0.4
33
+ version: 2.0.5
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: devise
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -157,7 +157,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
157
157
  version: '0'
158
158
  segments:
159
159
  - 0
160
- hash: 1393669055922669137
160
+ hash: -3083907870298684741
161
161
  required_rubygems_version: !ruby/object:Gem::Requirement
162
162
  none: false
163
163
  requirements:
@@ -166,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
166
  version: '0'
167
167
  segments:
168
168
  - 0
169
- hash: 1393669055922669137
169
+ hash: -3083907870298684741
170
170
  requirements: []
171
171
  rubyforge_project: refinerycms
172
172
  rubygems_version: 1.8.22