22import logging
33import json
44import z3
5+ import itertools
56from dataclasses import asdict
67from pathlib import Path
78from iamspy .iam import AuthorizationDetails , ResourcePolicy , RootOrganization , DataModel , json_serial
@@ -393,33 +394,17 @@ def which_can_i(
393394 """
394395 Used by the CLI to provide the which-can-i call.
395396 """
396- with self as solver :
397- logger .debug ("Identifying model conditions" )
398- model_conditions = get_conditions (self .model_vars )
399- logger .debug (f"Model conditions identified as: { model_conditions } " )
400-
401- query_conditions = self ._generate_query_conditions (
397+ for resource in resources :
398+ if self .can_i (
402399 source = source_arn ,
403400 action = action ,
404- resource = resources ,
401+ resource = resource ,
405402 conditions = conditions ,
406403 condition_file = condition_file ,
407404 strict_conditions = strict_conditions ,
408- model_conditions = model_conditions ,
409- )
410-
411- logger .debug ("Adding generated query conditions" )
412- # solver.set(threads=4)
413- solver .add (* query_conditions )
414- sat = solver .check () == z3 .sat
415- while sat :
416- r = z3 .String ("r" )
417- m = solver .model ()
418- resource = m [r ]
405+ ):
419406 logger .debug (f"Found { resource } as a potential candidate" )
420- yield str (resource )[1 :- 1 ]
421- solver .add (r != resource )
422- sat = solver .check () == z3 .sat
407+ yield resource
423408
424409 def who_can_batch_resource (
425410 self ,
@@ -444,26 +429,17 @@ def who_can_batch_resource(
444429 for identity in gaad .RoleDetailList + gaad .UserDetailList :
445430 sources .add (identity .Arn )
446431
447- solver = self .generate_solver (
448- source = list (sources ),
449- action = action ,
450- resource = resources ,
451- conditions = conditions ,
452- condition_file = condition_file ,
453- strict_conditions = strict_conditions ,
454- )
455-
456- sat = solver .check () == z3 .sat
457- while sat :
458- s = z3 .String ("s" )
459- r = z3 .String ("r" )
460- m = solver .model ()
461- source = str (m [s ])[1 :- 1 ]
462- resource = str (m [r ])[1 :- 1 ]
463- logger .debug (f"Found { source } as a potential candidate for { resource } " )
464- yield self .get_correct_case_principal (source ), resource
465- solver .add (z3 .Not (z3 .And (s == z3 .StringVal (source ), r == z3 .StringVal (resource ))))
466- sat = solver .check () == z3 .sat
432+ for source , resource in itertools .product (sources , resources ):
433+ if self .can_i (
434+ source = source ,
435+ action = action ,
436+ resource = resource ,
437+ conditions = conditions ,
438+ condition_file = condition_file ,
439+ strict_conditions = strict_conditions ,
440+ ):
441+ logger .debug (f"Found { source } as a potential candidate for { resource } " )
442+ yield source , resource
467443
468444 def supports_external (self ) -> List [str ]:
469445 with self as solver :
0 commit comments