diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/DistributedConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/DistributedConfigurationUtils.java index eb12788dfaff7..4f86535339cf5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/DistributedConfigurationUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/DistributedConfigurationUtils.java @@ -18,12 +18,19 @@ package org.apache.ignite.internal.cluster; import java.io.Serializable; +import java.util.Arrays; +import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.processors.configuration.distributed.DistributePropertyListener; +import org.apache.ignite.internal.processors.configuration.distributed.DistributedBooleanProperty; +import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationLifecycleListener; import org.apache.ignite.internal.processors.configuration.distributed.DistributedProperty; +import org.apache.ignite.internal.processors.configuration.distributed.DistributedPropertyDispatcher; +import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.jetbrains.annotations.NotNull; @@ -33,6 +40,9 @@ * Distributed configuration utilities methods. */ public final class DistributedConfigurationUtils { + /** */ + public static final String CONN_DISABLED_BY_ADMIN_ERR_MSG = "Connection disabled by administrator"; + /** */ private DistributedConfigurationUtils() { @@ -95,4 +105,34 @@ public static IgniteInternalFuture setDefaultValu } }; } + + /** + * @param subscriptionProcessor Processor to register properties. + * @param log Logger to log default values. + * @param types Connection types. + * @return Detached distributed property. + */ + public static List connectionAllowedProperty( + GridInternalSubscriptionProcessor subscriptionProcessor, + IgniteLogger log, + String... types + ) { + List props = Arrays.stream(types).map(type -> DistributedBooleanProperty.detachedBooleanProperty( + "allowNew" + type + "Connections", + "If true then new " + type.toUpperCase() + " connections allowed." + )).collect(Collectors.toList()); + + subscriptionProcessor.registerDistributedConfigurationListener(new DistributedConfigurationLifecycleListener() { + @Override public void onReadyToRegister(DistributedPropertyDispatcher dispatcher) { + props.forEach(dispatcher::registerProperty); + } + + @Override public void onReadyToWrite() { + props.forEach(prop -> setDefaultValue(prop, true, log)); + } + }); + + + return props; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java index 530371adfe025..cb6e000d2cd89 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java @@ -51,6 +51,7 @@ import org.apache.ignite.plugin.security.SecurityPermission; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.cluster.DistributedConfigurationUtils.CONN_DISABLED_BY_ADMIN_ERR_MSG; import static org.apache.ignite.internal.processors.odbc.ClientListenerMetrics.clientTypeLabel; /** @@ -557,12 +558,12 @@ private void ensureClientPermissions(ClientListenerConnectionContext connCtx) th if (!connAllowed.test(connCtx.clientType())) { // Allow to connect by the control.sh even if connection disabled to be able to invoke commands. if (!controlShClient) - throw new IgniteCheckedException("Connection disabled by administrator"); + throw new IgniteCheckedException(CONN_DISABLED_BY_ADMIN_ERR_MSG); - // TODO: checkme + // TODO: checkme in tests. if (connCtx.securityContext() != null) { try (OperationSecurityContext ignored = ctx.security().withContext(connCtx.securityContext())) { - ctx.security().authorize(SecurityPermission.CONNECT_AS_MAMAGEMENT_CLIENT); + ctx.security().authorize(SecurityPermission.ADMIN_OPS); } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java index 00f1b22a10e03..a2afefbb48075 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java @@ -41,13 +41,10 @@ import org.apache.ignite.configuration.OdbcConfiguration; import org.apache.ignite.configuration.SqlConnectorConfiguration; import org.apache.ignite.internal.GridKernalContext; -import org.apache.ignite.internal.cluster.DistributedConfigurationUtils; import org.apache.ignite.internal.managers.systemview.walker.ClientConnectionAttributeViewWalker; import org.apache.ignite.internal.managers.systemview.walker.ClientConnectionViewWalker; import org.apache.ignite.internal.processors.GridProcessorAdapter; import org.apache.ignite.internal.processors.configuration.distributed.DistributedBooleanProperty; -import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationLifecycleListener; -import org.apache.ignite.internal.processors.configuration.distributed.DistributedPropertyDispatcher; import org.apache.ignite.internal.processors.configuration.distributed.DistributedThinClientConfiguration; import org.apache.ignite.internal.processors.metric.MetricRegistryImpl; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext; @@ -72,6 +69,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.cluster.DistributedConfigurationUtils.connectionAllowedProperty; import static org.apache.ignite.internal.processors.metric.GridMetricManager.CLIENT_CONNECTOR_METRICS; import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName; import static org.apache.ignite.internal.processors.odbc.ClientListenerMetrics.clientTypeLabel; @@ -186,21 +184,12 @@ public ClientListenerProcessor(GridKernalContext ctx) { ? this::onOutboundMessageOffered : null; - Map allowConnMap = registerDistributedProperties(); - - Predicate connAllowed = type -> { - assert type != null : "Connection type is null"; - assert allowConnMap.containsKey(type) : "Unknown connection type: " + type; - - return allowConnMap.get(type).get() != Boolean.FALSE; - }; - for (int port = cliConnCfg.getPort(); port <= portTo && port <= 65535; port++) { try { srv = GridNioServer.builder() .address(hostAddr) .port(port) - .listener(new ClientListenerNioListener(ctx, busyLock, cliConnCfg, metrics, connAllowed)) + .listener(new ClientListenerNioListener(ctx, busyLock, cliConnCfg, metrics, connectionAllowedPredicate())) .logger(log) .selectorCount(selectorCnt) .igniteInstanceName(ctx.igniteInstanceName()) @@ -266,29 +255,33 @@ public ClientListenerProcessor(GridKernalContext ctx) { } } - private Map registerDistributedProperties() { + /** + * @return Predicate to check is connection for specific client type allowed by administrator. + * @see ClientListenerNioListener#ODBC_CLIENT + * @see ClientListenerNioListener#JDBC_CLIENT + * @see ClientListenerNioListener#THIN_CLIENT + */ + private Predicate connectionAllowedPredicate() { Map allowConnMap = new HashMap<>(); - Function prop = type -> DistributedBooleanProperty.detachedBooleanProperty( - "allowNew" + type + "Connections", - "If true then new " + type.toUpperCase() + " connections allowed. Default is true." + List props = connectionAllowedProperty( + ctx.internalSubscriptionProcessor(), + log, + "Odbc", + "Jdbc", + "Thin" ); - allowConnMap.put(ODBC_CLIENT, prop.apply("Odbc")); - allowConnMap.put(JDBC_CLIENT, prop.apply("Jdbc")); - allowConnMap.put(THIN_CLIENT, prop.apply("Thin")); + allowConnMap.put(ODBC_CLIENT, props.get(0)); + allowConnMap.put(JDBC_CLIENT, props.get(1)); + allowConnMap.put(THIN_CLIENT, props.get(2)); - ctx.internalSubscriptionProcessor().registerDistributedConfigurationListener(new DistributedConfigurationLifecycleListener() { - @Override public void onReadyToRegister(DistributedPropertyDispatcher dispatcher) { - allowConnMap.values().forEach(dispatcher::registerProperty); - } + return type -> { + assert type != null : "Connection type is null"; + assert allowConnMap.containsKey(type) : "Unknown connection type: " + type; - @Override public void onReadyToWrite() { - allowConnMap.values().forEach(prop -> DistributedConfigurationUtils.setDefaultValue(prop, true, log)); - } - }); - - return allowConnMap; + return allowConnMap.get(type).get() != Boolean.FALSE; + }; } /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermission.java b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermission.java index c69efca39ecc3..e631dbd6634ec 100644 --- a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermission.java +++ b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermission.java @@ -18,7 +18,6 @@ package org.apache.ignite.plugin.security; import org.apache.ignite.cluster.ClusterState; -import org.apache.ignite.internal.processors.odbc.ClientListenerNioListener; import org.jetbrains.annotations.Nullable; /** @@ -118,13 +117,7 @@ public enum SecurityPermission { SQL_VIEW_CREATE, /** Permission to execute DROP VIEW command. */ - SQL_VIEW_DROP, - - /** - * Connect as a management client. - * @see ClientListenerNioListener#MANAGEMENT_CLIENT_ATTR - */ - CONNECT_AS_MAMAGEMENT_CLIENT; + SQL_VIEW_DROP; /** Enumerated values. */ private static final SecurityPermission[] VALS = values(); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 8cb424bab341e..4d3056ff829b2 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -79,9 +79,11 @@ import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.IgnitionEx; +import org.apache.ignite.internal.cluster.DistributedConfigurationUtils; import org.apache.ignite.internal.events.DiscoveryCustomEvent; import org.apache.ignite.internal.managers.discovery.CustomMessageWrapper; import org.apache.ignite.internal.managers.discovery.DiscoveryServerOnlyCustomMessage; +import org.apache.ignite.internal.processors.configuration.distributed.DistributedBooleanProperty; import org.apache.ignite.internal.processors.failure.FailureProcessor; import org.apache.ignite.internal.processors.security.SecurityContext; import org.apache.ignite.internal.processors.security.SecurityUtils; @@ -177,6 +179,7 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_COMPACT_FOOTER; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_BINARY_STRING_SER_VER_2; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_DFLT_SUID; +import static org.apache.ignite.internal.cluster.DistributedConfigurationUtils.CONN_DISABLED_BY_ADMIN_ERR_MSG; import static org.apache.ignite.internal.processors.security.SecurityUtils.authenticateLocalNode; import static org.apache.ignite.internal.processors.security.SecurityUtils.withSecurityContext; import static org.apache.ignite.spi.IgnitePortProtocol.TCP; @@ -297,6 +300,8 @@ class ServerImpl extends TcpDiscoveryImpl { private final ConcurrentMap>> pingMap = new ConcurrentHashMap<>(); + private DistributedBooleanProperty clientNodeConnectionAllowed; + /** * Maximum size of history of IDs of server nodes ever tried to join current topology (ever sent join request). */ @@ -470,6 +475,12 @@ class ServerImpl extends TcpDiscoveryImpl { /** {@inheritDoc} */ @Override public void onContextInitialized0(IgniteSpiContext spiCtx) throws IgniteSpiException { spiCtx.registerPort(tcpSrvr.port, TCP); + + clientNodeConnectionAllowed = DistributedConfigurationUtils.connectionAllowedProperty( + ((IgniteEx)spi.ignite()).context().internalSubscriptionProcessor(), + log, + "ClientNode" + ).get(0); } /** {@inheritDoc} */ @@ -4405,9 +4416,10 @@ else if (log.isDebugEnabled()) } } - IgniteNodeValidationResult err; + IgniteNodeValidationResult err = node.isClient() ? ensureClientJoinAllowed(node.id()) : null; - err = spi.getSpiContext().validateNode(node); + if (err == null) + err = spi.getSpiContext().validateNode(node); if (err == null) { try { @@ -6422,6 +6434,17 @@ private void checkConnection() { } } + /** + * @param nodeId Node id. + * @return {@code null} if connection allowed, error otherwise. + */ + private IgniteNodeValidationResult ensureClientJoinAllowed(UUID nodeId) { + if (clientNodeConnectionAllowed != null && clientNodeConnectionAllowed.get() == Boolean.FALSE) + return new IgniteNodeValidationResult(nodeId, CONN_DISABLED_BY_ADMIN_ERR_MSG); + + return null; + } + /** * Creates proper timeout helper taking in account current send state and ring state. *