44package com .microsoft .aad .msal4j ;
55
66import com .nimbusds .oauth2 .sdk .util .URLUtils ;
7- import org .apache .http .HttpStatus ;
8- import org .junit .jupiter .api .BeforeAll ;
9- import org .junit .jupiter .api .BeforeEach ;
7+ import org .junit .jupiter .api .Nested ;
108import org .junit .jupiter .api .Test ;
119import org .junit .jupiter .api .TestInstance ;
1210import org .junit .jupiter .api .extension .ExtendWith ;
1311import org .junit .jupiter .params .ParameterizedTest ;
1412import org .junit .jupiter .params .provider .MethodSource ;
13+ import org .junit .jupiter .params .provider .ValueSource ;
1514import org .mockito .junit .jupiter .MockitoExtension ;
1615
1716import java .net .SocketException ;
18- import java .net .URISyntaxException ;
1917import java .nio .file .Path ;
2018import java .nio .file .Paths ;
21- import java .time .Instant ;
22- import java .time .temporal .ChronoUnit ;
23- import java .util .Collections ;
2419import java .util .HashMap ;
2520import java .util .List ;
2621import java .util .Map ;
2722import java .util .concurrent .CompletableFuture ;
2823import java .util .concurrent .ExecutionException ;
2924
25+ import static com .microsoft .aad .msal4j .ManagedIdentitySourceType .*;
26+ import static com .microsoft .aad .msal4j .MsalError .*;
27+ import static com .microsoft .aad .msal4j .MsalErrorMessage .*;
28+ import static java .util .Collections .*;
29+ import static org .apache .http .HttpStatus .*;
3030import static org .junit .jupiter .api .Assertions .*;
3131import static org .mockito .Mockito .*;
3232
@@ -77,8 +77,8 @@ private HttpRequest expectedRequest(ManagedIdentitySourceType source, String res
7777 case APP_SERVICE : {
7878 endpoint = appServiceEndpoint ;
7979
80- queryParameters .put ("api-version" , Collections . singletonList ("2019-08-01" ));
81- queryParameters .put ("resource" , Collections . singletonList (resource ));
80+ queryParameters .put ("api-version" , singletonList ("2019-08-01" ));
81+ queryParameters .put ("resource" , singletonList (resource ));
8282
8383 headers .put ("X-IDENTITY-HEADER" , "secret" );
8484 break ;
@@ -89,43 +89,43 @@ private HttpRequest expectedRequest(ManagedIdentitySourceType source, String res
8989 headers .put ("ContentType" , "application/x-www-form-urlencoded" );
9090 headers .put ("Metadata" , "true" );
9191
92- bodyParameters .put ("resource" , Collections . singletonList (resource ));
92+ bodyParameters .put ("resource" , singletonList (resource ));
9393
94- queryParameters .put ("resource" , Collections . singletonList (resource ));
94+ queryParameters .put ("resource" , singletonList (resource ));
9595 return new HttpRequest (HttpMethod .GET , computeUri (endpoint , queryParameters ), headers , URLUtils .serializeParameters (bodyParameters ));
9696 }
9797 case IMDS : {
9898 endpoint = IMDS_ENDPOINT ;
99- queryParameters .put ("api-version" , Collections . singletonList ("2018-02-01" ));
100- queryParameters .put ("resource" , Collections . singletonList (resource ));
99+ queryParameters .put ("api-version" , singletonList ("2018-02-01" ));
100+ queryParameters .put ("resource" , singletonList (resource ));
101101 headers .put ("Metadata" , "true" );
102102 break ;
103103 }
104104 case AZURE_ARC : {
105105 endpoint = azureArcEndpoint ;
106106
107- queryParameters .put ("api-version" , Collections . singletonList ("2019-11-01" ));
108- queryParameters .put ("resource" , Collections . singletonList (resource ));
107+ queryParameters .put ("api-version" , singletonList ("2019-11-01" ));
108+ queryParameters .put ("resource" , singletonList (resource ));
109109
110110 headers .put ("Metadata" , "true" );
111111 break ;
112112 }
113113 case SERVICE_FABRIC :
114114 endpoint = serviceFabricEndpoint ;
115- queryParameters .put ("api-version" , Collections . singletonList ("2019-07-01-preview" ));
116- queryParameters .put ("resource" , Collections . singletonList (resource ));
115+ queryParameters .put ("api-version" , singletonList ("2019-07-01-preview" ));
116+ queryParameters .put ("resource" , singletonList (resource ));
117117 break ;
118118 }
119119
120120 switch (id .getIdType ()) {
121121 case CLIENT_ID :
122- queryParameters .put ("client_id" , Collections . singletonList (id .getUserAssignedId ()));
122+ queryParameters .put ("client_id" , singletonList (id .getUserAssignedId ()));
123123 break ;
124124 case RESOURCE_ID :
125- queryParameters .put ("mi_res_id" , Collections . singletonList (id .getUserAssignedId ()));
125+ queryParameters .put ("mi_res_id" , singletonList (id .getUserAssignedId ()));
126126 break ;
127127 case OBJECT_ID :
128- queryParameters .put ("object_id" , Collections . singletonList (id .getUserAssignedId ()));
128+ queryParameters .put ("object_id" , singletonList (id .getUserAssignedId ()));
129129 break ;
130130 }
131131
@@ -511,43 +511,6 @@ void managedIdentity_RequestFailed_UnreachableNetwork(ManagedIdentitySourceType
511511 verify (httpClientMock , times (1 )).send (any ());
512512 }
513513
514- @ Test
515- void azureArcManagedIdentity_MissingAuthHeader () throws Exception {
516- IEnvironmentVariables environmentVariables = new EnvironmentVariablesHelper (ManagedIdentitySourceType .AZURE_ARC , azureArcEndpoint );
517- ManagedIdentityApplication .setEnvironmentVariables (environmentVariables );
518- DefaultHttpClient httpClientMock = mock (DefaultHttpClient .class );
519-
520- HttpResponse response = new HttpResponse ();
521- response .statusCode (HttpStatus .SC_UNAUTHORIZED );
522-
523- when (httpClientMock .send (any ())).thenReturn (response );
524-
525- miApp = ManagedIdentityApplication
526- .builder (ManagedIdentityId .systemAssigned ())
527- .httpClient (httpClientMock )
528- .build ();
529-
530- // Clear caching to avoid cross test pollution.
531- miApp .tokenCache ().accessTokens .clear ();
532-
533- try {
534- miApp .acquireTokenForManagedIdentity (
535- ManagedIdentityParameters .builder (resource )
536- .build ()).get ();
537- } catch (Exception exception ) {
538- assert (exception .getCause () instanceof MsalServiceException );
539-
540- MsalServiceException miException = (MsalServiceException ) exception .getCause ();
541- assertEquals (ManagedIdentitySourceType .AZURE_ARC .name (), miException .managedIdentitySource ());
542- assertEquals (MsalError .MANAGED_IDENTITY_REQUEST_FAILED , miException .errorCode ());
543- assertEquals (MsalErrorMessage .MANAGED_IDENTITY_NO_CHALLENGE_ERROR , miException .getMessage ());
544- return ;
545- }
546-
547- fail ("MsalServiceException is expected but not thrown." );
548- verify (httpClientMock , times (1 )).send (any ());
549- }
550-
551514 @ ParameterizedTest
552515 @ MethodSource ("com.microsoft.aad.msal4j.ManagedIdentityTestDataProvider#createDataError" )
553516 void managedIdentity_SharedCache (ManagedIdentitySourceType source , String endpoint ) throws Exception {
@@ -589,81 +552,85 @@ void managedIdentity_SharedCache(ManagedIdentitySourceType source, String endpoi
589552 verify (httpClientMock , times (1 )).send (any ());
590553 }
591554
592- @ Test
593- void azureArcManagedIdentity_InvalidAuthHeader () throws Exception {
594- IEnvironmentVariables environmentVariables = new EnvironmentVariablesHelper (ManagedIdentitySourceType .AZURE_ARC , azureArcEndpoint );
595- ManagedIdentityApplication .setEnvironmentVariables (environmentVariables );
596- DefaultHttpClient httpClientMock = mock (DefaultHttpClient .class );
597-
598- HttpResponse response = new HttpResponse ();
599- response .statusCode (HttpStatus .SC_UNAUTHORIZED );
600- response .headers ().put ("WWW-Authenticate" , Collections .singletonList ("xyz" ));
555+ @ Nested
556+ class AzureArc {
601557
602- when (httpClientMock .send (any ())).thenReturn (response );
558+ @ Test
559+ void missingAuthHeader () throws Exception {
560+ mockHttpResponse (emptyMap ());
603561
604- miApp = ManagedIdentityApplication
605- .builder (ManagedIdentityId .systemAssigned ())
606- .httpClient (httpClientMock )
607- .build ();
608-
609- // Clear caching to avoid cross test pollution.
610- miApp .tokenCache ().accessTokens .clear ();
562+ assertMsalServiceException (MANAGED_IDENTITY_REQUEST_FAILED , MANAGED_IDENTITY_NO_CHALLENGE_ERROR );
563+ }
611564
612- try {
613- miApp .acquireTokenForManagedIdentity (
614- ManagedIdentityParameters .builder (resource )
615- .build ()).get ();
616- } catch (Exception exception ) {
617- assert (exception .getCause () instanceof MsalServiceException );
565+ @ ParameterizedTest
566+ @ ValueSource (strings = {"WWW-Authenticate" , "Www-Authenticate" })
567+ void invalidAuthHeader (String authHeaderKey ) throws Exception {
568+ mockHttpResponse (singletonMap (authHeaderKey , singletonList ("xyz" )));
618569
619- MsalServiceException miException = (MsalServiceException ) exception .getCause ();
620- assertEquals (ManagedIdentitySourceType .AZURE_ARC .name (), miException .managedIdentitySource ());
621- assertEquals (MsalError .MANAGED_IDENTITY_REQUEST_FAILED , miException .errorCode ());
622- assertEquals (MsalErrorMessage .MANAGED_IDENTITY_INVALID_CHALLENGE , miException .getMessage ());
623- return ;
570+ assertMsalServiceException (MANAGED_IDENTITY_REQUEST_FAILED ,
571+ MANAGED_IDENTITY_INVALID_CHALLENGE );
624572 }
625573
626- fail ("MsalServiceException is expected but not thrown." );
627- verify (httpClientMock , times (1 )).send (any ());
628- }
574+ @ ParameterizedTest
575+ @ ValueSource (strings = {"WWW-Authenticate" , "Www-Authenticate" })
576+ void validPathWithMissingFile (String authHeaderKey )
577+ throws Exception {
578+ Path validPathWithMissingFile = Paths .get (
579+ System .getenv ("ProgramData" ) + "/AzureConnectedMachineAgent/Tokens/secret.key" );
629580
630- @ Test
631- void azureArcManagedIdentityAuthheaderValidationTest () throws Exception {
632- IEnvironmentVariables environmentVariables = new EnvironmentVariablesHelper (ManagedIdentitySourceType .AZURE_ARC , azureArcEndpoint );
633- ManagedIdentityApplication .setEnvironmentVariables (environmentVariables );
634- DefaultHttpClient httpClientMock = mock (DefaultHttpClient .class );
581+ mockHttpResponse (singletonMap (authHeaderKey , singletonList ("Basic realm=" + validPathWithMissingFile )));
635582
636- //Both a missing file and an invalid path structure should throw an exception
637- Path validPathWithMissingFile = Paths . get ( System . getenv ( "ProgramData" )+ "/AzureConnectedMachineAgent/Tokens/secret.key" );
638- Path invalidPathWithRealFile = Paths . get ( this . getClass (). getResource ( "/msi-azure-arc-secret.txt" ). toURI ());
583+ assertMsalServiceException ( MANAGED_IDENTITY_FILE_READ_ERROR ,
584+ MANAGED_IDENTITY_INVALID_FILEPATH );
585+ }
639586
640- // Mock 401 response that returns WWW-Authenticate header
641- HttpResponse response = new HttpResponse ();
642- response .statusCode (HttpStatus .SC_UNAUTHORIZED );
643- response .headers ().put ("WWW-Authenticate" , Collections .singletonList ("Basic realm=" + validPathWithMissingFile ));
587+ @ ParameterizedTest
588+ @ ValueSource (strings = {"WWW-Authenticate" , "Www-Authenticate" })
589+ void invalidPathWithRealFile (String authHeaderKey )
590+ throws Exception {
591+ Path invalidPathWithRealFile = Paths .get (
592+ this .getClass ().getResource ("/msi-azure-arc-secret.txt" ).toURI ());
644593
645- when ( httpClientMock . send ( expectedRequest ( ManagedIdentitySourceType . AZURE_ARC , resource ))). thenReturn ( response );
594+ mockHttpResponse ( singletonMap ( authHeaderKey , singletonList ( "Basic realm=" + invalidPathWithRealFile )) );
646595
647- miApp = ManagedIdentityApplication
648- .builder (ManagedIdentityId .systemAssigned ())
649- .httpClient (httpClientMock )
650- .build ();
596+ assertMsalServiceException (MANAGED_IDENTITY_FILE_READ_ERROR ,
597+ MANAGED_IDENTITY_INVALID_FILEPATH );
598+ }
651599
652- // Clear caching to avoid cross test pollution.
653- miApp .tokenCache ().accessTokens .clear ();
600+ private void mockHttpResponse (Map <String , ? extends List <String >> responseHeaders ) throws Exception {
601+ IEnvironmentVariables environmentVariables = new EnvironmentVariablesHelper (AZURE_ARC , azureArcEndpoint );
602+ ManagedIdentityApplication .setEnvironmentVariables (environmentVariables );
603+ DefaultHttpClient httpClientMock = mock (DefaultHttpClient .class );
654604
655- CompletableFuture <IAuthenticationResult > future = miApp .acquireTokenForManagedIdentity (ManagedIdentityParameters .builder (resource ).build ());
605+ HttpResponse response = new HttpResponse ();
606+ response .statusCode (SC_UNAUTHORIZED );
607+ response .headers ().putAll (responseHeaders );
656608
657- ExecutionException ex = assertThrows ( ExecutionException . class , future :: get );
658- assertTrue ( ex . getCause () instanceof MsalServiceException );
659- assertTrue ( ex . getMessage (). contains ( MsalErrorMessage . MANAGED_IDENTITY_INVALID_FILEPATH ) );
609+ when ( httpClientMock . send (
610+ expectedRequest ( AZURE_ARC , resource ))). thenReturn (
611+ response );
660612
661- response .headers ().put ("WWW-Authenticate" , Collections .singletonList ("Basic realm=" + invalidPathWithRealFile ));
613+ miApp = ManagedIdentityApplication
614+ .builder (ManagedIdentityId .systemAssigned ())
615+ .httpClient (httpClientMock )
616+ .build ();
662617
663- future = miApp .acquireTokenForManagedIdentity (ManagedIdentityParameters .builder (resource ).build ());
618+ // Clear caching to avoid cross test pollution.
619+ miApp .tokenCache ().accessTokens .clear ();
620+ }
664621
665- ex = assertThrows (ExecutionException .class , future ::get );
666- assertTrue (ex .getCause () instanceof MsalServiceException );
667- assertTrue (ex .getMessage ().contains (MsalErrorMessage .MANAGED_IDENTITY_INVALID_FILEPATH ));
622+ private void assertMsalServiceException (String errorCode , String message ) throws Exception {
623+ CompletableFuture <IAuthenticationResult > future =
624+ miApp .acquireTokenForManagedIdentity (
625+ ManagedIdentityParameters .builder (resource ).build ());
626+
627+ ExecutionException ex = assertThrows (ExecutionException .class , future ::get );
628+ assertInstanceOf (MsalServiceException .class , ex .getCause ());
629+ MsalServiceException msalException = (MsalServiceException ) ex .getCause ();
630+ assertEquals (AZURE_ARC .name (),
631+ msalException .managedIdentitySource ());
632+ assertEquals (errorCode , msalException .errorCode ());
633+ assertTrue (ex .getMessage ().contains (message ));
634+ }
668635 }
669636}
0 commit comments