use of io.cdap.cdap.proto.security.Permission in project cdap by caskdata.
the class AuthorizationTest method testCrossNSService.
@Test
public void testCrossNSService() throws Exception {
createAuthNamespace();
ApplicationId appId = AUTH_NAMESPACE.app(CrossNsDatasetAccessApp.APP_NAME);
ArtifactId artifact = AUTH_NAMESPACE.artifact(CrossNsDatasetAccessApp.class.getSimpleName(), "1.0-SNAPSHOT");
Map<EntityId, Set<? extends Permission>> neededPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(appId, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET)).put(artifact, EnumSet.of(StandardPermission.CREATE)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
ProgramId programId = appId.service(CrossNsDatasetAccessApp.SERVICE_NAME);
cleanUpEntities.add(programId);
// grant bob namespace access
grantAndAssertSuccess(AUTH_NAMESPACE, BOB, EnumSet.of(StandardPermission.GET));
// grant bob execute on program
grantAndAssertSuccess(programId, BOB, ImmutableSet.of(ApplicationPermission.EXECUTE, StandardPermission.GET));
// new privilege required due to capability validations
grantAndAssertSuccess(artifact, BOB, EnumSet.of(StandardPermission.GET));
ApplicationManager appManager = deployApplication(AUTH_NAMESPACE, CrossNsDatasetAccessApp.class);
// switch to to ALICE
SecurityRequestContext.setUserId(ALICE.getName());
ServiceManager serviceManager = appManager.getServiceManager(CrossNsDatasetAccessApp.SERVICE_NAME);
testSystemDatasetAccessFromService(serviceManager);
testCrossNSDatasetAccessFromService(serviceManager);
}
use of io.cdap.cdap.proto.security.Permission in project cdap by caskdata.
the class AuthorizationTest method testCrossNSDatasetAccessFromService.
private void testCrossNSDatasetAccessFromService(ServiceManager serviceManager) throws Exception {
NamespaceMeta outputDatasetNS = new NamespaceMeta.Builder().setName("outputNS").build();
NamespaceId outputDatasetNSId = outputDatasetNS.getNamespaceId();
DatasetId datasetId = outputDatasetNSId.dataset("store");
Map<EntityId, Set<? extends Permission>> neededPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(outputDatasetNSId, EnumSet.of(StandardPermission.GET, StandardPermission.CREATE, StandardPermission.DELETE)).put(datasetId, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET, StandardPermission.DELETE)).put(outputDatasetNSId.datasetType("keyValueTable"), EnumSet.of(StandardPermission.UPDATE)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
getNamespaceAdmin().create(outputDatasetNS);
addDatasetInstance(datasetId, "keyValueTable");
// switch to BOB
SecurityRequestContext.setUserId(BOB.getName());
Map<String, String> args = ImmutableMap.of(CrossNsDatasetAccessApp.OUTPUT_DATASET_NS, outputDatasetNS.getNamespaceId().getNamespace(), CrossNsDatasetAccessApp.OUTPUT_DATASET_NAME, "store");
// Start the service as BOB
serviceManager.start(args);
// Call to the service would result in failure due to BOB doesn't have permission on the namespace as set in args
URL url = new URL(serviceManager.getServiceURL(5, TimeUnit.SECONDS), "write/data");
HttpResponse response = executeAuthenticated(HttpRequest.put(url));
Assert.assertEquals(500, response.getResponseCode());
// This is a hack that works around the fact that we cannot properly catch exceptions in the service handler.
// TODO: Figure out a way to stop checking error messages.
Assert.assertTrue("Wrong message " + response.getResponseBodyAsString(), response.getResponseBodyAsString().contains("'" + BOB + "' has insufficient privileges"));
serviceManager.stop();
serviceManager.waitForStopped(10, TimeUnit.SECONDS);
SecurityRequestContext.setUserId(ALICE.getName());
assertDatasetIsEmpty(outputDatasetNS.getNamespaceId(), "store");
// Give BOB permission to write to the dataset in another namespace
grantAndAssertSuccess(datasetId, BOB, EnumSet.of(StandardPermission.GET, StandardPermission.UPDATE));
// switch back to BOB to run service again
SecurityRequestContext.setUserId(BOB.getName());
// Write data in another namespace should be successful now
serviceManager.start(args);
for (int i = 0; i < 10; i++) {
url = new URL(serviceManager.getServiceURL(5, TimeUnit.SECONDS), "write/" + i);
response = executeAuthenticated(HttpRequest.put(url));
Assert.assertEquals(200, response.getResponseCode());
}
serviceManager.stop();
serviceManager.waitForStopped(10, TimeUnit.SECONDS);
// switch back to alice and verify the data its fine now to verify.
SecurityRequestContext.setUserId(ALICE.getName());
DataSetManager<KeyValueTable> dataSetManager = getDataset(outputDatasetNS.getNamespaceId().dataset("store"));
KeyValueTable results = dataSetManager.get();
for (int i = 0; i < 10; i++) {
byte[] key = String.valueOf(i).getBytes(Charsets.UTF_8);
Assert.assertArrayEquals(key, results.read(key));
}
getNamespaceAdmin().delete(outputDatasetNS.getNamespaceId());
}
use of io.cdap.cdap.proto.security.Permission in project cdap by caskdata.
the class AuthorizationTest method testScheduleAuth.
@Test
public void testScheduleAuth() throws Exception {
createAuthNamespace();
ApplicationId appId = AUTH_NAMESPACE.app(AppWithSchedule.class.getSimpleName());
Map<EntityId, Set<? extends Permission>> neededPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(appId, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET)).put(AUTH_NAMESPACE.artifact(AppWithSchedule.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset(AppWithSchedule.INPUT_NAME), EnumSet.of(StandardPermission.CREATE, StandardPermission.GET)).put(AUTH_NAMESPACE.dataset(AppWithSchedule.OUTPUT_NAME), EnumSet.of(StandardPermission.CREATE, StandardPermission.GET)).put(AUTH_NAMESPACE.datasetType(ObjectStore.class.getName()), EnumSet.of(StandardPermission.UPDATE)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
ApplicationManager appManager = deployApplication(AUTH_NAMESPACE, AppWithSchedule.class);
String workflowName = AppWithSchedule.SampleWorkflow.class.getSimpleName();
ProgramId workflowID = new ProgramId(AUTH_NAMESPACE.getNamespace(), AppWithSchedule.class.getSimpleName(), ProgramType.WORKFLOW, workflowName);
cleanUpEntities.add(workflowID);
final WorkflowManager workflowManager = appManager.getWorkflowManager(workflowName);
ScheduleManager scheduleManager = workflowManager.getSchedule(AppWithSchedule.EVERY_HOUR_SCHEDULE);
// switch to BOB
SecurityRequestContext.setUserId(BOB.getName());
// try to resume schedule as BOB. It should fail since BOB does not have execute privileges on the programs
try {
scheduleManager.resume();
Assert.fail("Resuming schedule should have failed since BOB does not have EXECUTE on the program");
} catch (UnauthorizedException e) {
// Expected
}
// bob should also not be able see the status of the schedule
try {
scheduleManager.status(HttpURLConnection.HTTP_FORBIDDEN);
Assert.fail("Getting schedule status should have failed since BOB does not have any privilege on the program");
} catch (UnauthorizedException e) {
// Expected
}
// give BOB READ permission in the workflow
grantAndAssertSuccess(workflowID, BOB, EnumSet.of(StandardPermission.GET));
// switch to BOB
SecurityRequestContext.setUserId(BOB.getName());
// try to resume schedule as BOB. It should fail since BOB has READ but not EXECUTE on the workflow
try {
scheduleManager.resume();
Assert.fail("Resuming schedule should have failed since BOB does not have EXECUTE on the program");
} catch (UnauthorizedException e) {
// Expected
}
// but BOB should be able to get schedule status now
Assert.assertEquals(ProgramScheduleStatus.SUSPENDED.name(), scheduleManager.status(HttpURLConnection.HTTP_OK));
// give BOB EXECUTE permission in the workflow
grantAndAssertSuccess(workflowID, BOB, EnumSet.of(ApplicationPermission.EXECUTE));
// switch to BOB
SecurityRequestContext.setUserId(BOB.getName());
// try to resume the schedule. This should pass and workflow should run
scheduleManager.resume();
Assert.assertEquals(ProgramScheduleStatus.SCHEDULED.name(), scheduleManager.status(HttpURLConnection.HTTP_OK));
// suspend the schedule so that it does not start running again
scheduleManager.suspend();
Assert.assertEquals(ProgramScheduleStatus.SUSPENDED.name(), scheduleManager.status(HttpURLConnection.HTTP_OK));
ScheduleId scheduleId = new ScheduleId(appId.getNamespace(), appId.getApplication(), appId.getVersion(), "testSchedule");
ScheduleDetail scheduleDetail = new ScheduleDetail(AUTH_NAMESPACE.getNamespace(), AppWithSchedule.class.getSimpleName(), "1.0-SNAPSHOT", "testSchedule", "Something 2", new ScheduleProgramInfo(SchedulableProgramType.WORKFLOW, workflowName), Collections.<String, String>emptyMap(), new TimeTrigger("*/1 * * * *"), Collections.<Constraint>emptyList(), TimeUnit.HOURS.toMillis(6), null, null);
try {
addSchedule(scheduleId, scheduleDetail);
Assert.fail("Adding schedule should fail since BOB does not have AMDIN on the app");
} catch (UnauthorizedException e) {
// expected
}
// grant BOB EXECUTE on the app
grantAndAssertSuccess(appId, BOB, EnumSet.of(ApplicationPermission.EXECUTE));
// add schedule should succeed
addSchedule(scheduleId, scheduleDetail);
Assert.assertEquals(ProgramScheduleStatus.SUSPENDED.name(), workflowManager.getSchedule(scheduleId.getSchedule()).status(HttpURLConnection.HTTP_OK));
// update schedule should succeed
updateSchedule(scheduleId, scheduleDetail);
Assert.assertEquals(ProgramScheduleStatus.SUSPENDED.name(), workflowManager.getSchedule(scheduleId.getSchedule()).status(HttpURLConnection.HTTP_OK));
// revoke EXECUTE from BOB
getAccessController().revoke(Authorizable.fromEntityId(appId), BOB, EnumSet.of(ApplicationPermission.EXECUTE));
try {
// delete schedule should fail since we revoke the ADMIN privilege from BOB
deleteSchedule(scheduleId);
Assert.fail("Deleting schedule should fail since BOB does not have AMDIN on the app");
} catch (UnauthorizedException e) {
// expected
}
try {
updateSchedule(scheduleId, scheduleDetail);
Assert.fail("Updating schedule should fail since BOB does not have AMDIN on the app");
} catch (UnauthorizedException e) {
// expected
}
// grant BOB EXECUTE on the app again
grantAndAssertSuccess(appId, BOB, EnumSet.of(ApplicationPermission.EXECUTE));
deleteSchedule(scheduleId);
workflowManager.getSchedule(scheduleId.getSchedule()).status(HttpURLConnection.HTTP_NOT_FOUND);
// switch to Alice
SecurityRequestContext.setUserId(ALICE.getName());
}
use of io.cdap.cdap.proto.security.Permission in project cdap by caskdata.
the class AuthorizationTest method deployDummyAppWithImpersonation.
private void deployDummyAppWithImpersonation(NamespaceMeta nsMeta, @Nullable String appOwner) throws Exception {
NamespaceId namespaceId = nsMeta.getNamespaceId();
ApplicationId dummyAppId = namespaceId.app(DummyApp.class.getSimpleName());
ArtifactId artifactId = namespaceId.artifact(DummyApp.class.getSimpleName(), "1.0-SNAPSHOT");
DatasetId datasetId = namespaceId.dataset("whom");
DatasetTypeId datasetTypeId = namespaceId.datasetType(KeyValueTable.class.getName());
String owner = appOwner != null ? appOwner : nsMeta.getConfig().getPrincipal();
KerberosPrincipalId principalId = new KerberosPrincipalId(owner);
Principal principal = new Principal(owner, Principal.PrincipalType.USER);
DatasetId dummyDatasetId = namespaceId.dataset("customDataset");
DatasetTypeId dummyTypeId = namespaceId.datasetType(DummyApp.CustomDummyDataset.class.getName());
DatasetModuleId dummyModuleId = namespaceId.datasetModule((DummyApp.CustomDummyDataset.class.getName()));
// these are the privileges that are needed to deploy the app if no impersonation is involved,
// can check testApps() for more info
Map<EntityId, Set<? extends Permission>> neededPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(dummyAppId, EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(artifactId, EnumSet.of(StandardPermission.CREATE)).put(datasetId, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET)).put(datasetTypeId, EnumSet.of(StandardPermission.UPDATE)).put(principalId, EnumSet.of(AccessPermission.SET_OWNER)).put(dummyDatasetId, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET)).put(dummyTypeId, EnumSet.of(StandardPermission.UPDATE)).put(dummyModuleId, EnumSet.of(StandardPermission.UPDATE)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
// add the artifact
addAppArtifact(artifactId, DummyApp.class);
AppRequest<? extends Config> appRequest = new AppRequest<>(new ArtifactSummary(artifactId.getArtifact(), artifactId.getVersion()), null, appOwner);
try {
deployApplication(dummyAppId, appRequest);
Assert.fail();
} catch (Exception e) {
// expected
}
// revoke privileges on datasets from alice, she does not need these privileges to deploy the app
// the owner will need these privileges to deploy
revokeAndAssertSuccess(datasetId);
revokeAndAssertSuccess(datasetTypeId);
revokeAndAssertSuccess(dummyDatasetId);
revokeAndAssertSuccess(dummyTypeId);
revokeAndAssertSuccess(dummyModuleId);
// grant privileges to owner
grantAndAssertSuccess(namespaceId, principal, EnumSet.of(StandardPermission.GET));
grantAndAssertSuccess(datasetId, principal, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET));
grantAndAssertSuccess(datasetTypeId, principal, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET));
grantAndAssertSuccess(dummyDatasetId, principal, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET));
grantAndAssertSuccess(dummyTypeId, principal, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET));
grantAndAssertSuccess(dummyModuleId, principal, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET));
// this time it should be successful
deployApplication(dummyAppId, appRequest);
// clean up the privilege on the owner principal id
revokeAndAssertSuccess(principalId);
}
use of io.cdap.cdap.proto.security.Permission in project cdap by caskdata.
the class AuthorizationTest method testCrossNSSystemDatasetAccessWithAuthSpark.
private void testCrossNSSystemDatasetAccessWithAuthSpark(SparkManager sparkManager) throws Exception {
addDatasetInstance(NamespaceId.SYSTEM.dataset("table1"), "keyValueTable").create();
addDatasetInstance(NamespaceId.SYSTEM.dataset("table2"), "keyValueTable").create();
NamespaceMeta otherNS = new NamespaceMeta.Builder().setName("otherNS").build();
NamespaceId otherNSId = otherNS.getNamespaceId();
DatasetId otherTableId = otherNSId.dataset("otherTable");
Map<EntityId, Set<? extends Permission>> neededPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(otherNSId, EnumSet.of(StandardPermission.GET, StandardPermission.CREATE, StandardPermission.DELETE)).put(otherTableId, EnumSet.of(StandardPermission.GET, StandardPermission.CREATE, StandardPermission.DELETE)).put(otherNSId.datasetType("keyValueTable"), EnumSet.of(StandardPermission.UPDATE)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
getNamespaceAdmin().create(otherNS);
addDatasetInstance(otherTableId, "keyValueTable").create();
addDummyData(NamespaceId.SYSTEM, "table1");
// give privilege to BOB on all the datasets
grantAndAssertSuccess(NamespaceId.SYSTEM.dataset("table1"), BOB, EnumSet.of(StandardPermission.GET));
grantAndAssertSuccess(NamespaceId.SYSTEM.dataset("table2"), BOB, EnumSet.of(StandardPermission.UPDATE));
grantAndAssertSuccess(otherNS.getNamespaceId().dataset("otherTable"), BOB, ALL_STANDARD_PERMISSIONS);
// Switch to Bob and run the spark program. this will fail because bob is trying to read from a system dataset
SecurityRequestContext.setUserId(BOB.getName());
Map<String, String> args = ImmutableMap.of(TestSparkCrossNSDatasetApp.INPUT_DATASET_NAMESPACE, NamespaceId.SYSTEM.getNamespace(), TestSparkCrossNSDatasetApp.INPUT_DATASET_NAME, "table1", TestSparkCrossNSDatasetApp.OUTPUT_DATASET_NAMESPACE, otherNS.getNamespaceId().getNamespace(), TestSparkCrossNSDatasetApp.OUTPUT_DATASET_NAME, "otherTable");
assertProgramFailure(args, sparkManager);
assertDatasetIsEmpty(otherNS.getNamespaceId(), "otherTable");
// try running spark job with valid input namespace but writing to system namespace this should fail too
args = ImmutableMap.of(TestSparkCrossNSDatasetApp.INPUT_DATASET_NAMESPACE, otherNS.getNamespaceId().getNamespace(), TestSparkCrossNSDatasetApp.INPUT_DATASET_NAME, "otherTable", TestSparkCrossNSDatasetApp.OUTPUT_DATASET_NAMESPACE, NamespaceId.SYSTEM.getNamespace(), TestSparkCrossNSDatasetApp.OUTPUT_DATASET_NAME, "table2");
addDummyData(otherNS.getNamespaceId(), "otherTable");
assertProgramFailure(args, sparkManager);
assertDatasetIsEmpty(NamespaceId.SYSTEM, "table2");
// switch to back to ALICE
SecurityRequestContext.setUserId(ALICE.getName());
// cleanup
deleteDatasetInstance(NamespaceId.SYSTEM.dataset("table1"));
deleteDatasetInstance(NamespaceId.SYSTEM.dataset("table2"));
getNamespaceAdmin().delete(otherNS.getNamespaceId());
}
Aggregations