IGNITE-8135: SQL: authentication for CREATE TABLE and DROP TABLE commands. This closes #3801.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/a57c9e1f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/a57c9e1f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/a57c9e1f Branch: refs/heads/ignite-7708 Commit: a57c9e1f2a00fea310de5eabba92a642942b9796 Parents: 7a1d0ea Author: devozerov <voze...@gridgain.com> Authored: Thu Apr 12 15:02:57 2018 +0300 Committer: devozerov <voze...@gridgain.com> Committed: Thu Apr 12 15:02:57 2018 +0300 ---------------------------------------------------------------------- .../apache/ignite/client/ClientException.java | 3 +- .../internal/client/thin/ClientQueryCursor.java | 6 ++- .../platform/client/ClientRequestHandler.java | 7 ++- .../cache/ClientCacheSqlFieldsQueryRequest.java | 19 +++++-- .../security/SecurityContextHolder.java | 53 ++++++++++++++++++++ .../query/h2/ddl/DdlStatementsProcessor.java | 9 ++++ 6 files changed, 91 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/a57c9e1f/modules/core/src/main/java/org/apache/ignite/client/ClientException.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/client/ClientException.java b/modules/core/src/main/java/org/apache/ignite/client/ClientException.java index 0555635..b0d9f6c 100644 --- a/modules/core/src/main/java/org/apache/ignite/client/ClientException.java +++ b/modules/core/src/main/java/org/apache/ignite/client/ClientException.java @@ -20,7 +20,7 @@ package org.apache.ignite.client; /** * Common thin client checked exception. */ -public class ClientException extends Exception { +public class ClientException extends RuntimeException { /** Serial version uid. */ private static final long serialVersionUID = 0L; @@ -28,6 +28,7 @@ public class ClientException extends Exception { * Constructs a new exception with {@code null} as its detail message. */ public ClientException() { + // No-op. } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/a57c9e1f/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientQueryCursor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientQueryCursor.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientQueryCursor.java index 9367cfd..086fab8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientQueryCursor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientQueryCursor.java @@ -54,6 +54,7 @@ class ClientQueryCursor<T> implements QueryCursor<T> { pager.close(); } catch (Exception ignored) { + // No-op. } } @@ -76,7 +77,10 @@ class ClientQueryCursor<T> implements QueryCursor<T> { currPageIt = currPage.iterator(); } catch (ClientException e) { - throw new RuntimeException("Failed to retrieve query results", e); + throw e; + } + catch (Exception e) { + throw new ClientException("Failed to retrieve query results", e); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/a57c9e1f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java index faa50bc..5ed0d38 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java @@ -22,6 +22,7 @@ import org.apache.ignite.internal.processors.authentication.AuthorizationContext import org.apache.ignite.internal.processors.odbc.ClientListenerRequest; import org.apache.ignite.internal.processors.odbc.ClientListenerRequestHandler; import org.apache.ignite.internal.processors.odbc.ClientListenerResponse; +import org.apache.ignite.internal.processors.security.SecurityContextHolder; /** * Thin client request handler. @@ -47,8 +48,10 @@ public class ClientRequestHandler implements ClientListenerRequestHandler { /** {@inheritDoc} */ @Override public ClientListenerResponse handle(ClientListenerRequest req) { - if (authCtx != null) + if (authCtx != null) { AuthorizationContext.context(authCtx); + SecurityContextHolder.set(ctx.securityContext()); + } try { return ((ClientRequest)req).process(ctx); @@ -56,6 +59,8 @@ public class ClientRequestHandler implements ClientListenerRequestHandler { finally { if (authCtx != null) AuthorizationContext.clear(); + + SecurityContextHolder.clear(); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/a57c9e1f/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheSqlFieldsQueryRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheSqlFieldsQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheSqlFieldsQueryRequest.java index 3aa95bf..53f6353 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheSqlFieldsQueryRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheSqlFieldsQueryRequest.java @@ -28,8 +28,11 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementType; import org.apache.ignite.internal.processors.platform.cache.PlatformCache; import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext; import org.apache.ignite.internal.processors.platform.client.ClientResponse; +import org.apache.ignite.internal.processors.platform.client.ClientStatus; +import org.apache.ignite.internal.processors.platform.client.IgniteClientException; import org.apache.ignite.internal.processors.query.QueryUtils; -import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.plugin.security.SecurityException; /** * Sql query request. @@ -95,7 +98,7 @@ public class ClientCacheSqlFieldsQueryRequest extends ClientCacheRequest { if (qry.getSchema() == null) { String schema = QueryUtils.normalizeSchemaName(desc.cacheName(), - desc.cacheConfiguration().getSqlSchema()); + desc.cacheConfiguration().getSqlSchema()); qry.setSchema(schema); } @@ -108,7 +111,7 @@ public class ClientCacheSqlFieldsQueryRequest extends ClientCacheRequest { FieldsQueryCursor cur = curs.get(0); ClientCacheFieldsQueryCursor cliCur = new ClientCacheFieldsQueryCursor( - cur, qry.getPageSize(), ctx); + cur, qry.getPageSize(), ctx); long cursorId = ctx.resources().put(cliCur); @@ -119,6 +122,16 @@ public class ClientCacheSqlFieldsQueryRequest extends ClientCacheRequest { catch (Exception e) { ctx.decrementCursors(); + SecurityException securityEx = X.cause(e, SecurityException.class); + + if (securityEx != null) { + throw new IgniteClientException( + ClientStatus.SECURITY_VIOLATION, + "Client is not authorized to perform this operation", + securityEx + ); + } + throw e; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/a57c9e1f/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityContextHolder.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityContextHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityContextHolder.java new file mode 100644 index 0000000..14d70c9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityContextHolder.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.security; + +import org.jetbrains.annotations.Nullable; + +/** + * Thread-local security context. + */ +public class SecurityContextHolder { + /** Context. */ + private static final ThreadLocal<SecurityContext> CTX = new ThreadLocal<>(); + + /** + * Get security context. + * + * @return Security context. + */ + @Nullable public static SecurityContext get() { + return CTX.get(); + } + + /** + * Set security context. + * + * @param ctx Context. + */ + public static void set(@Nullable SecurityContext ctx) { + CTX.set(ctx); + } + + /** + * Clear security context. + */ + public static void clear() { + set(null); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a57c9e1f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index b148969..bc5c1e0 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -34,6 +34,8 @@ import org.apache.ignite.cache.query.FieldsQueryCursor; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.processors.authentication.AuthorizationContext; +import org.apache.ignite.internal.processors.authentication.UserManagementOperation; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; @@ -56,6 +58,8 @@ import org.apache.ignite.internal.processors.query.h2.sql.GridSqlDropTable; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlStatement; import org.apache.ignite.internal.processors.query.schema.SchemaOperationException; +import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.processors.security.SecurityContextHolder; import org.apache.ignite.internal.sql.command.SqlAlterTableCommand; import org.apache.ignite.internal.sql.command.SqlAlterUserCommand; import org.apache.ignite.internal.sql.command.SqlCommand; @@ -67,6 +71,7 @@ import org.apache.ignite.internal.sql.command.SqlIndexColumn; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.security.SecurityPermission; import org.h2.command.Prepared; import org.h2.command.ddl.AlterTableAlterColumn; import org.h2.command.ddl.CreateIndex; @@ -316,6 +321,8 @@ public class DdlStatementsProcessor { } } else if (stmt0 instanceof GridSqlCreateTable) { + ctx.security().authorize(null, SecurityPermission.CACHE_CREATE, SecurityContextHolder.get()); + GridSqlCreateTable cmd = (GridSqlCreateTable)stmt0; if (!F.eq(QueryUtils.DFLT_SCHEMA, cmd.schemaName())) @@ -349,6 +356,8 @@ public class DdlStatementsProcessor { } } else if (stmt0 instanceof GridSqlDropTable) { + ctx.security().authorize(null, SecurityPermission.CACHE_DESTROY, SecurityContextHolder.get()); + GridSqlDropTable cmd = (GridSqlDropTable)stmt0; if (!F.eq(QueryUtils.DFLT_SCHEMA, cmd.schemaName()))