diff --git a/.gitignore b/.gitignore
index 65e3686fbcb9..9f22cd8fdf2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,8 +29,8 @@ settings.xml
.checkstyle
# netbeans
-nb-configuration.xml
-*/nb-configuration.xml
+**/nb-configuration.xml
+**/nbproject
.mvn/wrapper/maven-wrapper.jar
diff --git a/core/pom.xml b/core/pom.xml
index 0da66e6f056d..d2fd08e502ca 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -197,6 +197,11 @@ limitations under the License.
sqllinetest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/core/src/main/java/org/apache/calcite/access/AlwaysPassAuthorization.java b/core/src/main/java/org/apache/calcite/access/AlwaysPassAuthorization.java
new file mode 100644
index 000000000000..dbc44a5114e5
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/AlwaysPassAuthorization.java
@@ -0,0 +1,32 @@
+/*
+ * 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.calcite.access;
+
+/**
+ * Dummy guard that ensures backward compatibility where all access is granted to schema
+ */
+public class AlwaysPassAuthorization implements Authorization {
+
+ public static final Authorization INSTANCE = new AlwaysPassAuthorization();
+
+ @Override public boolean accessGranted(AuthorizationRequest request) {
+ return true;
+ }
+
+}
+
+// End AlwaysPassAuthorization.java
diff --git a/core/src/main/java/org/apache/calcite/access/Authorization.java b/core/src/main/java/org/apache/calcite/access/Authorization.java
new file mode 100644
index 000000000000..462f8f3113f2
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/Authorization.java
@@ -0,0 +1,28 @@
+/*
+ * 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.calcite.access;
+
+/**
+ * Guard for checking against access types of schema tables or other elements
+ */
+public interface Authorization {
+
+ boolean accessGranted(AuthorizationRequest request);
+
+}
+
+// End Authorization.java
diff --git a/core/src/main/java/org/apache/calcite/access/AuthorizationFactory.java b/core/src/main/java/org/apache/calcite/access/AuthorizationFactory.java
new file mode 100644
index 000000000000..6faf2b016bb0
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/AuthorizationFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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.calcite.access;
+
+import java.util.Map;
+
+/**
+ *
+ * Factory that creates AuthorisationGuard
+ */
+public interface AuthorizationFactory {
+
+ /**
+ * Populates this factory with configuration. It is assured that this method is called first,
+ * before any others on this factory.
+ */
+ void init(Map operand);
+
+ /**
+ * Creates guard instancee for specific schema configuration
+ */
+ Authorization create(Map operand);
+
+}
+
+// End AuthorizationFactory.java
diff --git a/core/src/main/java/org/apache/calcite/access/AuthorizationRequest.java b/core/src/main/java/org/apache/calcite/access/AuthorizationRequest.java
new file mode 100644
index 000000000000..a7c099cc7bf7
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/AuthorizationRequest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.calcite.access;
+
+import org.apache.calcite.sql.SqlAccessEnum;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
+import org.apache.calcite.sql.validate.SqlValidatorTable;
+
+import java.util.List;
+
+/**
+ * Wraps data needed for guard to decide whether access should be granted or not.
+ */
+public class AuthorizationRequest {
+
+ private final SqlAccessEnum requiredAccess;
+ private final SqlNode node;
+ private final SqlValidatorTable table;
+ private final List objectPath;
+ private final SqlValidatorCatalogReader catalogReader;
+
+ public AuthorizationRequest(
+ SqlAccessEnum requiredAccess,
+ SqlNode node,
+ SqlValidatorTable table,
+ List objectPath,
+ SqlValidatorCatalogReader catalogReader) {
+ this.requiredAccess = requiredAccess;
+ this.node = node;
+ this.table = table;
+ this.objectPath = objectPath;
+ this.catalogReader = catalogReader;
+ }
+
+ public SqlAccessEnum getRequiredAccess() {
+ return requiredAccess;
+ }
+
+ public SqlNode getNode() {
+ return node;
+ }
+
+ public SqlValidatorTable getTable() {
+ return table;
+ }
+
+ public List getObjectPath() {
+ return objectPath;
+ }
+
+ public SqlValidatorCatalogReader getCatalogReader() {
+ return catalogReader;
+ }
+
+}
+
+// End AuthorizationRequest.java
diff --git a/core/src/main/java/org/apache/calcite/access/CalcitePrincipal.java b/core/src/main/java/org/apache/calcite/access/CalcitePrincipal.java
new file mode 100644
index 000000000000..decf2a05dd58
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/CalcitePrincipal.java
@@ -0,0 +1,27 @@
+/*
+ * 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.calcite.access;
+
+/**
+ * Responsible handling principal and its access to schemas
+ */
+public interface CalcitePrincipal {
+
+ String getName();
+}
+
+// End CalcitePrincipal.java
diff --git a/core/src/main/java/org/apache/calcite/access/CalcitePrincipalFairy.java b/core/src/main/java/org/apache/calcite/access/CalcitePrincipalFairy.java
new file mode 100644
index 000000000000..2f00707339ec
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/CalcitePrincipalFairy.java
@@ -0,0 +1,38 @@
+/*
+ * 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.calcite.access;
+
+/**
+ * Simple placeholder for principal currently "logged in through connection"
+ */
+public class CalcitePrincipalFairy {
+
+ public static final CalcitePrincipalFairy INSTANCE = new CalcitePrincipalFairy();
+
+ private static final ThreadLocal THREAD_LOCAL
+ = new ThreadLocal();
+
+ public void register(CalcitePrincipal principal) {
+ THREAD_LOCAL.set(principal);
+ }
+
+ public CalcitePrincipal get() {
+ return THREAD_LOCAL.get();
+ }
+}
+
+// End CalcitePrincipalFairy.java
diff --git a/core/src/main/java/org/apache/calcite/access/CalcitePrincipalImpl.java b/core/src/main/java/org/apache/calcite/access/CalcitePrincipalImpl.java
new file mode 100644
index 000000000000..79a47cf895bb
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/CalcitePrincipalImpl.java
@@ -0,0 +1,42 @@
+/*
+ * 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.calcite.access;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ *
+ */
+public class CalcitePrincipalImpl implements CalcitePrincipal {
+
+ public static CalcitePrincipal fromName(String user) {
+ return StringUtils.isNotBlank(user) ? new CalcitePrincipalImpl(user) : null;
+ }
+
+ private final String name;
+
+ private CalcitePrincipalImpl(String name) {
+ this.name = name;
+ }
+
+ @Override public String getName() {
+ return name;
+ }
+
+}
+
+// End CalcitePrincipalImpl.java
diff --git a/core/src/main/java/org/apache/calcite/access/PrincipalBasedAuthFactory.java b/core/src/main/java/org/apache/calcite/access/PrincipalBasedAuthFactory.java
new file mode 100644
index 000000000000..71f6675c378d
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/PrincipalBasedAuthFactory.java
@@ -0,0 +1,59 @@
+/*
+ * 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.calcite.access;
+
+import org.apache.calcite.sql.SqlAccessType;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Factory of principal based access
+ */
+public class PrincipalBasedAuthFactory implements AuthorizationFactory {
+
+ private static final Pattern OWNER_PATTERN = Pattern.compile("\\s*OWNER\\s*");
+
+ @Override public void init(Map operand) {
+ }
+
+ @Override public Authorization create(Map operand) {
+ Map accessMap = new HashMap<>();
+ Set owners = new HashSet<>();
+ convert(operand, accessMap, owners);
+ return new PrincipalBasedAuthorization(CalcitePrincipalFairy.INSTANCE, accessMap, owners);
+ }
+
+ private void convert(
+ Map operand,
+ Map accessMap,
+ Set owners) {
+ for (Map.Entry entry : operand.entrySet()) {
+ if (OWNER_PATTERN.matcher(entry.getValue()).matches()) {
+ owners.add(entry.getKey());
+ } else {
+ accessMap.put(entry.getKey(), SqlAccessType.create(entry.getValue()));
+ }
+ }
+ }
+
+}
+
+// End PrincipalBasedAuthFactory.java
diff --git a/core/src/main/java/org/apache/calcite/access/PrincipalBasedAuthorization.java b/core/src/main/java/org/apache/calcite/access/PrincipalBasedAuthorization.java
new file mode 100644
index 000000000000..e18b44908119
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/PrincipalBasedAuthorization.java
@@ -0,0 +1,94 @@
+/*
+ * 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.calcite.access;
+
+import org.apache.calcite.jdbc.CalciteSchema;
+import org.apache.calcite.sql.SqlAccessType;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Guard that checks whether principal has required access to schema
+ */
+public class PrincipalBasedAuthorization implements Authorization {
+
+ private final Map accessMap;
+ private final Set owners;
+ private final CalcitePrincipalFairy fairy;
+
+ public PrincipalBasedAuthorization(
+ CalcitePrincipalFairy fairy,
+ Map accessMap,
+ Set owners) {
+ this.accessMap = accessMap;
+ this.fairy = fairy;
+ this.owners = ImmutableSet.copyOf(owners);
+ }
+
+ @Override public boolean accessGranted(AuthorizationRequest request) {
+ CalcitePrincipal principal = fairy.get();
+ return accessGranted(principal, request);
+ }
+
+ private boolean accessGranted(CalcitePrincipal principal, AuthorizationRequest request) {
+ // If no principal - this authorization assumes no access granted
+ if (principal == null) {
+ return false;
+ }
+ // owners are always authorized to all requests
+ if (owners.contains(principal.getName())) {
+ return true;
+ }
+ // otherwise check in user to access type map
+ if (accessMap.getOrDefault(principal.getName(), SqlAccessType.NONE)
+ .allowsAccess(request.getRequiredAccess())) {
+ return true;
+ }
+ // otherwise check if view and check authorization for owner of view schema
+ if (request.getObjectPath() != null && !request.getObjectPath().isEmpty()) {
+ List path = request.getObjectPath().subList(0, request.getObjectPath().size() - 1);
+ CalciteSchema schema = SqlValidatorUtil.getSchema(
+ request.getCatalogReader().getRootSchema(),
+ path,
+ request.getCatalogReader().nameMatcher());
+ PrincipalBasedAuthorization authorization
+ = (PrincipalBasedAuthorization) schema.getAuthorization();
+ for (String ownerName : authorization.getOwners()) {
+ if (accessGranted(mockedPrincipal(ownerName), request)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public Set getOwners() {
+ return owners;
+ }
+
+ private CalcitePrincipal mockedPrincipal(String ownerName) {
+ return CalcitePrincipalImpl.fromName(ownerName);
+ }
+
+}
+
+// End PrincipalBasedAuthorization.java
diff --git a/core/src/main/java/org/apache/calcite/access/package-info.java b/core/src/main/java/org/apache/calcite/access/package-info.java
new file mode 100644
index 000000000000..4fe67277ad82
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/access/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Authorization and identity logic is here.
+ */
+@PackageMarker
+package org.apache.calcite.access;
+
+import org.apache.calcite.avatica.util.PackageMarker;
+
+// End package-info.java
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index ada433324d5d..f3c198e4b32e 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -16,6 +16,8 @@
*/
package org.apache.calcite.adapter.enumerable;
+import org.apache.calcite.access.CalcitePrincipal;
+import org.apache.calcite.access.CalcitePrincipalFairy;
import org.apache.calcite.avatica.util.DateTimeUtils;
import org.apache.calcite.avatica.util.TimeUnit;
import org.apache.calcite.avatica.util.TimeUnitRange;
@@ -483,11 +485,12 @@ public Expression implement(RexToLixTranslator translator,
new MethodImplementor(BuiltInMethod.IS_JSON_SCALAR.method)), false);
// System functions
- final SystemFunctionImplementor systemFunctionImplementor =
- new SystemFunctionImplementor();
- map.put(USER, systemFunctionImplementor);
- map.put(CURRENT_USER, systemFunctionImplementor);
- map.put(SESSION_USER, systemFunctionImplementor);
+ final UserFunctionImplementor userFunctionImplementor = new UserFunctionImplementor();
+ map.put(USER, userFunctionImplementor);
+ map.put(CURRENT_USER, userFunctionImplementor);
+ map.put(SESSION_USER, userFunctionImplementor);
+ final SystemFunctionImplementor systemFunctionImplementor
+ = new SystemFunctionImplementor();
map.put(SYSTEM_USER, systemFunctionImplementor);
map.put(CURRENT_PATH, systemFunctionImplementor);
map.put(CURRENT_ROLE, systemFunctionImplementor);
@@ -2483,11 +2486,7 @@ public Expression implement(
}
final SqlOperator op = call.getOperator();
final Expression root = translator.getRoot();
- if (op == CURRENT_USER
- || op == SESSION_USER
- || op == USER) {
- return Expressions.constant("sa");
- } else if (op == SYSTEM_USER) {
+ if (op == SYSTEM_USER) {
return Expressions.constant(System.getProperty("user.name"));
} else if (op == CURRENT_PATH
|| op == CURRENT_ROLE
@@ -2511,8 +2510,25 @@ public Expression implement(
}
}
- /** Implements "IS XXX" operations such as "IS NULL"
- * or "IS NOT TRUE".
+ /**
+ * Implementation of user functions which deduce user from connection properties
+ */
+ private static class UserFunctionImplementor implements CallImplementor {
+
+ @Override public Expression implement(
+ RexToLixTranslator translator,
+ RexCall call,
+ NullAs nullAs) {
+ CalcitePrincipal principal = CalcitePrincipalFairy.INSTANCE.get();
+ return principal != null
+ ? Expressions.constant(principal.getName())
+ : Expressions.constant(System.getProperty("user.name"));
+ }
+
+ }
+
+ /**
+ * Implements "IS XXX" operations such as "IS NULL" or "IS NOT TRUE".
*
*
What these operators have in common:
* 1. They return TRUE or FALSE, never NULL.
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
index b366aeac291c..f709d47f4832 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java
@@ -70,6 +70,10 @@ public interface CalciteConnectionConfig extends ConnectionConfig {
T typeSystem(Class typeSystemClass, T defaultTypeSystem);
/** @see CalciteConnectionProperty#CONFORMANCE */
SqlConformance conformance();
+ /**
+ * @see CalciteConnectionProperty#USER
+ */
+ String user();
}
// End CalciteConnectionConfig.java
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
index 6c176b8669de..a103bd10b5c5 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
@@ -86,6 +86,12 @@ public NullCollation defaultNullCollation() {
.getEnum(NullCollation.class, NullCollation.HIGH);
}
+ public String user() {
+ return CalciteConnectionProperty.USER
+ .wrap(properties)
+ .getString();
+ }
+
public T fun(Class operatorTableClass, T defaultOperatorTable) {
final String fun =
CalciteConnectionProperty.FUN.wrap(properties).getString();
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
index dea9200ac770..f259afd38558 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
@@ -141,7 +141,9 @@ public enum CalciteConnectionProperty implements ConnectionProperty {
TYPE_SYSTEM("typeSystem", Type.PLUGIN, null, false),
/** SQL conformance level. */
- CONFORMANCE("conformance", Type.ENUM, SqlConformanceEnum.DEFAULT, false);
+ CONFORMANCE("conformance", Type.ENUM, SqlConformanceEnum.DEFAULT, false),
+
+ USER("user", Type.STRING, null, false);
private final String camelName;
private final Type type;
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
index 486f0d2650f6..76af92992cb0 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.jdbc;
+import org.apache.calcite.access.Authorization;
import org.apache.calcite.rel.type.RelProtoDataType;
import org.apache.calcite.schema.Function;
import org.apache.calcite.schema.Schema;
@@ -252,6 +253,7 @@ protected CalciteSchema snapshot(CalciteSchema parent, SchemaVersion version) {
CalciteSchema subSchemaSnapshot = subSchema.snapshot(snapshot, version);
snapshot.subSchemaMap.put(subSchema.name, subSchemaSnapshot);
}
+ snapshot.setGuard(getAuthorization());
return snapshot;
}
@@ -327,8 +329,7 @@ private static class SubSchemaCache {
private SubSchemaCache(final CalciteSchema calciteSchema,
Set names) {
this.names = NameSet.immutableCopyOf(names);
- this.cache = CacheBuilder.newBuilder().build(
- new CacheLoader() {
+ this.cache = CacheBuilder.newBuilder().build(new CacheLoader() {
@SuppressWarnings("NullableProblems")
@Override public CalciteSchema load(String schemaName) {
final Schema subSchema =
@@ -337,7 +338,14 @@ private SubSchemaCache(final CalciteSchema calciteSchema,
throw new RuntimeException("sub-schema " + schemaName
+ " not found");
}
- return new CachingCalciteSchema(calciteSchema, subSchema, schemaName);
+ CachingCalciteSchema cache
+ = new CachingCalciteSchema(calciteSchema, subSchema, schemaName);
+ try {
+ Authorization guard
+ = calciteSchema.subSchemaMap.map().get(schemaName).getAuthorization();
+ cache.setGuard(guard);
+ } catch (NullPointerException e) { }
+ return cache;
}
});
}
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
index 7df8c3ee5133..67e68900e3ab 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
@@ -17,6 +17,9 @@
package org.apache.calcite.jdbc;
import org.apache.calcite.DataContext;
+import org.apache.calcite.access.CalcitePrincipal;
+import org.apache.calcite.access.CalcitePrincipalFairy;
+import org.apache.calcite.access.CalcitePrincipalImpl;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.avatica.AvaticaConnection;
import org.apache.calcite.avatica.AvaticaFactory;
@@ -82,6 +85,8 @@
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
/**
* Implementation of JDBC connection
* in the Calcite engine.
@@ -143,6 +148,10 @@ protected CalciteConnectionImpl(Driver driver, AvaticaFactory factory,
this.properties.put(InternalProperty.UNQUOTED_CASING, cfg.unquotedCasing());
this.properties.put(InternalProperty.QUOTED_CASING, cfg.quotedCasing());
this.properties.put(InternalProperty.QUOTING, cfg.quoting());
+ String username = cfg.user();
+ if (!isBlank(username)) {
+ CalcitePrincipalFairy.INSTANCE.register(CalcitePrincipalImpl.fromName(username));
+ }
}
CalciteMetaImpl meta() {
@@ -552,6 +561,10 @@ public CalcitePrepare.SparkHandler spark() {
final boolean enable = config().spark();
return CalcitePrepare.Dummy.getSparkHandler(enable);
}
+
+ public CalcitePrincipal getPrincipal() {
+ return CalcitePrincipalImpl.fromName(connection.config().user());
+ }
}
/** Implementation of {@link DataContext} that has few variables and is
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index afc5252ae379..2ac66a0c43d6 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -127,6 +127,7 @@ interface Context {
/** Gets a runner; it can execute a relational expression. */
RelRunner getRelRunner();
+
}
/** Callback to register Spark as the main engine. */
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
index fa25f695dfc6..3c25d3b43880 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
@@ -16,6 +16,8 @@
*/
package org.apache.calcite.jdbc;
+import org.apache.calcite.access.AlwaysPassAuthorization;
+import org.apache.calcite.access.Authorization;
import org.apache.calcite.linq4j.function.Experimental;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.materialize.Lattice;
@@ -68,6 +70,7 @@ public abstract class CalciteSchema {
protected final NameMap nullaryFunctionMap;
protected final NameMap subSchemaMap;
private List extends List> path;
+ private Authorization guard = AlwaysPassAuthorization.INSTANCE;
protected CalciteSchema(CalciteSchema parent, Schema schema,
String name, NameMap subSchemaMap,
@@ -538,6 +541,14 @@ public boolean removeType(String name) {
return typeMap.remove(name) != null;
}
+ public void setGuard(Authorization guard) {
+ this.guard = guard;
+ }
+
+ public Authorization getAuthorization() {
+ return guard;
+ }
+
/**
* Entry in a schema, such as a table or sub-schema.
*
@@ -717,6 +728,10 @@ public void add(String name, RelProtoDataType type) {
public void add(String name, Lattice lattice) {
CalciteSchema.this.add(name, lattice);
}
+
+ @Override public void setAuthorization(Authorization guard) {
+ CalciteSchema.this.setGuard(guard);
+ }
}
/**
diff --git a/core/src/main/java/org/apache/calcite/model/JsonAuthorization.java b/core/src/main/java/org/apache/calcite/model/JsonAuthorization.java
new file mode 100644
index 000000000000..4c5ced627476
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/model/JsonAuthorization.java
@@ -0,0 +1,42 @@
+/*
+ * 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.calcite.model;
+
+import java.util.Map;
+
+/**
+ * JSON element that represents access definition to defined schema
+ */
+public class JsonAuthorization {
+ /** Name of the factory class implementing Access level logic to schema
+ *
+ *
Required
+ */
+ public String factory;
+
+ /** Contains attributes to be passed to the factory.
+ *
+ *
May be a JSON object (represented as Map) or null.
+ */
+ public Map operand;
+
+ public void accept(ModelHandler modelHandler) {
+ modelHandler.visit(this);
+ }
+}
+
+// End JsonAuthorization.java
diff --git a/core/src/main/java/org/apache/calcite/model/JsonRoot.java b/core/src/main/java/org/apache/calcite/model/JsonRoot.java
index 7d45013d9d53..b13d8ea0919f 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonRoot.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonRoot.java
@@ -60,6 +60,11 @@ public class JsonRoot {
*/
public String defaultSchema;
+ /**
+ * Factory for authorization logic
+ */
+ public JsonAuthorization authorization;
+
/** List of schema elements.
*
*
The list may be empty.
diff --git a/core/src/main/java/org/apache/calcite/model/JsonSchema.java b/core/src/main/java/org/apache/calcite/model/JsonSchema.java
index ce9c8013faa5..e9e79948fbea 100644
--- a/core/src/main/java/org/apache/calcite/model/JsonSchema.java
+++ b/core/src/main/java/org/apache/calcite/model/JsonSchema.java
@@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Schema schema element.
@@ -61,6 +62,11 @@ public abstract class JsonSchema {
*/
public List