Skip to content

Commit

Permalink
IGNITE-21587 SQL Calcite: Add operations authorization (#11278)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-plekhanov authored Mar 22, 2024
1 parent 89e3617 commit db4ac5f
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.apache.calcite.plan.Context;
import org.apache.calcite.plan.Contexts;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.sql.SqlInsert;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.tools.Frameworks;
Expand Down Expand Up @@ -88,12 +89,20 @@
import org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadataImpl;
import org.apache.ignite.internal.processors.query.calcite.prepare.Fragment;
import org.apache.ignite.internal.processors.query.calcite.prepare.FragmentPlan;
import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteRelShuttle;
import org.apache.ignite.internal.processors.query.calcite.prepare.MappingQueryContext;
import org.apache.ignite.internal.processors.query.calcite.prepare.MultiStepPlan;
import org.apache.ignite.internal.processors.query.calcite.prepare.PrepareServiceImpl;
import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlan;
import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlanCache;
import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.CreateTableCommand;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexBound;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexCount;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexScan;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableModify;
import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan;
import org.apache.ignite.internal.processors.query.calcite.schema.IgniteTable;
import org.apache.ignite.internal.processors.query.calcite.schema.SchemaHolder;
import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
Expand Down Expand Up @@ -568,6 +577,11 @@ private ListFieldsQueryCursor<?> mapAndExecutePlan(

List<Fragment> fragments = execPlan.fragments();

if (ctx.security().enabled()) {
for (Fragment fragment : fragments)
checkPermissions(fragment.root());
}

// Local execution
Fragment fragment = F.first(fragments);

Expand Down Expand Up @@ -741,6 +755,40 @@ private ListFieldsQueryCursor<?> mapAndExecutePlan(
return new ListFieldsQueryCursor<>(plan, it, ectx);
}

/** */
private void checkPermissions(IgniteRel root) {
IgniteRelShuttle shuttle = new IgniteRelShuttle() {
@Override public IgniteRel visit(IgniteTableModify rel) {
return authorize(rel, rel.getOperation() == TableModify.Operation.DELETE ?
IgniteTable.Operation.REMOVE : IgniteTable.Operation.PUT);
}

@Override public IgniteRel visit(IgniteTableScan rel) {
return authorize(rel, IgniteTable.Operation.READ);
}

@Override public IgniteRel visit(IgniteIndexScan rel) {
return authorize(rel, IgniteTable.Operation.READ);
}

@Override public IgniteRel visit(IgniteIndexCount rel) {
return authorize(rel, IgniteTable.Operation.READ);
}

@Override public IgniteRel visit(IgniteIndexBound rel) {
return authorize(rel, IgniteTable.Operation.READ);
}

private IgniteRel authorize(IgniteRel rel, IgniteTable.Operation op) {
rel.getTable().unwrap(IgniteTable.class).authorize(op);

return rel;
}
};

shuttle.visit(root);
}

/** */
private FieldsQueryCursor<List<?>> executeExplain(RootQuery<Row> qry, ExplainPlan plan) {
QueryCursorImpl<List<?>> cur = new QueryCursorImpl<>(singletonList(singletonList(plan.plan())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.UUID;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
import org.apache.ignite.internal.processors.security.SecurityContext;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.thread.IgniteStripedThreadPoolExecutor;

Expand All @@ -33,6 +34,9 @@ public class QueryTaskExecutorImpl extends AbstractService implements QueryTaskE
/** */
public static final String THREAD_POOL_NAME = "CalciteQueryExecutor";

/** */
private final GridKernalContext ctx;

/** */
private IgniteStripedThreadPoolExecutor stripedThreadPoolExecutor;

Expand All @@ -42,6 +46,7 @@ public class QueryTaskExecutorImpl extends AbstractService implements QueryTaskE
/** */
public QueryTaskExecutorImpl(GridKernalContext ctx) {
super(ctx);
this.ctx = ctx;
}

/**
Expand All @@ -60,9 +65,11 @@ public void exceptionHandler(Thread.UncaughtExceptionHandler eHnd) {

/** {@inheritDoc} */
@Override public void execute(UUID qryId, long fragmentId, Runnable qryTask) {
SecurityContext secCtx = ctx.security().securityContext();

stripedThreadPoolExecutor.execute(
() -> {
try {
try (AutoCloseable ignored = ctx.security().withContext(secCtx)) {
qryTask.run();
}
catch (Throwable e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.apache.ignite.internal.processors.query.stat.ObjectStatisticsImpl;
import org.apache.ignite.internal.processors.query.stat.StatisticsKey;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.plugin.security.SecurityPermission;
import org.jetbrains.annotations.Nullable;

/**
Expand Down Expand Up @@ -165,6 +166,27 @@ public CacheTableImpl(GridKernalContext ctx, CacheTableDescriptor desc) {
return desc.typeDescription().tableName();
}

/** {@inheritDoc} */
@Override public void authorize(Operation op) {
SecurityPermission perm;

switch (op) {
case READ:
perm = SecurityPermission.CACHE_READ;
break;
case PUT:
perm = SecurityPermission.CACHE_PUT;
break;
case REMOVE:
perm = SecurityPermission.CACHE_REMOVE;
break;
default:
throw new AssertionError("Unexpected operation type: " + op);
}

ctx.security().authorize(desc.cacheInfo().name(), perm);
}

/** {@inheritDoc} */
@Override public <C> C unwrap(Class<C> aCls) {
if (aCls.isInstance(desc))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,21 @@ public <Row> Iterable<Row> scan(
* @return Table name.
*/
String name();

/**
* Authorizes operation on table.
*/
void authorize(Operation op);

/** */
enum Operation {
/** */
READ,

/** */
PUT,

/** */
REMOVE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ public SystemViewTableImpl(SystemViewTableDescriptorImpl<?> desc) {
return desc.name();
}

/** {@inheritDoc} */
@Override public void authorize(Operation op) {
// No-op.
}

/** */
private static class StatisticsImpl implements Statistic {
/** {@inheritDoc} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.apache.ignite.internal.processors.query.calcite.message.TestIoManager;
import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription;
import org.apache.ignite.internal.processors.query.calcite.prepare.BaseQueryContext;
import org.apache.ignite.internal.processors.security.NoOpIgniteSecurityProcessor;
import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.plugin.extensions.communication.Message;
Expand Down Expand Up @@ -162,6 +163,7 @@ public void setup() throws Exception {
GridTestKernalContext kernal = newContext();

kernal.add(new GridTimeoutProcessor(kernal));
kernal.add(new NoOpIgniteSecurityProcessor(kernal));

QueryTaskExecutorImpl taskExecutor = new QueryTaskExecutorImpl(kernal);
taskExecutor.stripedThreadPoolExecutor(new IgniteTestStripedThreadPoolExecutor(
Expand Down
Loading

0 comments on commit db4ac5f

Please sign in to comment.