1package autorest
2
3// Copyright 2017 Microsoft Corporation
4//
5//  Licensed under the Apache License, Version 2.0 (the "License");
6//  you may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at
8//
9//      http://www.apache.org/licenses/LICENSE-2.0
10//
11//  Unless required by applicable law or agreed to in writing, software
12//  distributed under the License is distributed on an "AS IS" BASIS,
13//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14//  See the License for the specific language governing permissions and
15//  limitations under the License.
16
17import (
18	"fmt"
19	"net/http"
20	"reflect"
21	"strings"
22	"testing"
23
24	"github.com/Azure/go-autorest/autorest/adal"
25	"github.com/Azure/go-autorest/autorest/mocks"
26)
27
28const (
29	TestTenantID                = "TestTenantID"
30	TestAuxTenent1              = "aux1"
31	TestAuxTenent2              = "aux2"
32	TestAuxTenent3              = "aux3"
33	TestActiveDirectoryEndpoint = "https://login/test.com/"
34)
35
36func TestWithAuthorizer(t *testing.T) {
37	r1 := mocks.NewRequest()
38
39	na := &NullAuthorizer{}
40	r2, err := Prepare(r1,
41		na.WithAuthorization())
42	if err != nil {
43		t.Fatalf("autorest: NullAuthorizer#WithAuthorization returned an unexpected error (%v)", err)
44	} else if !reflect.DeepEqual(r1, r2) {
45		t.Fatalf("autorest: NullAuthorizer#WithAuthorization modified the request -- received %v, expected %v", r2, r1)
46	}
47}
48
49func TestTokenWithAuthorization(t *testing.T) {
50	token := &adal.Token{
51		AccessToken: "TestToken",
52		Resource:    "https://azure.microsoft.com/",
53		Type:        "Bearer",
54	}
55
56	ba := NewBearerAuthorizer(token)
57	req, err := Prepare(&http.Request{}, ba.WithAuthorization())
58	if err != nil {
59		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
60	} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", token.AccessToken) {
61		t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
62	}
63}
64
65func TestServicePrincipalTokenWithAuthorizationNoRefresh(t *testing.T) {
66	oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
67	if err != nil {
68		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
69	}
70	spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", nil)
71	if err != nil {
72		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
73	}
74	spt.SetAutoRefresh(false)
75	s := mocks.NewSender()
76	spt.SetSender(s)
77
78	ba := NewBearerAuthorizer(spt)
79	req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
80	if err != nil {
81		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
82	} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.OAuthToken()) {
83		t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
84	}
85}
86
87func TestServicePrincipalTokenWithAuthorizationRefresh(t *testing.T) {
88
89	oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
90	if err != nil {
91		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
92	}
93	refreshed := false
94	spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", func(t adal.Token) error {
95		refreshed = true
96		return nil
97	})
98	if err != nil {
99		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
100	}
101
102	jwt := `{
103		"access_token" : "accessToken",
104		"expires_in"   : "3600",
105		"expires_on"   : "test",
106		"not_before"   : "test",
107		"resource"     : "test",
108		"token_type"   : "Bearer"
109	}`
110	body := mocks.NewBody(jwt)
111	resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
112	c := mocks.NewSender()
113	s := DecorateSender(c,
114		(func() SendDecorator {
115			return func(s Sender) Sender {
116				return SenderFunc(func(r *http.Request) (*http.Response, error) {
117					return resp, nil
118				})
119			}
120		})())
121	spt.SetSender(s)
122
123	ba := NewBearerAuthorizer(spt)
124	req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
125	if err != nil {
126		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
127	} else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.OAuthToken()) {
128		t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header")
129	}
130
131	if !refreshed {
132		t.Fatal("azure: BearerAuthorizer#WithAuthorization must refresh the token")
133	}
134}
135
136func TestServicePrincipalTokenWithAuthorizationReturnsErrorIfConnotRefresh(t *testing.T) {
137	oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
138	if err != nil {
139		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
140	}
141	spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", nil)
142	if err != nil {
143		t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err)
144	}
145
146	s := mocks.NewSender()
147	s.AppendResponse(mocks.NewResponseWithStatus("400 Bad Request", http.StatusBadRequest))
148	spt.SetSender(s)
149
150	ba := NewBearerAuthorizer(spt)
151	_, err = Prepare(mocks.NewRequest(), ba.WithAuthorization())
152	if err == nil {
153		t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to return an error when refresh fails")
154	}
155}
156
157func TestBearerAuthorizerCallback(t *testing.T) {
158	tenantString := "123-tenantID-456"
159	resourceString := "https://fake.resource.net"
160
161	s := mocks.NewSender()
162	resp := mocks.NewResponseWithStatus("401 Unauthorized", http.StatusUnauthorized)
163	mocks.SetResponseHeader(resp, bearerChallengeHeader, bearer+" \"authorization\"=\"https://fake.net/"+tenantString+"\",\"resource\"=\""+resourceString+"\"")
164	s.AppendResponse(resp)
165
166	auth := NewBearerAuthorizerCallback(s, func(tenantID, resource string) (*BearerAuthorizer, error) {
167		if tenantID != tenantString {
168			t.Fatal("BearerAuthorizerCallback: bad tenant ID")
169		}
170		if resource != resourceString {
171			t.Fatal("BearerAuthorizerCallback: bad resource")
172		}
173
174		oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, tenantID)
175		if err != nil {
176			t.Fatalf("azure: NewOAuthConfig returned an error (%v)", err)
177		}
178
179		spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", resource)
180		if err != nil {
181			t.Fatalf("azure: NewServicePrincipalToken returned an error (%v)", err)
182		}
183
184		spt.SetSender(s)
185		return NewBearerAuthorizer(spt), nil
186	})
187
188	_, err := Prepare(mocks.NewRequest(), auth.WithAuthorization())
189	if err == nil {
190		t.Fatal("azure: BearerAuthorizerCallback#WithAuthorization failed to return an error when refresh fails")
191	}
192}
193
194func TestApiKeyAuthorization(t *testing.T) {
195
196	headers := make(map[string]interface{})
197	queryParameters := make(map[string]interface{})
198
199	dummyAuthHeader := "dummyAuthHeader"
200	dummyAuthHeaderValue := "dummyAuthHeaderValue"
201
202	dummyAuthQueryParameter := "dummyAuthQueryParameter"
203	dummyAuthQueryParameterValue := "dummyAuthQueryParameterValue"
204
205	headers[dummyAuthHeader] = dummyAuthHeaderValue
206	queryParameters[dummyAuthQueryParameter] = dummyAuthQueryParameterValue
207
208	aka := NewAPIKeyAuthorizer(headers, queryParameters)
209
210	req, err := Prepare(mocks.NewRequest(), aka.WithAuthorization())
211
212	if err != nil {
213		t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization returned an error (%v)", err)
214	} else if req.Header.Get(http.CanonicalHeaderKey(dummyAuthHeader)) != dummyAuthHeaderValue {
215		t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization failed to set %s header", dummyAuthHeader)
216
217	} else if req.URL.Query().Get(dummyAuthQueryParameter) != dummyAuthQueryParameterValue {
218		t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization failed to set %s query parameter", dummyAuthQueryParameterValue)
219	}
220}
221
222func TestCognitivesServicesAuthorization(t *testing.T) {
223	subscriptionKey := "dummyKey"
224	csa := NewCognitiveServicesAuthorizer(subscriptionKey)
225	req, err := Prepare(mocks.NewRequest(), csa.WithAuthorization())
226
227	if err != nil {
228		t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization returned an error (%v)", err)
229	} else if req.Header.Get(http.CanonicalHeaderKey(bingAPISdkHeader)) != golangBingAPISdkHeaderValue {
230		t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization failed to set %s header", bingAPISdkHeader)
231	} else if req.Header.Get(http.CanonicalHeaderKey(apiKeyAuthorizerHeader)) != subscriptionKey {
232		t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization failed to set %s header", apiKeyAuthorizerHeader)
233	}
234}
235
236func TestBasicAuthorization(t *testing.T) {
237	ba := NewBasicAuthorizer("Aladdin", "open sesame")
238	req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
239
240	if err != nil {
241		t.Fatalf("BasicAuthorizer#WithAuthorization returned an error (%v)", err)
242	} else if req.Header.Get(http.CanonicalHeaderKey(authorization)) != basic+" QWxhZGRpbjpvcGVuIHNlc2FtZQ==" {
243		t.Fatalf("BasicAuthorizer#WithAuthorization failed to set %s header", authorization)
244	}
245}
246
247func TestBasicAuthorizationPasswordOnly(t *testing.T) {
248	ba := NewBasicAuthorizer("", "dummyKey")
249	req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization())
250
251	if err != nil {
252		t.Fatalf("BasicAuthorizer#WithAuthorization returned an error (%v)", err)
253	} else if req.Header.Get(http.CanonicalHeaderKey(authorization)) != basic+" OmR1bW15S2V5" {
254		t.Fatalf("BasicAuthorizer#WithAuthorization failed to set %s header", authorization)
255	}
256}
257
258type mockMTSPTProvider struct {
259	p string
260	a []string
261}
262
263func (m mockMTSPTProvider) PrimaryOAuthToken() string {
264	return m.p
265}
266
267func (m mockMTSPTProvider) AuxiliaryOAuthTokens() []string {
268	return m.a
269}
270
271func TestMultitenantAuthorizationOne(t *testing.T) {
272	mtSPTProvider := mockMTSPTProvider{
273		p: "primary",
274		a: []string{TestAuxTenent1},
275	}
276	mt := NewMultiTenantServicePrincipalTokenAuthorizer(mtSPTProvider)
277	req, err := Prepare(mocks.NewRequest(), mt.WithAuthorization())
278	if err != nil {
279		t.Fatalf("unexpected error: %v", err)
280	}
281	if primary := req.Header.Get(headerAuthorization); primary != "Bearer primary" {
282		t.Fatalf("bad primary authorization header %s", primary)
283	}
284	if aux := req.Header.Get(headerAuxAuthorization); aux != "Bearer aux1" {
285		t.Fatalf("bad auxiliary authorization header %s", aux)
286	}
287}
288
289func TestMultitenantAuthorizationThree(t *testing.T) {
290	mtSPTProvider := mockMTSPTProvider{
291		p: "primary",
292		a: []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3},
293	}
294	mt := NewMultiTenantServicePrincipalTokenAuthorizer(mtSPTProvider)
295	req, err := Prepare(mocks.NewRequest(), mt.WithAuthorization())
296	if err != nil {
297		t.Fatalf("unexpected error: %v", err)
298	}
299	if primary := req.Header.Get(headerAuthorization); primary != "Bearer primary" {
300		t.Fatalf("bad primary authorization header %s", primary)
301	}
302	if aux := req.Header.Get(headerAuxAuthorization); aux != "Bearer aux1; Bearer aux2; Bearer aux3" {
303		t.Fatalf("bad auxiliary authorization header %s", aux)
304	}
305}
306
307func TestMultiTenantServicePrincipalTokenWithAuthorizationRefresh(t *testing.T) {
308	multiTenantCfg, err := adal.NewMultiTenantOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID, []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3}, adal.OAuthOptions{})
309	if err != nil {
310		t.Fatalf("azure: adal#NewMultiTenantOAuthConfig returned an error (%v)", err)
311	}
312	mtSpt, err := adal.NewMultiTenantServicePrincipalToken(multiTenantCfg, "id", "secret", "resource")
313	if err != nil {
314		t.Fatalf("azure: adal#NewMultiTenantServicePrincipalToken returned an error (%v)", err)
315	}
316
317	primaryToken := `{
318		"access_token" : "primary token refreshed",
319		"expires_in"   : "3600",
320		"expires_on"   : "test",
321		"not_before"   : "test",
322		"resource"     : "test",
323		"token_type"   : "Bearer"
324	}`
325
326	auxToken1 := `{
327		"access_token" : "aux token 1 refreshed",
328		"expires_in"   : "3600",
329		"expires_on"   : "test",
330		"not_before"   : "test",
331		"resource"     : "test",
332		"token_type"   : "Bearer"
333	}`
334
335	auxToken2 := `{
336		"access_token" : "aux token 2 refreshed",
337		"expires_in"   : "3600",
338		"expires_on"   : "test",
339		"not_before"   : "test",
340		"resource"     : "test",
341		"token_type"   : "Bearer"
342	}`
343
344	auxToken3 := `{
345		"access_token" : "aux token 3 refreshed",
346		"expires_in"   : "3600",
347		"expires_on"   : "test",
348		"not_before"   : "test",
349		"resource"     : "test",
350		"token_type"   : "Bearer"
351	}`
352
353	s := mocks.NewSender()
354	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(primaryToken), http.StatusOK, "OK"))
355	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(auxToken1), http.StatusOK, "OK"))
356	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(auxToken2), http.StatusOK, "OK"))
357	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(auxToken3), http.StatusOK, "OK"))
358
359	mtSpt.PrimaryToken.SetSender(s)
360	for _, aux := range mtSpt.AuxiliaryTokens {
361		aux.SetSender(s)
362	}
363
364	mta := NewMultiTenantServicePrincipalTokenAuthorizer(mtSpt)
365	req, err := Prepare(mocks.NewRequest(), mta.WithAuthorization())
366	if err != nil {
367		t.Fatalf("azure: multiTenantSPTAuthorizer#WithAuthorization returned an error (%v)", err)
368	}
369	if ah := req.Header.Get(http.CanonicalHeaderKey("Authorization")); ah != fmt.Sprintf("Bearer %s", mtSpt.PrimaryOAuthToken()) {
370		t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization failed to set Authorization header for primary token")
371	} else if ah != "Bearer primary token refreshed" {
372		t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization primary token value doesn't match")
373	}
374	auxTokens := mtSpt.AuxiliaryOAuthTokens()
375	for i := range auxTokens {
376		auxTokens[i] = fmt.Sprintf("Bearer %s", auxTokens[i])
377	}
378	auxHeader := req.Header.Get(http.CanonicalHeaderKey(headerAuxAuthorization))
379	if auxHeader != strings.Join(auxTokens, "; ") {
380		t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization failed to set Authorization header for auxiliary tokens")
381	}
382	for i := range auxTokens {
383		if auxTokens[i] != fmt.Sprintf("Bearer aux token %d refreshed", i+1) {
384			t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization auxiliary token value doesn't match")
385		}
386	}
387}
388
389func TestMultiTenantServicePrincipalTokenWithAuthorizationRefreshFail1(t *testing.T) {
390	multiTenantCfg, err := adal.NewMultiTenantOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID, []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3}, adal.OAuthOptions{})
391	if err != nil {
392		t.Fatalf("azure: adal#NewMultiTenantOAuthConfig returned an error (%v)", err)
393	}
394	mtSpt, err := adal.NewMultiTenantServicePrincipalToken(multiTenantCfg, "id", "secret", "resource")
395	if err != nil {
396		t.Fatalf("azure: adal#NewMultiTenantServicePrincipalToken returned an error (%v)", err)
397	}
398
399	s := mocks.NewSender()
400	s.AppendResponse(mocks.NewResponseWithStatus("access denied", http.StatusForbidden))
401
402	mtSpt.PrimaryToken.SetSender(s)
403	for _, aux := range mtSpt.AuxiliaryTokens {
404		aux.SetSender(s)
405	}
406
407	mta := NewMultiTenantServicePrincipalTokenAuthorizer(mtSpt)
408	_, err = Prepare(mocks.NewRequest(), mta.WithAuthorization())
409	if err == nil {
410		t.Fatalf("azure: multiTenantSPTAuthorizer#WithAuthorization unexpected nil error")
411	}
412}
413
414func TestMultiTenantServicePrincipalTokenWithAuthorizationRefreshFail2(t *testing.T) {
415	multiTenantCfg, err := adal.NewMultiTenantOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID, []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3}, adal.OAuthOptions{})
416	if err != nil {
417		t.Fatalf("azure: adal#NewMultiTenantOAuthConfig returned an error (%v)", err)
418	}
419	mtSpt, err := adal.NewMultiTenantServicePrincipalToken(multiTenantCfg, "id", "secret", "resource")
420	if err != nil {
421		t.Fatalf("azure: adal#NewMultiTenantServicePrincipalToken returned an error (%v)", err)
422	}
423
424	primaryToken := `{
425		"access_token" : "primary token refreshed",
426		"expires_in"   : "3600",
427		"expires_on"   : "test",
428		"not_before"   : "test",
429		"resource"     : "test",
430		"token_type"   : "Bearer"
431	}`
432
433	s := mocks.NewSender()
434	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(primaryToken), http.StatusOK, "OK"))
435	s.AppendResponse(mocks.NewResponseWithStatus("access denied", http.StatusForbidden))
436
437	mtSpt.PrimaryToken.SetSender(s)
438	for _, aux := range mtSpt.AuxiliaryTokens {
439		aux.SetSender(s)
440	}
441
442	mta := NewMultiTenantServicePrincipalTokenAuthorizer(mtSpt)
443	_, err = Prepare(mocks.NewRequest(), mta.WithAuthorization())
444	if err == nil {
445		t.Fatalf("azure: multiTenantSPTAuthorizer#WithAuthorization unexpected nil error")
446	}
447}
448