diff --git a/CHANGELOG b/CHANGELOG index 1d1c6d26e11..924f9c6204d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ v 7.5.0 - Fix LDAP config lookup for provider 'ldap' - Add Atlassian Bamboo CI service (Drew Blessing) - Mentioned @user will receive email even if he is not participating in issue or commit + - Session API: Use case-insensitive authentication like in UI (Andrey Krivko) v 7.4.2 - Fix internal snippet exposing for unauthenticated users @@ -49,7 +50,7 @@ v 7.4.0 - Fix ambiguous sha problem with mentioned commit - Fixed bug with apostrophe when at mentioning users - Add active directory ldap option - - Developers can push to wiki repo. Protected branches does not affect wiki repo any more + - Developers can push to wiki repo. Protected branches does not affect wiki repo any more - Faster rev list - Fix branch removal diff --git a/app/models/user.rb b/app/models/user.rb index 154cc0f3e16..52e63cde6f9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -226,6 +226,11 @@ class User < ActiveRecord::Base where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%") end + def by_login(login) + where('lower(username) = :value OR lower(email) = :value', + value: login.to_s.downcase).first + end + def by_username_or_id(name_or_id) where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first end diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index ae33c529b93..30509528b8b 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -1,7 +1,7 @@ module Gitlab class Auth def find(login, password) - user = User.find_by(email: login) || User.find_by(username: login) + user = User.by_login(login) # If no user is found, or it's an LDAP server, try LDAP. # LDAP users are only authenticated via LDAP diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index 1f3e1a4a3c1..95fc7e16a11 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -10,13 +10,21 @@ describe Gitlab::Auth do password: password, password_confirmation: password) end - let(:username) { 'john' } + let(:username) { 'John' } # username isn't lowercase, test this let(:password) { 'my-secret' } it "should find user by valid login/password" do expect( gl_auth.find(username, password) ).to eql user end + it 'should find user by valid email/password with case-insensitive email' do + expect(gl_auth.find(user.email.upcase, password)).to eql user + end + + it 'should find user by valid username/password with case-insensitive username' do + expect(gl_auth.find(username.upcase, password)).to eql user + end + it "should not find user with invalid password" do password = 'wrong' expect( gl_auth.find(username, password) ).to_not eql user diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6ad57b06e06..6d865cfc691 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -287,6 +287,20 @@ describe User do end end + describe '.by_login' do + let(:username) { 'John' } + let!(:user) { create(:user, username: username) } + + it 'should get the correct user' do + expect(User.by_login(user.email.upcase)).to eq user + expect(User.by_login(user.email)).to eq user + expect(User.by_login(username.downcase)).to eq user + expect(User.by_login(username)).to eq user + expect(User.by_login(nil)).to be_nil + expect(User.by_login('')).to be_nil + end + end + describe 'all_ssh_keys' do it { should have_many(:keys).dependent(:destroy) } diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index 013f425d6ce..57b2e6cbd6a 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -19,6 +19,32 @@ describe API::API, api: true do end end + context 'when email has case-typo and password is valid' do + it 'should return private token' do + post api('/session'), email: user.email.upcase, password: '12345678' + expect(response.status).to eq 201 + + expect(json_response['email']).to eq user.email + expect(json_response['private_token']).to eq user.private_token + expect(json_response['is_admin']).to eq user.is_admin? + expect(json_response['can_create_project']).to eq user.can_create_project? + expect(json_response['can_create_group']).to eq user.can_create_group? + end + end + + context 'when login has case-typo and password is valid' do + it 'should return private token' do + post api('/session'), login: user.username.upcase, password: '12345678' + expect(response.status).to eq 201 + + expect(json_response['email']).to eq user.email + expect(json_response['private_token']).to eq user.private_token + expect(json_response['is_admin']).to eq user.is_admin? + expect(json_response['can_create_project']).to eq user.can_create_project? + expect(json_response['can_create_group']).to eq user.can_create_group? + end + end + context "when invalid password" do it "should return authentication error" do post api("/session"), email: user.email, password: '123'