]> source.dussan.org Git - redmine.git/commitdiff
Change User#login to be case-insensitive. #2473
authorEric Davis <edavis@littlestreamsoftware.com>
Sun, 20 Jun 2010 21:40:50 +0000 (21:40 +0000)
committerEric Davis <edavis@littlestreamsoftware.com>
Sun, 20 Jun 2010 21:40:50 +0000 (21:40 +0000)
This change also overrides User#find_by_login to give priority to exact
matches in the login.

Contributed by Greg Mefford

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3807 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/user.rb
test/unit/user_test.rb

index a38a091701e2a0ec576639f22ae4b7f7386c30c0..5d0254ee1c7637a1fb0b9e9827b9ccd92199a544 100644 (file)
@@ -53,7 +53,7 @@ class User < Principal
   attr_protected :login, :admin, :password, :password_confirmation, :hashed_password, :group_ids
        
   validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
-  validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
+  validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }, :case_sensitive => false
   validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
   # Login must contain lettres, numbers, underscores only
   validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
@@ -96,7 +96,7 @@ class User < Principal
   def self.try_to_login(login, password)
     # Make sure no one can sign in with an empty password
     return nil if password.to_s.empty?
-    user = find(:first, :conditions => ["login=?", login])
+    user = find_by_login(login)
     if user
       # user is already in local database
       return nil if !user.active?
@@ -222,6 +222,15 @@ class User < Principal
     notified_projects_ids
   end
   
+  # case-insensitive fall-over
+  def self.find_by_login(login)
+    # First look for an exact match
+    user = find(:first, :conditions => ["login = ?", login])
+    # Fail over to case-insensitive if none was found
+    user = find(:first, :conditions => ["LOWER(login) = ?", login.to_s.downcase]) if user.nil?
+    return user
+  end
+
   def self.find_by_rss_key(key)
     token = Token.find_by_value(key)
     token && token.user.active? ? token.user : nil
index 77a9ee984763c5006ab4bd10d1e105a89648d005..8d66e86da4c297ca1d333ab391244b272a1462ee 100644 (file)
@@ -55,6 +55,21 @@ class UserTest < ActiveSupport::TestCase
     assert user.save
   end
   
+  context "User.login" do
+    should "be case-insensitive." do
+      u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
+      u.login = 'newuser'
+      u.password, u.password_confirmation = "password", "password"
+      assert u.save
+      
+      u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
+      u.login = 'NewUser'
+      u.password, u.password_confirmation = "password", "password"
+      assert !u.save
+      assert_equal I18n.translate('activerecord.errors.messages.taken'), u.errors.on(:login)
+    end
+  end
+
   def test_mail_uniqueness_should_not_be_case_sensitive
     u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
     u.login = 'newuser1'
@@ -88,6 +103,25 @@ class UserTest < ActiveSupport::TestCase
     assert_equal 1, @admin.errors.count
   end
   
+  context "User#try_to_login" do
+    should "fall-back to case-insensitive if user login is not found as-typed." do
+      user = User.try_to_login("AdMin", "admin")
+      assert_kind_of User, user
+      assert_equal "admin", user.login
+    end
+
+    should "select the exact matching user first" do
+      case_sensitive_user = User.generate_with_protected!(:login => 'changed', :password => 'admin', :password_confirmation => 'admin')
+      # bypass validations to make it appear like existing data
+      case_sensitive_user.update_attribute(:login, 'ADMIN')
+
+      user = User.try_to_login("ADMIN", "admin")
+      assert_kind_of User, user
+      assert_equal "ADMIN", user.login
+
+    end
+  end
+
   def test_password
     user = User.try_to_login("admin", "admin")
     assert_kind_of User, user