refinerycms-authentication 2.0.4 → 2.0.5

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.
@@ -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