use of co.cask.cdap.proto.id.ProgramId in project cdap by caskdata.
the class AuthorizationTest method testPrograms.
@Test
public void testPrograms() throws Exception {
createAuthNamespace();
grantAndAssertSuccess(AUTH_NAMESPACE.app(DummyApp.class.getSimpleName()), ALICE, EnumSet.of(Action.ADMIN));
ApplicationId dummyAppId = AUTH_NAMESPACE.app(DummyApp.class.getSimpleName());
final ProgramId serviceId = dummyAppId.service(DummyApp.Greeting.SERVICE_NAME);
Map<EntityId, Set<Action>> neededPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(dummyAppId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.artifact(DummyApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset("whom"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.stream("who"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetType(KeyValueTable.class.getName()), EnumSet.of(Action.ADMIN)).put(serviceId, EnumSet.of(Action.EXECUTE, Action.ADMIN)).put(AUTH_NAMESPACE.dataset("customDataset"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetType(DummyApp.CustomDummyDataset.class.getName()), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetModule(DummyApp.CustomDummyDataset.class.getName()), EnumSet.of(Action.ADMIN)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
final ApplicationManager dummyAppManager = deployApplication(AUTH_NAMESPACE, DummyApp.class);
// alice should be able to start and stop programs in the app she deployed since she has execute privilege
dummyAppManager.startProgram(Id.Service.fromEntityId(serviceId));
ServiceManager greetingService = dummyAppManager.getServiceManager(serviceId.getProgram());
greetingService.waitForRun(ProgramRunStatus.RUNNING, 10, TimeUnit.SECONDS);
// alice should be able to set instances for the program
greetingService.setInstances(2);
Assert.assertEquals(2, greetingService.getProvisionedInstances());
// alice should also be able to save runtime arguments for all future runs of the program
Map<String, String> args = ImmutableMap.of("key", "value");
greetingService.setRuntimeArgs(args);
// Alice should be able to get runtime arguments as she has ADMIN on it
Assert.assertEquals(args, greetingService.getRuntimeArgs());
dummyAppManager.stopProgram(Id.Service.fromEntityId(serviceId));
greetingService.waitForRun(ProgramRunStatus.KILLED, 10, TimeUnit.SECONDS);
// Bob should not be able to start programs in dummy app because he does not have privileges on it
SecurityRequestContext.setUserId(BOB.getName());
try {
dummyAppManager.startProgram(Id.Service.fromEntityId(serviceId));
Assert.fail("Bob should not be able to start the service because he does not have execute privileges on it.");
} catch (RuntimeException expected) {
// noinspection ThrowableResultOfMethodCallIgnored
Assert.assertTrue(Throwables.getRootCause(expected) instanceof UnauthorizedException);
}
try {
dummyAppManager.getInfo();
Assert.fail("Bob should not be able to read the app info with out privileges");
} catch (Exception expected) {
// expected
}
// setting instances should fail because Bob does not have admin privileges on the program
try {
greetingService.setInstances(3);
Assert.fail("Setting instances should have failed because bob does not have admin privileges on the service.");
} catch (RuntimeException expected) {
// noinspection ThrowableResultOfMethodCallIgnored
Assert.assertTrue(Throwables.getRootCause(expected) instanceof UnauthorizedException);
}
try {
greetingService.setRuntimeArgs(args);
Assert.fail("Setting runtime arguments should have failed because bob does not have admin privileges on the " + "service");
} catch (UnauthorizedException expected) {
// expected
}
try {
greetingService.getRuntimeArgs();
Assert.fail("Getting runtime arguments should have failed because bob does not have one of READ, WRITE, ADMIN " + "privileges on the service");
} catch (UnauthorizedException expected) {
// expected
}
SecurityRequestContext.setUserId(ALICE.getName());
dummyAppManager.delete();
}
use of co.cask.cdap.proto.id.ProgramId in project cdap by caskdata.
the class AuthorizationTest method testAddDropPartitions.
@Test
public void testAddDropPartitions() throws Exception {
createAuthNamespace();
ApplicationId appId = AUTH_NAMESPACE.app(PartitionTestApp.class.getSimpleName());
DatasetId datasetId = AUTH_NAMESPACE.dataset(PartitionTestApp.PFS_NAME);
Map<EntityId, Set<Action>> neededPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(appId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.artifact(PartitionTestApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(Action.ADMIN)).put(datasetId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetType(PartitionedFileSet.class.getName()), EnumSet.of(Action.ADMIN)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
ProgramId programId = appId.program(ProgramType.SERVICE, PartitionTestApp.PFS_SERVICE_NAME);
grantAndAssertSuccess(programId, BOB, EnumSet.of(Action.EXECUTE));
cleanUpEntities.add(programId);
grantAndAssertSuccess(datasetId, BOB, EnumSet.of(Action.READ));
cleanUpEntities.add(datasetId);
ApplicationManager appMgr = deployApplication(AUTH_NAMESPACE, PartitionTestApp.class);
SecurityRequestContext.setUserId(BOB.getName());
String partition = "p1";
String subPartition = "1";
String text = "some random text for pfs";
ServiceManager pfsService = appMgr.getServiceManager(PartitionTestApp.PFS_SERVICE_NAME);
pfsService.start();
pfsService.waitForRun(ProgramRunStatus.RUNNING, 1, TimeUnit.MINUTES);
URL pfsURL = pfsService.getServiceURL();
String apiPath = String.format("partitions/%s/subpartitions/%s", partition, subPartition);
URL url = new URL(pfsURL, apiPath);
HttpRequest request;
HttpResponse response;
try {
request = HttpRequest.post(url).withBody(text).build();
response = HttpRequests.execute(request);
// should fail because bob does not have write privileges on the dataset
Assert.assertEquals(500, response.getResponseCode());
} finally {
pfsService.stop();
pfsService.waitForRun(ProgramRunStatus.KILLED, 1, TimeUnit.MINUTES);
}
// grant read and write on dataset and restart
grantAndAssertSuccess(datasetId, BOB, EnumSet.of(Action.WRITE, Action.READ));
pfsService.start();
pfsService.waitForRun(ProgramRunStatus.RUNNING, 1, TimeUnit.MINUTES);
pfsURL = pfsService.getServiceURL();
url = new URL(pfsURL, apiPath);
try {
request = HttpRequest.post(url).withBody(text).build();
response = HttpRequests.execute(request);
// should succeed now because bob was granted write privileges on the dataset
Assert.assertEquals(200, response.getResponseCode());
// make sure that the partition was added
request = HttpRequest.get(url).build();
response = HttpRequests.execute(request);
Assert.assertEquals(200, response.getResponseCode());
Assert.assertEquals(text, response.getResponseBodyAsString());
// drop the partition
request = HttpRequest.delete(url).build();
response = HttpRequests.execute(request);
Assert.assertEquals(200, response.getResponseCode());
} finally {
pfsService.stop();
pfsService.waitForRuns(ProgramRunStatus.KILLED, 2, 1, TimeUnit.MINUTES);
SecurityRequestContext.setUserId(ALICE.getName());
}
}
use of co.cask.cdap.proto.id.ProgramId in project cdap by caskdata.
the class AuthorizationTest method testApps.
@Test
@Category(SlowTests.class)
public void testApps() throws Exception {
try {
deployApplication(NamespaceId.DEFAULT, DummyApp.class);
Assert.fail("App deployment should fail because alice does not have ADMIN privilege on the application");
} catch (UnauthorizedException e) {
// Expected
}
createAuthNamespace();
Authorizer authorizer = getAuthorizer();
ApplicationId dummyAppId = AUTH_NAMESPACE.app(DummyApp.class.getSimpleName());
Map<EntityId, Set<Action>> neededPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(dummyAppId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.artifact(DummyApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset("whom"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.stream("who"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset("customDataset"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetType(KeyValueTable.class.getName()), EnumSet.of(Action.ADMIN)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
// alice will not be able to deploy the app since she does not have privilege on the implicit dataset module
try {
deployApplication(AUTH_NAMESPACE, DummyApp.class);
Assert.fail();
} catch (UnauthorizedException e) {
// expected
}
// grant alice the required implicit type and module
grantAndAssertSuccess(AUTH_NAMESPACE.datasetType(DummyApp.CustomDummyDataset.class.getName()), ALICE, EnumSet.of(Action.ADMIN));
cleanUpEntities.add(AUTH_NAMESPACE.datasetType(DummyApp.CustomDummyDataset.class.getName()));
grantAndAssertSuccess(AUTH_NAMESPACE.datasetModule(DummyApp.CustomDummyDataset.class.getName()), ALICE, EnumSet.of(Action.ADMIN));
cleanUpEntities.add(AUTH_NAMESPACE.datasetModule(DummyApp.CustomDummyDataset.class.getName()));
// this time it should be successful
ApplicationManager appManager = deployApplication(AUTH_NAMESPACE, DummyApp.class);
// Bob should not have any privileges on Alice's app
Assert.assertTrue("Bob should not have any privileges on alice's app", authorizer.listPrivileges(BOB).isEmpty());
// update should succeed because alice has admin privileges on the app
appManager.update(new AppRequest(new ArtifactSummary(DummyApp.class.getSimpleName(), "1.0-SNAPSHOT")));
// Update should fail for Bob
SecurityRequestContext.setUserId(BOB.getName());
try {
appManager.update(new AppRequest(new ArtifactSummary(DummyApp.class.getSimpleName(), "1.0-SNAPSHOT")));
Assert.fail("App update should have failed because Bob does not have admin privileges on the app.");
} catch (UnauthorizedException expected) {
// expected
}
// grant READ and WRITE to Bob
grantAndAssertSuccess(dummyAppId, BOB, ImmutableSet.of(Action.READ, Action.WRITE));
// delete should fail
try {
appManager.delete();
} catch (UnauthorizedException expected) {
// expected
}
// grant ADMIN to Bob. Now delete should succeed
grantAndAssertSuccess(dummyAppId, BOB, ImmutableSet.of(Action.ADMIN));
// deletion should succeed since BOB has privileges on the app
appManager.delete();
// Should still have the privilege for the app since we no longer revoke privileges after deletion of an entity
Assert.assertTrue(!getAuthorizer().isVisible(Collections.singleton(dummyAppId), BOB).isEmpty());
// bob should still have privileges granted to him
Assert.assertEquals(3, authorizer.listPrivileges(BOB).size());
// switch back to Alice
SecurityRequestContext.setUserId(ALICE.getName());
// Deploy a couple of apps in the namespace
// Deploy dummy app should be successful since we already pre-grant the required privileges
deployApplication(AUTH_NAMESPACE, DummyApp.class);
final ApplicationId appId = AUTH_NAMESPACE.app(AllProgramsApp.NAME);
Map<EntityId, Set<Action>> anotherAppNeededPrivilege = ImmutableMap.<EntityId, Set<Action>>builder().put(appId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.artifact(AllProgramsApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME2), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME3), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DS_WITH_SCHEMA_NAME), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.stream(AllProgramsApp.STREAM_NAME), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetType(ObjectMappedTable.class.getName()), EnumSet.of(Action.ADMIN)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, anotherAppNeededPrivilege);
Map<EntityId, Set<Action>> bobDatasetPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME2), EnumSet.of(Action.ADMIN)).build();
Map<EntityId, Set<Action>> bobProgramPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(appId.program(ProgramType.FLOW, AllProgramsApp.NoOpFlow.NAME), EnumSet.of(Action.EXECUTE)).put(appId.program(ProgramType.SERVICE, AllProgramsApp.NoOpService.NAME), EnumSet.of(Action.EXECUTE)).put(appId.program(ProgramType.WORKER, AllProgramsApp.NoOpWorker.NAME), EnumSet.of(Action.EXECUTE)).build();
setUpPrivilegeAndRegisterForDeletion(BOB, bobDatasetPrivileges);
setUpPrivilegeAndRegisterForDeletion(BOB, bobProgramPrivileges);
deployApplication(AUTH_NAMESPACE, AllProgramsApp.class);
// Switch to BOB since he does not have any privilege
SecurityRequestContext.setUserId(BOB.getName());
// deleting all apps should fail because bob does not have admin privileges on the apps and the namespace
try {
deleteAllApplications(AUTH_NAMESPACE);
Assert.fail("Deleting all applications in the namespace should have failed because bob does not have ADMIN " + "privilege on the workflow app.");
} catch (UnauthorizedException expected) {
// expected
}
ApplicationDetail applicationDetail = getAppDetail(appId);
Assert.assertEquals(bobDatasetPrivileges.keySet(), Sets.<EntityId>newHashSet(Iterables.transform(applicationDetail.getDatasets(), new Function<DatasetDetail, DatasetId>() {
@Override
public DatasetId apply(DatasetDetail input) {
return appId.getNamespaceId().dataset(input.getName());
}
})));
Assert.assertEquals(bobProgramPrivileges.keySet(), Sets.<EntityId>newHashSet(Iterables.transform(applicationDetail.getPrograms(), new Function<ProgramRecord, ProgramId>() {
@Override
public ProgramId apply(ProgramRecord input) {
return appId.program(input.getType(), input.getName());
}
})));
Assert.assertEquals(Collections.emptyList(), applicationDetail.getStreams());
// Switch to ALICE, deletion should be successful since ALICE has ADMIN privileges
SecurityRequestContext.setUserId(ALICE.getName());
deleteAllApplications(AUTH_NAMESPACE);
}
use of co.cask.cdap.proto.id.ProgramId 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<Action>> neededPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(appId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.artifact(AppWithSchedule.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AppWithSchedule.INPUT_NAME), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.dataset(AppWithSchedule.OUTPUT_NAME), EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.datasetType(ObjectStore.class.getName()), EnumSet.of(Action.ADMIN)).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(Action.READ));
// 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(Action.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);
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 ADMIN on the app
grantAndAssertSuccess(appId, BOB, EnumSet.of(Action.ADMIN));
// 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 ADMIN from BOB
getAuthorizer().revoke(Authorizable.fromEntityId(appId), BOB, EnumSet.of(Action.ADMIN));
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 ADMIN on the app again
grantAndAssertSuccess(appId, BOB, EnumSet.of(Action.ADMIN));
deleteSchedule(scheduleId);
workflowManager.getSchedule(scheduleId.getSchedule()).status(HttpURLConnection.HTTP_NOT_FOUND);
// switch to Alice
SecurityRequestContext.setUserId(ALICE.getName());
}
use of co.cask.cdap.proto.id.ProgramId in project cdap by caskdata.
the class AuthorizationTest method testCrossNSFlowlet.
@Test
public void testCrossNSFlowlet() throws Exception {
createAuthNamespace();
ApplicationId appId = AUTH_NAMESPACE.app(CrossNsDatasetAccessApp.APP_NAME);
StreamId streamId = AUTH_NAMESPACE.stream(CrossNsDatasetAccessApp.STREAM_NAME);
Map<EntityId, Set<Action>> neededPrivileges = ImmutableMap.<EntityId, Set<Action>>builder().put(appId, EnumSet.of(Action.ADMIN)).put(AUTH_NAMESPACE.artifact(CrossNsDatasetAccessApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(Action.ADMIN)).put(streamId, EnumSet.of(Action.ADMIN)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, neededPrivileges);
ProgramId programId = appId.flow(CrossNsDatasetAccessApp.FLOW_NAME);
cleanUpEntities.add(programId);
// grant bob execute on program and READ/WRITE on stream
grantAndAssertSuccess(programId, BOB, EnumSet.of(Action.EXECUTE));
grantAndAssertSuccess(streamId, BOB, EnumSet.of(Action.WRITE, Action.READ));
ApplicationManager appManager = deployApplication(AUTH_NAMESPACE, CrossNsDatasetAccessApp.class);
// switch to BOB
SecurityRequestContext.setUserId(BOB.getName());
// Send data to stream as BOB this ensures that BOB can write to a stream in auth namespace
StreamManager streamManager = getStreamManager(AUTH_NAMESPACE.stream(CrossNsDatasetAccessApp.STREAM_NAME));
for (int i = 0; i < 10; i++) {
streamManager.send(String.valueOf(i).getBytes());
}
// switch to back to ALICE
SecurityRequestContext.setUserId(ALICE.getName());
final FlowManager flowManager = appManager.getFlowManager(CrossNsDatasetAccessApp.FLOW_NAME);
testSystemDatasetAccessFromFlowlet(flowManager);
testCrossNSDatasetAccessFromFlowlet(flowManager);
}
Aggregations