github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/azure/internal/azureauth/serviceprincipal_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package azureauth_test
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"time"
    14  
    15  	"github.com/Azure/azure-sdk-for-go/services/authorization/mgmt/2015-07-01/authorization"
    16  	"github.com/Azure/go-autorest/autorest"
    17  	"github.com/Azure/go-autorest/autorest/adal"
    18  	"github.com/Azure/go-autorest/autorest/mocks"
    19  	"github.com/Azure/go-autorest/autorest/to"
    20  	"github.com/juju/clock/testclock"
    21  	"github.com/juju/testing"
    22  	jc "github.com/juju/testing/checkers"
    23  	"github.com/juju/utils"
    24  	gc "gopkg.in/check.v1"
    25  
    26  	"github.com/juju/juju/provider/azure/internal/ad"
    27  	"github.com/juju/juju/provider/azure/internal/azureauth"
    28  	"github.com/juju/juju/provider/azure/internal/azuretesting"
    29  )
    30  
    31  func clockStartTime() time.Time {
    32  	t, _ := time.Parse("2006-Jan-02 3:04am", "2016-Sep-19 9:47am")
    33  	return t
    34  }
    35  
    36  type InteractiveSuite struct {
    37  	testing.IsolationSuite
    38  	clock   *testclock.Clock
    39  	newUUID func() (utils.UUID, error)
    40  }
    41  
    42  var _ = gc.Suite(&InteractiveSuite{})
    43  
    44  func deviceCodeSender() autorest.Sender {
    45  	return azuretesting.NewSenderWithValue(adal.DeviceCode{
    46  		DeviceCode: to.StringPtr("device-code"),
    47  		Interval:   to.Int64Ptr(1), // 1 second between polls
    48  		Message:    to.StringPtr("open your browser, etc."),
    49  	})
    50  }
    51  
    52  func tokenSender() autorest.Sender {
    53  	return azuretesting.NewSenderWithValue(adal.Token{
    54  		RefreshToken: "refresh-token",
    55  		ExpiresOn:    json.Number(fmt.Sprint(time.Now().Add(time.Hour).Unix())),
    56  	})
    57  }
    58  
    59  func passwordCredentialsListSender() autorest.Sender {
    60  	return azuretesting.NewSenderWithValue(ad.PasswordCredentialsListResult{
    61  		Value: []ad.PasswordCredential{{
    62  			KeyId: "password-credential-key-id",
    63  		}},
    64  	})
    65  }
    66  
    67  func updatePasswordCredentialsSender() autorest.Sender {
    68  	sender := mocks.NewSender()
    69  	sender.AppendResponse(mocks.NewResponseWithStatus("", http.StatusNoContent))
    70  	return sender
    71  }
    72  
    73  func currentUserSender() autorest.Sender {
    74  	return azuretesting.NewSenderWithValue(ad.AADObject{
    75  		DisplayName: "Foo Bar",
    76  	})
    77  }
    78  
    79  func createServicePrincipalSender() autorest.Sender {
    80  	return azuretesting.NewSenderWithValue(ad.ServicePrincipal{
    81  		ApplicationID: "cbb548f1-5039-4836-af0b-727e8571f6a9",
    82  		ObjectID:      "sp-object-id",
    83  	})
    84  }
    85  
    86  func createServicePrincipalAlreadyExistsSender(withUTF8BOM bool) autorest.Sender {
    87  	sender := mocks.NewSender()
    88  	bodyData := `{"odata.error":{"code":"Request_MultipleObjectsWithSameKeyValue"}}`
    89  	if withUTF8BOM {
    90  		bodyData = "\ufeff" + bodyData
    91  	}
    92  	body := mocks.NewBody(bodyData)
    93  	sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusConflict, ""))
    94  	return sender
    95  }
    96  
    97  func createServicePrincipalNotExistSender() autorest.Sender {
    98  	sender := mocks.NewSender()
    99  	bodyData := `{"odata.error":{"code":"Request_ResourceNotFound","message":{"lang":"en","value":"... does not exist in the directory ..."}}}`
   100  	body := mocks.NewBody(bodyData)
   101  	sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusNotFound, ""))
   102  	return sender
   103  }
   104  
   105  func createServicePrincipalNotReferenceSender() autorest.Sender {
   106  	sender := mocks.NewSender()
   107  	// Error message cribbed from https://github.com/kubernetes/kubernetes-anywhere/issues/251
   108  	bodyData := `{"odata.error":{"code":"Request_BadRequest","message":{"lang":"en","value":"The appId of the service principal does not reference a valid application object."}}}`
   109  	body := mocks.NewBody(bodyData)
   110  	sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, ""))
   111  	return sender
   112  }
   113  
   114  func servicePrincipalListSender() autorest.Sender {
   115  	return azuretesting.NewSenderWithValue(ad.ServicePrincipalListResult{
   116  		Value: []ad.ServicePrincipal{{
   117  			ApplicationID: "cbb548f1-5039-4836-af0b-727e8571f6a9",
   118  			ObjectID:      "sp-object-id",
   119  		}},
   120  	})
   121  }
   122  
   123  func roleDefinitionListSender() autorest.Sender {
   124  	roleDefinitions := []authorization.RoleDefinition{{
   125  		ID:   to.StringPtr("owner-role-id"),
   126  		Name: to.StringPtr("Owner"),
   127  	}}
   128  	return azuretesting.NewSenderWithValue(authorization.RoleDefinitionListResult{
   129  		Value: &roleDefinitions,
   130  	})
   131  }
   132  
   133  func roleAssignmentSender() autorest.Sender {
   134  	return azuretesting.NewSenderWithValue(authorization.RoleAssignment{})
   135  }
   136  
   137  func roleAssignmentAlreadyExistsSender() autorest.Sender {
   138  	sender := mocks.NewSender()
   139  	body := mocks.NewBody(`{"error":{"code":"RoleAssignmentExists", "message":"Odata v4 compliant message"}}`)
   140  	sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusConflict, ""))
   141  	return sender
   142  }
   143  
   144  func roleAssignmentPrincipalNotExistSender() autorest.Sender {
   145  	sender := mocks.NewSender()
   146  	// Based on https://github.com/Azure/azure-powershell/issues/655#issuecomment-186332230
   147  	body := mocks.NewBody(`{"error":{"code":"PrincipalNotFound","message":"Principal foo does not exist in the directory bar"}}`)
   148  	sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusNotFound, ""))
   149  	return sender
   150  }
   151  
   152  func (s *InteractiveSuite) SetUpTest(c *gc.C) {
   153  	s.IsolationSuite.SetUpTest(c)
   154  	uuids := []string{
   155  		"33333333-3333-3333-3333-333333333333", // password
   156  		"44444444-4444-4444-4444-444444444444", // password key ID
   157  		"55555555-5555-5555-5555-555555555555", // role assignment ID
   158  	}
   159  	s.newUUID = func() (utils.UUID, error) {
   160  		uuid, err := utils.UUIDFromString(uuids[0])
   161  		if err != nil {
   162  			return utils.UUID{}, err
   163  		}
   164  		uuids = uuids[1:]
   165  		return uuid, nil
   166  	}
   167  	s.clock = testclock.NewClock(clockStartTime())
   168  }
   169  
   170  func (s *InteractiveSuite) TestInteractive(c *gc.C) {
   171  	var requests []*http.Request
   172  	spc := azureauth.ServicePrincipalCreator{
   173  		Sender: &azuretesting.Senders{
   174  			oauthConfigSender(),
   175  			deviceCodeSender(),
   176  			tokenSender(), // CheckForUserCompletion returns a token.
   177  
   178  			// Token.Refresh returns a token. We do this
   179  			// twice: once for ARM, and once for AAD.
   180  			tokenSender(),
   181  			tokenSender(),
   182  
   183  			currentUserSender(),
   184  			createServicePrincipalSender(),
   185  			roleDefinitionListSender(),
   186  			roleAssignmentSender(),
   187  		},
   188  		RequestInspector: azuretesting.RequestRecorder(&requests),
   189  		Clock:            s.clock,
   190  		NewUUID:          s.newUUID,
   191  	}
   192  
   193  	var stderr bytes.Buffer
   194  	subscriptionId := "22222222-2222-2222-2222-222222222222"
   195  	sdkCtx := context.Background()
   196  
   197  	appId, password, err := spc.InteractiveCreate(sdkCtx, &stderr, azureauth.ServicePrincipalParams{
   198  		GraphEndpoint:             "https://graph.invalid",
   199  		GraphResourceId:           "https://graph.invalid",
   200  		ResourceManagerEndpoint:   "https://arm.invalid",
   201  		ResourceManagerResourceId: "https://management.core.invalid/",
   202  		SubscriptionId:            subscriptionId,
   203  	})
   204  	c.Assert(err, jc.ErrorIsNil)
   205  	c.Assert(appId, gc.Equals, "cbb548f1-5039-4836-af0b-727e8571f6a9")
   206  	c.Assert(password, gc.Equals, "33333333-3333-3333-3333-333333333333")
   207  	c.Assert(stderr.String(), gc.Equals, `
   208  Initiating interactive authentication.
   209  
   210  open your browser, etc.
   211  
   212  Authenticated as "Foo Bar".
   213  `[1:])
   214  
   215  	c.Assert(requests, gc.HasLen, 9)
   216  	c.Check(requests[0].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222")
   217  	c.Check(requests[1].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/devicecode")
   218  	c.Check(requests[2].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   219  	c.Check(requests[3].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   220  	c.Check(requests[4].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   221  	c.Check(requests[5].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/me")
   222  	c.Check(requests[6].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals")
   223  	c.Check(requests[7].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleDefinitions")
   224  	c.Check(requests[8].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleAssignments/55555555-5555-5555-5555-555555555555")
   225  
   226  	// The service principal creation includes the password. Check that the
   227  	// password returned from the function is the same as the one set in the
   228  	// request.
   229  	var params ad.ServicePrincipalCreateParameters
   230  	err = json.NewDecoder(requests[6].Body).Decode(&params)
   231  	c.Assert(err, jc.ErrorIsNil)
   232  	c.Assert(params.PasswordCredentials, gc.HasLen, 1)
   233  	assertPasswordCredential(c, params.PasswordCredentials[0])
   234  }
   235  
   236  func assertPasswordCredential(c *gc.C, cred ad.PasswordCredential) {
   237  	startDate := cred.StartDate
   238  	endDate := cred.EndDate
   239  	c.Assert(startDate, gc.Equals, clockStartTime())
   240  	c.Assert(endDate.Sub(startDate), gc.Equals, 365*24*time.Hour)
   241  
   242  	cred.StartDate = time.Time{}
   243  	cred.EndDate = time.Time{}
   244  	c.Assert(cred, jc.DeepEquals, ad.PasswordCredential{
   245  		CustomKeyIdentifier: []byte("juju-20160919"),
   246  		KeyId:               "44444444-4444-4444-4444-444444444444",
   247  		Value:               "33333333-3333-3333-3333-333333333333",
   248  	})
   249  }
   250  
   251  func (s *InteractiveSuite) TestInteractiveRoleAssignmentAlreadyExists(c *gc.C) {
   252  	var requests []*http.Request
   253  	spc := azureauth.ServicePrincipalCreator{
   254  		Sender: &azuretesting.Senders{
   255  			oauthConfigSender(),
   256  			deviceCodeSender(),
   257  			tokenSender(),
   258  			tokenSender(),
   259  			tokenSender(),
   260  			currentUserSender(),
   261  			createServicePrincipalSender(),
   262  			roleDefinitionListSender(),
   263  			roleAssignmentAlreadyExistsSender(),
   264  		},
   265  		RequestInspector: azuretesting.RequestRecorder(&requests),
   266  		Clock:            s.clock,
   267  		NewUUID:          s.newUUID,
   268  	}
   269  	sdkCtx := context.Background()
   270  	_, _, err := spc.InteractiveCreate(sdkCtx, ioutil.Discard, azureauth.ServicePrincipalParams{
   271  		GraphEndpoint:             "https://graph.invalid",
   272  		GraphResourceId:           "https://graph.invalid",
   273  		ResourceManagerEndpoint:   "https://arm.invalid",
   274  		ResourceManagerResourceId: "https://management.core.invalid/",
   275  		SubscriptionId:            "22222222-2222-2222-2222-222222222222",
   276  	})
   277  	c.Assert(err, jc.ErrorIsNil)
   278  }
   279  
   280  func (s *InteractiveSuite) TestInteractiveServicePrincipalAlreadyExists(c *gc.C) {
   281  	s.testInteractiveServicePrincipalAlreadyExists(c, false)
   282  }
   283  
   284  func (s *InteractiveSuite) TestInteractiveServicePrincipalAlreadyExistsWithUTF8BOM(c *gc.C) {
   285  	// We have observed that Azure sometimes responds with UTF-8 BOMs in
   286  	// JSON-encoded responses. Go's JSON decoder does not like this, so
   287  	// we have to strip it off. See:
   288  	//     https://bugs.launchpad.net/juju/+bug/1657448
   289  	s.testInteractiveServicePrincipalAlreadyExists(c, true)
   290  }
   291  
   292  func (s *InteractiveSuite) testInteractiveServicePrincipalAlreadyExists(c *gc.C, withUTF8BOM bool) {
   293  	var requests []*http.Request
   294  	spc := azureauth.ServicePrincipalCreator{
   295  		Sender: &azuretesting.Senders{
   296  			oauthConfigSender(),
   297  			deviceCodeSender(),
   298  			tokenSender(),
   299  			tokenSender(),
   300  			tokenSender(),
   301  			currentUserSender(),
   302  			createServicePrincipalAlreadyExistsSender(withUTF8BOM),
   303  			servicePrincipalListSender(),
   304  			passwordCredentialsListSender(),
   305  			updatePasswordCredentialsSender(),
   306  			roleDefinitionListSender(),
   307  			roleAssignmentAlreadyExistsSender(),
   308  		},
   309  		RequestInspector: azuretesting.RequestRecorder(&requests),
   310  		Clock:            s.clock,
   311  		NewUUID:          s.newUUID,
   312  	}
   313  	sdkCtx := context.Background()
   314  	_, password, err := spc.InteractiveCreate(sdkCtx, ioutil.Discard, azureauth.ServicePrincipalParams{
   315  		GraphEndpoint:             "https://graph.invalid",
   316  		GraphResourceId:           "https://graph.invalid",
   317  		ResourceManagerEndpoint:   "https://arm.invalid",
   318  		ResourceManagerResourceId: "https://management.core.invalid/",
   319  		SubscriptionId:            "22222222-2222-2222-2222-222222222222",
   320  	})
   321  	c.Assert(err, jc.ErrorIsNil)
   322  	c.Assert(password, gc.Equals, "33333333-3333-3333-3333-333333333333")
   323  
   324  	c.Assert(requests, gc.HasLen, 12)
   325  	c.Check(requests[0].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222")
   326  	c.Check(requests[1].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/devicecode")
   327  	c.Check(requests[2].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   328  	c.Check(requests[3].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   329  	c.Check(requests[4].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   330  	c.Check(requests[5].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/me")
   331  	c.Check(requests[6].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals")                                  // create
   332  	c.Check(requests[7].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals")                                  // list
   333  	c.Check(requests[8].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals/sp-object-id/passwordCredentials") // list
   334  	c.Check(requests[9].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals/sp-object-id/passwordCredentials") // update
   335  	c.Check(requests[10].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleDefinitions")
   336  	c.Check(requests[11].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleAssignments/55555555-5555-5555-5555-555555555555")
   337  
   338  	// Make sure that we don't wipe existing password credentials, and that
   339  	// the new password credential matches the one returned from the
   340  	// function.
   341  	var params ad.PasswordCredentialsUpdateParameters
   342  	err = json.NewDecoder(requests[9].Body).Decode(&params)
   343  	c.Assert(err, jc.ErrorIsNil)
   344  	c.Assert(params.Value, gc.HasLen, 2)
   345  	c.Assert(params.Value[0], jc.DeepEquals, ad.PasswordCredential{
   346  		KeyId:     "password-credential-key-id",
   347  		StartDate: time.Time{}.UTC(),
   348  		EndDate:   time.Time{}.UTC(),
   349  	})
   350  	assertPasswordCredential(c, params.Value[1])
   351  }
   352  
   353  func (s *InteractiveSuite) TestInteractiveServicePrincipalApplicationNotExist(c *gc.C) {
   354  	s.testInteractiveRetriesCreateServicePrincipal(c, createServicePrincipalNotExistSender())
   355  }
   356  
   357  func (s *InteractiveSuite) TestInteractiveServicePrincipalApplicationNotReference(c *gc.C) {
   358  	s.testInteractiveRetriesCreateServicePrincipal(c, createServicePrincipalNotReferenceSender())
   359  }
   360  
   361  func (s *InteractiveSuite) testInteractiveRetriesCreateServicePrincipal(c *gc.C, errorSender autorest.Sender) {
   362  	var requests []*http.Request
   363  	spc := azureauth.ServicePrincipalCreator{
   364  		Sender: &azuretesting.Senders{
   365  			oauthConfigSender(),
   366  			deviceCodeSender(),
   367  			tokenSender(),
   368  			tokenSender(),
   369  			tokenSender(),
   370  			currentUserSender(),
   371  			errorSender,
   372  			createServicePrincipalSender(),
   373  			roleDefinitionListSender(),
   374  			roleAssignmentAlreadyExistsSender(),
   375  		},
   376  		RequestInspector: azuretesting.RequestRecorder(&requests),
   377  		Clock: &testclock.AutoAdvancingClock{
   378  			Clock:   s.clock,
   379  			Advance: s.clock.Advance,
   380  		},
   381  		NewUUID: s.newUUID,
   382  	}
   383  	sdkCtx := context.Background()
   384  	_, password, err := spc.InteractiveCreate(sdkCtx, ioutil.Discard, azureauth.ServicePrincipalParams{
   385  		GraphEndpoint:             "https://graph.invalid",
   386  		GraphResourceId:           "https://graph.invalid",
   387  		ResourceManagerEndpoint:   "https://arm.invalid",
   388  		ResourceManagerResourceId: "https://management.core.invalid/",
   389  		SubscriptionId:            "22222222-2222-2222-2222-222222222222",
   390  	})
   391  	c.Assert(err, jc.ErrorIsNil)
   392  	c.Assert(password, gc.Equals, "33333333-3333-3333-3333-333333333333")
   393  
   394  	c.Assert(requests, gc.HasLen, 10)
   395  	c.Check(requests[0].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222")
   396  	c.Check(requests[1].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/devicecode")
   397  	c.Check(requests[2].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   398  	c.Check(requests[3].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   399  	c.Check(requests[4].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   400  	c.Check(requests[5].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/me")
   401  	c.Check(requests[6].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals") // create
   402  	c.Check(requests[7].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals") // create
   403  	c.Check(requests[8].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleDefinitions")
   404  	c.Check(requests[9].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleAssignments/55555555-5555-5555-5555-555555555555")
   405  }
   406  
   407  func (s *InteractiveSuite) TestInteractiveRetriesRoleAssignment(c *gc.C) {
   408  	var requests []*http.Request
   409  	spc := azureauth.ServicePrincipalCreator{
   410  		Sender: &azuretesting.Senders{
   411  			oauthConfigSender(),
   412  			deviceCodeSender(),
   413  			tokenSender(),
   414  			tokenSender(),
   415  			tokenSender(),
   416  			currentUserSender(),
   417  			createServicePrincipalSender(),
   418  			roleDefinitionListSender(),
   419  			roleAssignmentPrincipalNotExistSender(),
   420  			roleAssignmentSender(),
   421  		},
   422  		RequestInspector: azuretesting.RequestRecorder(&requests),
   423  		Clock: &testclock.AutoAdvancingClock{
   424  			Clock:   s.clock,
   425  			Advance: s.clock.Advance,
   426  		},
   427  		NewUUID: s.newUUID,
   428  	}
   429  	sdkCtx := context.Background()
   430  	_, password, err := spc.InteractiveCreate(sdkCtx, ioutil.Discard, azureauth.ServicePrincipalParams{
   431  		GraphEndpoint:             "https://graph.invalid",
   432  		GraphResourceId:           "https://graph.invalid",
   433  		ResourceManagerEndpoint:   "https://arm.invalid",
   434  		ResourceManagerResourceId: "https://management.core.invalid/",
   435  		SubscriptionId:            "22222222-2222-2222-2222-222222222222",
   436  	})
   437  	c.Assert(err, jc.ErrorIsNil)
   438  	c.Assert(password, gc.Equals, "33333333-3333-3333-3333-333333333333")
   439  
   440  	c.Assert(requests, gc.HasLen, 10)
   441  	c.Check(requests[0].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222")
   442  	c.Check(requests[1].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/devicecode")
   443  	c.Check(requests[2].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   444  	c.Check(requests[3].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   445  	c.Check(requests[4].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/oauth2/token")
   446  	c.Check(requests[5].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/me")
   447  	c.Check(requests[6].URL.Path, gc.Equals, "/11111111-1111-1111-1111-111111111111/servicePrincipals") // create
   448  	c.Check(requests[7].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleDefinitions")
   449  	c.Check(requests[8].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleAssignments/55555555-5555-5555-5555-555555555555")
   450  	c.Check(requests[9].URL.Path, gc.Equals, "/subscriptions/22222222-2222-2222-2222-222222222222/providers/Microsoft.Authorization/roleAssignments/55555555-5555-5555-5555-555555555555")
   451  }