use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class AuthorizationUtil method ensureOnePrivilege.
/**
* Ensures that the principal has at least one {@link Action privilege} in the expected action set
* on the specified entity id.
* <p>
* TODO: remove this once we have api support for OR privilege enforce
*
* @param entityId the entity to be checked
* @param actionSet the set of privileges
* @param authorizationEnforcer enforcer to make the authorization check
* @param principal the principal to be checked
* @throws UnauthorizedException if the principal does not have any privilege in the action set on the entity
*/
public static void ensureOnePrivilege(co.cask.cdap.proto.id.EntityId entityId, Set<Action> actionSet, AuthorizationEnforcer authorizationEnforcer, Principal principal) throws Exception {
boolean isAuthorized = false;
for (Action action : actionSet) {
try {
authorizationEnforcer.enforce(entityId, principal, action);
isAuthorized = true;
break;
} catch (UnauthorizedException e) {
// continue to next action
}
}
if (!isAuthorized) {
throw new UnauthorizedException(principal, actionSet, entityId, false);
}
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class StreamAdminTest method testCreateExist.
@Test
public void testCreateExist() throws Exception {
SecurityRequestContext.setUserId(USER.getName());
StreamAdmin streamAdmin = getStreamAdmin();
String streamName = "streamName";
StreamId streamId = FOO_NAMESPACE.stream(streamName);
StreamId otherStreamId = OTHER_NAMESPACE.stream(streamName);
// grant some privileges to the stream so that the user can check the existence
grantAndAssertSuccess(streamId, USER, EnumSet.of(Action.EXECUTE));
grantAndAssertSuccess(otherStreamId, USER, EnumSet.of(Action.EXECUTE));
Assert.assertFalse(streamAdmin.exists(streamId));
Assert.assertFalse(streamAdmin.exists(otherStreamId));
try {
streamAdmin.create(streamId);
Assert.fail("User should not be able to create a stream in this namespace.");
} catch (UnauthorizedException e) {
// expected
}
// grant admin access for user to stream
grantAndAssertSuccess(streamId, USER, ImmutableSet.of(Action.ADMIN));
streamAdmin.create(streamId);
// Even though both streams have the same name, {@code otherStreamId} does not exist because it is in a different
// namespace than the one created above.
Assert.assertTrue(streamAdmin.exists(streamId));
Assert.assertFalse(streamAdmin.exists(otherStreamId));
try {
streamAdmin.create(otherStreamId);
Assert.fail("User should not be able to create a stream in this namespace.");
} catch (UnauthorizedException e) {
// expected
}
// grant admin access for user to stream in other_namespace
grantAndAssertSuccess(otherStreamId, USER, ImmutableSet.of(Action.ADMIN));
streamAdmin.create(otherStreamId);
Assert.assertTrue(streamAdmin.exists(otherStreamId));
// the user should be able to drop the stream, they had created
streamAdmin.drop(otherStreamId);
Assert.assertFalse(streamAdmin.exists(otherStreamId));
// revoke the permission for the user on the stream in foo_namespace
revokeAndAssertSuccess(streamId, USER, EnumSet.allOf(Action.class));
try {
streamAdmin.drop(streamId);
Assert.fail("User should not be able to delete a stream in this namespace.");
} catch (UnauthorizedException e) {
// expected
}
// grant WRITE permission to the user but they still should not be able to drop the stream
grantAndAssertSuccess(streamId, USER, ImmutableSet.of(Action.WRITE));
try {
streamAdmin.drop(streamId);
Assert.fail("User should not be able to delete a stream with only Write Action access.");
} catch (UnauthorizedException e) {
// expected
}
// grant admin access and the user should then be able to drop the stream
grantAndAssertSuccess(streamId, USER, ImmutableSet.of(Action.ADMIN));
streamAdmin.drop(streamId);
Assert.assertFalse(streamAdmin.exists(streamId));
// clean up privilege
getAuthorizer().revoke(Authorizable.fromEntityId(streamId));
getAuthorizer().revoke(Authorizable.fromEntityId(otherStreamId));
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class StreamAdminTest method testOwner.
@Test
public void testOwner() throws Exception {
// create a stream with owner
StreamAdmin streamAdmin = getStreamAdmin();
OwnerAdmin ownerAdmin = getOwnerAdmin();
StreamId stream = FOO_NAMESPACE.stream("stream");
Properties properties = new Properties();
String ownerPrincipal = "user/somehost@somekdc.net";
KerberosPrincipalId principalId = new KerberosPrincipalId(ownerPrincipal);
properties.put(Constants.Security.PRINCIPAL, ownerPrincipal);
try {
streamAdmin.create(stream, properties);
Assert.fail();
} catch (UnauthorizedException e) {
// expected since user does not have privilege on the stream and the owner principal
}
// grant privilege on the stream to the user
grantAndAssertSuccess(stream, USER, EnumSet.of(Action.ADMIN));
try {
streamAdmin.create(stream, properties);
Assert.fail();
} catch (UnauthorizedException e) {
// expected since user doesn ot have privilege on the owner principal
}
// grant privilege to the owner principal
grantAndAssertSuccess(principalId, USER, EnumSet.of(Action.ADMIN));
// creation should work this time
streamAdmin.create(stream, properties);
Assert.assertTrue(streamAdmin.exists(stream));
// Check that the owner information got stored in owner store
Assert.assertTrue(ownerAdmin.exists(stream));
// also verify that we are able to get owner information back in properties
Assert.assertEquals(ownerPrincipal, streamAdmin.getProperties(stream).getOwnerPrincipal());
// updating stream owner should fail
try {
streamAdmin.updateConfig(stream, new StreamProperties(1L, null, null, null, "user/somekdc.net"));
Assert.fail();
} catch (UnauthorizedException e) {
// expected
}
// trying to create same stream with different owner should fail
properties.put(Constants.Security.PRINCIPAL, "someOtherUser/someHost@somekdc.net");
try {
streamAdmin.create(stream, properties);
Assert.fail("Should have failed to add the same stream with different owner");
} catch (UnauthorizedException e) {
// expected
}
// ensure that the previous owner still exists
Assert.assertEquals(ownerPrincipal, streamAdmin.getProperties(stream).getOwnerPrincipal());
// drop the stream which should also delete the owner info
streamAdmin.drop(stream);
Assert.assertFalse(ownerAdmin.exists(stream));
// clean up the privileges
revokeAndAssertSuccess(stream, USER, EnumSet.of(Action.ADMIN));
revokeAndAssertSuccess(principalId, USER, EnumSet.of(Action.ADMIN));
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class StreamAdminTest method testDropAllInNamespace.
@Test
public void testDropAllInNamespace() throws Exception {
StreamAdmin streamAdmin = getStreamAdmin();
StreamId otherStream = OTHER_NAMESPACE.stream("otherStream");
List<StreamId> fooStreams = Lists.newArrayList();
for (int i = 0; i < 4; i++) {
fooStreams.add(FOO_NAMESPACE.stream("stream" + i));
}
List<StreamId> allStreams = Lists.newArrayList();
allStreams.addAll(fooStreams);
allStreams.add(otherStream);
for (StreamId stream : allStreams) {
// grant privilege to the stream
grantAndAssertSuccess(stream, USER, EnumSet.of(Action.ADMIN));
streamAdmin.create(stream);
writeEvent(stream);
// all of the streams should have data in it after writing to them
Assert.assertNotEquals(0, getStreamSize(stream));
}
// revoke ADMIN from one of the streams and grant READ on the stream to make sure USER is not able to delete but
// able to list
revokeAndAssertSuccess(fooStreams.get(0), USER, EnumSet.of(Action.ADMIN));
grantAndAssertSuccess(fooStreams.get(0), USER, EnumSet.of(Action.READ));
// the drop all should fail since USER does not have ADMIN on one of the streams in the namespace
try {
streamAdmin.dropAllInNamespace(FOO_NAMESPACE);
Assert.fail();
} catch (UnauthorizedException e) {
// expected
}
// all streams should exist
Assert.assertEquals(fooStreams.size(), streamAdmin.listStreams(FOO_NAMESPACE).size());
// grant ADMIN again and this time drop all should succeed
grantAndAssertSuccess(fooStreams.get(0), USER, EnumSet.of(Action.ADMIN));
revokeAndAssertSuccess(fooStreams.get(0), USER, EnumSet.of(Action.READ));
streamAdmin.dropAllInNamespace(FOO_NAMESPACE);
// All of the streams within the default namespace should no longer exist
for (StreamId defaultStream : fooStreams) {
Assert.assertFalse(streamAdmin.exists(defaultStream));
}
// otherStream isn't in the foo namespace so its data is not deleted in the above call to dropAllInNamespace.
Assert.assertNotEquals(0, getStreamSize(otherStream));
// truncate should also delete all the data of a stream
streamAdmin.truncate(otherStream);
Assert.assertEquals(0, getStreamSize(otherStream));
// clean up privileges
for (StreamId stream : allStreams) {
// revoke privilege to the stream
revokeAndAssertSuccess(stream, USER, EnumSet.of(Action.ADMIN));
}
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class DatasetInstanceService method create.
/**
* Creates a dataset instance.
*
* @param namespaceId the namespace to create the dataset instance in
* @param name the name of the new dataset instance
* @param props the properties for the new dataset instance
* @throws NamespaceNotFoundException if the specified namespace was not found
* @throws DatasetAlreadyExistsException if a dataset with the same name already exists
* @throws DatasetTypeNotFoundException if the dataset type was not found
* @throws UnauthorizedException if perimeter security and authorization are enabled, and the current user does not
* have {@link Action#WRITE} privilege on the #instance's namespace
*/
void create(String namespaceId, String name, DatasetInstanceConfiguration props) throws Exception {
NamespaceId namespace = ConversionHelpers.toNamespaceId(namespaceId);
DatasetId datasetId = ConversionHelpers.toDatasetInstanceId(namespaceId, name);
Principal requestingUser = authenticationContext.getPrincipal();
String ownerPrincipal = props.getOwnerPrincipal();
// need to enforce on the principal id if impersonation is involved
KerberosPrincipalId effectiveOwner = SecurityUtil.getEffectiveOwner(ownerAdmin, namespace, ownerPrincipal);
if (!DatasetsUtil.isSystemDatasetInUserNamespace(datasetId)) {
if (effectiveOwner != null) {
authorizationEnforcer.enforce(effectiveOwner, requestingUser, Action.ADMIN);
}
authorizationEnforcer.enforce(datasetId, requestingUser, Action.ADMIN);
}
ensureNamespaceExists(namespace);
DatasetSpecification existing = instanceManager.get(datasetId);
if (existing != null) {
throw new DatasetAlreadyExistsException(datasetId);
}
// for creation, we need enforcement for dataset type for user dataset, but bypass for system datasets
DatasetTypeMeta typeMeta = getTypeInfo(namespace, props.getTypeName(), DatasetsUtil.isSystemDatasetInUserNamespace(datasetId));
if (typeMeta == null) {
// Type not found in the instance's namespace and the system namespace. Bail out.
throw new DatasetTypeNotFoundException(ConversionHelpers.toDatasetTypeId(namespace, props.getTypeName()));
}
LOG.info("Creating dataset {}.{}, type name: {}, properties: {}", namespaceId, name, props.getTypeName(), props.getProperties());
// exists or not
if (ownerPrincipal != null) {
KerberosPrincipalId owner = new KerberosPrincipalId(ownerPrincipal);
ownerAdmin.add(datasetId, owner);
}
try {
DatasetSpecification spec = opExecutorClient.create(datasetId, typeMeta, DatasetProperties.builder().addAll(props.getProperties()).setDescription(props.getDescription()).build());
instanceManager.add(namespace, spec);
metaCache.invalidate(datasetId);
publishAudit(datasetId, AuditType.CREATE);
// Enable explore
enableExplore(datasetId, spec, props);
} catch (Exception e) {
// there was a problem in creating the dataset instance so delete the owner if it got added earlier
// safe to call for entities which does not have an owner too
ownerAdmin.delete(datasetId);
throw e;
}
}
Aggregations