diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AppFabricServiceRuntimeModule.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AppFabricServiceRuntimeModule.java index 24c028a0471d..928438233031 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AppFabricServiceRuntimeModule.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AppFabricServiceRuntimeModule.java @@ -34,6 +34,7 @@ import com.google.inject.name.Named; import com.google.inject.name.Names; import com.google.inject.util.Modules; +import io.cdap.cdap.api.auditlogging.AuditLogPublisherService; import io.cdap.cdap.api.feature.FeatureFlagsProvider; import io.cdap.cdap.app.deploy.Configurator; import io.cdap.cdap.app.deploy.Manager; @@ -82,6 +83,7 @@ import io.cdap.cdap.gateway.handlers.VersionHandler; import io.cdap.cdap.gateway.handlers.WorkflowHttpHandler; import io.cdap.cdap.gateway.handlers.WorkflowStatsSLAHttpHandler; +import io.cdap.cdap.gateway.handlers.meta.AuditLogPublisherHandler; import io.cdap.cdap.gateway.handlers.meta.RemotePrivilegesHandler; import io.cdap.cdap.internal.app.deploy.ConfiguratorFactory; import io.cdap.cdap.internal.app.deploy.ConfiguratorFactoryProvider; @@ -152,6 +154,7 @@ import io.cdap.cdap.scheduler.CoreSchedulerService; import io.cdap.cdap.scheduler.Scheduler; import io.cdap.cdap.securestore.spi.SecretStore; +import io.cdap.cdap.security.auth.service.DefaultAuditLogPublisherService; import io.cdap.cdap.security.encryption.guice.DataStorageAeadEncryptionModule; import io.cdap.cdap.security.impersonation.DefaultOwnerAdmin; import io.cdap.cdap.security.impersonation.DefaultUGIProvider; @@ -434,6 +437,8 @@ protected void configure() { bind(EventWriterProvider.class).to(EventWriterExtensionProvider.class); bind(MetricsProvider.class).to(SparkProgramStatusMetricsProvider.class); + bind(AuditLogPublisherService.class).to(DefaultAuditLogPublisherService.class); + Multibinder handlerBinder = Multibinder.newSetBinder( binder(), HttpHandler.class, Names.named(Constants.AppFabric.HANDLERS_BINDING)); @@ -461,6 +466,7 @@ protected void configure() { handlerBinder.addBinding().to(AuthorizationHandler.class); handlerBinder.addBinding().to(SecureStoreHandler.class); handlerBinder.addBinding().to(RemotePrivilegesHandler.class); + handlerBinder.addBinding().to(AuditLogPublisherHandler.class); handlerBinder.addBinding().to(OperationalStatsHttpHandler.class); handlerBinder.addBinding().to(ProfileHttpHandler.class); handlerBinder.addBinding().to(ProvisionerHttpHandler.class); diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AuthorizationModule.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AuthorizationModule.java index da99a96b42de..73ae4a7fe119 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AuthorizationModule.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/AuthorizationModule.java @@ -27,6 +27,7 @@ import com.google.inject.assistedinject.FactoryModuleBuilder; import io.cdap.cdap.api.Admin; import io.cdap.cdap.api.Transactional; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.data.DatasetContext; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.api.security.store.SecureStoreManager; @@ -43,6 +44,7 @@ import io.cdap.cdap.security.authorization.DefaultAuthorizationContext; import io.cdap.cdap.security.authorization.DelegatingPermissionManager; import io.cdap.cdap.security.authorization.DelegatingRoleController; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.authorization.RoleController; import io.cdap.cdap.security.spi.authorization.AccessController; import io.cdap.cdap.security.spi.authorization.AuthorizationContext; diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/InMemoryProgramRunnerModule.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/InMemoryProgramRunnerModule.java index 9e892326aa31..e964cd3c602f 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/InMemoryProgramRunnerModule.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/guice/InMemoryProgramRunnerModule.java @@ -24,6 +24,7 @@ import com.google.inject.multibindings.MapBinder; import com.google.inject.name.Named; import io.cdap.cdap.api.artifact.ArtifactManager; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.app.runtime.ProgramRunner; import io.cdap.cdap.app.runtime.ProgramRunnerFactory; import io.cdap.cdap.app.runtime.ProgramRuntimeProvider; @@ -43,6 +44,8 @@ import io.cdap.cdap.proto.ProgramType; import java.net.InetAddress; import java.net.InetSocketAddress; + +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import org.apache.twill.api.ServiceAnnouncer; import org.apache.twill.common.Cancellable; import org.apache.twill.discovery.Discoverable; diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/preview/DefaultPreviewRunnerManager.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/preview/DefaultPreviewRunnerManager.java index d30b83c195b0..7bcf0fdc691c 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/app/preview/DefaultPreviewRunnerManager.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/app/preview/DefaultPreviewRunnerManager.java @@ -27,6 +27,7 @@ import com.google.inject.Scopes; import com.google.inject.name.Named; import com.google.inject.util.Modules; +import io.cdap.cdap.api.auditlogging.AuditLogPublisherService; import io.cdap.cdap.api.security.store.SecureStore; import io.cdap.cdap.app.guice.ProgramRunnerRuntimeModule; import io.cdap.cdap.common.NotFoundException; @@ -55,6 +56,7 @@ import io.cdap.cdap.metrics.guice.MetricsClientRuntimeModule; import io.cdap.cdap.proto.id.ApplicationId; import io.cdap.cdap.security.auth.context.AuthenticationContextModules; +import io.cdap.cdap.security.auth.service.DefaultAuditLogPublisherService; import io.cdap.cdap.security.guice.CoreSecurityRuntimeModule; import io.cdap.cdap.security.guice.preview.PreviewSecureStoreModule; import java.net.InetAddress; @@ -194,6 +196,12 @@ protected void configure() { bind(LogAppender.class).to(PreviewTMSLogAppender.class).in(Scopes.SINGLETON); } }, + new AbstractModule() { + @Override + protected void configure() { + bind(AuditLogPublisherService.class).to(DefaultAuditLogPublisherService.class).in(Scopes.SINGLETON); + } + }, new MessagingServerRuntimeModule().getInMemoryModules(), Modules.override(new MetadataReaderWriterModules().getInMemoryModules()) .with(new AbstractModule() { diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/gateway/handlers/meta/AuditLogPublisherHandler.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/gateway/handlers/meta/AuditLogPublisherHandler.java new file mode 100644 index 000000000000..86d597b1a3a2 --- /dev/null +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/gateway/handlers/meta/AuditLogPublisherHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2016-2021 Cask Data, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package io.cdap.cdap.gateway.handlers.meta; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import io.cdap.cdap.api.auditlogging.AuditLogPublisherService; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; +import io.cdap.http.HttpResponder; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingDeque; +import javax.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +/** + * An HTTP Handler that runs inside the master and communicates with + * {@link AuditLogPublisherService} to send the audit logs received to publish. + * + */ +@Path(AbstractRemoteSystemOpsHandler.VERSION + "/execute") +public class AuditLogPublisherHandler extends AbstractRemoteSystemOpsHandler { + + private static final Logger LOG = LoggerFactory.getLogger(AuditLogPublisherHandler.class); + private final AuditLogPublisherService auditLogPublisherService; + + @Inject + AuditLogPublisherHandler(AuditLogPublisherService auditLogPublisherService) { + this.auditLogPublisherService = auditLogPublisherService; + } + + @POST + @Path("/publishbatch") + public void publishBatch(FullHttpRequest request, HttpResponder responder) throws Exception { + LOG.debug("SANKET in handler publishbatch for {}", request.content().toString(StandardCharsets.UTF_8)); + Type queueType = new TypeToken>(){}.getType(); + Queue deserializedQueue = + new Gson().fromJson(request.content().toString(StandardCharsets.UTF_8), queueType); + LOG.debug("SANKET in handler publishbatch , q size {}", deserializedQueue.size()); + auditLogPublisherService.addAuditContexts(deserializedQueue); + responder.sendStatus(HttpResponseStatus.OK); + } +} diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/DefaultPreviewManager.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/DefaultPreviewManager.java index 44e7ebcafda1..9f0d5c271cf8 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/DefaultPreviewManager.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/DefaultPreviewManager.java @@ -31,6 +31,7 @@ import com.google.inject.name.Names; import com.google.inject.util.Modules; import io.cdap.cdap.api.annotation.Name; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.api.security.AccessException; import io.cdap.cdap.app.preview.PreviewConfigModule; @@ -93,6 +94,7 @@ import io.cdap.cdap.security.auth.context.AuthenticationContextModules; import io.cdap.cdap.security.authorization.AccessControllerInstantiator; import io.cdap.cdap.security.authorization.DefaultContextAccessEnforcer; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.guice.CoreSecurityRuntimeModule; import io.cdap.cdap.security.impersonation.DefaultOwnerAdmin; import io.cdap.cdap.security.impersonation.DefaultUGIProvider; @@ -388,6 +390,7 @@ protected void configure() { bind(LevelDBTableService.class).toInstance(previewLevelDBTableService); bind(RemoteExecutionLogProcessor.class).to(LogAppenderLogProcessor.class) .in(Scopes.SINGLETON); + bind(AuditLogPublisher.class).to(RemoteAuditLogPublisher.class).in(Scopes.SINGLETON); } @Provides diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/PreviewRunnerTwillRunnable.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/PreviewRunnerTwillRunnable.java index 80bf2cb202c8..d32c10ade249 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/PreviewRunnerTwillRunnable.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/preview/PreviewRunnerTwillRunnable.java @@ -30,6 +30,7 @@ import com.google.inject.Module; import com.google.inject.Scopes; import com.google.inject.assistedinject.FactoryModuleBuilder; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.common.Bytes; import io.cdap.cdap.app.deploy.Configurator; import io.cdap.cdap.app.preview.PreviewConfigModule; @@ -70,6 +71,7 @@ import io.cdap.cdap.proto.id.NamespaceId; import io.cdap.cdap.security.auth.context.AuthenticationContextModules; import io.cdap.cdap.security.authorization.AuthorizationEnforcementModule; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.guice.SecureStoreClientModule; import io.cdap.cdap.security.impersonation.CurrentUGIProvider; import io.cdap.cdap.security.impersonation.UGIProvider; @@ -267,6 +269,7 @@ protected void configure() { bind(ArtifactLocalizerClient.class).in(Scopes.SINGLETON); // Preview runner pods should not have any elevated privileges, so use the current UGI. bind(UGIProvider.class).to(CurrentUGIProvider.class); + bind(AuditLogPublisher.class).to(RemoteAuditLogPublisher.class).in(Scopes.SINGLETON); } }); diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/TaskWorkerTwillRunnable.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/TaskWorkerTwillRunnable.java index aaa219c3e947..eeeaee8106aa 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/TaskWorkerTwillRunnable.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/TaskWorkerTwillRunnable.java @@ -25,6 +25,8 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; +import com.google.inject.Scopes; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.common.conf.CConfiguration; import io.cdap.cdap.common.conf.Constants; @@ -48,6 +50,7 @@ import io.cdap.cdap.metrics.guice.MetricsClientRuntimeModule; import io.cdap.cdap.proto.id.NamespaceId; import io.cdap.cdap.security.auth.context.AuthenticationContextModules; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.guice.CoreSecurityModule; import io.cdap.cdap.security.guice.CoreSecurityRuntimeModule; import java.io.File; @@ -115,6 +118,7 @@ protected void configure() { bind(DiscoveryServiceClient.class) .toProvider( new SupplierProviderBridge<>(masterEnv.getDiscoveryServiceClientSupplier())); + bind(AuditLogPublisher.class).to(RemoteAuditLogPublisher.class).in(Scopes.SINGLETON); } }); modules.add(new RemoteLogAppenderModule()); diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/sidecar/ArtifactLocalizerTwillRunnable.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/sidecar/ArtifactLocalizerTwillRunnable.java index 584b0c9943c3..22beab3043a6 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/sidecar/ArtifactLocalizerTwillRunnable.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/sidecar/ArtifactLocalizerTwillRunnable.java @@ -25,6 +25,8 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; +import com.google.inject.Scopes; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.feature.FeatureFlagsProvider; import io.cdap.cdap.app.guice.DistributedArtifactManagerModule; import io.cdap.cdap.common.conf.CConfiguration; @@ -53,6 +55,7 @@ import io.cdap.cdap.proto.id.NamespaceId; import io.cdap.cdap.security.auth.TokenManager; import io.cdap.cdap.security.auth.context.AuthenticationContextModules; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.guice.CoreSecurityModule; import io.cdap.cdap.security.guice.CoreSecurityRuntimeModule; import java.io.File; @@ -133,6 +136,7 @@ protected void configure() { bind(DiscoveryServiceClient.class) .toProvider( new SupplierProviderBridge<>(masterEnv.getDiscoveryServiceClientSupplier())); + bind(AuditLogPublisher.class).to(RemoteAuditLogPublisher.class).in(Scopes.SINGLETON); } }); modules.add(new RemoteLogAppenderModule()); diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/system/SystemWorkerTwillRunnable.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/system/SystemWorkerTwillRunnable.java index b59f84d86c4b..883195dc7b0e 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/system/SystemWorkerTwillRunnable.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/internal/app/worker/system/SystemWorkerTwillRunnable.java @@ -31,6 +31,7 @@ import com.google.inject.multibindings.OptionalBinder; import com.google.inject.util.Modules; import io.cdap.cdap.api.artifact.ArtifactManager; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.app.guice.AppFabricServiceRuntimeModule; import io.cdap.cdap.app.guice.AuthorizationModule; @@ -84,6 +85,7 @@ import io.cdap.cdap.security.auth.KeyManager; import io.cdap.cdap.security.auth.context.AuthenticationContextModules; import io.cdap.cdap.security.authorization.AuthorizationEnforcementModule; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.guice.CoreSecurityModule; import io.cdap.cdap.security.guice.FileBasedCoreSecurityModule; import io.cdap.cdap.security.guice.SecureStoreClientModule; @@ -189,6 +191,7 @@ protected void configure() { protected void configure() { bind(MetadataPublisher.class).to(MessagingMetadataPublisher.class); bind(MetadataServiceClient.class).to(DefaultMetadataServiceClient.class); + bind(AuditLogPublisher.class).to(RemoteAuditLogPublisher.class).in(Scopes.SINGLETON); } } )); diff --git a/cdap-app-fabric/src/main/java/io/cdap/cdap/master/environment/k8s/AbstractServiceMain.java b/cdap-app-fabric/src/main/java/io/cdap/cdap/master/environment/k8s/AbstractServiceMain.java index 33de125eac3d..2e4b85a92c15 100644 --- a/cdap-app-fabric/src/main/java/io/cdap/cdap/master/environment/k8s/AbstractServiceMain.java +++ b/cdap-app-fabric/src/main/java/io/cdap/cdap/master/environment/k8s/AbstractServiceMain.java @@ -26,6 +26,9 @@ import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; +import com.google.inject.Scopes; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; +import io.cdap.cdap.api.auditlogging.AuditLogPublisherService; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.app.preview.PreviewConfigModule; import io.cdap.cdap.common.app.MainClassLoader; @@ -55,6 +58,7 @@ import io.cdap.cdap.metrics.guice.MetricsClientRuntimeModule; import io.cdap.cdap.security.auth.TokenManager; import io.cdap.cdap.security.auth.context.AuthenticationContextModules; +import io.cdap.cdap.security.authorization.RemoteAuditLogPublisher; import io.cdap.cdap.security.guice.CoreSecurityModule; import io.cdap.cdap.security.guice.CoreSecurityRuntimeModule; import io.cdap.cdap.security.impersonation.SecurityUtil; @@ -179,7 +183,12 @@ protected void configure() { } }); modules.add(getLogAppenderModule()); - + modules.add(new AbstractModule() { + @Override + protected void configure() { + bind(AuditLogPublisher.class).to(RemoteAuditLogPublisher.class).in(Scopes.SINGLETON); + } + }); CoreSecurityModule coreSecurityModule = CoreSecurityRuntimeModule.getDistributedModule(cConf); modules.add(coreSecurityModule); if (coreSecurityModule.requiresZKClient()) { @@ -202,6 +211,7 @@ protected void configure() { // Add Services services.add(injector.getInstance(MetricsCollectionService.class)); + if (SecurityUtil.isInternalAuthEnabled(cConf)) { services.add(injector.getInstance(TokenManager.class)); } diff --git a/cdap-common/src/main/java/io/cdap/cdap/api/auditlogging/AuditLogPublisher.java b/cdap-common/src/main/java/io/cdap/cdap/api/auditlogging/AuditLogPublisher.java new file mode 100644 index 000000000000..ad874256b812 --- /dev/null +++ b/cdap-common/src/main/java/io/cdap/cdap/api/auditlogging/AuditLogPublisher.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2024 Cask Data, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package io.cdap.cdap.api.auditlogging; + + +import com.google.common.util.concurrent.Service; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; + +import java.util.Queue; + + +/** + * Service to publish audit log to central audit log service in app fabric + */ +public interface AuditLogPublisher { + + /** + * pushes the log entry to respective external service + */ + void publish(Queue auditLogContexts); +} \ No newline at end of file diff --git a/cdap-common/src/main/java/io/cdap/cdap/api/auditlogging/AuditLogPublisherService.java b/cdap-common/src/main/java/io/cdap/cdap/api/auditlogging/AuditLogPublisherService.java new file mode 100644 index 000000000000..d7b94f567dbe --- /dev/null +++ b/cdap-common/src/main/java/io/cdap/cdap/api/auditlogging/AuditLogPublisherService.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2024 Cask Data, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package io.cdap.cdap.api.auditlogging; + + +import com.google.common.util.concurrent.Service; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; + +import java.io.IOException; +import java.util.Queue; + + +/** + * Service to batch and publish audit log to external auth service. + */ +public interface AuditLogPublisherService extends Service { + + /** + * pushes the log entry to respective external service + */ + void publish() throws IOException; + + /** + * add to service's pending list for publishing + */ + void addAuditContexts(Queue auditLogContextQueue); +} \ No newline at end of file diff --git a/cdap-common/src/main/java/io/cdap/cdap/common/conf/Constants.java b/cdap-common/src/main/java/io/cdap/cdap/common/conf/Constants.java index fbe8cd91d5e4..77d2df79a1f4 100644 --- a/cdap-common/src/main/java/io/cdap/cdap/common/conf/Constants.java +++ b/cdap-common/src/main/java/io/cdap/cdap/common/conf/Constants.java @@ -2540,4 +2540,11 @@ public static final class Operation { public static final String ERROR_NOTIFICATION_KEY = "operation.notification.error"; public static final String USER_ID_NOTIFICATION_KEY = "userId"; } + + /** + * Constants for Data Plane Audit Logging + */ + public static final class AuditLogging { + public static final String AUDIT_LOG_PUBLISH_INTERVAL_SECONDS = "auditlog.publish.interval.seconds"; + } } diff --git a/cdap-common/src/main/java/io/cdap/cdap/common/http/AuthenticationChannelHandler.java b/cdap-common/src/main/java/io/cdap/cdap/common/http/AuthenticationChannelHandler.java index d1e1b3d1f07a..9b70148ee08f 100644 --- a/cdap-common/src/main/java/io/cdap/cdap/common/http/AuthenticationChannelHandler.java +++ b/cdap-common/src/main/java/io/cdap/cdap/common/http/AuthenticationChannelHandler.java @@ -16,13 +16,16 @@ package io.cdap.cdap.common.http; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.common.conf.Constants; import io.cdap.cdap.proto.security.Credential; import io.cdap.cdap.security.spi.authentication.SecurityRequestContext; import io.cdap.cdap.security.spi.authentication.UnauthenticatedException; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; +import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelPromise; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; @@ -36,7 +39,7 @@ * An UpstreamHandler that verifies the userId in a request header and updates the {@code * SecurityRequestContext}. */ -public class AuthenticationChannelHandler extends ChannelInboundHandlerAdapter { +public class AuthenticationChannelHandler extends ChannelDuplexHandler { private static final Logger LOG = LoggerFactory.getLogger(AuthenticationChannelHandler.class); @@ -47,9 +50,14 @@ public class AuthenticationChannelHandler extends ChannelInboundHandlerAdapter { private static final String EMPTY_USER_IP = "CDAP-empty-user-ip"; private final boolean internalAuthEnabled; + private final boolean auditLoggingEnabled; + private final AuditLogPublisher auditLogPublisher; - public AuthenticationChannelHandler(boolean internalAuthEnabled) { + public AuthenticationChannelHandler(boolean internalAuthEnabled, boolean auditLoggingEnabled, + AuditLogPublisher auditLogPublisher) { this.internalAuthEnabled = internalAuthEnabled; + this.auditLoggingEnabled = auditLoggingEnabled; + this.auditLogPublisher = auditLogPublisher; } /** @@ -118,14 +126,22 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception SecurityRequestContext.setUserIp(currentUserIp); } + ctx.fireChannelRead(msg); + } + + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + try { - ctx.fireChannelRead(msg); + if (auditLoggingEnabled && msg instanceof HttpResponse) { + auditLogPublisher.publish(SecurityRequestContext.getAuditLogQueue()); + } + super.write(ctx, msg, promise); } finally { SecurityRequestContext.reset(); } } - @Override + @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { LOG.error("Got exception: {}", cause.getMessage(), cause); // TODO: add WWW-Authenticate header for 401 response - REACTOR-900 diff --git a/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceBuilder.java b/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceBuilder.java index 70b8125c1708..656dedfd9d13 100644 --- a/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceBuilder.java +++ b/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceBuilder.java @@ -15,11 +15,15 @@ */ package io.cdap.cdap.common.http; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; +import io.cdap.cdap.api.feature.FeatureFlagsProvider; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.common.HttpExceptionHandler; import io.cdap.cdap.common.conf.CConfiguration; import io.cdap.cdap.common.conf.Constants; +import io.cdap.cdap.common.feature.DefaultFeatureFlagsProvider; import io.cdap.cdap.common.metrics.MetricsReporterHook; +import io.cdap.cdap.features.Feature; import io.cdap.http.ChannelPipelineModifier; import io.cdap.http.NettyHttpService; import io.netty.channel.ChannelPipeline; @@ -28,7 +32,7 @@ import javax.annotation.Nullable; /** - * Provides a {@link io.cdap.http.NettyHttpService.Builder} that has common settings built-in. + * Provides a {@link NettyHttpService.Builder} that has common settings built-in. */ public class CommonNettyHttpServiceBuilder extends NettyHttpService.Builder { @@ -38,9 +42,12 @@ public class CommonNettyHttpServiceBuilder extends NettyHttpService.Builder { private ChannelPipelineModifier additionalModifier; public CommonNettyHttpServiceBuilder(CConfiguration cConf, String serviceName, - MetricsCollectionService metricsCollectionService) { + MetricsCollectionService metricsCollectionService, AuditLogPublisher auditLogPublisher) { super(serviceName); if (cConf.getBoolean(Constants.Security.ENABLED)) { + + FeatureFlagsProvider featureFlagsProvider = new DefaultFeatureFlagsProvider(cConf); + boolean auditLoggingEnabled = Feature.DATAPLANE_AUDIT_LOGGING.isEnabled(featureFlagsProvider) ; pipelineModifier = new ChannelPipelineModifier() { @Override public void modify(ChannelPipeline pipeline) { @@ -51,7 +58,7 @@ public void modify(ChannelPipeline pipeline) { EventExecutor executor = pipeline.context("dispatcher").executor(); pipeline.addBefore(executor, "dispatcher", AUTHENTICATOR_NAME, new AuthenticationChannelHandler(cConf.getBoolean(Constants.Security - .INTERNAL_AUTH_ENABLED))); + .INTERNAL_AUTH_ENABLED), auditLoggingEnabled, auditLogPublisher)); } }; } @@ -60,6 +67,12 @@ public void modify(ChannelPipeline pipeline) { new MetricsReporterHook(cConf, metricsCollectionService, serviceName))); } + //TODO : Remove , this is for compiling test classes + public CommonNettyHttpServiceBuilder(CConfiguration cConf, String serviceName, + MetricsCollectionService metricsCollectionService) { + this(cConf, serviceName, metricsCollectionService, null); + } + /** * Sets pipeline modifier, preserving the security one installed in constructor. */ diff --git a/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceFactory.java b/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceFactory.java index 83e3225962b6..5e817601fa39 100644 --- a/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceFactory.java +++ b/cdap-common/src/main/java/io/cdap/cdap/common/http/CommonNettyHttpServiceFactory.java @@ -17,6 +17,7 @@ package io.cdap.cdap.common.http; import com.google.inject.Inject; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; import io.cdap.cdap.api.metrics.MetricsCollectionService; import io.cdap.cdap.common.conf.CConfiguration; @@ -28,12 +29,23 @@ public class CommonNettyHttpServiceFactory { private final CConfiguration cConf; private final MetricsCollectionService metricsCollectionService; + private final AuditLogPublisher auditLogPublisher; @Inject public CommonNettyHttpServiceFactory(CConfiguration cConf, - MetricsCollectionService metricsCollectionService) { + MetricsCollectionService metricsCollectionService, + AuditLogPublisher auditLogPublisher) { this.cConf = cConf; this.metricsCollectionService = metricsCollectionService; + this.auditLogPublisher = auditLogPublisher; + } + + //TODO : remove + public CommonNettyHttpServiceFactory(CConfiguration cConf, + MetricsCollectionService metricsCollectionService) { + this.cConf = cConf; + this.metricsCollectionService = metricsCollectionService; + this.auditLogPublisher = null; } /** @@ -43,6 +55,6 @@ public CommonNettyHttpServiceFactory(CConfiguration cConf, * @return {@link CommonNettyHttpServiceBuilder} */ public CommonNettyHttpServiceBuilder builder(String serviceName) { - return new CommonNettyHttpServiceBuilder(cConf, serviceName, metricsCollectionService); + return new CommonNettyHttpServiceBuilder(cConf, serviceName, metricsCollectionService, auditLogPublisher); } } diff --git a/cdap-common/src/main/resources/cdap-default.xml b/cdap-common/src/main/resources/cdap-default.xml index 2f5180d2cef3..9e8eae9947be 100644 --- a/cdap-common/src/main/resources/cdap-default.xml +++ b/cdap-common/src/main/resources/cdap-default.xml @@ -6021,6 +6021,14 @@ + + feature.dataplane.audit.logging.enabled + true + + Enables dataplane audit logging for RBAC instances. + + + artifact.cache.bind.address 0.0.0.0 @@ -6428,4 +6436,12 @@ + + auditlog.publish.interval.seconds + 20 + + The interval between Audit log publish calls to external auth in seconds. + + + diff --git a/cdap-common/src/test/java/io/cdap/cdap/common/http/AuthenticationChannelHandlerTest.java b/cdap-common/src/test/java/io/cdap/cdap/common/http/AuthenticationChannelHandlerTest.java index 4f739f5a04fa..f623dc5104b2 100644 --- a/cdap-common/src/test/java/io/cdap/cdap/common/http/AuthenticationChannelHandlerTest.java +++ b/cdap-common/src/test/java/io/cdap/cdap/common/http/AuthenticationChannelHandlerTest.java @@ -41,7 +41,7 @@ public class AuthenticationChannelHandlerTest { @Before public void initHandler() { boolean internalAuthEnabled = true; - handler = new AuthenticationChannelHandler(internalAuthEnabled); + handler = new AuthenticationChannelHandler(internalAuthEnabled, false, null); ctx = mock(ChannelHandlerContext.class, RETURNS_DEEP_STUBS); req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "foo"); } diff --git a/cdap-data-fabric/src/main/java/io/cdap/cdap/data/runtime/DataSetServiceModules.java b/cdap-data-fabric/src/main/java/io/cdap/cdap/data/runtime/DataSetServiceModules.java index 4885492c3faf..827e54834ea6 100644 --- a/cdap-data-fabric/src/main/java/io/cdap/cdap/data/runtime/DataSetServiceModules.java +++ b/cdap-data-fabric/src/main/java/io/cdap/cdap/data/runtime/DataSetServiceModules.java @@ -196,6 +196,7 @@ protected void configure() { bind(DatasetTypeService.class).to(AuthorizationDatasetTypeService.class); expose(DatasetTypeService.class); + } }); } diff --git a/cdap-features/src/main/java/io/cdap/cdap/features/Feature.java b/cdap-features/src/main/java/io/cdap/cdap/features/Feature.java index a1b79703135f..292f54e64af3 100644 --- a/cdap-features/src/main/java/io/cdap/cdap/features/Feature.java +++ b/cdap-features/src/main/java/io/cdap/cdap/features/Feature.java @@ -44,7 +44,8 @@ public enum Feature { WRANGLER_SCHEMA_MANAGEMENT("6.10.0"), NAMESPACED_SERVICE_ACCOUNTS("6.10.0"), WRANGLER_KRYO_SERIALIZATION("6.10.1"), - SOURCE_CONTROL_MANAGEMENT_GITLAB_BITBUCKET("6.10.1"); + SOURCE_CONTROL_MANAGEMENT_GITLAB_BITBUCKET("6.10.1"), + DATAPLANE_AUDIT_LOGGING("6.10.1"); private final PlatformInfo.Version versionIntroduced; private final boolean defaultAfterIntroduction; diff --git a/cdap-master/src/main/java/io/cdap/cdap/master/environment/k8s/AppFabricServiceMain.java b/cdap-master/src/main/java/io/cdap/cdap/master/environment/k8s/AppFabricServiceMain.java index 1e5fb4eef6a8..94ec2a0ce575 100644 --- a/cdap-master/src/main/java/io/cdap/cdap/master/environment/k8s/AppFabricServiceMain.java +++ b/cdap-master/src/main/java/io/cdap/cdap/master/environment/k8s/AppFabricServiceMain.java @@ -24,6 +24,7 @@ import com.google.inject.Module; import com.google.inject.Scopes; import com.google.inject.util.Modules; +import io.cdap.cdap.api.auditlogging.AuditLogPublisherService; import io.cdap.cdap.app.guice.AppFabricServiceRuntimeModule; import io.cdap.cdap.app.guice.AuthorizationModule; import io.cdap.cdap.app.guice.MonitorHandlerModule; @@ -60,6 +61,7 @@ import io.cdap.cdap.operations.OperationalStatsService; import io.cdap.cdap.operations.guice.OperationalStatsModule; import io.cdap.cdap.proto.id.NamespaceId; +import io.cdap.cdap.security.auth.service.DefaultAuditLogPublisherService; import io.cdap.cdap.security.authorization.AccessControllerInstantiator; import io.cdap.cdap.security.authorization.AuthorizationEnforcementModule; import io.cdap.cdap.security.guice.SecureStoreServerModule; @@ -123,6 +125,7 @@ protected void configure() { // TODO (CDAP-14677): find a better way to inject metadata publisher bind(MetadataPublisher.class).to(MessagingMetadataPublisher.class); bind(MetadataServiceClient.class).to(DefaultMetadataServiceClient.class); + bind(AuditLogPublisherService.class).to(DefaultAuditLogPublisherService.class); } } ); @@ -158,6 +161,8 @@ protected void addServices(Injector injector, List services, () -> injector.getInstance(NamespaceInitializerService.class), RetryStrategies.exponentialDelay(200, 5000, TimeUnit.MILLISECONDS))); + services.add(injector.getInstance(AuditLogPublisherService.class)); + if (cConf.getBoolean(Constants.TaskWorker.POOL_ENABLE)) { services.add(injector.getInstance(TaskWorkerServiceLauncher.class)); } diff --git a/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authentication/SecurityRequestContext.java b/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authentication/SecurityRequestContext.java index 4ff21a9b085b..0c6b670bfade 100644 --- a/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authentication/SecurityRequestContext.java +++ b/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authentication/SecurityRequestContext.java @@ -131,4 +131,12 @@ public static void enqueueAuditLogContext(AuditLogContext auditLog) { public static void clearAuditLogQueue(AuditLogContext auditLog) { auditLogContextQueue.remove(); } + + public static Queue getAuditLogQueue() { + Queue queue = auditLogContextQueue.get(); + if (queue == null) { + return new ArrayDeque<>(); + } + return queue; + } } diff --git a/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AccessControllerSpi.java b/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AccessControllerSpi.java index 46fb21f00138..9358af7868c3 100644 --- a/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AccessControllerSpi.java +++ b/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AccessControllerSpi.java @@ -50,7 +50,8 @@ * This is newer version of {@link AccessController} */ @Beta -public interface AccessControllerSpi extends PermissionManagerSpi, RoleControllerSpi, AccessEnforcerSpi { +public interface AccessControllerSpi extends PermissionManagerSpi, RoleControllerSpi, AccessEnforcerSpi, + AuditLoggerSpi { /** * Initialize the {@link AccessControllerSpi}. Authorization extensions can use this method to access diff --git a/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AuditLoggerSpi.java b/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AuditLoggerSpi.java new file mode 100644 index 000000000000..5663628d6674 --- /dev/null +++ b/cdap-security-spi/src/main/java/io/cdap/cdap/security/spi/authorization/AuditLoggerSpi.java @@ -0,0 +1,27 @@ +package io.cdap.cdap.security.spi.authorization; + +import io.cdap.cdap.api.annotation.Beta; + +import java.util.Queue; + +/** + * An SPI that delegates the collection of {@link AuditLogContext}s to an extension that will publish the log events + * to the respective destination. + */ +@Beta +public interface AuditLoggerSpi { + /** + * The status of a call for authorization check. + */ + enum PublishStatus { + PUBLISHED, + UNSUCCESSFUL + } + + /** + * TODO : THIS IS WIP : Needs to be modified based on how auth extension works. + * @return {@link PublishStatus} + */ + PublishStatus publish(Queue auditLogContexts); + +} diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/auth/service/DefaultAuditLogPublisherService.java b/cdap-security/src/main/java/io/cdap/cdap/security/auth/service/DefaultAuditLogPublisherService.java new file mode 100644 index 000000000000..2a270fcba724 --- /dev/null +++ b/cdap-security/src/main/java/io/cdap/cdap/security/auth/service/DefaultAuditLogPublisherService.java @@ -0,0 +1,90 @@ +/* + * Copyright © 2024 Cask Data, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package io.cdap.cdap.security.auth.service; + +import com.google.common.util.concurrent.AbstractScheduledService; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import io.cdap.cdap.api.auditlogging.AuditLogPublisherService; +import io.cdap.cdap.common.conf.CConfiguration; +import io.cdap.cdap.common.conf.Constants; +import io.cdap.cdap.common.service.AbstractRetryableScheduledService; +import io.cdap.cdap.common.service.RetryStrategies; +import io.cdap.cdap.security.authorization.AccessControllerInstantiator; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; +import io.cdap.cdap.security.spi.authorization.AuditLoggerSpi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The default implementation of {@link AuditLogPublisherService} , which runs in the app-fabric and receives + * a collection of {@link AuditLogContext}s . This class is responsible to store them in a queue and timely publish + * them to an SPI. + */ +@Singleton +public class DefaultAuditLogPublisherService extends AbstractRetryableScheduledService + implements AuditLogPublisherService { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultAuditLogPublisherService.class); + private final int publishIntervalSeconds; + private static AtomicBoolean publishing = new AtomicBoolean(false); + private ScheduledExecutorService executor; + private final AccessControllerInstantiator accessControllerInstantiator; + + Queue auditLogContextQueue = new LinkedBlockingDeque<>(); + + @Inject + public DefaultAuditLogPublisherService(CConfiguration conf, + AccessControllerInstantiator accessControllerInstantiator) { + super(RetryStrategies.exponentialDelay(10, 200, TimeUnit.MILLISECONDS)); + this.accessControllerInstantiator = accessControllerInstantiator; + this.publishIntervalSeconds = conf.getInt(Constants.AuditLogging.AUDIT_LOG_PUBLISH_INTERVAL_SECONDS); + } + + /** + * Runs the task in one scheduled iteration. + * + * @return the number of milliseconds to delay until the next call to this method + * @throws Exception if the task failed + */ + @Override + protected long runTask() throws Exception { + publish(); + return publishIntervalSeconds; + } + + @Override + public synchronized void publish() throws IOException { + AuditLoggerSpi.PublishStatus publishStatus = this.accessControllerInstantiator.get().publish(auditLogContextQueue); + if (!publishStatus.equals(AuditLoggerSpi.PublishStatus.PUBLISHED)){ + throw new IOException(); + } + auditLogContextQueue.clear(); + } + + @Override + public void addAuditContexts(Queue q) { + auditLogContextQueue.addAll(q); + } +} \ No newline at end of file diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java index 7964eac036ba..5a6307d727f0 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/AccessControllerWrapper.java @@ -34,6 +34,7 @@ import io.cdap.cdap.security.spi.authorization.UnauthorizedException; import java.util.Collections; import java.util.Map; +import java.util.Queue; import java.util.Set; import java.util.stream.Collectors; @@ -259,4 +260,13 @@ private AuthorizationResponse createAuthResultFromUnauthorizedExp(UnauthorizedEx .setAddendum(e.getAddendum()) .build(); } + + /** + * TODO : THIS IS WIP : Needs to be modified based on how auth extension works. + * @return {@link PublishStatus} + */ + @Override + public PublishStatus publish(Queue auditLogContexts) { + return PublishStatus.PUBLISHED; + } } diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/NoOpAccessControllerV2.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/NoOpAccessControllerV2.java index 3353f73c29a8..a4aa20b5f357 100644 --- a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/NoOpAccessControllerV2.java +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/NoOpAccessControllerV2.java @@ -24,10 +24,12 @@ import io.cdap.cdap.proto.security.Principal; import io.cdap.cdap.proto.security.Role; import io.cdap.cdap.security.spi.authorization.AccessControllerSpi; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; import io.cdap.cdap.security.spi.authorization.AuthorizationResponse; import io.cdap.cdap.security.spi.authorization.AuthorizedResult; import java.util.Collections; import java.util.Map; +import java.util.Queue; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -119,4 +121,16 @@ public AuthorizedResult> listAllRoles(Principal caller) { public AuthorizedResult> listGrants(Principal principal, Principal caller) { return new AuthorizedResult<>(Collections.emptySet(), AuthorizationResponse.Builder.defaultNotRequired()); } + + /** + * TODO : THIS IS WIP : Needs to be modified based on how auth extension works. + * + * @param auditLogContexts + * @return {@link PublishStatus} + */ + @Override + public PublishStatus publish(Queue auditLogContexts) { + //no-op + return PublishStatus.PUBLISHED; + } } diff --git a/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAuditLogPublisher.java b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAuditLogPublisher.java new file mode 100644 index 000000000000..f131c9e3115f --- /dev/null +++ b/cdap-security/src/main/java/io/cdap/cdap/security/authorization/RemoteAuditLogPublisher.java @@ -0,0 +1,50 @@ +/* + * Copyright © 2016-2018 Cask Data, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package io.cdap.cdap.security.authorization; + +import com.google.inject.Inject; +import io.cdap.cdap.api.auditlogging.AuditLogPublisher; +import io.cdap.cdap.common.conf.Constants; +import io.cdap.cdap.common.internal.remote.RemoteClientFactory; +import io.cdap.cdap.common.internal.remote.RemoteOpsClient; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; +import io.cdap.cdap.security.spi.authorization.UnauthorizedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Queue; + +/** + * + */ +public class RemoteAuditLogPublisher extends RemoteOpsClient implements AuditLogPublisher { + + private static final Logger LOG = LoggerFactory.getLogger(RemoteAuditLogPublisher.class); + + @Inject + RemoteAuditLogPublisher(RemoteClientFactory remoteClientFactory) { + super(remoteClientFactory, Constants.Service.APP_FABRIC_HTTP); + } + + public void publish(Queue auditLogContexts) + throws UnauthorizedException { + if (!auditLogContexts.isEmpty()) { + LOG.warn("SANKET : Got audit log more than 1"); + executeRequest("publishbatch", auditLogContexts); + } + } +} diff --git a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerInstantiatorTest.java b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerInstantiatorTest.java index 2af83be3eef3..1e2f900b9796 100644 --- a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerInstantiatorTest.java +++ b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/AccessControllerInstantiatorTest.java @@ -36,6 +36,7 @@ import io.cdap.cdap.security.spi.authentication.AuthenticationContext; import io.cdap.cdap.security.spi.authorization.AccessController; import io.cdap.cdap.security.spi.authorization.AccessControllerSpi; +import io.cdap.cdap.security.spi.authorization.AuditLogContext; import io.cdap.cdap.security.spi.authorization.AuthorizationContext; import io.cdap.cdap.security.spi.authorization.AuthorizationResponse; import io.cdap.cdap.security.spi.authorization.AuthorizedResult; @@ -48,6 +49,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Queue; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarEntry; @@ -596,5 +598,10 @@ public AuthorizedResult> listGrants(Principal caller, Pri throws AccessException { return null; } + + @Override + public PublishStatus publish(Queue auditLogContexts) { + return null; + } } } diff --git a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAccessControllerV2.java b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAccessControllerV2.java index 3bd760bd02a0..6793d0af8a8b 100644 --- a/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAccessControllerV2.java +++ b/cdap-security/src/test/java/io/cdap/cdap/security/authorization/InMemoryAccessControllerV2.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Objects; import java.util.Properties; +import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -286,6 +287,17 @@ private boolean isParent(EntityId guessingParent, Map guessi return true; } + /** + * TODO : THIS IS WIP : Needs to be modified based on how we want handle publishing internally. + * + * @param auditLogContexts + * @return {@link PublishStatus} + */ + @Override + public PublishStatus publish(Queue auditLogContexts) { + return PublishStatus.PUBLISHED; + } + public final class AuthorizableEntityId { private final EntityId entityId;