PageRenderTime 67ms CodeModel.GetById 26ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/requests/api/api_helpers_spec.rb

https://gitlab.com/haleksandre/gitlab-ce
Ruby | 264 lines | 241 code | 23 blank | 0 comment | 4 complexity | 4fe5f26976a17de6beb32a4b646b132d MD5 | raw file
  1require 'spec_helper'
  2
  3describe API::Helpers, api: true do
  4  include API::Helpers
  5  include ApiHelpers
  6  include SentryHelper
  7
  8  let(:user) { create(:user) }
  9  let(:admin) { create(:admin) }
 10  let(:key) { create(:key, user: user) }
 11
 12  let(:params) { {} }
 13  let(:env) { {} }
 14
 15  def set_env(token_usr, identifier)
 16    clear_env
 17    clear_param
 18    env[API::Helpers::PRIVATE_TOKEN_HEADER] = token_usr.private_token
 19    env[API::Helpers::SUDO_HEADER] = identifier
 20  end
 21
 22  def set_param(token_usr, identifier)
 23    clear_env
 24    clear_param
 25    params[API::Helpers::PRIVATE_TOKEN_PARAM] = token_usr.private_token
 26    params[API::Helpers::SUDO_PARAM] = identifier
 27  end
 28
 29  def clear_env
 30    env.delete(API::Helpers::PRIVATE_TOKEN_HEADER)
 31    env.delete(API::Helpers::SUDO_HEADER)
 32  end
 33
 34  def clear_param
 35    params.delete(API::Helpers::PRIVATE_TOKEN_PARAM)
 36    params.delete(API::Helpers::SUDO_PARAM)
 37  end
 38
 39  def error!(message, status)
 40    raise Exception
 41  end
 42
 43  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        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
 48        expect(current_user).to be_nil
 49      end
 50
 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        expect(current_user).to be_nil
 55      end
 56
 57      it "leaves user as is when sudo not specified" do
 58        env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
 59        expect(current_user).to eq(user)
 60        clear_env
 61        params[API::Helpers::PRIVATE_TOKEN_PARAM] = user.private_token
 62        expect(current_user).to eq(user)
 63      end
 64    end
 65
 66    describe "when authenticating using a user's personal access tokens" do
 67      let(:personal_access_token) { create(:personal_access_token, user: user) }
 68
 69      it "returns nil for an invalid token" do
 70        env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'
 71        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
 72        expect(current_user).to be_nil
 73      end
 74
 75      it "returns nil for a user without access" do
 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        expect(current_user).to be_nil
 79      end
 80
 81      it "leaves user as is when sudo not specified" do
 82        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
 83        expect(current_user).to eq(user)
 84        clear_env
 85        params[API::Helpers::PRIVATE_TOKEN_PARAM] = personal_access_token.token
 86        expect(current_user).to eq(user)
 87      end
 88
 89      it 'does not allow revoked tokens' do
 90        personal_access_token.revoke!
 91        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
 92        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
 93        expect(current_user).to be_nil
 94      end
 95
 96      it 'does not allow expired tokens' do
 97        personal_access_token.update_attributes!(expires_at: 1.day.ago)
 98        env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
 99        allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
100        expect(current_user).to be_nil
101      end
102    end
103
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    end
114
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
125
126    it "throws an error when the user cannot be found for a given id" do
127      id = user.id + admin.id
128      expect(user.id).not_to eq(id)
129      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
136
137    it "throws an error when the user cannot be found for a given username" do
138      username = "#{user.username}#{admin.username}"
139      expect(user.username).not_to eq(username)
140      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
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    end
158
159    it "handles multiple sudo's to oneself" do
160      set_env(admin, user.id)
161      expect(current_user).to eq(user)
162      expect(current_user).to eq(user)
163      set_env(admin, user.username)
164      expect(current_user).to eq(user)
165      expect(current_user).to eq(user)
166
167      set_param(admin, user.id)
168      expect(current_user).to eq(user)
169      expect(current_user).to eq(user)
170      set_param(admin, user.username)
171      expect(current_user).to eq(user)
172      expect(current_user).to eq(user)
173    end
174
175    it "handles multiple sudo's to oneself using string ids" do
176      set_env(admin, user.id.to_s)
177      expect(current_user).to eq(user)
178      expect(current_user).to eq(user)
179
180      set_param(admin, user.id.to_s)
181      expect(current_user).to eq(user)
182      expect(current_user).to eq(user)
183    end
184  end
185
186  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    end
198
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    end
214  end
215
216  describe '.to_boolean' do
217    it 'converts a valid string to a boolean' do
218      expect(to_boolean('true')).to be_truthy
219      expect(to_boolean('YeS')).to be_truthy
220      expect(to_boolean('t')).to be_truthy
221      expect(to_boolean('1')).to be_truthy
222      expect(to_boolean('ON')).to be_truthy
223      expect(to_boolean('FaLse')).to be_falsy
224      expect(to_boolean('F')).to be_falsy
225      expect(to_boolean('NO')).to be_falsy
226      expect(to_boolean('n')).to be_falsy
227      expect(to_boolean('0')).to be_falsy
228      expect(to_boolean('oFF')).to be_falsy
229    end
230
231    it 'converts an invalid string to nil' do
232      expect(to_boolean('fals')).to be_nil
233      expect(to_boolean('yeah')).to be_nil
234      expect(to_boolean('')).to be_nil
235      expect(to_boolean(nil)).to be_nil
236    end
237  end
238
239  describe '.handle_api_exception' do
240    before do
241      allow_any_instance_of(self.class).to receive(:sentry_enabled?).and_return(true)
242      allow_any_instance_of(self.class).to receive(:rack_response)
243    end
244
245    it 'does not report a MethodNotAllowed exception to Sentry' do
246      exception = Grape::Exceptions::MethodNotAllowed.new({ 'X-GitLab-Test' => '1' })
247      allow(exception).to receive(:backtrace).and_return(caller)
248
249      expect(Raven).not_to receive(:capture_exception).with(exception)
250
251      handle_api_exception(exception)
252    end
253
254    it 'does report RuntimeError to Sentry' do
255      exception = RuntimeError.new('test error')
256      allow(exception).to receive(:backtrace).and_return(caller)
257
258      expect_any_instance_of(self.class).to receive(:sentry_context)
259      expect(Raven).to receive(:capture_exception).with(exception)
260
261      handle_api_exception(exception)
262    end
263  end
264end