auth_spec.rb 9.6 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

P
Pawel Chojnacki 已提交
61 62
    include_examples 'user login operation with unique ip limit' do
      let(:user) { create(:user, password: 'password') }
63

P
Pawel Chojnacki 已提交
64
      def operation
65 66 67 68
        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))
      end
    end

69 70 71 72
    context 'while using LFS authenticate' do
      it 'recognizes user lfs tokens' do
        user = create(:user)
        token = Gitlab::LfsToken.new(user).token
73

74 75 76
        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
77

78 79 80
      it 'recognizes deploy key lfs tokens' do
        key = create(:deploy_key)
        token = Gitlab::LfsToken.new(key).token
81

82 83 84
        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
85

86
      it 'does not try password auth before oauth' do
87
        user = create(:user)
88 89 90
        token = Gitlab::LfsToken.new(user).token

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

92 93 94 95 96 97 98 99 100 101
        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
102
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'oauth2')
103
        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))
104 105 106
      end

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

109 110
        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))
111
      end
112 113 114 115 116 117

      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
118 119
    end

120 121 122
    context 'while using personal access tokens as passwords' do
      let(:user) { create(:user) }
      let(:token_w_api_scope) { create(:personal_access_token, user: user, scopes: ['api']) }
123

124
      it 'succeeds for personal access tokens with the `api` scope' do
125
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.email)
126
        expect(gl_auth.find_for_git_client(user.email, token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities))
127 128 129 130
      end

      it 'fails for personal access tokens with other scopes' do
        personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
131

132 133
        expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: user.email)
        expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
134
      end
135 136 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 162 163 164

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

        gl_auth.find_for_git_client(user.email, token_w_api_scope.token, project: nil, ip: 'ip')
      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
165 166 167 168 169
    end

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

170 171
      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)
172 173 174
    end
  end

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

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

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

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

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

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

P
Pawel Chojnacki 已提交
207 208 209 210 211 212
    include_examples 'user login operation with unique ip limit' do
      def operation
        expect(gl_auth.find_with_user_password(username, password)).to eql user
      end
    end

213
    context "with ldap enabled" do
214 215 216
      before do
        allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
      end
217 218

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

221
        gl_auth.find_with_user_password(username, password)
222 223 224
      end

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

227
        gl_auth.find_with_user_password('ldap_user', 'password')
228 229
      end
    end
D
Dmitriy Zaporozhets 已提交
230
  end
K
Kamil Trzcinski 已提交
231 232 233

  private

234
  def build_authentication_abilities
K
Kamil Trzcinski 已提交
235 236 237 238 239 240 241 242
    [
      :read_project,
      :build_download_code,
      :build_read_container_image,
      :build_create_container_image
    ]
  end

243
  def read_authentication_abilities
K
Kamil Trzcinski 已提交
244 245 246 247 248 249 250
    [
      :read_project,
      :download_code,
      :read_container_image
    ]
  end

251 252
  def full_authentication_abilities
    read_authentication_abilities + [
K
Kamil Trzcinski 已提交
253
      :push_code,
K
Kamil Trzcinski 已提交
254
      :create_container_image
K
Kamil Trzcinski 已提交
255 256
    ]
  end
D
Dmitriy Zaporozhets 已提交
257
end