@@ -1258,6 +1258,30 @@ public void testAllActionsForKey() throws OMException {
12581258 assertThat (resolvedFromRangerAuthorizer ).isEqualTo (expectedResolvedRanger );
12591259 }
12601260
1261+ @ Test
1262+ public void testAllActionsForKeyWithPrefixCondition () throws OMException {
1263+ final String json = "{\n " +
1264+ " \" Statement\" : [{\n " +
1265+ " \" Effect\" : \" Allow\" ,\n " +
1266+ " \" Action\" : \" s3:*\" ,\n " +
1267+ " \" Resource\" : \" arn:aws:s3:::my-bucket/*\" ,\n " +
1268+ " \" Condition\" : {\n " +
1269+ " \" StringLike\" : {\n " +
1270+ " \" s3:prefix\" : [ \" team/folder\" , \" team/folder/*\" ]\n " +
1271+ " }\n " +
1272+ " }\n " +
1273+ " }]\n " +
1274+ "}" ;
1275+
1276+ final Set <OzoneGrant > resolvedFromNativeAuthorizer = resolve (json , VOLUME , NATIVE );
1277+ final Set <OzoneGrant > resolvedFromRangerAuthorizer = resolve (json , VOLUME , RANGER );
1278+
1279+ // Ensure what we got is what we expected - only ListBucket supports s3:prefix and that is a bucket action,
1280+ // not object action
1281+ assertThat (resolvedFromNativeAuthorizer ).isEmpty ();
1282+ assertThat (resolvedFromRangerAuthorizer ).isEmpty ();
1283+ }
1284+
12611285 @ Test
12621286 public void testAllActionsForBucket () throws OMException {
12631287 final String json = "{\n " +
@@ -1287,6 +1311,46 @@ public void testAllActionsForBucket() throws OMException {
12871311 assertThat (resolvedFromRangerAuthorizer ).isEqualTo (expectedResolvedRanger );
12881312 }
12891313
1314+ @ Test
1315+ public void testAllActionsForBucketWithPrefixCondition () throws OMException {
1316+ final String json = "{\n " +
1317+ " \" Statement\" : [{\n " +
1318+ " \" Effect\" : \" Allow\" ,\n " +
1319+ " \" Action\" : \" s3:*\" ,\n " +
1320+ " \" Resource\" : \" arn:aws:s3:::my-bucket\" ,\n " +
1321+ " \" Condition\" : {\n " +
1322+ " \" StringLike\" : {\n " +
1323+ " \" s3:prefix\" : [ \" team/folder\" , \" team/folder/*\" ]\n " +
1324+ " }\n " +
1325+ " }\n " +
1326+ " }]\n " +
1327+ "}" ;
1328+
1329+ final Set <OzoneGrant > resolvedFromNativeAuthorizer = resolve (json , VOLUME , NATIVE );
1330+ final Set <OzoneGrant > resolvedFromRangerAuthorizer = resolve (json , VOLUME , RANGER );
1331+
1332+ // Ensure what we got is what we expected
1333+ final Set <OzoneGrant > expectedResolvedNative = new LinkedHashSet <>();
1334+ // Expected for native: READ, LIST ACLs for bucket (only ListBucket supports s3:prefix); volume READ;
1335+ // prefix "team/folder", "team/folder/" READ
1336+ final Set <IOzoneObj > bucketSet = objSet (bucket ("my-bucket" ));
1337+ final Set <ACLType > bucketAcls = acls (READ , LIST );
1338+ expectedResolvedNative .add (
1339+ new OzoneGrant (objSet (volume (), prefix ("my-bucket" , "team/folder" ), prefix ("my-bucket" , "team/folder/" )),
1340+ acls (READ )));
1341+ expectedResolvedNative .add (new OzoneGrant (bucketSet , bucketAcls ));
1342+ assertThat (resolvedFromNativeAuthorizer ).isEqualTo (expectedResolvedNative );
1343+
1344+ // Expected for Ranger: READ, LIST ACLs for bucket (only ListBucket supports s3:prefix); volume READ,
1345+ // key "team/folder", "team/folder/*" READ
1346+ final Set <OzoneGrant > expectedResolvedRanger = new LinkedHashSet <>();
1347+ expectedResolvedRanger .add (
1348+ new OzoneGrant (objSet (volume (), key ("my-bucket" , "team/folder" ), key ("my-bucket" , "team/folder/*" )),
1349+ acls (READ )));
1350+ expectedResolvedRanger .add (new OzoneGrant (bucketSet , bucketAcls ));
1351+ assertThat (resolvedFromRangerAuthorizer ).isEqualTo (expectedResolvedRanger );
1352+ }
1353+
12901354 @ Test
12911355 public void testMultipleResourcesInSeparateStatements () throws OMException {
12921356 final String json = "{\n " +
@@ -1517,11 +1581,11 @@ public void testIgnoresUnsupportedActionsWhenSupportedActionsAreIncluded() throw
15171581 " \" Effect\" : \" Allow\" ,\n " +
15181582 " \" Action\" : [\n " +
15191583 " \" s3:GetAccelerateConfiguration\" ,\n " + // unsupported action
1520- " \" s3:GetBucketAcl\" ,\n " +
1584+ " \" s3:GetBucketAcl\" ,\n " + // ignored because it doesn't support s3:prefix condition
15211585 " \" s3:GetObject\" ,\n " + // object-level action not applied for bucket
15221586 " \" s3:GetObjectAcl\" ,\n " + // unsupported action
15231587 " \" s3:ListBucket\" ,\n " +
1524- " \" s3:ListBucketMultipartUploads\" \n " +
1588+ " \" s3:ListBucketMultipartUploads\" \n " + // ignored because it doesn't support s3:prefix condition
15251589 " ],\n " +
15261590 " \" Resource\" : \" arn:aws:s3:::bucket1\" ,\n " +
15271591 " \" Condition\" : {\n " +
@@ -1539,16 +1603,16 @@ public void testIgnoresUnsupportedActionsWhenSupportedActionsAreIncluded() throw
15391603 // Ensure what we got is what we expected
15401604 final Set <OzoneGrant > expectedResolvedNative = new LinkedHashSet <>();
15411605
1542- // Expected for native: READ, LIST, READ_ACL bucket acls; volume and prefixes "team/folder", "team/folder/" READ
1606+ // Expected for native: READ, LIST bucket acls; volume and prefixes "team/folder", "team/folder/" READ
15431607 final Set <IOzoneObj > bucketSet = objSet (bucket ("bucket1" ));
1544- final Set <ACLType > bucketAcls = acls (READ , LIST , READ_ACL );
1608+ final Set <ACLType > bucketAcls = acls (READ , LIST );
15451609 expectedResolvedNative .add (new OzoneGrant (bucketSet , bucketAcls ));
15461610 expectedResolvedNative .add (new OzoneGrant (
15471611 objSet (volume (), prefix ("bucket1" , "team/folder" ), prefix ("bucket1" , "team/folder/" )), acls (READ )));
15481612 assertThat (resolvedFromNativeAuthorizer ).isEqualTo (expectedResolvedNative );
15491613
15501614 final Set <OzoneGrant > expectedResolvedRanger = new LinkedHashSet <>();
1551- // Expected for Ranger: READ, LIST, READ_ACL bucket acls; volume and keys "team/folder" and "team/folder/*" READ
1615+ // Expected for Ranger: READ, LIST bucket acls; volume and keys "team/folder" and "team/folder/*" READ
15521616 expectedResolvedRanger .add (new OzoneGrant (bucketSet , bucketAcls ));
15531617 expectedResolvedRanger .add (new OzoneGrant (
15541618 objSet (volume (), key ("bucket1" , "team/folder" ), key ("bucket1" , "team/folder/*" )), acls (READ )));
@@ -1569,17 +1633,37 @@ public void testMultiplePrefixesWithWildcards() throws OMException {
15691633 final Set <OzoneGrant > resolvedFromNativeAuthorizer = resolve (json , VOLUME , NATIVE );
15701634 final Set <OzoneGrant > resolvedFromRangerAuthorizer = resolve (json , VOLUME , RANGER );
15711635
1572- // Ensure what we got is what we expected
1636+ // s3:prefix conditions do not apply to object actions like s3:GetObject.
1637+ assertThat (resolvedFromNativeAuthorizer ).isEmpty ();
1638+ assertThat (resolvedFromRangerAuthorizer ).isEmpty ();
1639+ }
1640+
1641+ @ Test
1642+ public void testListAndGetWithPrefixConditionSkipsObjectAction () throws OMException {
1643+ final String json = "{\n " +
1644+ " \" Statement\" : [{\n " +
1645+ " \" Effect\" : \" Allow\" ,\n " +
1646+ " \" Action\" : [\" s3:ListBucket\" , \" s3:GetObject\" ],\n " +
1647+ " \" Resource\" : [\" arn:aws:s3:::logs\" , \" arn:aws:s3:::logs/*\" ],\n " +
1648+ " \" Condition\" : { \" StringLike\" : { \" s3:prefix\" : \" team/*\" } }\n " +
1649+ " }]\n " +
1650+ "}" ;
1651+
1652+ final Set <OzoneGrant > resolvedFromNativeAuthorizer = resolve (json , VOLUME , NATIVE );
1653+ final Set <OzoneGrant > resolvedFromRangerAuthorizer = resolve (json , VOLUME , RANGER );
1654+
1655+ // Expected for native (GetObject is ignored because s3:prefix is present): READ, LIST bucket acls; volume READ;
1656+ // prefix "log/team" READ
15731657 final Set <OzoneGrant > expectedResolvedNative = new LinkedHashSet <>();
1574- // Expected for native: READ acl on prefix "" (condition prefixes are ignored); bucket READ; volume READ;
1575- final Set <IOzoneObj > readObjectsNative = objSet (prefix ("logs" , "" ), bucket ("logs" ), volume ());
1576- expectedResolvedNative .add (new OzoneGrant (readObjectsNative , acls (READ )));
1658+ expectedResolvedNative .add (new OzoneGrant (objSet (bucket ("logs" )), acls (READ , LIST )));
1659+ expectedResolvedNative .add (new OzoneGrant (objSet (volume (), prefix ("logs" , "team/" )), acls (READ )));
15771660 assertThat (resolvedFromNativeAuthorizer ).isEqualTo (expectedResolvedNative );
15781661
1662+ // Expected for Ranger (GetObject is ignored because s3:prefix is present): READ, LIST bucket acls; volume READ;
1663+ // key "log/team/*" READ
15791664 final Set <OzoneGrant > expectedResolvedRanger = new LinkedHashSet <>();
1580- // Expected for Ranger: READ acl on key "*" (condition prefixes are ignored)
1581- final Set <IOzoneObj > keySet = objSet (key ("logs" , "*" ), bucket ("logs" ), volume ());
1582- expectedResolvedRanger .add (new OzoneGrant (keySet , acls (READ )));
1665+ expectedResolvedRanger .add (new OzoneGrant (objSet (bucket ("logs" )), acls (READ , LIST )));
1666+ expectedResolvedRanger .add (new OzoneGrant (objSet (volume (), key ("logs" , "team/*" )), acls (READ )));
15831667 assertThat (resolvedFromRangerAuthorizer ).isEqualTo (expectedResolvedRanger );
15841668 }
15851669
@@ -1701,6 +1785,35 @@ public void testObjectActionOnAllResources() throws OMException {
17011785 assertThat (resolvedFromRangerAuthorizer ).isEqualTo (expectedResolvedRanger );
17021786 }
17031787
1788+ @ Test
1789+ public void testAllActionsOnAllResourcesWithPrefixCondition () throws OMException {
1790+ final String json = "{\n " +
1791+ " \" Statement\" : [{\n " +
1792+ " \" Effect\" : \" Allow\" ,\n " +
1793+ " \" Action\" : \" s3:*\" ,\n " +
1794+ " \" Resource\" : \" *\" ,\n " +
1795+ " \" Condition\" : {\n " +
1796+ " \" StringLike\" : {\n " +
1797+ " \" s3:prefix\" : [ \" team/folder\" , \" team/folder/*\" ]\n " +
1798+ " }\n " +
1799+ " }\n " +
1800+ " }]\n " +
1801+ "}" ;
1802+
1803+ // Wildcards on bucket are not supported for Native authorizer
1804+ expectBucketWildcardUnsupportedExceptionForNativeAuthorizer (json );
1805+
1806+ final Set <OzoneGrant > resolvedFromRangerAuthorizer = resolve (json , VOLUME , RANGER );
1807+ // Ensure what we got is what we expected
1808+ final Set <OzoneGrant > expectedResolvedRanger = new LinkedHashSet <>();
1809+ // Expected for Ranger: (only ListBucket supports s3:prefix) READ volume; READ, LIST acl on bucket;
1810+ // READ on key "team/folder", "team/folder/*"
1811+ expectedResolvedRanger .add (new OzoneGrant (objSet (bucket ("*" )), acls (READ , LIST )));
1812+ expectedResolvedRanger .add (
1813+ new OzoneGrant (objSet (volume (), key ("*" , "team/folder" ), key ("*" , "team/folder/*" )), acls (READ )));
1814+ assertThat (resolvedFromRangerAuthorizer ).isEqualTo (expectedResolvedRanger );
1815+ }
1816+
17041817 @ Test
17051818 public void testAllActionsOnAllResources () throws OMException {
17061819 final String json = "{\n " +
0 commit comments