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);