/**
* 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.falcon.regression.security;
import org.apache.falcon.regression.Entities.FeedMerlin;
import org.apache.falcon.regression.core.bundle.Bundle;
import org.apache.falcon.regression.core.enumsAndConstants.MerlinConstants;
import org.apache.falcon.regression.core.helpers.ColoHelper;
import org.apache.falcon.regression.core.helpers.entity.AbstractEntityHelper;
import org.apache.falcon.regression.core.util.AssertUtil;
import org.apache.falcon.regression.core.util.BundleUtil;
import org.apache.falcon.regression.core.util.HadoopUtil;
import org.apache.falcon.regression.core.util.MatrixUtil;
import org.apache.falcon.regression.core.util.OSUtil;
import org.apache.falcon.regression.testHelper.BaseTestClass;
import org.apache.hadoop.fs.FileSystem;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* Tests ACL of feed with different operations.
*/
@Test(groups = "authorization")
public class FeedAclTest extends BaseTestClass {
private ColoHelper cluster = servers.get(0);
private FileSystem clusterFS = serverFS.get(0);
private String baseTestDir = cleanAndGetTestDir();
private String aggregateWorkflowDir = baseTestDir + "/aggregator";
private String feedInputPath = baseTestDir + "/input" + MINUTE_DATE_PATTERN;
private final AbstractEntityHelper feedHelper = prism.getFeedHelper();
private String feedString;
@BeforeClass(alwaysRun = true)
public void uploadWorkflow() throws Exception {
HadoopUtil.uploadDir(clusterFS, aggregateWorkflowDir, OSUtil.RESOURCES_OOZIE);
}
@BeforeMethod(alwaysRun = true)
public void setup() throws Exception {
Bundle bundle = BundleUtil.readELBundle();
bundles[0] = new Bundle(bundle, cluster);
bundles[0].generateUniqueBundle(this);
bundles[0].setInputFeedDataPath(feedInputPath);
bundles[0].setProcessWorkflow(aggregateWorkflowDir);
bundles[0].setInputFeedACL(MerlinConstants.CURRENT_USER_NAME,
MerlinConstants.CURRENT_USER_GROUP, "*");
feedString = bundles[0].getInputFeedFromBundle();
}
/**
* Test feed read operation by different types of user.
* @param user the user that would attempt operation
* @param op the read operation that would be performed
* @param isAllowed is operation expected to go through
* @throws Exception
*/
@Test(dataProvider = "generateUserReadOpsPermissions")
public void othersReadFeed(final String user, final EntityOp op, final boolean isAllowed)
throws Exception {
bundles[0].submitClusters(prism);
bundles[0].submitFeeds(prism);
final boolean executeRes = op.executeAs(user, feedHelper, feedString);
Assert.assertEquals(executeRes, isAllowed, "Unexpected result user " + user
+ " performing: " + op);
}
@DataProvider(name = "generateUserReadOpsPermissions")
public Object[][] generateUserReadOpsPermissions() {
final EntityOp[] falconReadOps = {EntityOp.status, EntityOp.dependency,
EntityOp.listing, EntityOp.definition, };
final Object[][] allowedCombinations = MatrixUtil.crossProduct(
new String[]{MerlinConstants.FALCON_SUPER_USER_NAME,
MerlinConstants.FALCON_SUPER_USER2_NAME,
MerlinConstants.USER2_NAME, },
falconReadOps,
new Boolean[]{true}
);
final Object[][] notAllowedCombinations = MatrixUtil.crossProduct(
new String[]{MerlinConstants.DIFFERENT_USER_NAME},
falconReadOps,
new Boolean[]{false}
);
return MatrixUtil.append(allowedCombinations, notAllowedCombinations);
}
/**
* Test edit operation on submitted feed by different users.
* @param user the user that would attempt operation
* @param op the edit operation that would be performed
* @param isAllowed is operation expected to go through
* @throws Exception
*/
@Test(dataProvider = "generateUserSubmittedEditOpsPermission")
public void othersEditSubmittedFeed(final String user, final EntityOp op, boolean isAllowed)
throws Exception {
bundles[0].submitClusters(prism);
bundles[0].submitFeeds(prism);
if (op == EntityOp.update) {
feedString = new FeedMerlin(feedString).withProperty("abc", "xyz").toString();
}
final boolean executeRes = op.executeAs(user, feedHelper, feedString);
Assert.assertEquals(executeRes, isAllowed, "Unexpected result user " + user
+ " performing: " + op);
}
@DataProvider(name = "generateUserSubmittedEditOpsPermission")
public Object[][] generateUserSubmittedEditOpsPermission() {
final EntityOp[] falconEditOps = {EntityOp.delete, EntityOp.update};
final Object[][] allowedCombinations = MatrixUtil.crossProduct(
new String[]{MerlinConstants.FALCON_SUPER_USER_NAME,
MerlinConstants.FALCON_SUPER_USER2_NAME,
MerlinConstants.USER2_NAME, },
falconEditOps,
new Boolean[]{true}
);
final Object[][] notAllowedCombinations = MatrixUtil.crossProduct(
new String[]{MerlinConstants.DIFFERENT_USER_NAME},
falconEditOps,
new Boolean[]{false}
);
return MatrixUtil.append(allowedCombinations, notAllowedCombinations);
}
/**
* Test edit operation on scheduled feed by different users.
* @param user the user that would attempt operation
* @param op the edit operation that would be performed
* @param isAllowed is operation expected to go through
* @throws Exception
*/
@Test(dataProvider = "generateUserScheduledEditOpsPermission")
public void othersEditScheduledFeed(final String user, final EntityOp op, boolean isAllowed)
throws Exception {
bundles[0].submitClusters(prism);
bundles[0].submitAndScheduleAllFeeds();
if (op == EntityOp.resume) {
feedHelper.suspend(feedString);
} else if (op == EntityOp.update) {
feedString = new FeedMerlin(feedString).withProperty("abc", "xyz").toString();
}
final boolean executeRes = op.executeAs(user, feedHelper, feedString);
Assert.assertEquals(executeRes, isAllowed, "Unexpected result user " + user
+ " performing: " + op);
}
@DataProvider(name = "generateUserScheduledEditOpsPermission")
public Object[][] generateUserScheduledEditOpsPermission() {
final Object[][] allowedCombinations = MatrixUtil.crossProduct(
new String[]{MerlinConstants.FALCON_SUPER_USER_NAME,
MerlinConstants.FALCON_SUPER_USER2_NAME,
MerlinConstants.USER2_NAME, },
new EntityOp[]{EntityOp.delete, EntityOp.update, EntityOp.suspend, EntityOp.resume, },
new Boolean[]{true, }
);
final Object[][] notAllowedCombinations = MatrixUtil.crossProduct(
new String[]{MerlinConstants.DIFFERENT_USER_NAME, },
new EntityOp[]{EntityOp.delete, EntityOp.update,
EntityOp.suspend, EntityOp.resume, },
new Boolean[]{false, }
);
return MatrixUtil.append(allowedCombinations, notAllowedCombinations);
}
/**
* Test feed acl modification.
* @throws Exception
*/
@Test(dataProvider = "generateAclOwnerAndGroup")
public void feedAclUpdate(final String newOwner, final String newGroup) throws Exception {
bundles[0].submitClusters(prism);
final String oldFeed = bundles[0].getInputFeedFromBundle();
AssertUtil.assertSucceeded(feedHelper.submitAndSchedule(oldFeed));
final FeedMerlin feedMerlin = new FeedMerlin(oldFeed);
feedMerlin.setACL(newOwner, newGroup, "*");
final String newFeed = feedMerlin.toString();
AssertUtil.assertFailed(feedHelper.update(oldFeed, newFeed),
"AuthorizationException: Permission denied");
}
@DataProvider(name = "generateAclOwnerAndGroup")
public Object[][] generateAclOwnerAndGroup() {
return new Object[][]{
//{MerlinConstants.USER2_NAME, MerlinConstants.CURRENT_USER_GROUP},
{MerlinConstants.DIFFERENT_USER_NAME, MerlinConstants.DIFFERENT_USER_GROUP},
};
}
@AfterMethod(alwaysRun = true)
public void tearDown() {
removeTestClassEntities();
}
}