use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class ArtifactHttpHandler method addArtifact.
@POST
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}")
@AuditPolicy(AuditDetail.HEADERS)
public BodyConsumer addArtifact(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") final String namespaceId, @PathParam("artifact-name") final String artifactName, @HeaderParam(VERSION_HEADER) final String artifactVersion, @HeaderParam(EXTENDS_HEADER) final String parentArtifactsStr, @HeaderParam(PLUGINS_HEADER) String pluginClasses) throws NamespaceNotFoundException, BadRequestException {
final NamespaceId namespace = validateAndGetNamespace(namespaceId);
// and validated there
if (artifactVersion != null && !artifactVersion.isEmpty()) {
validateAndGetArtifactId(namespace, artifactName, artifactVersion);
}
final Set<ArtifactRange> parentArtifacts = parseExtendsHeader(namespace, parentArtifactsStr);
final Set<PluginClass> additionalPluginClasses;
if (pluginClasses == null) {
additionalPluginClasses = ImmutableSet.of();
} else {
try {
additionalPluginClasses = GSON.fromJson(pluginClasses, PLUGINS_TYPE);
} catch (JsonParseException e) {
responder.sendString(HttpResponseStatus.BAD_REQUEST, String.format("%s header '%s' is invalid: %s", PLUGINS_HEADER, pluginClasses, e.getMessage()));
return null;
}
}
try {
// copy the artifact contents to local tmp directory
final File destination = File.createTempFile("artifact-", ".jar", tmpDir);
return new AbstractBodyConsumer(destination) {
@Override
protected void onFinish(HttpResponder responder, File uploadedFile) {
try {
String version = (artifactVersion == null || artifactVersion.isEmpty()) ? getBundleVersion(uploadedFile) : artifactVersion;
ArtifactId artifactId = validateAndGetArtifactId(namespace, artifactName, version);
// add the artifact to the repo
artifactRepository.addArtifact(Id.Artifact.fromEntityId(artifactId), uploadedFile, parentArtifacts, additionalPluginClasses);
responder.sendString(HttpResponseStatus.OK, "Artifact added successfully");
} catch (ArtifactRangeNotFoundException e) {
responder.sendString(HttpResponseStatus.NOT_FOUND, e.getMessage());
} catch (ArtifactAlreadyExistsException e) {
responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
} catch (WriteConflictException e) {
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Conflict while writing artifact, please try again.");
} catch (IOException e) {
LOG.error("Exception while trying to write artifact {}-{}-{}.", namespaceId, artifactName, artifactVersion, e);
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Error performing IO while writing artifact.");
} catch (BadRequestException e) {
responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
} catch (UnauthorizedException e) {
responder.sendString(HttpResponseStatus.FORBIDDEN, e.getMessage());
} catch (Exception e) {
LOG.error("Error while writing artifact {}-{}-{}", namespaceId, artifactName, artifactVersion, e);
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Error while adding artifact.");
}
}
private String getBundleVersion(File file) throws BadRequestException, IOException {
try (JarFile jarFile = new JarFile(file)) {
Manifest manifest = jarFile.getManifest();
if (manifest == null) {
throw new BadRequestException("Unable to derive version from artifact because it does not contain a manifest. " + "Please package the jar with a manifest, or explicitly specify the artifact version.");
}
Attributes attributes = manifest.getMainAttributes();
String version = attributes == null ? null : attributes.getValue(ManifestFields.BUNDLE_VERSION);
if (version == null) {
throw new BadRequestException("Unable to derive version from artifact because manifest does not contain Bundle-Version attribute. " + "Please include Bundle-Version in the manifest, or explicitly specify the artifact version.");
}
return version;
} catch (ZipException e) {
throw new BadRequestException("Artifact is not in zip format. Please make sure it is a jar file.");
}
}
};
} catch (IOException e) {
LOG.error("Exception creating temp file to place artifact {} contents", artifactName, e);
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Server error creating temp file for artifact.");
return null;
}
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class DefaultNamespaceAdmin method get.
/**
* Gets details of a namespace
*
* @param namespaceId the {@link Id.Namespace} of the requested namespace
* @return the {@link NamespaceMeta} of the requested namespace
* @throws NamespaceNotFoundException if the requested namespace is not found
* @throws UnauthorizedException if the namespace is not authorized to the logged-user
*/
@Override
public NamespaceMeta get(NamespaceId namespaceId) throws Exception {
Principal principal = authenticationContext.getPrincipal();
boolean isAuthorzied = true;
// See: CDAP-7387
if (masterShortUserName == null || !masterShortUserName.equals(principal.getName())) {
try {
AuthorizationUtil.ensureAccess(namespaceId, authorizationEnforcer, principal);
} catch (UnauthorizedException e) {
isAuthorzied = false;
}
}
NamespaceMeta namespaceMeta = null;
try {
namespaceMeta = namespaceMetaCache.get(namespaceId);
} catch (Exception e) {
if (isAuthorzied) {
Throwable cause = e.getCause();
if (cause instanceof NamespaceNotFoundException || cause instanceof IOException || cause instanceof UnauthorizedException) {
throw (Exception) cause;
}
throw e;
}
}
// If the requesting user is same as namespace owner, we do not care about if the user is authorized or not
if (namespaceMeta != null && principal.getName().equals(namespaceMeta.getConfig().getPrincipal())) {
return namespaceMeta;
}
if (!isAuthorzied) {
throw new UnauthorizedException(String.format("Namespace %s is not visible to principal %s since the principal does not have any " + "privilege on this namespace or any entity in this namespace.", namespaceId, principal));
}
return namespaceMeta;
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class FlowletProcessDriver method handleProcessEntry.
/**
* Invokes to perform dequeue and optionally invoke the user process input / tick method if dequeue gave a non
* empty result.
*
* @param entry Contains information about the process method and queue.
* @param processQueue The queue for queuing up all process input methods in a flowlet instance.
* @param <T> Type of input of the process method accepted.
*
* @return {@code true} if the entry is handled completely (regardless of process result), {@code false} otherwise.
*/
private <T> boolean handleProcessEntry(FlowletProcessEntry<T> entry, PriorityQueue<FlowletProcessEntry<?>> processQueue) {
if (!entry.shouldProcess()) {
return false;
}
ProcessMethod<T> processMethod = entry.getProcessSpec().getProcessMethod();
if (processMethod.needsInput()) {
flowletContext.getProgramMetrics().increment("process.tuples.attempt.read", 1);
}
// Begin transaction and dequeue
try {
TransactionContext txContext = dataFabricFacade.createTransactionContext();
startTx(txContext);
try {
InputDatum<T> input = entry.getProcessSpec().getQueueReader().dequeue(0, TimeUnit.MILLISECONDS);
if (!input.needProcess()) {
entry.backOff();
// End the transaction if nothing in the queue
txContext.finish();
return false;
}
// Resetting back-off time to minimum back-off time,
// since an entry to process was de-queued and most likely more entries will follow.
entry.resetBackOff();
// Call the process method and commit the transaction. The current process entry will put
// back to queue in the postProcess method (either a retry copy or itself).
ProcessMethod.ProcessResult<?> result = processMethod.invoke(input);
postProcess(processMethodCallback(processQueue, entry, input), txContext, input, result);
return true;
} catch (Throwable t) {
LOG.error("System failure: {}", flowletContext, t);
try {
txContext.abort();
} catch (Throwable e) {
LOG.error("Fail to abort transaction: {}", flowletContext, e);
}
if (Throwables.getRootCause(t) instanceof UnauthorizedException) {
throw t;
}
}
} catch (Throwable t) {
LOG.error("Failed to start transaction.", t);
if (Throwables.getRootCause(t) instanceof UnauthorizedException) {
Throwables.propagate(t);
}
}
return false;
}
use of co.cask.cdap.security.spi.authorization.UnauthorizedException in project cdap by caskdata.
the class DefaultSecureStoreServiceTest method testSecureStoreAccess.
@Test
public void testSecureStoreAccess() throws Exception {
final SecureKeyId secureKeyId1 = NamespaceId.DEFAULT.secureKey(KEY1);
SecurityRequestContext.setUserId(ALICE.getName());
try {
secureStoreManager.putSecureData(NamespaceId.DEFAULT.getNamespace(), KEY1, VALUE1, DESCRIPTION1, Collections.<String, String>emptyMap());
Assert.fail("Alice should not be able to store a key since she does not have WRITE privileges on the namespace");
} catch (UnauthorizedException expected) {
// expected
}
// Grant ALICE admin access to the secure key
grantAndAssertSuccess(secureKeyId1, ALICE, EnumSet.of(Action.ADMIN));
// Write should succeed
secureStoreManager.putSecureData(NamespaceId.DEFAULT.getNamespace(), KEY1, VALUE1, DESCRIPTION1, Collections.<String, String>emptyMap());
// Listing should return the value just written
Map<String, String> secureKeyListEntries = secureStore.listSecureData(NamespaceId.DEFAULT.getNamespace());
Assert.assertEquals(1, secureKeyListEntries.size());
Assert.assertTrue(secureKeyListEntries.containsKey(KEY1));
Assert.assertEquals(DESCRIPTION1, secureKeyListEntries.get(KEY1));
revokeAndAssertSuccess(secureKeyId1, ALICE, EnumSet.allOf(Action.class));
// Should not be able to list the keys since ALICE does not have privilege on the secure key
try {
secureStore.listSecureData(NamespaceId.DEFAULT.getNamespace());
} catch (UnauthorizedException e) {
// expected
}
// Give BOB read access and verify that he can read the stored data
SecurityRequestContext.setUserId(BOB.getName());
grantAndAssertSuccess(NamespaceId.DEFAULT, BOB, EnumSet.of(Action.READ));
grantAndAssertSuccess(secureKeyId1, BOB, EnumSet.of(Action.READ));
Assert.assertEquals(VALUE1, new String(secureStore.getSecureData(NamespaceId.DEFAULT.getNamespace(), KEY1).get(), Charsets.UTF_8));
secureKeyListEntries = secureStore.listSecureData(NamespaceId.DEFAULT.getNamespace());
Assert.assertEquals(1, secureKeyListEntries.size());
// BOB should not be able to delete the key
try {
secureStoreManager.deleteSecureData(NamespaceId.DEFAULT.getNamespace(), KEY1);
Assert.fail("Bob should not be able to delete a key since he does not have ADMIN privileges on the key");
} catch (UnauthorizedException expected) {
// expected
}
// Grant Bob ADMIN access and he should be able to delete the key
grantAndAssertSuccess(secureKeyId1, BOB, ImmutableSet.of(Action.ADMIN));
secureStoreManager.deleteSecureData(NamespaceId.DEFAULT.getNamespace(), KEY1);
Assert.assertEquals(0, secureStore.listSecureData(NamespaceId.DEFAULT.getNamespace()).size());
Predicate<Privilege> secureKeyIdFilter = new Predicate<Privilege>() {
@Override
public boolean apply(Privilege input) {
return input.getAuthorizable().equals(Authorizable.fromEntityId(secureKeyId1));
}
};
}
Aggregations