use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class AuthorizationTest method testStreams.
@Test
@Category(SlowTests.class)
public void testStreams() throws Exception {
createAuthNamespace();
StreamId streamId = AUTH_NAMESPACE.stream("someStream");
grantAndAssertSuccess(streamId, ALICE, EnumSet.allOf(Action.class));
cleanUpEntities.add(streamId);
// create stream as alice
getStreamManager(streamId).createStream();
// grant admin to BOB on the stream id so he can create the stream
grantAndAssertSuccess(streamId, BOB, ImmutableSet.of(Action.ADMIN));
// switch to bob
SecurityRequestContext.setUserId(BOB.getName());
// try to create the same stream as bob
// this will not fail since stream create is idempotent
getStreamManager(streamId).createStream();
// verify that alice and bob privilege do not change
assertAllAccess(ALICE, streamId);
getAuthorizer().enforce(streamId, BOB, Action.ADMIN);
try {
getAuthorizer().enforce(streamId, BOB, EnumSet.of(Action.READ, Action.WRITE, Action.EXECUTE));
} catch (UnauthorizedException e) {
// expected
}
// set user id back to ALICE so we can delete the namespace and the stream in the namespace
SecurityRequestContext.setUserId(ALICE.getName());
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class AuthorizationTest method testDeployAppWithoutOwner.
private void testDeployAppWithoutOwner() throws Exception {
NamespaceId namespaceId = new NamespaceId("namespaceImpersonation");
// We will create a namespace as owner bob, the keytab url is provided to pass the check for DefaultNamespaceAdmin
// in unit test, it is useless, since impersonation will never happen
NamespaceMeta ownerNSMeta = new NamespaceMeta.Builder().setName(namespaceId.getNamespace()).setPrincipal(BOB.getName()).setKeytabURI("/tmp/").build();
KerberosPrincipalId bobPrincipalId = new KerberosPrincipalId(BOB.getName());
// grant alice admin to the namespace, but creation should still fail since alice needs to have privilege on
// principal bob
grantAndAssertSuccess(namespaceId, ALICE, EnumSet.of(Action.ADMIN));
cleanUpEntities.add(namespaceId);
try {
getNamespaceAdmin().create(ownerNSMeta);
Assert.fail("Namespace creation should fail since alice does not have privilege on principal bob");
} catch (UnauthorizedException e) {
// expected
}
// grant alice admin on principal bob, now creation of namespace should work
grantAndAssertSuccess(bobPrincipalId, ALICE, EnumSet.of(Action.ADMIN));
cleanUpEntities.add(bobPrincipalId);
getNamespaceAdmin().create(ownerNSMeta);
// deploy dummy app with ns impersonation
deployDummyAppWithImpersonation(ownerNSMeta, null);
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class AuthorizationTest method testDeleteSystemDatasets.
/**
* This test is to make sure we do not bypass the authorization check for datasets in system namespace
*/
@Test
public void testDeleteSystemDatasets() throws Exception {
// create a random user and try to delete a system dataset
UserGroupInformation remoteUser = UserGroupInformation.createRemoteUser("random");
remoteUser.doAs(new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
deleteDatasetInstance(NamespaceId.SYSTEM.dataset("app.meta"));
Assert.fail();
} catch (UnauthorizedException e) {
// Expected
} catch (Exception e) {
Assert.fail("Getting incorrect exception");
}
return null;
}
});
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class AppLifecycleHttpHandler method deployAppFromArtifact.
// normally we wouldn't want to use a body consumer but would just want to read the request body directly
// since it wont be big. But the deploy app API has one path with different behavior based on content type
// the other behavior requires a BodyConsumer and only have one method per path is allowed,
// so we have to use a BodyConsumer
private BodyConsumer deployAppFromArtifact(final ApplicationId appId) throws IOException {
// createTempFile() needs a prefix of at least 3 characters
return new AbstractBodyConsumer(File.createTempFile("apprequest-" + appId, ".json", tmpDir)) {
@Override
protected void onFinish(HttpResponder responder, File uploadedFile) {
try (FileReader fileReader = new FileReader(uploadedFile)) {
AppRequest<?> appRequest = DECODE_GSON.fromJson(fileReader, AppRequest.class);
ArtifactSummary artifactSummary = appRequest.getArtifact();
KerberosPrincipalId ownerPrincipalId = appRequest.getOwnerPrincipal() == null ? null : new KerberosPrincipalId(appRequest.getOwnerPrincipal());
// if we don't null check, it gets serialized to "null"
String configString = appRequest.getConfig() == null ? null : GSON.toJson(appRequest.getConfig());
try {
applicationLifecycleService.deployApp(appId.getParent(), appId.getApplication(), appId.getVersion(), artifactSummary, configString, createProgramTerminator(), ownerPrincipalId, appRequest.canUpdateSchedules());
} catch (DatasetManagementException e) {
if (e.getCause() instanceof UnauthorizedException) {
throw (UnauthorizedException) e.getCause();
} else {
throw e;
}
}
responder.sendString(HttpResponseStatus.OK, "Deploy Complete");
} catch (ArtifactNotFoundException e) {
responder.sendString(HttpResponseStatus.NOT_FOUND, e.getMessage());
} catch (ConflictException e) {
responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
} catch (UnauthorizedException e) {
responder.sendString(HttpResponseStatus.FORBIDDEN, e.getMessage());
} catch (InvalidArtifactException e) {
responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
} catch (IOException e) {
LOG.error("Error reading request body for creating app {}.", appId);
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format("Error while reading json request body for app %s.", appId));
} catch (Exception e) {
LOG.error("Deploy failure", e);
responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
}
}
};
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class AppLifecycleHttpHandler method updateApp.
/**
* Updates an existing application.
*/
@POST
@Path("/apps/{app-id}/update")
@AuditPolicy(AuditDetail.REQUEST_BODY)
public void updateApp(FullHttpRequest request, HttpResponder responder, @PathParam("namespace-id") final String namespaceId, @PathParam("app-id") final String appName) throws NotFoundException, BadRequestException, UnauthorizedException, IOException {
ApplicationId appId = validateApplicationId(namespaceId, appName);
AppRequest appRequest;
try (Reader reader = new InputStreamReader(new ByteBufInputStream(request.content()), StandardCharsets.UTF_8)) {
appRequest = DECODE_GSON.fromJson(reader, AppRequest.class);
} catch (IOException e) {
LOG.error("Error reading request to update app {} in namespace {}.", appName, namespaceId, e);
throw new IOException("Error reading request body.");
} catch (JsonSyntaxException e) {
throw new BadRequestException("Request body is invalid json: " + e.getMessage());
}
try {
applicationLifecycleService.updateApp(appId, appRequest, createProgramTerminator());
responder.sendString(HttpResponseStatus.OK, "Update complete.");
} catch (InvalidArtifactException e) {
throw new BadRequestException(e.getMessage());
} catch (ConflictException e) {
responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
} catch (NotFoundException | UnauthorizedException e) {
throw e;
} catch (Exception e) {
// this is the same behavior as deploy app pipeline, but this is bad behavior. Error handling needs improvement.
LOG.error("Deploy failure", e);
responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
}
}
Aggregations