HADOOP-14442. Owner support for ranger-wasb integration. Contributed by Varada Hemeswari
This commit is contained in:
parent
bd6a2172e0
commit
89bb8bfe58
@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A {@link FileSystem} for reading and writing files stored on <a
|
||||
@ -1441,12 +1441,14 @@ private void performAuthCheck(Path requestingAccessForPath, WasbAuthorizationOpe
|
||||
requestingAccessForPath = requestingAccessForPath.makeQualified(getUri(), getWorkingDirectory());
|
||||
originalPath = originalPath.makeQualified(getUri(), getWorkingDirectory());
|
||||
|
||||
if (!this.authorizer.authorize(requestingAccessForPath.toString(), accessType.toString())) {
|
||||
String owner = getOwnerForPath(requestingAccessForPath);
|
||||
|
||||
if (!this.authorizer.authorize(requestingAccessForPath.toString(), accessType.toString(), owner)) {
|
||||
throw new WasbAuthorizationException(operation
|
||||
+ " operation for Path : " + originalPath.toString() + " not allowed");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3173,4 +3175,40 @@ private static String encodeKey(String aKey) {
|
||||
// Return to the caller with the randomized key.
|
||||
return randomizedKey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper method to retrieve owner information for a given path.
|
||||
* The method returns empty string in case the file is not found or the metadata does not contain owner information
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public String getOwnerForPath(Path absolutePath) throws IOException {
|
||||
String owner = "";
|
||||
FileMetadata meta = null;
|
||||
String key = pathToKey(absolutePath);
|
||||
try {
|
||||
|
||||
meta = store.retrieveMetadata(key);
|
||||
|
||||
if (meta != null) {
|
||||
owner = meta.getPermissionStatus().getUserName();
|
||||
LOG.debug("Retrieved '{}' as owner for path - {}", owner, absolutePath);
|
||||
} else {
|
||||
// meta will be null if file/folder doen not exist
|
||||
LOG.debug("Cannot find file/folder - '{}'. Returning owner as empty string", absolutePath);
|
||||
}
|
||||
} catch(IOException ex) {
|
||||
|
||||
Throwable innerException = NativeAzureFileSystemHelper.checkForAzureStorageException(ex);
|
||||
boolean isfileNotFoundException = innerException instanceof StorageException
|
||||
&& NativeAzureFileSystemHelper.isFileNotFoundException((StorageException) innerException);
|
||||
|
||||
// should not throw when the exception is related to blob/container/file/folder not found
|
||||
if (!isfileNotFoundException) {
|
||||
String errorMsg = "Could not retrieve owner information for path - " + absolutePath;
|
||||
LOG.error(errorMsg);
|
||||
throw new IOException(errorMsg, ex);
|
||||
}
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +87,12 @@ public class RemoteWasbAuthorizerImpl implements WasbAuthorizerInterface {
|
||||
private static final String DELEGATION_TOKEN_QUERY_PARAM_NAME =
|
||||
"delegation";
|
||||
|
||||
/**
|
||||
* Query parameter name for sending owner of the specific resource {@value}
|
||||
*/
|
||||
private static final String WASB_RESOURCE_OWNER_QUERY_PARAM_NAME =
|
||||
"wasb_resource_owner";
|
||||
|
||||
private WasbRemoteCallHelper remoteCallHelper = null;
|
||||
private String delegationToken;
|
||||
private boolean isSecurityEnabled;
|
||||
@ -119,7 +125,7 @@ public void init(Configuration conf)
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authorize(String wasbAbsolutePath, String accessType)
|
||||
public boolean authorize(String wasbAbsolutePath, String accessType, String resourceOwner)
|
||||
throws WasbAuthorizationException, IOException {
|
||||
|
||||
try {
|
||||
@ -140,6 +146,10 @@ public boolean authorize(String wasbAbsolutePath, String accessType)
|
||||
uriBuilder.addParameter(DELEGATION_TOKEN_QUERY_PARAM_NAME,
|
||||
delegationToken);
|
||||
}
|
||||
if (resourceOwner != null && StringUtils.isNotEmpty(resourceOwner)) {
|
||||
uriBuilder.addParameter(WASB_RESOURCE_OWNER_QUERY_PARAM_NAME,
|
||||
resourceOwner);
|
||||
}
|
||||
|
||||
String responseBody = null;
|
||||
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
|
||||
|
@ -43,10 +43,11 @@ public void init(Configuration conf)
|
||||
|
||||
* @param wasbAbolutePath : Absolute WASB Path used for access.
|
||||
* @param accessType : Type of access
|
||||
* @param owner : owner of the file/folder specified in the wasb path
|
||||
* @return : true - If access allowed false - If access is not allowed.
|
||||
* @throws WasbAuthorizationException - On authorization exceptions
|
||||
* @throws IOException - When not able to reach the authorizer
|
||||
*/
|
||||
boolean authorize(String wasbAbolutePath, String accessType)
|
||||
boolean authorize(String wasbAbolutePath, String accessType, String owner)
|
||||
throws WasbAuthorizationException, IOException;
|
||||
}
|
@ -22,7 +22,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.util.StringUtils;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
|
||||
/**
|
||||
@ -32,8 +34,9 @@
|
||||
public class MockWasbAuthorizerImpl implements WasbAuthorizerInterface {
|
||||
|
||||
private Map<AuthorizationComponent, Boolean> 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<AuthorizationComponent, Boolean>();
|
||||
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<AuthorizationComponent, Boolean> 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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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<Void>() {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user