36
36
import reactor .core .publisher .Flux ;
37
37
import reactor .core .publisher .Mono ;
38
38
39
+ import java .lang .reflect .Field ;
39
40
import java .time .OffsetDateTime ;
40
41
import java .time .ZonedDateTime ;
41
42
import java .util .List ;
42
43
import java .util .Properties ;
43
44
import java .util .UUID ;
45
+ import java .util .ArrayList ;
46
+ import java .util .Collections ;
47
+ import java .util .Map ;
44
48
45
49
public class AadAuthorizationTests extends TestSuiteBase {
46
50
private final static Logger log = LoggerFactory .getLogger (AadAuthorizationTests .class );
@@ -193,6 +197,106 @@ public void createAadTokenCredential() throws InterruptedException {
193
197
Thread .sleep (SHUTDOWN_TIMEOUT );
194
198
}
195
199
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
+
196
300
private ItemSample getDocumentDefinition (String itemId , String partitionKeyValue ) {
197
301
ItemSample itemSample = new ItemSample ();
198
302
itemSample .id = itemId ;
@@ -219,11 +323,16 @@ public void afterMethod() {
219
323
public void afterClass () {
220
324
}
221
325
222
- class AadSimpleEmulatorTokenCredential implements TokenCredential {
326
+ static class AadSimpleEmulatorTokenCredential implements TokenCredential {
223
327
private final String emulatorKeyEncoded ;
224
328
private final String AAD_HEADER_COSMOS_EMULATOR = "{\" typ\" :\" JWT\" ,\" alg\" :\" RS256\" ,\" x5t\" :\" CosmosEmulatorPrimaryMaster\" ,\" kid\" :\" CosmosEmulatorPrimaryMaster\" }" ;
225
329
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\" ]}" ;
226
330
331
+ private static volatile List <String > lastScopes = Collections .emptyList ();
332
+
333
+ public static List <String > getLastScopes () {
334
+ return lastScopes ;
335
+ }
227
336
public AadSimpleEmulatorTokenCredential (String emulatorKey ) {
228
337
if (emulatorKey == null || emulatorKey .isEmpty ()) {
229
338
throw new IllegalArgumentException ("emulatorKey" );
@@ -234,6 +343,11 @@ public AadSimpleEmulatorTokenCredential(String emulatorKey) {
234
343
235
344
@ Override
236
345
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
+
237
351
String aadToken = emulatorKey_based_AAD_String ();
238
352
return Mono .just (new AccessToken (aadToken , OffsetDateTime .now ().plusHours (2 )));
239
353
}
0 commit comments