diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java index 0ba47ef4f0..b61baabb4a 100644 --- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java +++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java @@ -200,7 +200,7 @@ public FolderRenamePending(Path redoFile, NativeAzureFileSystem fs) JsonNode oldFolderName = json.get("OldFolderName"); JsonNode newFolderName = json.get("NewFolderName"); if (oldFolderName == null || newFolderName == null) { - this.committed = false; + this.committed = false; } else { this.srcKey = oldFolderName.textValue(); this.dstKey = newFolderName.textValue(); @@ -349,7 +349,7 @@ public String makeRenamePendingFileContents() { return contents; } - + /** * This is an exact copy of org.codehaus.jettison.json.JSONObject.quote * method. @@ -639,7 +639,7 @@ public String getScheme() { return "wasb"; } - + /** *

* A {@link FileSystem} for reading and writing files stored on authRules; + private boolean performOwnerMatch; - // The full qualified URL to the root directory + // The full qualified URL to the root directory private String qualifiedPrefixUrl; public MockWasbAuthorizerImpl(NativeAzureFileSystem fs) { @@ -43,15 +46,22 @@ public MockWasbAuthorizerImpl(NativeAzureFileSystem fs) { @Override public void init(Configuration conf) { + init(conf, false); + } + + /* + authorization matches owner with currentUserShortName while evaluating auth rules + if currentUserShortName is set to a string that is not empty + */ + public void init(Configuration conf, boolean matchOwner) { authRules = new HashMap(); + this.performOwnerMatch = matchOwner; } public void addAuthRule(String wasbAbsolutePath, String accessType, boolean access) { - - wasbAbsolutePath = qualifiedPrefixUrl + wasbAbsolutePath; - - AuthorizationComponent component = wasbAbsolutePath.endsWith("*") + wasbAbsolutePath = qualifiedPrefixUrl + wasbAbsolutePath; + AuthorizationComponent component = wasbAbsolutePath.endsWith("*") ? new AuthorizationComponent("^" + wasbAbsolutePath.replace("*", ".*"), accessType) : new AuthorizationComponent(wasbAbsolutePath, accessType); @@ -59,18 +69,40 @@ public void addAuthRule(String wasbAbsolutePath, } @Override - public boolean authorize(String wasbAbsolutePath, String accessType) + public boolean authorize(String wasbAbsolutePath, String accessType, String owner) throws WasbAuthorizationException { if (wasbAbsolutePath.endsWith(NativeAzureFileSystem.FolderRenamePending.SUFFIX)) { return true; } + String currentUserShortName = ""; + if (this.performOwnerMatch) { + try { + UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); + currentUserShortName = ugi.getShortUserName(); + } catch (Exception e) { + //no op + } + } + + // In case of root("/"), owner match does not happen because owner is returned as empty string. + // we try to force owner match just for purpose of tests to make sure all operations work seemlessly with owner. + if (this.performOwnerMatch + && StringUtils.equalsIgnoreCase(wasbAbsolutePath, qualifiedPrefixUrl + "/")) { + owner = currentUserShortName; + } + + boolean shouldEvaluateOwnerAccess = owner != null && !owner.isEmpty() + && this.performOwnerMatch; + + boolean isOwnerMatch = StringUtils.equalsIgnoreCase(currentUserShortName, owner); + AuthorizationComponent component = new AuthorizationComponent(wasbAbsolutePath, accessType); if (authRules.containsKey(component)) { - return authRules.get(component); + return shouldEvaluateOwnerAccess ? isOwnerMatch && authRules.get(component) : authRules.get(component); } else { // Regex-pattern match if we don't have a straight match for (Map.Entry entry : authRules.entrySet()) { @@ -79,12 +111,16 @@ public boolean authorize(String wasbAbsolutePath, String accessType) String keyAccess = key.getAccessType(); if (keyPath.endsWith("*") && Pattern.matches(keyPath, wasbAbsolutePath) && keyAccess.equals(accessType)) { - return entry.getValue(); + return shouldEvaluateOwnerAccess ? isOwnerMatch && entry.getValue() : entry.getValue(); } } return false; } } + + public void deleteAllAuthRules() { + authRules.clear(); + } } class AuthorizationComponent { diff --git a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorization.java b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorization.java index f7a2eb796f..a0276cb5f5 100644 --- a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorization.java +++ b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorization.java @@ -29,6 +29,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import com.google.common.annotations.VisibleForTesting; import static org.apache.hadoop.fs.azure.AzureNativeFileSystemStore.KEY_USE_SECURE_MODE; @@ -38,6 +39,9 @@ public class TestNativeAzureFileSystemAuthorization extends AbstractWasbTestBase { + @VisibleForTesting + protected MockWasbAuthorizerImpl authorizer; + @Override protected AzureBlobStorageTestAccount createTestAccount() throws Exception { Configuration conf = new Configuration(); @@ -54,9 +58,8 @@ public void beforeMethod() { Assume.assumeTrue("Test valid when both SecureMode and Authorization are enabled .. skipping", useSecureMode && useAuthorization); - Assume.assumeTrue( - useSecureMode && useAuthorization - ); + authorizer = new MockWasbAuthorizerImpl(fs); + authorizer.init(null); } @@ -66,12 +69,12 @@ public void beforeMethod() { /** * Setup up permissions to allow a recursive delete for cleanup purposes. */ - private void allowRecursiveDelete(NativeAzureFileSystem fs, MockWasbAuthorizerImpl authorizer, String path) { + protected void allowRecursiveDelete(NativeAzureFileSystem fs, String path) { int index = path.lastIndexOf('/'); String parent = (index == 0) ? "/" : path.substring(0, index); - authorizer.init(null); + authorizer.deleteAllAuthRules(); authorizer.addAuthRule(parent, WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule((path.endsWith("*") ? path : path+"*"), WasbAuthorizationOperations.WRITE.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -80,7 +83,7 @@ private void allowRecursiveDelete(NativeAzureFileSystem fs, MockWasbAuthorizerIm /** * Setup the expected exception class, and exception message that the test is supposed to fail with */ - private void setExpectedFailureMessage(String operation, Path path) { + protected void setExpectedFailureMessage(String operation, Path path) { expectedEx.expect(WasbAuthorizationException.class); expectedEx.expectMessage(String.format("%s operation for Path : %s not allowed", operation, path.makeQualified(fs.getUri(), fs.getWorkingDirectory()))); @@ -98,8 +101,6 @@ public void testCreateAccessWithoutCreateIntermediateFoldersCheckPositive() thro Path parentDir = new Path("/"); Path testPath = new Path(parentDir, "test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -126,8 +127,6 @@ public void testCreateAccessWithCreateIntermediateFoldersCheckPositive() throws Path parentDir = new Path("/testCreateAccessCheckPositive/1/2/3"); Path testPath = new Path(parentDir, "test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -137,7 +136,7 @@ public void testCreateAccessWithCreateIntermediateFoldersCheckPositive() throws ContractTestUtils.assertPathExists(fs, "testPath was not created", testPath); } finally { - allowRecursiveDelete(fs, authorizer, "/testCreateAccessCheckPositive"); + allowRecursiveDelete(fs, "/testCreateAccessCheckPositive"); fs.delete(new Path("/testCreateAccessCheckPositive"), true); } } @@ -156,8 +155,6 @@ public void testCreateAccessWithOverwriteCheckNegative() throws Throwable { setExpectedFailureMessage("create", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -186,8 +183,6 @@ public void testCreateAccessWithOverwriteCheckPositive() throws Throwable { Path parentDir = new Path("/"); Path testPath = new Path(parentDir, "test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.WRITE.toString(), true); @@ -219,8 +214,6 @@ public void testCreateAccessCheckNegative() throws Throwable { setExpectedFailureMessage("create", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), false); fs.updateWasbAuthorizer(authorizer); @@ -229,7 +222,7 @@ public void testCreateAccessCheckNegative() throws Throwable { } finally { /* Provide permissions to cleanup in case the file got created */ - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -245,8 +238,6 @@ public void testListAccessCheckPositive() throws Throwable { Path intermediateFolders = new Path(parentDir, "1/2/3/"); Path testPath = new Path(intermediateFolders, "test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -256,7 +247,7 @@ public void testListAccessCheckPositive() throws Throwable { fs.listStatus(testPath); } finally { - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -274,8 +265,6 @@ public void testListAccessCheckNegative() throws Throwable { setExpectedFailureMessage("liststatus", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), false); fs.updateWasbAuthorizer(authorizer); @@ -285,7 +274,7 @@ public void testListAccessCheckNegative() throws Throwable { fs.listStatus(testPath); } finally { - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -301,8 +290,6 @@ public void testRenameAccessCheckPositive() throws Throwable { Path srcPath = new Path(parentDir, "test1.dat"); Path dstPath = new Path(parentDir, "test2.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); /* to create parentDir */ authorizer.addAuthRule(parentDir.toString(), WasbAuthorizationOperations.WRITE.toString(), true); /* for rename */ authorizer.addAuthRule(srcPath.toString(), WasbAuthorizationOperations.READ.toString(), true); /* for exists */ @@ -317,7 +304,7 @@ public void testRenameAccessCheckPositive() throws Throwable { ContractTestUtils.assertPathDoesNotExist(fs, "sourcePath exists after rename!", srcPath); } finally { - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -335,8 +322,6 @@ public void testRenameAccessCheckNegative() throws Throwable { setExpectedFailureMessage("rename", srcPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); /* to create parent dir */ authorizer.addAuthRule(parentDir.toString(), WasbAuthorizationOperations.WRITE.toString(), false); authorizer.addAuthRule(srcPath.toString(), WasbAuthorizationOperations.READ.toString(), true); @@ -351,7 +336,7 @@ public void testRenameAccessCheckNegative() throws Throwable { } finally { ContractTestUtils.assertPathExists(fs, "sourcePath does not exist after rename failure!", srcPath); - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -370,8 +355,6 @@ public void testRenameAccessCheckNegativeOnDstFolder() throws Throwable { setExpectedFailureMessage("rename", dstPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); /* to create parent dir */ authorizer.addAuthRule(parentSrcDir.toString(), WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(parentDstDir.toString(), WasbAuthorizationOperations.WRITE.toString(), false); @@ -386,7 +369,7 @@ public void testRenameAccessCheckNegativeOnDstFolder() throws Throwable { ContractTestUtils.assertPathDoesNotExist(fs, "destPath does not exist", dstPath); } finally { ContractTestUtils.assertPathExists(fs, "sourcePath does not exist after rename !", srcPath); - allowRecursiveDelete(fs, authorizer, parentSrcDir.toString()); + allowRecursiveDelete(fs, parentSrcDir.toString()); fs.delete(parentSrcDir, true); } } @@ -403,8 +386,6 @@ public void testRenameAccessCheckPositiveOnDstFolder() throws Throwable { Path parentDstDir = new Path("/testRenameAccessCheckPositiveDst"); Path dstPath = new Path(parentDstDir, "test2.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); /* to create parent dirs */ authorizer.addAuthRule(parentSrcDir.toString(), WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(parentDstDir.toString(), WasbAuthorizationOperations.WRITE.toString(), true); @@ -420,10 +401,10 @@ public void testRenameAccessCheckPositiveOnDstFolder() throws Throwable { ContractTestUtils.assertPathDoesNotExist(fs, "sourcePath does not exist", srcPath); ContractTestUtils.assertPathExists(fs, "destPath does not exist", dstPath); } finally { - allowRecursiveDelete(fs, authorizer, parentSrcDir.toString()); + allowRecursiveDelete(fs, parentSrcDir.toString()); fs.delete(parentSrcDir, true); - allowRecursiveDelete(fs, authorizer, parentDstDir.toString()); + allowRecursiveDelete(fs, parentDstDir.toString()); fs.delete(parentDstDir, true); } } @@ -438,8 +419,6 @@ public void testReadAccessCheckPositive() throws Throwable { Path parentDir = new Path("/testReadAccessCheckPositive"); Path testPath = new Path(parentDir, "test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -463,7 +442,7 @@ public void testReadAccessCheckPositive() throws Throwable { if(inputStream != null) { inputStream.close(); } - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -481,8 +460,6 @@ public void testReadAccessCheckNegative() throws Throwable { setExpectedFailureMessage("read", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), false); fs.updateWasbAuthorizer(authorizer); @@ -505,7 +482,7 @@ public void testReadAccessCheckNegative() throws Throwable { if (inputStream != null) { inputStream.close(); } - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -520,8 +497,6 @@ public void testFileDeleteAccessCheckPositive() throws Throwable { Path parentDir = new Path("/"); Path testPath = new Path(parentDir, "test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -547,8 +522,6 @@ public void testFileDeleteAccessCheckNegative() throws Throwable { setExpectedFailureMessage("delete", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -558,7 +531,7 @@ public void testFileDeleteAccessCheckNegative() throws Throwable { /* Remove permissions for delete to force failure */ - authorizer.init(null); + authorizer.deleteAllAuthRules(); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), false); fs.updateWasbAuthorizer(authorizer); @@ -566,7 +539,7 @@ public void testFileDeleteAccessCheckNegative() throws Throwable { } finally { /* Restore permissions to force a successful delete */ - authorizer.init(null); + authorizer.deleteAllAuthRules(); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -587,8 +560,6 @@ public void testFileDeleteAccessWithIntermediateFoldersCheckPositive() throws Th Path parentDir = new Path("/testDeleteIntermediateFolder"); Path testPath = new Path(parentDir, "1/2/test.dat"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); // for create and delete authorizer.addAuthRule("/testDeleteIntermediateFolder*", WasbAuthorizationOperations.WRITE.toString(), true); // for recursive delete @@ -602,7 +573,7 @@ public void testFileDeleteAccessWithIntermediateFoldersCheckPositive() throws Th ContractTestUtils.assertPathDoesNotExist(fs, "testPath exists after deletion!", parentDir); } finally { - allowRecursiveDelete(fs, authorizer, parentDir.toString()); + allowRecursiveDelete(fs, parentDir.toString()); fs.delete(parentDir, true); } } @@ -616,8 +587,6 @@ public void testGetFileStatusPositive() throws Throwable { Path testPath = new Path("/"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -635,8 +604,6 @@ public void testGetFileStatusNegative() throws Throwable { setExpectedFailureMessage("getFileStatus", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.READ.toString(), false); fs.updateWasbAuthorizer(authorizer); @@ -652,8 +619,6 @@ public void testMkdirsCheckPositive() throws Throwable { Path testPath = new Path("/testMkdirsAccessCheckPositive/1/2/3"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -663,7 +628,7 @@ public void testMkdirsCheckPositive() throws Throwable { ContractTestUtils.assertIsDirectory(fs, testPath); } finally { - allowRecursiveDelete(fs, authorizer, "/testMkdirsAccessCheckPositive"); + allowRecursiveDelete(fs, "/testMkdirsAccessCheckPositive"); fs.delete(new Path("/testMkdirsAccessCheckPositive"), true); } } @@ -679,8 +644,6 @@ public void testMkdirsCheckNegative() throws Throwable { setExpectedFailureMessage("mkdirs", testPath); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), false); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); @@ -690,12 +653,11 @@ public void testMkdirsCheckNegative() throws Throwable { ContractTestUtils.assertPathDoesNotExist(fs, "testPath was not created", testPath); } finally { - allowRecursiveDelete(fs, authorizer, "/testMkdirsAccessCheckNegative"); + allowRecursiveDelete(fs, "/testMkdirsAccessCheckNegative"); fs.delete(new Path("/testMkdirsAccessCheckNegative"), true); } } - /** * Positive test triple slash format (wasb:///) access check * @throws Throwable @@ -705,8 +667,6 @@ public void testListStatusWithTripleSlashCheckPositive() throws Throwable { Path testPath = new Path("/"); - MockWasbAuthorizerImpl authorizer = new MockWasbAuthorizerImpl(fs); - authorizer.init(null); authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); fs.updateWasbAuthorizer(authorizer); diff --git a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorizationWithOwner.java b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorizationWithOwner.java new file mode 100644 index 0000000000..3329e6763f --- /dev/null +++ b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/TestNativeAzureFileSystemAuthorizationWithOwner.java @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.fs.azure; + +import org.apache.hadoop.fs.contract.ContractTestUtils; +import org.apache.hadoop.security.UserGroupInformation; +import java.security.PrivilegedExceptionAction; + +import org.apache.hadoop.fs.Path; +import org.junit.Test; +import org.junit.Before; +import static org.junit.Assert.assertEquals; + +/** + * Test class that runs wasb authorization tests with owner check enabled. + */ +public class TestNativeAzureFileSystemAuthorizationWithOwner + extends TestNativeAzureFileSystemAuthorization { + + @Before + public void beforeMethod() { + super.beforeMethod(); + authorizer.init(null, true); + } + + /** + * Test case when owner matches current user + */ + @Test + public void testOwnerPermissionPositive() throws Throwable { + + Path parentDir = new Path("/testOwnerPermissionPositive"); + Path testPath = new Path(parentDir, "test.data"); + + authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); + authorizer.addAuthRule(testPath.toString(), WasbAuthorizationOperations.READ.toString(), true); + authorizer.addAuthRule(parentDir.toString(), WasbAuthorizationOperations.WRITE.toString(), true); + // additional rule used for assertPathExists + authorizer.addAuthRule(parentDir.toString(), WasbAuthorizationOperations.READ.toString(), true); + fs.updateWasbAuthorizer(authorizer); + + try { + // creates parentDir with owner as current user + fs.mkdirs(parentDir); + ContractTestUtils.assertPathExists(fs, "parentDir does not exist", parentDir); + + fs.create(testPath); + fs.getFileStatus(testPath); + ContractTestUtils.assertPathExists(fs, "testPath does not exist", testPath); + + } finally { + allowRecursiveDelete(fs, parentDir.toString()); + fs.delete(parentDir, true); + } + } + + /** + * Negative test case for owner does not match current user + */ + @Test + public void testOwnerPermissionNegative() throws Throwable { + expectedEx.expect(WasbAuthorizationException.class); + + Path parentDir = new Path("/testOwnerPermissionNegative"); + Path childDir = new Path(parentDir, "childDir"); + + setExpectedFailureMessage("mkdirs", childDir); + + authorizer.addAuthRule("/", WasbAuthorizationOperations.WRITE.toString(), true); + authorizer.addAuthRule(parentDir.toString(), WasbAuthorizationOperations.WRITE.toString(), true); + + fs.updateWasbAuthorizer(authorizer); + + try{ + fs.mkdirs(parentDir); + UserGroupInformation ugiSuperUser = UserGroupInformation.createUserForTesting( + "testuser", new String[] {}); + + ugiSuperUser.doAs(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + fs.mkdirs(childDir); + return null; + } + }); + + } finally { + allowRecursiveDelete(fs, parentDir.toString()); + fs.delete(parentDir, true); + } + } + + /** + * Test to verify that retrieving owner information does not + * throw when file/folder does not exist + */ + @Test + public void testRetrievingOwnerDoesNotFailWhenFileDoesNotExist() throws Throwable { + + Path testdirectory = new Path("/testDirectory123454565"); + + String owner = fs.getOwnerForPath(testdirectory); + assertEquals("", owner); + } +} +