/spec/requests/api/api_helpers_spec.rb
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