api_helpers_spec.rb 8.7 KB
Newer Older
1 2
require 'spec_helper'

3 4
describe API::Helpers, api: true do
  include API::Helpers
5
  include ApiHelpers
S
Stan Hu 已提交
6
  include SentryHelper
7

8 9 10 11 12 13 14 15 16 17
  let(:user) { create(:user) }
  let(:admin) { create(:admin) }
  let(:key) { create(:key, user: user) }

  let(:params) { {} }
  let(:env) { {} }

  def set_env(token_usr, identifier)
    clear_env
    clear_param
18 19
    env[API::Helpers::PRIVATE_TOKEN_HEADER] = token_usr.private_token
    env[API::Helpers::SUDO_HEADER] = identifier
20 21 22 23 24
  end

  def set_param(token_usr, identifier)
    clear_env
    clear_param
25 26
    params[API::Helpers::PRIVATE_TOKEN_PARAM] = token_usr.private_token
    params[API::Helpers::SUDO_PARAM] = identifier
27 28 29
  end

  def clear_env
30 31
    env.delete(API::Helpers::PRIVATE_TOKEN_HEADER)
    env.delete(API::Helpers::SUDO_HEADER)
32 33 34
  end

  def clear_param
35 36
    params.delete(API::Helpers::PRIVATE_TOKEN_PARAM)
    params.delete(API::Helpers::SUDO_PARAM)
37 38 39 40 41 42 43
  end

  def error!(message, status)
    raise Exception
  end

  describe ".current_user" do
44
    describe "when authenticating using a user's private token" do
45
      it "returns nil for an invalid token" do
46
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'
47 48 49 50
        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
        expect(current_user).to be_nil
      end

51
      it "returns nil for a user without access" do
52
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
53
        allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
54 55
        expect(current_user).to be_nil
      end
56

57
      it "leaves user as is when sudo not specified" do
58
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
59 60
        expect(current_user).to eq(user)
        clear_env
61
        params[API::Helpers::PRIVATE_TOKEN_PARAM] = user.private_token
62 63
        expect(current_user).to eq(user)
      end
64 65
    end

66 67 68
    describe "when authenticating using a user's personal access tokens" do
      let(:personal_access_token) { create(:personal_access_token, user: user) }

69
      it "returns nil for an invalid token" do
T
Timothy Andrew 已提交
70
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'
71 72 73 74
        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
        expect(current_user).to be_nil
      end

75
      it "returns nil for a user without access" do
T
Timothy Andrew 已提交
76
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
77
        allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
78 79 80
        expect(current_user).to be_nil
      end

81
      it "leaves user as is when sudo not specified" do
T
Timothy Andrew 已提交
82
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
83 84
        expect(current_user).to eq(user)
        clear_env
T
Timothy Andrew 已提交
85
        params[API::Helpers::PRIVATE_TOKEN_PARAM] = personal_access_token.token
86 87 88 89 90
        expect(current_user).to eq(user)
      end

      it 'does not allow revoked tokens' do
        personal_access_token.revoke!
T
Timothy Andrew 已提交
91
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
92 93 94 95 96 97
        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
        expect(current_user).to be_nil
      end

      it 'does not allow expired tokens' do
        personal_access_token.update_attributes!(expires_at: 1.day.ago)
T
Timothy Andrew 已提交
98
        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
99 100 101
        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
        expect(current_user).to be_nil
      end
102 103
    end

104
    it "changes current user to sudo when admin" do
105
      set_env(admin, user.id)
106
      expect(current_user).to eq(user)
107
      set_param(admin, user.id)
108
      expect(current_user).to eq(user)
109
      set_env(admin, user.username)
110
      expect(current_user).to eq(user)
111
      set_param(admin, user.username)
112
      expect(current_user).to eq(user)
113 114
    end

115
    it "throws an error when the current user is not an admin and attempting to sudo" do
116
      set_env(user, admin.id)
117
      expect { current_user }.to raise_error(Exception)
118
      set_param(user, admin.id)
119
      expect { current_user }.to raise_error(Exception)
120
      set_env(user, admin.username)
121
      expect { current_user }.to raise_error(Exception)
122
      set_param(user, admin.username)
123
      expect { current_user }.to raise_error(Exception)
124
    end
I
Izaak Alpert 已提交
125

126
    it "throws an error when the user cannot be found for a given id" do
127
      id = user.id + admin.id
128 129
      expect(user.id).not_to eq(id)
      expect(admin.id).not_to eq(id)
130
      set_env(admin, id)
131
      expect { current_user }.to raise_error(Exception)
132 133

      set_param(admin, id)
134
      expect { current_user }.to raise_error(Exception)
135
    end
I
Izaak Alpert 已提交
136

137
    it "throws an error when the user cannot be found for a given username" do
138
      username = "#{user.username}#{admin.username}"
139 140
      expect(user.username).not_to eq(username)
      expect(admin.username).not_to eq(username)
141
      set_env(admin, username)
142
      expect { current_user }.to raise_error(Exception)
143 144

      set_param(admin, username)
145
      expect { current_user }.to raise_error(Exception)
146
    end
I
Izaak Alpert 已提交
147

148
    it "handles sudo's to oneself" do
149
      set_env(admin, admin.id)
150
      expect(current_user).to eq(admin)
151
      set_param(admin, admin.id)
152
      expect(current_user).to eq(admin)
153
      set_env(admin, admin.username)
154
      expect(current_user).to eq(admin)
155
      set_param(admin, admin.username)
156
      expect(current_user).to eq(admin)
157 158
    end

159
    it "handles multiple sudo's to oneself" do
160
      set_env(admin, user.id)
161 162
      expect(current_user).to eq(user)
      expect(current_user).to eq(user)
163
      set_env(admin, user.username)
164 165
      expect(current_user).to eq(user)
      expect(current_user).to eq(user)
166 167

      set_param(admin, user.id)
168 169
      expect(current_user).to eq(user)
      expect(current_user).to eq(user)
170
      set_param(admin, user.username)
171 172
      expect(current_user).to eq(user)
      expect(current_user).to eq(user)
173
    end
I
Izaak Alpert 已提交
174

175
    it "handles multiple sudo's to oneself using string ids" do
176
      set_env(admin, user.id.to_s)
177 178
      expect(current_user).to eq(user)
      expect(current_user).to eq(user)
179 180

      set_param(admin, user.id.to_s)
181 182
      expect(current_user).to eq(user)
      expect(current_user).to eq(user)
183 184 185 186
    end
  end

  describe '.sudo_identifier' do
187
    it "returns integers when input is an int" do
188
      set_env(admin, '123')
189
      expect(sudo_identifier).to eq(123)
190
      set_env(admin, '0001234567890')
191
      expect(sudo_identifier).to eq(1234567890)
192 193

      set_param(admin, '123')
194
      expect(sudo_identifier).to eq(123)
195
      set_param(admin, '0001234567890')
196
      expect(sudo_identifier).to eq(1234567890)
197 198
    end

199
    it "returns string when input is an is not an int" do
200
      set_env(admin, '12.30')
201
      expect(sudo_identifier).to eq("12.30")
202
      set_env(admin, 'hello')
203
      expect(sudo_identifier).to eq('hello')
204
      set_env(admin, ' 123')
205
      expect(sudo_identifier).to eq(' 123')
206 207

      set_param(admin, '12.30')
208
      expect(sudo_identifier).to eq("12.30")
209
      set_param(admin, 'hello')
210
      expect(sudo_identifier).to eq('hello')
211
      set_param(admin, ' 123')
212
      expect(sudo_identifier).to eq(' 123')
213 214
    end
  end
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

  describe '.to_boolean' do
    it 'converts a valid string to a boolean' do
      expect(to_boolean('true')).to be_truthy
      expect(to_boolean('YeS')).to be_truthy
      expect(to_boolean('t')).to be_truthy
      expect(to_boolean('1')).to be_truthy
      expect(to_boolean('ON')).to be_truthy
      expect(to_boolean('FaLse')).to be_falsy
      expect(to_boolean('F')).to be_falsy
      expect(to_boolean('NO')).to be_falsy
      expect(to_boolean('n')).to be_falsy
      expect(to_boolean('0')).to be_falsy
      expect(to_boolean('oFF')).to be_falsy
    end

    it 'converts an invalid string to nil' do
      expect(to_boolean('fals')).to be_nil
      expect(to_boolean('yeah')).to be_nil
      expect(to_boolean('')).to be_nil
      expect(to_boolean(nil)).to be_nil
    end
  end
S
Stan Hu 已提交
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263

  describe '.handle_api_exception' do
    before do
      allow_any_instance_of(self.class).to receive(:sentry_enabled?).and_return(true)
      allow_any_instance_of(self.class).to receive(:rack_response)
    end

    it 'does not report a MethodNotAllowed exception to Sentry' do
      exception = Grape::Exceptions::MethodNotAllowed.new({ 'X-GitLab-Test' => '1' })
      allow(exception).to receive(:backtrace).and_return(caller)

      expect(Raven).not_to receive(:capture_exception).with(exception)

      handle_api_exception(exception)
    end

    it 'does report RuntimeError to Sentry' do
      exception = RuntimeError.new('test error')
      allow(exception).to receive(:backtrace).and_return(caller)

      expect_any_instance_of(self.class).to receive(:sentry_context)
      expect(Raven).to receive(:capture_exception).with(exception)

      handle_api_exception(exception)
    end
  end
J
Jeroen van Baarsen 已提交
264
end