1 package adal
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import (
18 "context"
19 "encoding/json"
20 "fmt"
21 "net/http"
22 "strings"
23 "testing"
24 "time"
25
26 "github.com/Azure/go-autorest/autorest/mocks"
27 )
28
29 const (
30 TestResource = "SomeResource"
31 TestClientID = "SomeClientID"
32 TestTenantID = "SomeTenantID"
33 TestActiveDirectoryEndpoint = "https://login.test.com/"
34 )
35
36 var (
37 testOAuthConfig, _ = NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
38 TestOAuthConfig = *testOAuthConfig
39 )
40
41 const MockDeviceCodeResponse = `
42 {
43 "device_code": "10000-40-1234567890",
44 "user_code": "ABCDEF",
45 "verification_url": "http://aka.ms/deviceauth",
46 "expires_in": "900",
47 "interval": "0"
48 }
49 `
50
51 const MockDeviceTokenResponse = `{
52 "access_token": "accessToken",
53 "refresh_token": "refreshToken",
54 "expires_in": "1000",
55 "expires_on": "2000",
56 "not_before": "3000",
57 "resource": "resource",
58 "token_type": "type"
59 }
60 `
61
62 func TestDeviceCodeIncludesResource(t *testing.T) {
63 sender := mocks.NewSender()
64 sender.AppendResponse(mocks.NewResponseWithContent(MockDeviceCodeResponse))
65
66 code, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
67 if err != nil {
68 t.Fatalf("adal: unexpected error initiating device auth")
69 }
70
71 if code.Resource != TestResource {
72 t.Fatalf("adal: InitiateDeviceAuth failed to stash the resource in the DeviceCode struct")
73 }
74 }
75
76 func TestDeviceCodeReturnsErrorIfSendingFails(t *testing.T) {
77 sender := mocks.NewSender()
78 sender.SetError(fmt.Errorf("this is an error"))
79
80 _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
81 if err == nil || !strings.Contains(err.Error(), errCodeSendingFails) {
82 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeSendingFails, err.Error())
83 }
84 }
85
86 func TestDeviceCodeReturnsErrorIfBadRequest(t *testing.T) {
87 sender := mocks.NewSender()
88 body := mocks.NewBody("doesn't matter")
89 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
90
91 _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
92 if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) {
93 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error())
94 }
95
96 if body.IsOpen() {
97 t.Fatalf("response body was left open!")
98 }
99 }
100
101 func TestDeviceCodeReturnsErrorIfCannotDeserializeDeviceCode(t *testing.T) {
102 gibberishJSON := strings.Replace(MockDeviceCodeResponse, "expires_in", "\":, :gibberish", -1)
103 sender := mocks.NewSender()
104 body := mocks.NewBody(gibberishJSON)
105 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
106
107 _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
108 if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) {
109 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error())
110 }
111
112 if body.IsOpen() {
113 t.Fatalf("response body was left open!")
114 }
115 }
116
117 func TestDeviceCodeReturnsErrorIfEmptyDeviceCode(t *testing.T) {
118 sender := mocks.NewSender()
119 body := mocks.NewBody("")
120 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
121
122 _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
123 if err != ErrDeviceCodeEmpty {
124 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", ErrDeviceCodeEmpty, err.Error())
125 }
126
127 if body.IsOpen() {
128 t.Fatalf("response body was left open!")
129 }
130 }
131
132 func deviceCode() *DeviceCode {
133 var deviceCode DeviceCode
134 _ = json.Unmarshal([]byte(MockDeviceCodeResponse), &deviceCode)
135 deviceCode.Resource = TestResource
136 deviceCode.ClientID = TestClientID
137 return &deviceCode
138 }
139
140 func TestDeviceTokenReturns(t *testing.T) {
141 sender := mocks.NewSender()
142 body := mocks.NewBody(MockDeviceTokenResponse)
143 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
144
145 _, err := WaitForUserCompletion(sender, deviceCode())
146 if err != nil {
147 t.Fatalf("adal: got error unexpectedly")
148 }
149
150 if body.IsOpen() {
151 t.Fatalf("response body was left open!")
152 }
153 }
154
155 func TestDeviceTokenReturnsErrorIfSendingFails(t *testing.T) {
156 sender := mocks.NewSender()
157 sender.SetError(fmt.Errorf("this is an error"))
158
159 _, err := WaitForUserCompletion(sender, deviceCode())
160 if err == nil || !strings.Contains(err.Error(), errTokenSendingFails) {
161 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenSendingFails, err.Error())
162 }
163 }
164
165 func TestDeviceTokenReturnsErrorIfServerError(t *testing.T) {
166 sender := mocks.NewSender()
167 body := mocks.NewBody("")
168 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusInternalServerError, "Internal Server Error"))
169
170 _, err := WaitForUserCompletion(sender, deviceCode())
171 if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) {
172 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error())
173 }
174
175 if body.IsOpen() {
176 t.Fatalf("response body was left open!")
177 }
178 }
179
180 func TestDeviceTokenReturnsErrorIfCannotDeserializeDeviceToken(t *testing.T) {
181 gibberishJSON := strings.Replace(MockDeviceTokenResponse, "expires_in", ";:\"gibberish", -1)
182 sender := mocks.NewSender()
183 body := mocks.NewBody(gibberishJSON)
184 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
185
186 _, err := WaitForUserCompletion(sender, deviceCode())
187 if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) {
188 t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error())
189 }
190
191 if body.IsOpen() {
192 t.Fatalf("response body was left open!")
193 }
194 }
195
196 func errorDeviceTokenResponse(message string) string {
197 return `{ "error": "` + message + `" }`
198 }
199
200 func TestDeviceTokenReturnsErrorIfAuthorizationPending(t *testing.T) {
201 sender := mocks.NewSender()
202 body := mocks.NewBody(errorDeviceTokenResponse("authorization_pending"))
203 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
204
205 _, err := CheckForUserCompletion(sender, deviceCode())
206 if err != ErrDeviceAuthorizationPending {
207 t.Fatalf("!!!")
208 }
209
210 if body.IsOpen() {
211 t.Fatalf("response body was left open!")
212 }
213 }
214
215 func TestDeviceTokenReturnsErrorIfSlowDown(t *testing.T) {
216 sender := mocks.NewSender()
217 body := mocks.NewBody(errorDeviceTokenResponse("slow_down"))
218 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
219
220 _, err := CheckForUserCompletion(sender, deviceCode())
221 if err != ErrDeviceSlowDown {
222 t.Fatalf("!!!")
223 }
224
225 if body.IsOpen() {
226 t.Fatalf("response body was left open!")
227 }
228 }
229
230 type deviceTokenSender struct {
231 errorString string
232 attempts int
233 }
234
235 func newDeviceTokenSender(deviceErrorString string) *deviceTokenSender {
236 return &deviceTokenSender{errorString: deviceErrorString, attempts: 0}
237 }
238
239 func (s *deviceTokenSender) Do(req *http.Request) (*http.Response, error) {
240 var resp *http.Response
241 if s.attempts < 1 {
242 s.attempts++
243 resp = mocks.NewResponseWithContent(errorDeviceTokenResponse(s.errorString))
244 } else {
245 resp = mocks.NewResponseWithContent(MockDeviceTokenResponse)
246 }
247 return resp, nil
248 }
249
250
251
252 func TestDeviceTokenSucceedsWithIntermediateAuthPending(t *testing.T) {
253 sender := newDeviceTokenSender("authorization_pending")
254
255 _, err := WaitForUserCompletion(sender, deviceCode())
256 if err != nil {
257 t.Fatalf("unexpected error occurred")
258 }
259 }
260
261
262 func TestDeviceTokenSucceedsWithIntermediateSlowDown(t *testing.T) {
263 sender := newDeviceTokenSender("slow_down")
264
265 _, err := WaitForUserCompletion(sender, deviceCode())
266 if err != nil {
267 t.Fatalf("unexpected error occurred")
268 }
269 }
270
271 func TestDeviceTokenReturnsErrorIfAccessDenied(t *testing.T) {
272 sender := mocks.NewSender()
273 body := mocks.NewBody(errorDeviceTokenResponse("access_denied"))
274 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
275
276 _, err := WaitForUserCompletion(sender, deviceCode())
277 if err != ErrDeviceAccessDenied {
278 t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceAccessDenied.Error(), err.Error())
279 }
280
281 if body.IsOpen() {
282 t.Fatalf("response body was left open!")
283 }
284 }
285
286 func TestDeviceTokenReturnsErrorIfCodeExpired(t *testing.T) {
287 sender := mocks.NewSender()
288 body := mocks.NewBody(errorDeviceTokenResponse("code_expired"))
289 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
290
291 _, err := WaitForUserCompletion(sender, deviceCode())
292 if err != ErrDeviceCodeExpired {
293 t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceCodeExpired.Error(), err.Error())
294 }
295
296 if body.IsOpen() {
297 t.Fatalf("response body was left open!")
298 }
299 }
300
301 func TestDeviceTokenReturnsErrorForUnknownError(t *testing.T) {
302 sender := mocks.NewSender()
303 body := mocks.NewBody(errorDeviceTokenResponse("unknown_error"))
304 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
305
306 _, err := WaitForUserCompletion(sender, deviceCode())
307 if err == nil {
308 t.Fatalf("failed to get error")
309 }
310 if err != ErrDeviceGeneric {
311 t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceGeneric.Error(), err.Error())
312 }
313
314 if body.IsOpen() {
315 t.Fatalf("response body was left open!")
316 }
317 }
318
319 func TestDeviceTokenReturnsErrorIfTokenEmptyAndStatusOK(t *testing.T) {
320 sender := mocks.NewSender()
321 body := mocks.NewBody("")
322 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
323
324 _, err := WaitForUserCompletion(sender, deviceCode())
325 if err != ErrOAuthTokenEmpty {
326 t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrOAuthTokenEmpty.Error(), err.Error())
327 }
328
329 if body.IsOpen() {
330 t.Fatalf("response body was left open!")
331 }
332 }
333
334 func TestWaitForUserCompletionWithContext(t *testing.T) {
335 sender := SenderFunc(func(*http.Request) (*http.Response, error) {
336 return mocks.NewResponseWithContent(`{"error":"authorization_pending"}`), nil
337 })
338 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
339 defer cancel()
340 _, err := WaitForUserCompletionWithContext(ctx, sender, deviceCode())
341 if err != context.DeadlineExceeded {
342 t.Fatalf("adal: got wrong error expected(%s) actual(%s)", context.DeadlineExceeded.Error(), err.Error())
343 }
344 }
345
View as plain text