You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2016/07/27 10:29:12 UTC
kylin git commit: KYLIN-1923 Add access controller to query
Repository: kylin
Updated Branches:
refs/heads/master 467226f40 -> 260b62e18
KYLIN-1923 Add access controller to query
Signed-off-by: Li Yang <li...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/260b62e1
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/260b62e1
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/260b62e1
Branch: refs/heads/master
Commit: 260b62e1886b29fd9b881c5c447f8af502162268
Parents: 467226f
Author: Cheng Wang <ch...@kyligence.io>
Authored: Fri Jul 22 15:24:56 2016 +0800
Committer: Li Yang <li...@apache.org>
Committed: Wed Jul 27 18:25:40 2016 +0800
----------------------------------------------------------------------
.../apache/kylin/common/KylinConfigBase.java | 6 ++-
.../kylin/query/relnode/OLAPAuthentication.java | 44 ++++++++++++++++++++
.../apache/kylin/query/relnode/OLAPContext.java | 16 +++++++
.../relnode/OLAPToEnumerableConverter.java | 37 +++++++++++++++-
.../apache/kylin/rest/service/QueryService.java | 10 +++++
5 files changed, 111 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kylin/blob/260b62e1/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
----------------------------------------------------------------------
diff --git a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index 312ecbf..01910d7 100644
--- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -502,7 +502,7 @@ abstract public class KylinConfigBase implements Serializable {
return Integer.parseInt(getOptional("kylin.dict.cache.max.entry", "3000"));
}
- public int getCachedSnapshotMaxEntrySize(){
+ public int getCachedSnapshotMaxEntrySize() {
return Integer.parseInt(getOptional("kylin.snapshot.cache.max.entry", "500"));
}
@@ -555,6 +555,10 @@ abstract public class KylinConfigBase implements Serializable {
return Integer.valueOf(this.getOptional("kylin.query.storage.visit.scanrange.max", "1000000"));
}
+ public String getQueryAccessController() {
+ return getOptional("kylin.query.access.controller", null);
+ }
+
public long getSequenceExpireTime() {
return Long.valueOf(this.getOptional("kylin.query.sequence.expire.time", "86400000"));//default a day
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/260b62e1/query/src/main/java/org/apache/kylin/query/relnode/OLAPAuthentication.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPAuthentication.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPAuthentication.java
new file mode 100644
index 0000000..14f1642
--- /dev/null
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPAuthentication.java
@@ -0,0 +1,44 @@
+/*
+ * 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.kylin.query.relnode;
+
+import java.util.ArrayList;
+
+/**
+ * Created by wangcheng on 7/8/16.
+ */
+public class OLAPAuthentication {
+ private String username;
+ private ArrayList<String> roles = new ArrayList<>();
+
+ public void parseUserInfo(String userInfo) {
+ String[] info = userInfo.split(",");
+ if (info.length > 0) //first element is username
+ this.username = info[0];
+ for (int i = 1; i < info.length; i++) //the remains should be roles which starts from index 1
+ this.roles.add(info[i]);
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ public ArrayList<String> getRoles() {
+ return this.roles;
+ }
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/260b62e1/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
index 7671856..c2e1b88 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
@@ -46,6 +46,7 @@ import com.google.common.collect.Lists;
public class OLAPContext {
public static final String PRM_ACCEPT_PARTIAL_RESULT = "AcceptPartialResult";
+ public static final String PRM_USER_AUTHEN_INFO = "UserAuthenInfo";
private static final ThreadLocal<Map<String, String>> _localPrarameters = new ThreadLocal<Map<String, String>>();
@@ -92,6 +93,9 @@ public class OLAPContext {
if (acceptPartialResult != null) {
this.storageContext.setAcceptPartialResult(Boolean.parseBoolean(acceptPartialResult));
}
+ String acceptUserInfo = parameters.get(PRM_USER_AUTHEN_INFO);
+ if (null != acceptUserInfo)
+ this.olapAuthen.parseUserInfo(acceptUserInfo);
}
}
@@ -128,6 +132,8 @@ public class OLAPContext {
// hive query
public String sql = "";
+ public OLAPAuthentication olapAuthen = new OLAPAuthentication();
+
public boolean isSimpleQuery() {
return (joins.size() == 0) && (groupByColumns.size() == 0) && (aggregations.size() == 0);
}
@@ -161,5 +167,15 @@ public class OLAPContext {
sortOrders.add(order);
}
}
+ public interface IAccessController {
+ /*
+ * @return {TupleFilter} if the filter condition exists
+ * @OLAPAuthentication the authentication info
+ * @columns required columns from logic query plan
+ * @realization the cube used in this query
+ * @OLAPInsufficientException no rights exception
+ */
+ public TupleFilter check(OLAPAuthentication olapAuthentication, Collection<TblColRef> columns, IRealization realization) throws IllegalArgumentException;
+ }
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/260b62e1/query/src/main/java/org/apache/kylin/query/relnode/OLAPToEnumerableConverter.java
----------------------------------------------------------------------
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPToEnumerableConverter.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPToEnumerableConverter.java
index de7e7e2..95ec617 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPToEnumerableConverter.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPToEnumerableConverter.java
@@ -38,6 +38,11 @@ import org.apache.calcite.rel.convert.ConverterImpl;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.SqlExplainLevel;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.ClassUtil;
+import org.apache.kylin.metadata.filter.LogicalTupleFilter;
+import org.apache.kylin.metadata.filter.TupleFilter;
+import org.apache.kylin.metadata.filter.TupleFilter.FilterOperatorEnum;
import org.apache.kylin.metadata.realization.IRealization;
import org.apache.kylin.query.routing.NoRealizationFoundException;
import org.apache.kylin.query.routing.QueryRouter;
@@ -68,7 +73,7 @@ public class OLAPToEnumerableConverter extends ConverterImpl implements Enumerab
OLAPRel.OLAPImplementor olapImplementor = new OLAPRel.OLAPImplementor();
olapImplementor.visitChild(getInput(), this);
- // find cube from olap context
+ // find cube from olap context and apply cell level security
try {
for (OLAPContext context : OLAPContext.getThreadLocalContexts()) {
// Context has no table scan is created by OLAPJoinRel which looks like
@@ -77,8 +82,16 @@ public class OLAPToEnumerableConverter extends ConverterImpl implements Enumerab
if (context.firstTableScan == null) {
continue;
}
+
IRealization realization = QueryRouter.selectRealization(context);
context.realization = realization;
+
+ String controllerCls = KylinConfig.getInstanceFromEnv().getQueryAccessController();
+ if (null != controllerCls && !controllerCls.isEmpty()) {
+ OLAPContext.IAccessController accessController = (OLAPContext.IAccessController) ClassUtil.newInstance(controllerCls);
+ TupleFilter tupleFilter = accessController.check(context.olapAuthen, context.allColumns, context.realization);
+ context.filter = and(context.filter, tupleFilter);
+ }
}
} catch (NoRealizationFoundException e) {
OLAPContext ctx0 = (OLAPContext) OLAPContext.getThreadLocalContexts().toArray()[0];
@@ -108,6 +121,28 @@ public class OLAPToEnumerableConverter extends ConverterImpl implements Enumerab
return impl.visitChild(this, 0, inputAsEnum, pref);
}
+ private TupleFilter and(TupleFilter f1, TupleFilter f2) {
+ if (f1 == null)
+ return f2;
+ if (f2 == null)
+ return f1;
+
+ if (f1.getOperator() == FilterOperatorEnum.AND) {
+ f1.addChild(f2);
+ return f1;
+ }
+
+ if (f2.getOperator() == FilterOperatorEnum.AND) {
+ f2.addChild(f1);
+ return f2;
+ }
+
+ LogicalTupleFilter and = new LogicalTupleFilter(FilterOperatorEnum.AND);
+ and.addChild(f1);
+ and.addChild(f2);
+ return and;
+ }
+
private Result buildHiveResult(EnumerableRelImplementor enumImplementor, Prefer pref, OLAPContext context) {
RelDataType hiveRowType = getRowType();
http://git-wip-us.apache.org/repos/asf/kylin/blob/260b62e1/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
index 84a5c67..32471ab 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
@@ -30,6 +30,7 @@ import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -71,6 +72,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@@ -260,6 +262,13 @@ public class QueryService extends BasicService {
}
private SQLResponse queryWithSqlMassage(SQLRequest sqlRequest) throws Exception {
+ String userInfo = SecurityContextHolder.getContext().getAuthentication().getName();
+ final Collection<? extends GrantedAuthority> grantedAuthorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
+ for (GrantedAuthority grantedAuthority : grantedAuthorities) {
+ userInfo += ",";
+ userInfo += grantedAuthority.getAuthority();
+ }
+
SQLResponse fakeResponse = QueryUtil.tableauIntercept(sqlRequest.getSql());
if (null != fakeResponse) {
logger.debug("Return fake response, is exception? " + fakeResponse.getIsException());
@@ -272,6 +281,7 @@ public class QueryService extends BasicService {
// add extra parameters into olap context, like acceptPartial
Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put(OLAPContext.PRM_USER_AUTHEN_INFO, userInfo);
parameters.put(OLAPContext.PRM_ACCEPT_PARTIAL_RESULT, String.valueOf(sqlRequest.isAcceptPartial()));
OLAPContext.setParameters(parameters);