use of io.cdap.cdap.security.spi.authorization.AccessController in project cdap by cdapio.
the class AccessControllerInstantiator method createAccessController.
/**
* Creates a new instance of the configured {@link AccessController} extension, based on the provided extension jar
* file and initialize it.
*
* @return a new instance of the configured {@link AccessController} extension
*/
private AccessController createAccessController(AccessControllerClassLoader classLoader) throws InvalidAccessControllerException {
Class<?> accessControllerClass = loadAccessControllerClass(classLoader);
// Set the context class loader to the AccessControllerClassLoader before creating a new instance of the extension,
// so all classes required in this process are created from the AccessControllerClassLoader.
ClassLoader oldClassLoader = ClassLoaders.setContextClassLoader(classLoader);
LOG.trace("Setting context classloader to {}. Old classloader was {}.", classLoader, oldClassLoader);
try {
AccessController accessController;
try {
Object extensionClass = instantiatorFactory.get(TypeToken.of(accessControllerClass)).create();
if (extensionClass instanceof AccessController) {
accessController = (AccessController) extensionClass;
} else {
accessController = new AuthorizerWrapper((Authorizer) extensionClass);
}
} catch (Exception e) {
throw new InvalidAccessControllerException(String.format("Error while instantiating for access controller extension %s. " + "Please make sure that the extension " + "is a public class with a default constructor.", accessControllerClass.getName()), e);
}
AuthorizationContext context = authorizationContextFactory.create(createExtensionProperties());
try {
accessController.initialize(context);
} catch (Exception e) {
throw new InvalidAccessControllerException(String.format("Error while initializing access control extension %s.", accessControllerClass.getName()), e);
}
return accessController;
} finally {
// After the process of creation of a new instance has completed (success or failure), reset the context
// classloader back to the original class loader.
ClassLoaders.setContextClassLoader(oldClassLoader);
LOG.trace("Resetting context classloader to {} from {}.", oldClassLoader, classLoader);
}
}
use of io.cdap.cdap.security.spi.authorization.AccessController in project cdap by cdapio.
the class AccessControllerInstantiator method close.
@Override
public void close() throws IOException {
try {
synchronized (this) {
closed = true;
AccessController accessController = this.accessController;
if (accessController != null) {
accessController.destroy();
}
}
} catch (Throwable t) {
LOG.warn("Failed to destroy accessController.", t);
} finally {
Closeables.closeQuietly(accessControllerClassLoader);
}
}
use of io.cdap.cdap.security.spi.authorization.AccessController in project cdap by cdapio.
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();
AccessController accessController = getAccessController();
ApplicationId dummyAppId = AUTH_NAMESPACE.app(DummyApp.class.getSimpleName());
Map<EntityId, Set<? extends Permission>> neededPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(dummyAppId, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET, StandardPermission.DELETE)).put(AUTH_NAMESPACE.artifact(DummyApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset("whom"), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset("customDataset"), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.datasetType(KeyValueTable.class.getName()), EnumSet.of(StandardPermission.UPDATE)).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(StandardPermission.GET, StandardPermission.CREATE));
cleanUpEntities.add(AUTH_NAMESPACE.datasetType(DummyApp.CustomDummyDataset.class.getName()));
grantAndAssertSuccess(AUTH_NAMESPACE.datasetModule(DummyApp.CustomDummyDataset.class.getName()), ALICE, EnumSet.of(StandardPermission.CREATE, StandardPermission.GET));
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", accessController.listGrants(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(AUTH_NAMESPACE, BOB, ImmutableSet.of(StandardPermission.GET));
grantAndAssertSuccess(dummyAppId, BOB, ImmutableSet.of(StandardPermission.GET, StandardPermission.UPDATE));
// delete should fail
try {
appManager.delete();
} catch (UnauthorizedException expected) {
// expected
}
// grant DELETE to Bob. Now delete should succeed
grantAndAssertSuccess(dummyAppId, BOB, ImmutableSet.of(StandardPermission.DELETE));
// 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(!getAccessController().isVisible(Collections.singleton(dummyAppId), BOB).isEmpty());
// bob should still have privileges granted to him
Assert.assertEquals(4, accessController.listGrants(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<? extends Permission>> anotherAppNeededPrivilege = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(appId, EnumSet.of(StandardPermission.GET, StandardPermission.CREATE, StandardPermission.DELETE)).put(AUTH_NAMESPACE.artifact(AllProgramsApp.class.getSimpleName(), "1.0-SNAPSHOT"), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME2), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME3), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DS_WITH_SCHEMA_NAME), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).put(AUTH_NAMESPACE.datasetType(ObjectMappedTable.class.getName()), EnumSet.of(StandardPermission.GET, StandardPermission.CREATE)).build();
setUpPrivilegeAndRegisterForDeletion(ALICE, anotherAppNeededPrivilege);
Map<EntityId, Set<? extends Permission>> bobDatasetPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME), EnumSet.of(StandardPermission.UPDATE)).put(AUTH_NAMESPACE.dataset(AllProgramsApp.DATASET_NAME2), EnumSet.of(StandardPermission.UPDATE)).build();
Map<EntityId, Set<? extends Permission>> bobProgramPrivileges = ImmutableMap.<EntityId, Set<? extends Permission>>builder().put(appId, EnumSet.of(StandardPermission.GET)).put(appId.program(ProgramType.SERVICE, AllProgramsApp.NoOpService.NAME), EnumSet.of(ApplicationPermission.EXECUTE)).put(appId.program(ProgramType.WORKER, AllProgramsApp.NoOpWorker.NAME), EnumSet.of(ApplicationPermission.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
}
// Switch to ALICE, deletion should be successful since ALICE has ADMIN privileges
SecurityRequestContext.setUserId(ALICE.getName());
deleteAllApplications(AUTH_NAMESPACE);
}
use of io.cdap.cdap.security.spi.authorization.AccessController in project cdap by cdapio.
the class AuthorizationTest method afterTest.
@After
@Override
public void afterTest() throws Exception {
AccessController accessController = getAccessController();
SecurityRequestContext.setUserId(ALICE.getName());
grantAndAssertSuccess(AUTH_NAMESPACE, SecurityRequestContext.toPrincipal(), EnumSet.of(StandardPermission.DELETE, StandardPermission.GET));
for (EntityId entityId : cleanUpEntities) {
grantAndAssertSuccess(entityId, SecurityRequestContext.toPrincipal(), EnumSet.of(StandardPermission.DELETE, StandardPermission.GET));
}
// clean up. remove the namespace if it exists
if (getNamespaceAdmin().exists(AUTH_NAMESPACE)) {
getNamespaceAdmin().delete(AUTH_NAMESPACE);
Assert.assertFalse(getNamespaceAdmin().exists(AUTH_NAMESPACE));
}
revokeAndAssertSuccess(AUTH_NAMESPACE);
for (EntityId entityId : cleanUpEntities) {
revokeAndAssertSuccess(entityId);
}
Assert.assertEquals(Collections.emptySet(), accessController.listGrants(ALICE));
}
use of io.cdap.cdap.security.spi.authorization.AccessController in project cdap by cdapio.
the class AuthorizationTest method testNamespaces.
@Test
public void testNamespaces() throws Exception {
NamespaceAdmin namespaceAdmin = getNamespaceAdmin();
AccessController accessController = getAccessController();
try {
namespaceAdmin.create(AUTH_NAMESPACE_META);
Assert.fail("Namespace create should have failed because alice is not authorized on " + AUTH_NAMESPACE);
} catch (UnauthorizedException expected) {
// expected
}
createAuthNamespace();
Assert.assertTrue(namespaceAdmin.list().contains(AUTH_NAMESPACE_META));
namespaceAdmin.get(AUTH_NAMESPACE);
// revoke privileges
revokeAndAssertSuccess(AUTH_NAMESPACE);
try {
Assert.assertTrue(namespaceAdmin.list().isEmpty());
namespaceAdmin.exists(AUTH_NAMESPACE);
Assert.fail("Namespace existence check should fail since the privilege of alice has been revoked");
} catch (UnauthorizedException expected) {
// expected
}
// grant privileges again
grantAndAssertSuccess(AUTH_NAMESPACE, ALICE, ImmutableSet.of(StandardPermission.GET, StandardPermission.UPDATE));
namespaceAdmin.exists(AUTH_NAMESPACE);
Assert.assertEquals(ImmutableSet.of(new GrantedPermission(AUTH_NAMESPACE, StandardPermission.GET), new GrantedPermission(AUTH_NAMESPACE, StandardPermission.UPDATE)), accessController.listGrants(ALICE));
NamespaceMeta updated = new NamespaceMeta.Builder(AUTH_NAMESPACE_META).setDescription("new desc").build();
namespaceAdmin.updateProperties(AUTH_NAMESPACE, updated);
Assert.assertEquals(updated, namespaceAdmin.get(AUTH_NAMESPACE));
}
Aggregations