Skip to content

Commit

Permalink
Make PreEnforcerProvider and all PreEnforcer a configurable DittoExte…
Browse files Browse the repository at this point in the history
…nsionPoint

Signed-off-by: Yannic Klem <yannic.klem@bosch.io>
  • Loading branch information
Yannic92 committed Jul 13, 2022
1 parent ddff687 commit 4ee6520
Show file tree
Hide file tree
Showing 35 changed files with 254 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;

import akka.actor.AbstractExtensionId;
import akka.actor.ActorSystem;
Expand Down Expand Up @@ -54,10 +56,6 @@ protected ExtensionId(final ExtensionIdConfig<T> extensionIdConfig) {
this.extensionIdConfig = extensionIdConfig;
}

protected ExtensionId(final Class<T> parentClass) {
this(new ExtensionIdConfig<>(parentClass, null, ConfigFactory.empty()));
}

@Override
public T createExtension(final ExtendedActorSystem system) {
return AkkaClassLoader.instantiate(system, extensionIdConfig.parentClass(),
Expand All @@ -66,7 +64,7 @@ public T createExtension(final ExtendedActorSystem system) {
List.of(system, extensionIdConfig.extensionConfig()));
}

protected ExtensionIdConfig<T> globalConfig (final ActorSystem actorSystem) {
protected ExtensionIdConfig<T> globalConfig(final ActorSystem actorSystem) {
return ExtensionIdConfig.of(
extensionIdConfig.parentClass(),
actorSystem.settings().config(),
Expand Down Expand Up @@ -96,8 +94,8 @@ protected String getImplementation(final ExtendedActorSystem actorSystem) {
protected abstract String getConfigPath();

public record ExtensionIdConfig<T extends Extension>(Class<T> parentClass,
@Nullable String extensionClass,
Config extensionConfig) {
@Nullable String extensionClass,
Config extensionConfig) {

private static final String EXTENSION_CLASS = "extension-class";
private static final String EXTENSION_CONFIG = "extension-config";
Expand All @@ -116,18 +114,26 @@ public static <T extends Extension> ExtensionIdConfig<T> of(
final String configKey) {

if (config.hasPath(configKey)) {
final Object anyRef = config.getAnyRef(configKey);
if (anyRef instanceof Map) {
// means that the entry is a config object
return ofObjectConfig(parentClass, config.getConfig(configKey));
} else {
// Allows shorthand configuration by just defining the fqcn if no extension config is desired.
return ofStringConfig(parentClass, config.getString(configKey));
}
final var configValue = config.getValue(configKey);
return of(parentClass, configValue);
}
return new ExtensionIdConfig<>(parentClass, null, ConfigFactory.empty());
}

@SuppressWarnings("unchecked")
public static <T extends Extension> ExtensionIdConfig<T> of(final Class<T> parentClass,
final ConfigValue configValue) {
final var valueType = configValue.valueType();
final Object unwrappedValue = configValue.unwrapped();
if (valueType == ConfigValueType.OBJECT) {
// means that the entry is a Map which can be used to create config object from
return ofObjectConfig(parentClass, ConfigFactory.parseMap((Map<String, ?>) unwrappedValue));
} else {
// Allows shorthand configuration by just defining the fqcn if no extension config is desired.
return ofStringConfig(parentClass, (String) unwrappedValue);
}
}

private static <T extends Extension> ExtensionIdConfig<T> ofStringConfig(
final Class<T> parentClass,
final String extensionClass) {
Expand Down
15 changes: 10 additions & 5 deletions connectivity/service/src/main/resources/connectivity.conf
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
ditto {
service-name = "connectivity"

pre-enforcers = [
"org.eclipse.ditto.policies.enforcement.pre.CommandWithOptionalEntityPreEnforcer",
"org.eclipse.ditto.policies.enforcement.pre.HeaderSetterPreEnforcer"
]

mongodb {
database = "connectivity"
database = ${?MONGO_DB_DATABASE}
Expand Down Expand Up @@ -42,6 +37,16 @@ ditto {
connection-enforcer-actor-props-factory = org.eclipse.ditto.connectivity.service.enforcement.NoOpEnforcerActorPropsFactory
# Provider for a custom connectivity-command interceptor.
custom-connectivity-command-interceptor-provider = "org.eclipse.ditto.connectivity.service.messaging.validation.NoOpConnectivityCommandInterceptorProvider"

pre-enforcer-provider {
extension-class = org.eclipse.ditto.policies.enforcement.pre.PreEnforcerProvider
extension-config = {
pre-enforcers = [
"org.eclipse.ditto.policies.enforcement.pre.CommandWithOptionalEntityPreEnforcer",
"org.eclipse.ditto.policies.enforcement.pre.HeaderSetterPreEnforcer"
]
}
}
}

persistence.operations.delay-after-persistence-actor-shutdown = 5s
Expand Down
13 changes: 9 additions & 4 deletions connectivity/service/src/test/resources/test.conf
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@ ditto {
}
connection-enforcer-actor-props-factory = org.eclipse.ditto.connectivity.service.enforcement.NoOpEnforcerActorPropsFactory
custom-connectivity-command-interceptor-provider = org.eclipse.ditto.connectivity.service.messaging.validation.NoOpConnectivityCommandInterceptorProvider
pre-enforcer-provider {
extension-class = org.eclipse.ditto.policies.enforcement.pre.PreEnforcerProvider
extension-config = {
pre-enforcers = [
"org.eclipse.ditto.policies.enforcement.pre.CommandWithOptionalEntityPreEnforcer",
"org.eclipse.ditto.policies.enforcement.pre.HeaderSetterPreEnforcer"
]
}
}
}
mapping-strategy.implementation = "org.eclipse.ditto.connectivity.api.ConnectivityMappingStrategies"
pre-enforcers = [
"org.eclipse.ditto.policies.enforcement.pre.CommandWithOptionalEntityPreEnforcer",
"org.eclipse.ditto.policies.enforcement.pre.HeaderSetterPreEnforcer"
]

ddata {
subscription-write-consistency = "local"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@

import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.base.model.signals.Signal;
import org.eclipse.ditto.internal.utils.config.DefaultScopedConfig;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.policies.enforcement.config.DefaultEntityCreationConfig;
import org.eclipse.ditto.policies.enforcement.config.EntityCreationConfig;
import org.eclipse.ditto.policies.model.Policy;
import org.eclipse.ditto.policies.model.PolicyId;
import org.eclipse.ditto.policies.model.signals.commands.modify.CreatePolicy;
Expand All @@ -38,11 +35,13 @@
import scala.PartialFunction;

/**
* Appends the globally configured {@link EntityCreationConfig#getDefaultNamespace() Default namespace} to creation
* Appends the globally configured {@link #DEFAULT_NAMESPACE_CONFIG_KEY Default namespace} to creation
* commands which do not include an explicit namespace.
*/
public final class DefaultNamespaceAppender implements SignalTransformer {

private static final String DEFAULT_NAMESPACE_CONFIG_KEY = "default-namespace";
private static final String FALLBACK_DEFAULT_NAMESPACE = "org.eclipse.ditto";
private final String defaultNamespace;
private final PartialFunction<Signal<?>, Signal<?>> signalTransformer;

Expand All @@ -52,10 +51,9 @@ public final class DefaultNamespaceAppender implements SignalTransformer {
* @param actorSystem the actor system in which to load the extension.
*/
public DefaultNamespaceAppender(final ActorSystem actorSystem, final Config config) {
final EntityCreationConfig entityCreationConfig = DefaultEntityCreationConfig.of(
DefaultScopedConfig.dittoScoped(actorSystem.settings().config())
);
defaultNamespace = entityCreationConfig.getDefaultNamespace();
defaultNamespace = config.hasPath(DEFAULT_NAMESPACE_CONFIG_KEY) ?
config.getString(DEFAULT_NAMESPACE_CONFIG_KEY) :
FALLBACK_DEFAULT_NAMESPACE;
signalTransformer = new PFBuilder<Signal<?>, Signal<?>>()
.match(CreateThing.class, this::handleCreateThing)
.match(CreatePolicy.class, this::handleCreatePolicy)
Expand Down
9 changes: 8 additions & 1 deletion edge/service/src/main/resources/ditto-edge-service.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
ditto {
extensions {
edge-command-forwarder-extension = org.eclipse.ditto.edge.service.dispatching.NoOpEdgeCommandForwarderExtension
signal-transformer = org.eclipse.ditto.edge.service.dispatching.DefaultNamespaceAppender
signal-transformer = {
extension-class = org.eclipse.ditto.edge.service.dispatching.DefaultNamespaceAppender
extension-config = {
# specifies the default namespace to use when e.g. creating things/policies via POST (without specifying a namespace)
default-namespace = "org.eclipse.ditto"
default-namespace = ${?DITTO_DEFAULT_NAMESPACE}
}
}
}

ask-with-retry {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# restrict entity creation
ditto.entity-creation {
# specifies the default namespace to use when e.g. creating things/policies via POST (without specifying a namespace)
default-namespace = "org.eclipse.ditto"
default-namespace = ${?DITTO_DEFAULT_NAMESPACE}

# this default entry allows every authenticated "auth-subject" to create any "resource-type" in any "namespace":
grant = [{}]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.eclipse.ditto.internal.utils.akka.actors.AbstractActorWithStashWithTimers;
import org.eclipse.ditto.internal.utils.akka.logging.DittoDiagnosticLoggingAdapter;
import org.eclipse.ditto.internal.utils.akka.logging.DittoLoggerFactory;
import org.eclipse.ditto.internal.utils.config.ScopedConfig;
import org.eclipse.ditto.internal.utils.metrics.DittoMetrics;
import org.eclipse.ditto.internal.utils.metrics.instruments.counter.Counter;
import org.eclipse.ditto.internal.utils.metrics.instruments.timer.PreparedTimer;
Expand All @@ -49,7 +50,10 @@
import org.eclipse.ditto.internal.utils.tracing.instruments.trace.StartedTrace;
import org.eclipse.ditto.policies.enforcement.pre.PreEnforcerProvider;

import com.typesafe.config.Config;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.PoisonPill;
import akka.actor.Props;
import akka.actor.ReceiveTimeout;
Expand Down Expand Up @@ -128,7 +132,9 @@ protected AbstractPersistenceSupervisor(@Nullable final ActorRef persistenceActo
this.enforcerChild = enforcerChild;
this.blockedNamespaces = blockedNamespaces;
this.defaultLocalAskTimeout = defaultLocalAskTimeout;
preEnforcer = PreEnforcerProvider.get(getContext().getSystem());
final var system = getContext().getSystem();
final var dittoExtensionsConfig = ScopedConfig.dittoExtension(system.settings().config());
preEnforcer = PreEnforcerProvider.get(system, dittoExtensionsConfig);
exponentialBackOffConfig = getExponentialBackOffConfig();
backOff = ExponentialBackOff.initial(exponentialBackOffConfig);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ public final class DefaultEntityCreationConfig implements EntityCreationConfig {

private static final String CONFIG_PATH = "entity-creation";

private final String defaultNamespace;
private final List<CreationRestrictionConfig> grant;
private final List<CreationRestrictionConfig> revoke;

private DefaultEntityCreationConfig(final ScopedConfig config) {
defaultNamespace = config.getString(ConfigValue.DEFAULT_NAMESPACE.getConfigPath());
grant = config.getConfigList(ConfigValue.GRANT.getConfigPath()).stream()
.map(DefaultCreationRestrictionConfig::of)
.toList();
Expand All @@ -53,12 +51,8 @@ private DefaultEntityCreationConfig(final ScopedConfig config) {
*/
public static DefaultEntityCreationConfig of(final Config config) {
return new DefaultEntityCreationConfig(
ConfigWithFallback.newInstance(config, CONFIG_PATH, EntityCreationConfig.ConfigValue.values()));
}

@Override
public String getDefaultNamespace() {
return defaultNamespace;
ConfigWithFallback.newInstance(config, CONFIG_PATH, EntityCreationConfig.ConfigValue.values())
);
}

@Override
Expand All @@ -80,19 +74,18 @@ public boolean equals(final Object o) {
return false;
}
final DefaultEntityCreationConfig that = (DefaultEntityCreationConfig) o;
return defaultNamespace.equals(that.defaultNamespace) && grant.equals(that.grant) && revoke.equals(that.revoke);
return grant.equals(that.grant) && revoke.equals(that.revoke);
}

@Override
public int hashCode() {
return Objects.hash(defaultNamespace, grant, revoke);
return Objects.hash(grant, revoke);
}

@Override
public String toString() {
return getClass().getSimpleName() + " [" +
"defaultNamespace=" + defaultNamespace +
", grant=" + grant +
"grant=" + grant +
", revoke=" + revoke +
"]";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@
@Immutable
public interface EntityCreationConfig {

/**
* Returns the default namespace which is used for creating entities, when no namespace is provided.
*
* @return the default namespace.
*/
String getDefaultNamespace();

/**
* Returns the list of creation config entries which would allow the creation.
*
Expand All @@ -56,11 +49,6 @@ public interface EntityCreationConfig {
*/
enum ConfigValue implements KnownConfigValue {

/**
* The default namespace to use for creating entities without specified namespace.
*/
DEFAULT_NAMESPACE("default-namespace", "org.eclipse.ditto"),

/**
* The list of creation config entries which would allow the creation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import org.eclipse.ditto.internal.utils.namespaces.BlockNamespaceBehavior;
import org.eclipse.ditto.internal.utils.namespaces.BlockedNamespaces;

import com.typesafe.config.Config;

import akka.actor.ActorSystem;

/**
Expand All @@ -33,7 +35,7 @@ public final class BlockedNamespacePreEnforcer implements PreEnforcer {
* @param actorSystem the actor system in which to load the extension.
*/
@SuppressWarnings("unused")
public BlockedNamespacePreEnforcer(final ActorSystem actorSystem) {
public BlockedNamespacePreEnforcer(final ActorSystem actorSystem, final Config config) {
blockNamespaceBehavior = BlockNamespaceBehavior.of(BlockedNamespaces.of(actorSystem));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.eclipse.ditto.json.JsonParseException;
import org.eclipse.ditto.json.JsonValue;

import com.typesafe.config.Config;

import akka.actor.ActorSystem;

/**
Expand All @@ -39,14 +41,10 @@ public final class CommandWithOptionalEntityPreEnforcer implements PreEnforcer {
* @param actorSystem the actor system in which to load the extension.
*/
@SuppressWarnings("unused")
public CommandWithOptionalEntityPreEnforcer(final ActorSystem actorSystem) {
public CommandWithOptionalEntityPreEnforcer(final ActorSystem actorSystem, final Config config) {
// no-op
}

static CommandWithOptionalEntityPreEnforcer createInstance() {
return new CommandWithOptionalEntityPreEnforcer(null);
}

@Override
public CompletionStage<Signal<?>> apply(final Signal<?> signal) {
return checkForHarmfulEntity(signal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@
import org.eclipse.ditto.base.model.signals.commands.Command;
import org.eclipse.ditto.internal.utils.akka.logging.DittoLoggerFactory;
import org.eclipse.ditto.internal.utils.akka.logging.ThreadSafeDittoLogger;
import org.eclipse.ditto.internal.utils.config.DefaultScopedConfig;
import org.eclipse.ditto.policies.enforcement.config.CreationRestrictionConfig;
import org.eclipse.ditto.policies.enforcement.config.DefaultEntityCreationConfig;
import org.eclipse.ditto.policies.enforcement.config.EntityCreationConfig;

import com.typesafe.config.Config;

import akka.actor.ActorSystem;

/**
Expand All @@ -52,8 +53,8 @@ public final class CreationRestrictionPreEnforcer implements PreEnforcer {
* @param actorSystem the actor system in which to load the extension.
*/
@SuppressWarnings("unused")
public CreationRestrictionPreEnforcer(final ActorSystem actorSystem) {
config = DefaultEntityCreationConfig.of(DefaultScopedConfig.dittoScoped(actorSystem.settings().config()));
public CreationRestrictionPreEnforcer(final ActorSystem actorSystem, final Config config) {
this.config = DefaultEntityCreationConfig.of(config);
}

boolean canCreate(final Context context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.eclipse.ditto.base.model.headers.DittoHeadersSettable;
import org.eclipse.ditto.base.model.signals.Signal;

import com.typesafe.config.Config;

import akka.actor.ActorSystem;

/**
Expand All @@ -38,7 +40,7 @@ public final class HeaderSetterPreEnforcer implements PreEnforcer {
* @param actorSystem the actor system in which to load the extension.
*/
@SuppressWarnings("unused")
public HeaderSetterPreEnforcer(final ActorSystem actorSystem) {
public HeaderSetterPreEnforcer(final ActorSystem actorSystem, final Config config) {
// no-op
}

Expand Down
Loading

0 comments on commit 4ee6520

Please sign in to comment.