Search in sources :

Example 11 with KerberosPrincipalId

use of co.cask.cdap.proto.id.KerberosPrincipalId in project cdap by caskdata.

the class ApplicationLifecycleService method deployApp.

private ApplicationWithPrograms deployApp(NamespaceId namespaceId, @Nullable String appName, @Nullable String appVersion, @Nullable String configStr, ProgramTerminator programTerminator, ArtifactDetail artifactDetail, @Nullable KerberosPrincipalId ownerPrincipal, boolean updateSchedules) throws Exception {
    // Now to deploy an app, we need ADMIN privilege on the owner principal if it is present, and also ADMIN on the app
    // But since at this point, app name is unknown to us, so the enforcement on the app is happening in the deploy
    // pipeline - LocalArtifactLoaderStage
    // need to enforce on the principal id if impersonation is involved
    KerberosPrincipalId effectiveOwner = SecurityUtil.getEffectiveOwner(ownerAdmin, namespaceId, ownerPrincipal == null ? null : ownerPrincipal.getPrincipal());
    Principal requestingUser = authenticationContext.getPrincipal();
    // impersonated principal
    if (effectiveOwner != null) {
        authorizationEnforcer.enforce(effectiveOwner, requestingUser, Action.ADMIN);
    }
    ApplicationClass appClass = Iterables.getFirst(artifactDetail.getMeta().getClasses().getApps(), null);
    if (appClass == null) {
        throw new InvalidArtifactException(String.format("No application class found in artifact '%s' in namespace '%s'.", artifactDetail.getDescriptor().getArtifactId(), namespaceId));
    }
    // deploy application with newly added artifact
    AppDeploymentInfo deploymentInfo = new AppDeploymentInfo(artifactDetail.getDescriptor(), namespaceId, appClass.getClassName(), appName, appVersion, configStr, ownerPrincipal, updateSchedules);
    Manager<AppDeploymentInfo, ApplicationWithPrograms> manager = managerFactory.create(programTerminator);
    // TODO: (CDAP-3258) Manager needs MUCH better error handling.
    ApplicationWithPrograms applicationWithPrograms;
    try {
        applicationWithPrograms = manager.deploy(deploymentInfo).get();
    } catch (ExecutionException e) {
        Throwables.propagateIfPossible(e.getCause(), Exception.class);
        throw Throwables.propagate(e.getCause());
    }
    return applicationWithPrograms;
}
Also used : AppDeploymentInfo(co.cask.cdap.internal.app.deploy.pipeline.AppDeploymentInfo) ApplicationWithPrograms(co.cask.cdap.internal.app.deploy.pipeline.ApplicationWithPrograms) ApplicationClass(co.cask.cdap.api.artifact.ApplicationClass) ExecutionException(java.util.concurrent.ExecutionException) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) Principal(co.cask.cdap.proto.security.Principal) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) CannotBeDeletedException(co.cask.cdap.common.CannotBeDeletedException) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) ExecutionException(java.util.concurrent.ExecutionException) NotFoundException(co.cask.cdap.common.NotFoundException)

Example 12 with KerberosPrincipalId

use of co.cask.cdap.proto.id.KerberosPrincipalId in project cdap by caskdata.

the class AppLifecycleHttpHandler method deployApplication.

private BodyConsumer deployApplication(final HttpResponder responder, final NamespaceId namespace, final String appId, final String archiveName, final String configString, @Nullable final String ownerPrincipal, final boolean updateSchedules) throws IOException {
    Id.Namespace idNamespace = Id.Namespace.fromEntityId(namespace);
    Location namespaceHomeLocation = namespacedLocationFactory.get(namespace);
    if (!namespaceHomeLocation.exists()) {
        String msg = String.format("Home directory %s for namespace %s not found", namespaceHomeLocation, namespace.getNamespace());
        LOG.error(msg);
        responder.sendString(HttpResponseStatus.NOT_FOUND, msg);
        return null;
    }
    if (archiveName == null || archiveName.isEmpty()) {
        responder.sendString(HttpResponseStatus.BAD_REQUEST, String.format("%s header not present. Please include the header and set its value to the jar name.", ARCHIVE_NAME_HEADER), new DefaultHttpHeaders().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE));
        return null;
    }
    // TODO: (CDAP-3258) error handling needs to be refactored here, should be able just to throw the exception,
    // but the caller catches all exceptions and responds with a 500
    final Id.Artifact artifactId;
    try {
        artifactId = Id.Artifact.parse(idNamespace, archiveName);
    } catch (IllegalArgumentException e) {
        responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
        return null;
    }
    KerberosPrincipalId ownerPrincipalId = ownerPrincipal == null ? null : new KerberosPrincipalId(ownerPrincipal);
    // Store uploaded content to a local temp file
    String namespacesDir = configuration.get(Constants.Namespace.NAMESPACES_DIR);
    File localDataDir = new File(configuration.get(Constants.CFG_LOCAL_DATA_DIR));
    File namespaceBase = new File(localDataDir, namespacesDir);
    File tempDir = new File(new File(namespaceBase, namespace.getNamespace()), configuration.get(Constants.AppFabric.TEMP_DIR)).getAbsoluteFile();
    if (!DirUtils.mkdirs(tempDir)) {
        throw new IOException("Could not create temporary directory at: " + tempDir);
    }
    final KerberosPrincipalId finalOwnerPrincipalId = ownerPrincipalId;
    return new AbstractBodyConsumer(File.createTempFile("app-", ".jar", tempDir)) {

        @Override
        protected void onFinish(HttpResponder responder, File uploadedFile) {
            try {
                // deploy app
                ApplicationWithPrograms app = applicationLifecycleService.deployAppAndArtifact(namespace, appId, artifactId, uploadedFile, configString, finalOwnerPrincipalId, createProgramTerminator(), updateSchedules);
                LOG.info("Successfully deployed app {} in namespace {} from artifact {} with configuration {} and " + "principal {}", app.getApplicationId().getApplication(), namespace.getNamespace(), artifactId, configString, finalOwnerPrincipalId);
                responder.sendString(HttpResponseStatus.OK, String.format("Successfully deployed app %s", app.getApplicationId().getApplication()));
            } catch (InvalidArtifactException e) {
                responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
            } catch (ArtifactAlreadyExistsException e) {
                responder.sendString(HttpResponseStatus.CONFLICT, String.format("Artifact '%s' already exists. Please use the API that creates an application from an existing artifact. " + "If you are trying to replace the artifact, please delete it and then try again.", artifactId));
            } catch (WriteConflictException e) {
                // don't really expect this to happen. It means after multiple retries there were still write conflicts.
                LOG.warn("Write conflict while trying to add artifact {}.", artifactId, e);
                responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Write conflict while adding artifact. This can happen if multiple requests to add " + "the same artifact occur simultaneously. Please try again.");
            } catch (UnauthorizedException e) {
                responder.sendString(HttpResponseStatus.FORBIDDEN, e.getMessage());
            } catch (ConflictException e) {
                responder.sendString(HttpResponseStatus.CONFLICT, e.getMessage());
            } catch (Exception e) {
                LOG.error("Deploy failure", e);
                responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage());
            }
        }
    };
}
Also used : HttpResponder(co.cask.http.HttpResponder) ConflictException(co.cask.cdap.common.ConflictException) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) IOException(java.io.IOException) ApplicationNotFoundException(co.cask.cdap.common.ApplicationNotFoundException) NamespaceNotFoundException(co.cask.cdap.common.NamespaceNotFoundException) ArtifactNotFoundException(co.cask.cdap.common.ArtifactNotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) ConflictException(co.cask.cdap.common.ConflictException) BadRequestException(co.cask.cdap.common.BadRequestException) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) DatasetManagementException(co.cask.cdap.api.dataset.DatasetManagementException) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) JsonSyntaxException(com.google.gson.JsonSyntaxException) IOException(java.io.IOException) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) ExecutionException(java.util.concurrent.ExecutionException) NotFoundException(co.cask.cdap.common.NotFoundException) ArtifactAlreadyExistsException(co.cask.cdap.common.ArtifactAlreadyExistsException) DefaultHttpHeaders(io.netty.handler.codec.http.DefaultHttpHeaders) AbstractBodyConsumer(co.cask.cdap.common.http.AbstractBodyConsumer) WriteConflictException(co.cask.cdap.internal.app.runtime.artifact.WriteConflictException) ApplicationWithPrograms(co.cask.cdap.internal.app.deploy.pipeline.ApplicationWithPrograms) UnauthorizedException(co.cask.cdap.security.spi.authorization.UnauthorizedException) ProgramId(co.cask.cdap.proto.id.ProgramId) Id(co.cask.cdap.common.id.Id) NamespaceId(co.cask.cdap.proto.id.NamespaceId) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) ApplicationId(co.cask.cdap.proto.id.ApplicationId) EntityId(co.cask.cdap.proto.id.EntityId) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) File(java.io.File) InvalidArtifactException(co.cask.cdap.common.InvalidArtifactException) Location(org.apache.twill.filesystem.Location)

Example 13 with KerberosPrincipalId

use of co.cask.cdap.proto.id.KerberosPrincipalId in project cdap by caskdata.

the class AuthorizationStreamAdmin method create.

@Nullable
@Override
public StreamConfig create(StreamId streamId, @Nullable Properties props) throws Exception {
    String specifiedOwnerPrincipal = props != null && props.containsKey(Constants.Security.PRINCIPAL) ? props.getProperty(Constants.Security.PRINCIPAL) : null;
    // need to enforce on the principal id if impersonation is involved
    KerberosPrincipalId effectiveOwner = SecurityUtil.getEffectiveOwner(ownerAdmin, streamId.getNamespaceId(), specifiedOwnerPrincipal);
    Principal requestingUser = authenticationContext.getPrincipal();
    if (effectiveOwner != null) {
        authorizationEnforcer.enforce(effectiveOwner, requestingUser, Action.ADMIN);
    }
    ensureAccess(streamId, Action.ADMIN);
    return delegate.create(streamId, props);
}
Also used : KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) Principal(co.cask.cdap.proto.security.Principal) Nullable(javax.annotation.Nullable)

Example 14 with KerberosPrincipalId

use of co.cask.cdap.proto.id.KerberosPrincipalId in project cdap by caskdata.

the class OwnerStoreTest method test.

@Test
public void test() throws Exception {
    OwnerStore ownerStore = getOwnerStore();
    StreamId streamId = NamespaceId.DEFAULT.stream("fooStream");
    // No owner info should exist for above stream
    Assert.assertNull(ownerStore.getOwner(streamId));
    // delete behavior is idempotent, so won't throw NotFoundException
    ownerStore.delete(streamId);
    // Storing an owner for the first time should work
    KerberosPrincipalId kerberosPrincipalId = new KerberosPrincipalId("alice/somehost@SOMEKDC.NET");
    ownerStore.add(streamId, kerberosPrincipalId);
    // owner principal should exists
    Assert.assertTrue(ownerStore.exists(streamId));
    // Should be able to get the principal back
    Assert.assertEquals(kerberosPrincipalId, ownerStore.getOwner(streamId));
    // Should not be able to update the owner principal
    try {
        ownerStore.add(streamId, new KerberosPrincipalId("bob@SOMEKDC.NET"));
        Assert.fail();
    } catch (AlreadyExistsException e) {
    // expected
    }
    // Should not be able to update the owner principal
    try {
        ownerStore.add(streamId, new KerberosPrincipalId("somePrincipal"));
        Assert.fail();
    } catch (AlreadyExistsException e) {
    // expected
    }
    // trying to update with invalid principal should fail early on with IllegalArgumentException
    try {
        ownerStore.add(streamId, new KerberosPrincipalId("b@ob@SOMEKDC.NET"));
        Assert.fail();
    } catch (IllegalArgumentException e) {
    // expected
    }
    // Trying to store owner information for unsupported type should fail
    try {
        ownerStore.add(NamespaceId.DEFAULT.topic("anotherStream"), new KerberosPrincipalId("somePrincipal"));
        Assert.fail();
    } catch (IllegalArgumentException e) {
    // expected
    }
    // delete the owner information
    ownerStore.delete(streamId);
    Assert.assertFalse(ownerStore.exists(streamId));
    Assert.assertNull(ownerStore.getOwner(streamId));
}
Also used : StreamId(co.cask.cdap.proto.id.StreamId) AlreadyExistsException(co.cask.cdap.common.AlreadyExistsException) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId) OwnerStore(co.cask.cdap.security.impersonation.OwnerStore) Test(org.junit.Test)

Example 15 with KerberosPrincipalId

use of co.cask.cdap.proto.id.KerberosPrincipalId in project cdap by caskdata.

the class AuthorizationUtil method getAppAuthorizingUser.

/**
 * Helper function to get the authorizing user for app deployment, the authorzing user will be the app owner if it
 * is present. If not, it will be the namespace owner. If that is also not present, it will be the user who is making
 * the request
 */
public static String getAppAuthorizingUser(OwnerAdmin ownerAdmin, AuthenticationContext authenticationContext, ApplicationId applicationId, @Nullable KerberosPrincipalId appOwner) throws IOException {
    KerberosPrincipalId effectiveOwner = SecurityUtil.getEffectiveOwner(ownerAdmin, applicationId.getNamespaceId(), appOwner == null ? null : appOwner.getPrincipal());
    // CDAP-13154 If impersonation is configured for either the application or namespace the effective owner will be
    // a kerberos principal which can have different form
    // (refer: https://docs.oracle.com/cd/E21455_01/common/tutorials/kerberos_principal.html). For example it can be
    // a complete principal name (alice/somehost.net@someREALM). For authorization we need the enforcement to happen
    // on the username and not the complete principal. The user name is the shortname of the principal so return the
    // shortname as authorizing user.
    String appAuthorizingUser = effectiveOwner != null ? new KerberosName(effectiveOwner.getPrincipal()).getShortName() : authenticationContext.getPrincipal().getName();
    LOG.trace("Returning {} as authorizing app user for {}", appAuthorizingUser, applicationId);
    return appAuthorizingUser;
}
Also used : KerberosName(org.apache.hadoop.security.authentication.util.KerberosName) KerberosPrincipalId(co.cask.cdap.proto.id.KerberosPrincipalId)

Aggregations

KerberosPrincipalId (co.cask.cdap.proto.id.KerberosPrincipalId)22 IOException (java.io.IOException)8 NamespaceId (co.cask.cdap.proto.id.NamespaceId)7 UnauthorizedException (co.cask.cdap.security.spi.authorization.UnauthorizedException)7 ExecutionException (java.util.concurrent.ExecutionException)6 NotFoundException (co.cask.cdap.common.NotFoundException)5 Principal (co.cask.cdap.proto.security.Principal)5 Nullable (javax.annotation.Nullable)5 DatasetManagementException (co.cask.cdap.api.dataset.DatasetManagementException)4 NamespaceNotFoundException (co.cask.cdap.common.NamespaceNotFoundException)4 ApplicationNotFoundException (co.cask.cdap.common.ApplicationNotFoundException)3 ArtifactAlreadyExistsException (co.cask.cdap.common.ArtifactAlreadyExistsException)3 ArtifactNotFoundException (co.cask.cdap.common.ArtifactNotFoundException)3 BadRequestException (co.cask.cdap.common.BadRequestException)3 InvalidArtifactException (co.cask.cdap.common.InvalidArtifactException)3 DatasetId (co.cask.cdap.proto.id.DatasetId)3 ApplicationSpecification (co.cask.cdap.api.app.ApplicationSpecification)2 ArtifactSummary (co.cask.cdap.api.artifact.ArtifactSummary)2 ConflictException (co.cask.cdap.common.ConflictException)2 AbstractBodyConsumer (co.cask.cdap.common.http.AbstractBodyConsumer)2