auth_spec.rb 9.5 KB
Newer Older
D
Dmitriy Zaporozhets 已提交
1 2
require 'spec_helper'

D
Douwe Maan 已提交
3
describe Gitlab::Auth, lib: true do
4
  let(:gl_auth) { described_class }
D
Dmitriy Zaporozhets 已提交
5

J
Jacob Vosmaer 已提交
6
  describe 'find_for_git_client' do
K
Kamil Trzcinski 已提交
7 8 9 10 11 12 13 14 15 16 17 18
    context 'build token' do
      subject { gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: project, ip: 'ip') }

      context 'for running build' do
        let!(:build) { create(:ci_build, :running) }
        let(:project) { build.project }

        before do
          expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'gitlab-ci-token')
        end

        it 'recognises user-less build' do
19
          expect(subject).to eq(Gitlab::Auth::Result.new(nil, build.project, :ci, build_authentication_abilities))
K
Kamil Trzcinski 已提交
20 21 22 23 24
        end

        it 'recognises user token' do
          build.update(user: create(:user))

25
          expect(subject).to eq(Gitlab::Auth::Result.new(build.user, build.project, :build, build_authentication_abilities))
K
Kamil Trzcinski 已提交
26 27 28
        end
      end

29
      (HasStatus::AVAILABLE_STATUSES - ['running']).each do |build_status|
30 31 32 33 34 35 36 37 38
        context "for #{build_status} build" do
          let!(:build) { create(:ci_build, status: build_status) }
          let(:project) { build.project }

          before do
            expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'gitlab-ci-token')
          end

          it 'denies authentication' do
39
            expect(subject).to eq(Gitlab::Auth::Result.new)
40
          end
K
Kamil Trzcinski 已提交
41 42 43 44 45
        end
      end
    end

    it 'recognizes other ci services' do
46
      project = create(:empty_project)
K
Kamil Trzcinski 已提交
47 48
      project.create_drone_ci_service(active: true)
      project.drone_ci_service.update(token: 'token')
F
Felipe Artur 已提交
49

50 51
      expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'drone-ci-token')
      expect(gl_auth.find_for_git_client('drone-ci-token', 'token', project: project, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, project, :ci, build_authentication_abilities))
52 53 54 55 56
    end

    it 'recognizes master passwords' do
      user = create(:user, password: 'password')

57 58
      expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.username)
      expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
59 60
    end

61 62 63 64
    context 'while using LFS authenticate' do
      it 'recognizes user lfs tokens' do
        user = create(:user)
        token = Gitlab::LfsToken.new(user).token
65

66 67 68
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.username)
        expect(gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :lfs_token, full_authentication_abilities))
      end
69

70 71 72
      it 'recognizes deploy key lfs tokens' do
        key = create(:deploy_key)
        token = Gitlab::LfsToken.new(key).token
73

74 75 76
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
        expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities))
      end
77

78
      it 'does not try password auth before oauth' do
79
        user = create(:user)
80 81 82
        token = Gitlab::LfsToken.new(user).token

        expect(gl_auth).not_to receive(:find_with_user_password)
83

84 85 86 87 88 89 90 91 92 93
        gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')
      end
    end

    context 'while using OAuth tokens as passwords' do
      let(:user) { create(:user) }
      let(:token_w_api_scope) { Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'api') }
      let(:application) { Doorkeeper::Application.create!(name: 'MyApp', redirect_uri: 'https://app.com', owner: user) }

      it 'succeeds for OAuth tokens with the `api` scope' do
94
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'oauth2')
95
        expect(gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities))
96 97 98
      end

      it 'fails for OAuth tokens with other scopes' do
99
        token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'read_user')
100

101 102
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'oauth2')
        expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
103
      end
104 105 106 107 108 109

      it 'does not try password auth before oauth' do
        expect(gl_auth).not_to receive(:find_with_user_password)

        gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')
      end
110 111
    end

112 113
    context 'while using personal access tokens as passwords' do
      it 'succeeds for personal access tokens with the `api` scope' do
S
Simon Vocella 已提交
114 115 116 117
        personal_access_token = create(:personal_access_token, scopes: ['api'])

        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
        expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, full_authentication_abilities))
118 119
      end

S
Simon Vocella 已提交
120 121
      it 'succeeds if it is an impersonation token' do
        personal_access_token = create(:personal_access_token, impersonation: true, scopes: [])
122

S
Simon Vocella 已提交
123 124
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
        expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, full_authentication_abilities))
125
      end
126

S
Simon Vocella 已提交
127 128 129 130 131 132
      it 'fails for personal access tokens with other scopes' do
        personal_access_token = create(:personal_access_token, scopes: ['read_user'])

        expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
        expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
      end
133

S
Simon Vocella 已提交
134 135 136
      it 'fails if password is nil' do
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
        expect(gl_auth.find_for_git_client('', nil, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
      end
    end

    context 'while using regular user and password' do
      it 'falls through lfs authentication' do
        user = create(
          :user,
          username: 'normal_user',
          password: 'my-secret',
        )

        expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
          .to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
      end

      it 'falls through oauth authentication when the username is oauth2' do
        user = create(
          :user,
          username: 'oauth2',
          password: 'my-secret',
        )

        expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
          .to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
      end
162 163 164 165 166
    end

    it 'returns double nil for invalid credentials' do
      login = 'foo'

167 168
      expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
      expect(gl_auth.find_for_git_client(login, 'bar', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new)
169 170 171
    end
  end

172
  describe 'find_with_user_password' do
173 174 175 176 177
    let!(:user) do
      create(:user,
        username: username,
        password: password,
        password_confirmation: password)
D
Dmitriy Zaporozhets 已提交
178
    end
179
    let(:username) { 'John' }     # username isn't lowercase, test this
180
    let(:password) { 'my-secret' }
D
Dmitriy Zaporozhets 已提交
181

182
    it "finds user by valid login/password" do
183
      expect( gl_auth.find_with_user_password(username, password) ).to eql user
D
Dmitriy Zaporozhets 已提交
184 185
    end

186
    it 'finds user by valid email/password with case-insensitive email' do
187
      expect(gl_auth.find_with_user_password(user.email.upcase, password)).to eql user
188 189
    end

190
    it 'finds user by valid username/password with case-insensitive username' do
191
      expect(gl_auth.find_with_user_password(username.upcase, password)).to eql user
192 193
    end

194
    it "does not find user with invalid password" do
195
      password = 'wrong'
196
      expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
D
Dmitriy Zaporozhets 已提交
197 198
    end

199
    it "does not find user with invalid login" do
200
      user = 'wrong'
201
      expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
202
    end
203 204

    context "with ldap enabled" do
205 206 207
      before do
        allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
      end
208 209

      it "tries to autheticate with db before ldap" do
210
        expect(Gitlab::LDAP::Authentication).not_to receive(:login)
211

212
        gl_auth.find_with_user_password(username, password)
213 214 215
      end

      it "uses ldap as fallback to for authentication" do
216
        expect(Gitlab::LDAP::Authentication).to receive(:login)
217

218
        gl_auth.find_with_user_password('ldap_user', 'password')
219 220
      end
    end
D
Dmitriy Zaporozhets 已提交
221
  end
K
Kamil Trzcinski 已提交
222 223 224

  private

225
  def build_authentication_abilities
K
Kamil Trzcinski 已提交
226 227 228 229 230 231 232 233
    [
      :read_project,
      :build_download_code,
      :build_read_container_image,
      :build_create_container_image
    ]
  end

234
  def read_authentication_abilities
K
Kamil Trzcinski 已提交
235 236 237 238 239 240 241
    [
      :read_project,
      :download_code,
      :read_container_image
    ]
  end

242 243
  def full_authentication_abilities
    read_authentication_abilities + [
K
Kamil Trzcinski 已提交
244
      :push_code,
K
Kamil Trzcinski 已提交
245
      :create_container_image
K
Kamil Trzcinski 已提交
246 247
    ]
  end
D
Dmitriy Zaporozhets 已提交
248
end