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"   : "12345",
106		"not_before"   : "67890",
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 := NewMultiTenantBearerAuthorizer(mtSPTProvider)
295	req, err := Prepare(mocks.NewRequest(), mt.WithAuthorization())
296	if err != nil {
297		t.Fatalf("unexpected error: %v", err)
298	}
299	if primary := mt.TokenProvider().PrimaryOAuthToken(); primary != mtSPTProvider.p {
300		t.Fatalf("bad primary authorization token %s", primary)
301	}
302	if aux := strings.Join(mt.TokenProvider().AuxiliaryOAuthTokens(), ","); aux != strings.Join(mtSPTProvider.a, ",") {
303		t.Fatalf("bad auxiliary authorization tokens %s", aux)
304	}
305	if primary := req.Header.Get(headerAuthorization); primary != "Bearer primary" {
306		t.Fatalf("bad primary authorization header %s", primary)
307	}
308	if aux := req.Header.Get(headerAuxAuthorization); aux != "Bearer aux1, Bearer aux2, Bearer aux3" {
309		t.Fatalf("bad auxiliary authorization header %s", aux)
310	}
311}
312
313func TestMultiTenantServicePrincipalTokenWithAuthorizationRefresh(t *testing.T) {
314	multiTenantCfg, err := adal.NewMultiTenantOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID, []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3}, adal.OAuthOptions{})
315	if err != nil {
316		t.Fatalf("azure: adal#NewMultiTenantOAuthConfig returned an error (%v)", err)
317	}
318	mtSpt, err := adal.NewMultiTenantServicePrincipalToken(multiTenantCfg, "id", "secret", "resource")
319	if err != nil {
320		t.Fatalf("azure: adal#NewMultiTenantServicePrincipalToken returned an error (%v)", err)
321	}
322
323	primaryToken := `{
324		"access_token" : "primary token refreshed",
325		"expires_in"   : "3600",
326		"expires_on"   : "12345",
327		"not_before"   : "67890",
328		"resource"     : "test",
329		"token_type"   : "Bearer"
330	}`
331
332	auxToken1 := `{
333		"access_token" : "aux token 1 refreshed",
334		"expires_in"   : "3600",
335		"expires_on"   : "12345",
336		"not_before"   : "67890",
337		"resource"     : "test",
338		"token_type"   : "Bearer"
339	}`
340
341	auxToken2 := `{
342		"access_token" : "aux token 2 refreshed",
343		"expires_in"   : "3600",
344		"expires_on"   : "12345",
345		"not_before"   : "67890",
346		"resource"     : "test",
347		"token_type"   : "Bearer"
348	}`
349
350	auxToken3 := `{
351		"access_token" : "aux token 3 refreshed",
352		"expires_in"   : "3600",
353		"expires_on"   : "12345",
354		"not_before"   : "67890",
355		"resource"     : "test",
356		"token_type"   : "Bearer"
357	}`
358
359	s := mocks.NewSender()
360	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(primaryToken), http.StatusOK, "OK"))
361	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(auxToken1), http.StatusOK, "OK"))
362	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(auxToken2), http.StatusOK, "OK"))
363	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(auxToken3), http.StatusOK, "OK"))
364
365	mtSpt.PrimaryToken.SetSender(s)
366	for _, aux := range mtSpt.AuxiliaryTokens {
367		aux.SetSender(s)
368	}
369
370	mta := NewMultiTenantServicePrincipalTokenAuthorizer(mtSpt)
371	req, err := Prepare(mocks.NewRequest(), mta.WithAuthorization())
372	if err != nil {
373		t.Fatalf("azure: multiTenantSPTAuthorizer#WithAuthorization returned an error (%v)", err)
374	}
375	if ah := req.Header.Get(http.CanonicalHeaderKey("Authorization")); ah != fmt.Sprintf("Bearer %s", mtSpt.PrimaryOAuthToken()) {
376		t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization failed to set Authorization header for primary token")
377	} else if ah != "Bearer primary token refreshed" {
378		t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization primary token value doesn't match")
379	}
380	auxTokens := mtSpt.AuxiliaryOAuthTokens()
381	for i := range auxTokens {
382		auxTokens[i] = fmt.Sprintf("Bearer %s", auxTokens[i])
383	}
384	auxHeader := req.Header.Get(http.CanonicalHeaderKey(headerAuxAuthorization))
385	if auxHeader != strings.Join(auxTokens, ", ") {
386		t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization failed to set Authorization header for auxiliary tokens")
387	}
388	for i := range auxTokens {
389		if auxTokens[i] != fmt.Sprintf("Bearer aux token %d refreshed", i+1) {
390			t.Fatal("azure: multiTenantSPTAuthorizer#WithAuthorization auxiliary token value doesn't match")
391		}
392	}
393}
394
395func TestMultiTenantServicePrincipalTokenWithAuthorizationRefreshFail1(t *testing.T) {
396	multiTenantCfg, err := adal.NewMultiTenantOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID, []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3}, adal.OAuthOptions{})
397	if err != nil {
398		t.Fatalf("azure: adal#NewMultiTenantOAuthConfig returned an error (%v)", err)
399	}
400	mtSpt, err := adal.NewMultiTenantServicePrincipalToken(multiTenantCfg, "id", "secret", "resource")
401	if err != nil {
402		t.Fatalf("azure: adal#NewMultiTenantServicePrincipalToken returned an error (%v)", err)
403	}
404
405	s := mocks.NewSender()
406	s.AppendResponse(mocks.NewResponseWithStatus("access denied", http.StatusForbidden))
407
408	mtSpt.PrimaryToken.SetSender(s)
409	for _, aux := range mtSpt.AuxiliaryTokens {
410		aux.SetSender(s)
411	}
412
413	mta := NewMultiTenantServicePrincipalTokenAuthorizer(mtSpt)
414	_, err = Prepare(mocks.NewRequest(), mta.WithAuthorization())
415	if err == nil {
416		t.Fatalf("azure: multiTenantSPTAuthorizer#WithAuthorization unexpected nil error")
417	}
418}
419
420func TestMultiTenantServicePrincipalTokenWithAuthorizationRefreshFail2(t *testing.T) {
421	multiTenantCfg, err := adal.NewMultiTenantOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID, []string{TestAuxTenent1, TestAuxTenent2, TestAuxTenent3}, adal.OAuthOptions{})
422	if err != nil {
423		t.Fatalf("azure: adal#NewMultiTenantOAuthConfig returned an error (%v)", err)
424	}
425	mtSpt, err := adal.NewMultiTenantServicePrincipalToken(multiTenantCfg, "id", "secret", "resource")
426	if err != nil {
427		t.Fatalf("azure: adal#NewMultiTenantServicePrincipalToken returned an error (%v)", err)
428	}
429
430	primaryToken := `{
431		"access_token" : "primary token refreshed",
432		"expires_in"   : "3600",
433		"expires_on"   : "test",
434		"not_before"   : "test",
435		"resource"     : "test",
436		"token_type"   : "Bearer"
437	}`
438
439	s := mocks.NewSender()
440	s.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(primaryToken), http.StatusOK, "OK"))
441	s.AppendResponse(mocks.NewResponseWithStatus("access denied", http.StatusForbidden))
442
443	mtSpt.PrimaryToken.SetSender(s)
444	for _, aux := range mtSpt.AuxiliaryTokens {
445		aux.SetSender(s)
446	}
447
448	mta := NewMultiTenantServicePrincipalTokenAuthorizer(mtSpt)
449	_, err = Prepare(mocks.NewRequest(), mta.WithAuthorization())
450	if err == nil {
451		t.Fatalf("azure: multiTenantSPTAuthorizer#WithAuthorization unexpected nil error")
452	}
453}
454