3636import reactor .core .publisher .Flux ;
3737import reactor .core .publisher .Mono ;
3838
39+ import java .lang .reflect .Field ;
3940import java .time .OffsetDateTime ;
4041import java .time .ZonedDateTime ;
4142import java .util .List ;
4243import java .util .Properties ;
4344import java .util .UUID ;
45+ import java .util .ArrayList ;
46+ import java .util .Collections ;
47+ import java .util .Map ;
4448
4549public class AadAuthorizationTests extends TestSuiteBase {
4650 private final static Logger log = LoggerFactory .getLogger (AadAuthorizationTests .class );
@@ -193,6 +197,106 @@ public void createAadTokenCredential() throws InterruptedException {
193197 Thread .sleep (SHUTDOWN_TIMEOUT );
194198 }
195199
200+ @ Test (groups = { "emulator" }, timeOut = 10 * TIMEOUT )
201+ public void testAadScopeOverride () throws Exception {
202+ CosmosAsyncClient setupClient = null ;
203+ CosmosAsyncClient aadClient = null ;
204+ String containerName = UUID .randomUUID ().toString ();
205+ String overrideScope = "https://cosmos.azure.com/.default" ;
206+
207+ try {
208+ setupClient = new CosmosClientBuilder ()
209+ .endpoint (TestConfigurations .HOST )
210+ .key (TestConfigurations .MASTER_KEY )
211+ .buildAsyncClient ();
212+
213+ setupClient .createDatabase (databaseId ).block ();
214+ setupClient .getDatabase (databaseId ).createContainer (containerName , PARTITION_KEY_PATH ).block ();
215+ } finally {
216+ if (setupClient != null ) {
217+ safeClose (setupClient );
218+ }
219+ }
220+
221+ Thread .sleep (TIMEOUT );
222+
223+ setEnv ("AZURE_COSMOS_AAD_SCOPE_OVERRIDE" , overrideScope );
224+
225+ TokenCredential emulatorCredential =
226+ new AadSimpleEmulatorTokenCredential (TestConfigurations .MASTER_KEY );
227+
228+ aadClient = new CosmosClientBuilder ()
229+ .endpoint (TestConfigurations .HOST )
230+ .credential (emulatorCredential )
231+ .buildAsyncClient ();
232+
233+ try {
234+ CosmosAsyncContainer container = aadClient
235+ .getDatabase (databaseId )
236+ .getContainer (containerName );
237+
238+ String itemId = UUID .randomUUID ().toString ();
239+ String pk = UUID .randomUUID ().toString ();
240+ ItemSample item = getDocumentDefinition (itemId , pk );
241+
242+ container .createItem (item ).block ();
243+
244+ List <String > scopes = AadSimpleEmulatorTokenCredential .getLastScopes ();
245+ assert scopes != null && scopes .size () == 1 ;
246+ assert overrideScope .equals (scopes .get (0 ));
247+
248+ container .deleteItem (item .id , new PartitionKey (item .mypk )).block ();
249+ } finally {
250+ try {
251+ CosmosAsyncClient cleanupClient = new CosmosClientBuilder ()
252+ .endpoint (TestConfigurations .HOST )
253+ .key (TestConfigurations .MASTER_KEY )
254+ .buildAsyncClient ();
255+ try {
256+ cleanupClient .getDatabase (databaseId ).delete ().block ();
257+ } finally {
258+ safeClose (cleanupClient );
259+ }
260+ } finally {
261+ if (aadClient != null ) {
262+ safeClose (aadClient );
263+ }
264+ setEnv ("AZURE_COSMOS_AAD_SCOPE_OVERRIDE" , "" );
265+ }
266+ }
267+
268+ Thread .sleep (SHUTDOWN_TIMEOUT );
269+ }
270+
271+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
272+ private static void setEnv (String key , String value ) throws Exception {
273+ Map <String , String > env = System .getenv ();
274+ Class <?> cl = env .getClass ();
275+ try {
276+ Field field = cl .getDeclaredField ("m" );
277+ field .setAccessible (true );
278+ Map <String , String > writableEnv = (Map <String , String >) field .get (env );
279+ if (value == null ) {
280+ writableEnv .remove (key );
281+ } else {
282+ writableEnv .put (key , value );
283+ }
284+ } catch (NoSuchFieldException nsfe ) {
285+ Field [] fields = cl .getDeclaredFields ();
286+ for (Field f : fields ) {
287+ if (f .getType ().getName ().equals ("java.util.Map" )) {
288+ f .setAccessible (true );
289+ Map <String , String > map = (Map <String , String >) f .get (env );
290+ if (value == null ) {
291+ map .remove (key );
292+ } else {
293+ map .put (key , value );
294+ }
295+ }
296+ }
297+ }
298+ }
299+
196300 private ItemSample getDocumentDefinition (String itemId , String partitionKeyValue ) {
197301 ItemSample itemSample = new ItemSample ();
198302 itemSample .id = itemId ;
@@ -219,11 +323,16 @@ public void afterMethod() {
219323 public void afterClass () {
220324 }
221325
222- class AadSimpleEmulatorTokenCredential implements TokenCredential {
326+ static class AadSimpleEmulatorTokenCredential implements TokenCredential {
223327 private final String emulatorKeyEncoded ;
224328 private final String AAD_HEADER_COSMOS_EMULATOR = "{\" typ\" :\" JWT\" ,\" alg\" :\" RS256\" ,\" x5t\" :\" CosmosEmulatorPrimaryMaster\" ,\" kid\" :\" CosmosEmulatorPrimaryMaster\" }" ;
225329 private final String AAD_CLAIM_COSMOS_EMULATOR_FORMAT = "{\" aud\" :\" https://localhost.localhost\" ,\" iss\" :\" https://sts.fake-issuer.net/7b1999a1-dfd7-440e-8204-00170979b984\" ,\" iat\" :%d,\" nbf\" :%d,\" exp\" :%d,\" aio\" :\" \" ,\" appid\" :\" localhost\" ,\" appidacr\" :\" 1\" ,\" idp\" :\" https://localhost:8081/\" ,\" oid\" :\" 96313034-4739-43cb-93cd-74193adbe5b6\" ,\" rh\" :\" \" ,\" sub\" :\" localhost\" ,\" tid\" :\" EmulatorFederation\" ,\" uti\" :\" \" ,\" ver\" :\" 1.0\" ,\" scp\" :\" user_impersonation\" ,\" groups\" :[\" 7ce1d003-4cb3-4879-b7c5-74062a35c66e\" ,\" e99ff30c-c229-4c67-ab29-30a6aebc3e58\" ,\" 5549bb62-c77b-4305-bda9-9ec66b85d9e4\" ,\" c44fd685-5c58-452c-aaf7-13ce75184f65\" ,\" be895215-eab5-43b7-9536-9ef8fe130330\" ]}" ;
226330
331+ private static volatile List <String > lastScopes = Collections .emptyList ();
332+
333+ public static List <String > getLastScopes () {
334+ return lastScopes ;
335+ }
227336 public AadSimpleEmulatorTokenCredential (String emulatorKey ) {
228337 if (emulatorKey == null || emulatorKey .isEmpty ()) {
229338 throw new IllegalArgumentException ("emulatorKey" );
@@ -234,6 +343,11 @@ public AadSimpleEmulatorTokenCredential(String emulatorKey) {
234343
235344 @ Override
236345 public Mono <AccessToken > getToken (TokenRequestContext tokenRequestContext ) {
346+ List <String > scopes = tokenRequestContext .getScopes (); // List<String>, not String[]
347+ lastScopes = (scopes != null && !scopes .isEmpty ())
348+ ? new ArrayList <>(scopes )
349+ : Collections .emptyList ();
350+
237351 String aadToken = emulatorKey_based_AAD_String ();
238352 return Mono .just (new AccessToken (aadToken , OffsetDateTime .now ().plusHours (2 )));
239353 }
0 commit comments