Repository: trinodb/trino (Java)
Date: 2020-11-13 02:04:48+00:00
Task type: Bug Fix

Issue:
GroupProvider groups are not available for View Access Control
View access control checks permissions of the view creator, since a View is equivalent to a Grant. If FileBasedAccessControl and a GroupProvider are being used this leads to surprising results, because GroupProviderManager.getGroups is never called for the creator, and catalog access rules based on groups will not be applied. 

@electrum 



Issue discussion:

Solution patch:
diff --git a/presto-main/src/main/java/io/prestosql/execution/CreateMaterializedViewTask.java b/presto-main/src/main/java/io/prestosql/execution/CreateMaterializedViewTask.java
index ceec57660d75..f550796e7d1a 100644
--- a/presto-main/src/main/java/io/prestosql/execution/CreateMaterializedViewTask.java
+++ b/presto-main/src/main/java/io/prestosql/execution/CreateMaterializedViewTask.java
@@ -16,21 +16,19 @@
 import com.google.common.util.concurrent.ListenableFuture;
 import io.prestosql.Session;
 import io.prestosql.connector.CatalogName;
-import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
 import io.prestosql.metadata.QualifiedObjectName;
 import io.prestosql.security.AccessControl;
 import io.prestosql.spi.PrestoException;
 import io.prestosql.spi.connector.ConnectorMaterializedViewDefinition;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.sql.analyzer.Analysis;
 import io.prestosql.sql.analyzer.Analyzer;
-import io.prestosql.sql.analyzer.FeaturesConfig;
 import io.prestosql.sql.parser.SqlParser;
 import io.prestosql.sql.tree.CreateMaterializedView;
 import io.prestosql.sql.tree.Expression;
 import io.prestosql.sql.tree.NodeRef;
 import io.prestosql.sql.tree.Parameter;
-import io.prestosql.sql.tree.Statement;
 import io.prestosql.transaction.TransactionManager;
 
 import javax.inject.Inject;
@@ -52,12 +50,13 @@ public class CreateMaterializedViewTask
         implements DataDefinitionTask<CreateMaterializedView>
 {
     private final SqlParser sqlParser;
+    private final GroupProvider groupProvider;
 
     @Inject
-    public CreateMaterializedViewTask(SqlParser sqlParser, FeaturesConfig featuresConfig)
+    public CreateMaterializedViewTask(SqlParser sqlParser, GroupProvider groupProvider)
     {
         this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
-        requireNonNull(featuresConfig, "featuresConfig is null");
+        this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
     }
 
     @Override
@@ -87,7 +86,8 @@ public ListenableFuture<?> execute(
 
         String sql = getFormattedSql(statement.getQuery(), sqlParser);
 
-        Analysis analysis = analyzeStatement(statement, session, metadata, accessControl, parameters, parameterLookup, stateMachine.getWarningCollector());
+        Analysis analysis = new Analyzer(session, metadata, sqlParser, groupProvider, accessControl, Optional.empty(), parameters, parameterLookup, stateMachine.getWarningCollector())
+                .analyze(statement);
 
         List<ConnectorMaterializedViewDefinition.Column> columns = analysis.getOutputDescriptor(statement.getQuery())
                 .getVisibleFields().stream()
@@ -123,17 +123,4 @@ public ListenableFuture<?> execute(
 
         return immediateFuture(null);
     }
-
-    private Analysis analyzeStatement(
-            Statement statement,
-            Session session,
-            Metadata metadata,
-            AccessControl accessControl,
-            List<Expression> parameters,
-            Map<NodeRef<Parameter>, Expression> parameterLookup,
-            WarningCollector warningCollector)
-    {
-        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.empty(), parameters, parameterLookup, warningCollector);
-        return analyzer.analyze(statement);
-    }
 }
diff --git a/presto-main/src/main/java/io/prestosql/execution/CreateViewTask.java b/presto-main/src/main/java/io/prestosql/execution/CreateViewTask.java
index 3e701f8e48f3..a6a17f34bea9 100644
--- a/presto-main/src/main/java/io/prestosql/execution/CreateViewTask.java
+++ b/presto-main/src/main/java/io/prestosql/execution/CreateViewTask.java
@@ -15,18 +15,16 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 import io.prestosql.Session;
-import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
 import io.prestosql.metadata.QualifiedObjectName;
 import io.prestosql.security.AccessControl;
 import io.prestosql.spi.connector.ConnectorViewDefinition;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.sql.analyzer.Analysis;
 import io.prestosql.sql.analyzer.Analyzer;
-import io.prestosql.sql.analyzer.FeaturesConfig;
 import io.prestosql.sql.parser.SqlParser;
 import io.prestosql.sql.tree.CreateView;
 import io.prestosql.sql.tree.Expression;
-import io.prestosql.sql.tree.Statement;
 import io.prestosql.transaction.TransactionManager;
 
 import javax.inject.Inject;
@@ -47,12 +45,13 @@ public class CreateViewTask
         implements DataDefinitionTask<CreateView>
 {
     private final SqlParser sqlParser;
+    private final GroupProvider groupProvider;
 
     @Inject
-    public CreateViewTask(SqlParser sqlParser, FeaturesConfig featuresConfig)
+    public CreateViewTask(SqlParser sqlParser, GroupProvider groupProvider)
     {
         this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
-        requireNonNull(featuresConfig, "featuresConfig is null");
+        this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
     }
 
     @Override
@@ -77,7 +76,8 @@ public ListenableFuture<?> execute(CreateView statement, TransactionManager tran
 
         String sql = getFormattedSql(statement.getQuery(), sqlParser);
 
-        Analysis analysis = analyzeStatement(statement, session, metadata, accessControl, parameters, stateMachine.getWarningCollector());
+        Analysis analysis = new Analyzer(session, metadata, sqlParser, groupProvider, accessControl, Optional.empty(), parameters, parameterExtractor(statement, parameters), stateMachine.getWarningCollector())
+                .analyze(statement);
 
         List<ViewColumn> columns = analysis.getOutputDescriptor(statement.getQuery())
                 .getVisibleFields().stream()
@@ -103,10 +103,4 @@ public ListenableFuture<?> execute(CreateView statement, TransactionManager tran
 
         return immediateFuture(null);
     }
-
-    private Analysis analyzeStatement(Statement statement, Session session, Metadata metadata, AccessControl accessControl, List<Expression> parameters, WarningCollector warningCollector)
-    {
-        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.empty(), parameters, parameterExtractor(statement, parameters), warningCollector);
-        return analyzer.analyze(statement);
-    }
 }
diff --git a/presto-main/src/main/java/io/prestosql/execution/SqlQueryExecution.java b/presto-main/src/main/java/io/prestosql/execution/SqlQueryExecution.java
index f621961d1910..c215fd309471 100644
--- a/presto-main/src/main/java/io/prestosql/execution/SqlQueryExecution.java
+++ b/presto-main/src/main/java/io/prestosql/execution/SqlQueryExecution.java
@@ -43,6 +43,7 @@
 import io.prestosql.server.protocol.Slug;
 import io.prestosql.spi.PrestoException;
 import io.prestosql.spi.QueryId;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.type.TypeOperators;
 import io.prestosql.split.SplitManager;
 import io.prestosql.split.SplitSource;
@@ -133,7 +134,9 @@ private SqlQueryExecution(
             QueryStateMachine stateMachine,
             Slug slug,
             Metadata metadata,
-            TypeOperators typeOperators, AccessControl accessControl,
+            TypeOperators typeOperators,
+            GroupProvider groupProvider,
+            AccessControl accessControl,
             SqlParser sqlParser,
             SplitManager splitManager,
             NodePartitioningManager nodePartitioningManager,
@@ -180,7 +183,7 @@ private SqlQueryExecution(
             this.stateMachine = requireNonNull(stateMachine, "stateMachine is null");
 
             // analyze query
-            this.analysis = analyze(preparedQuery, stateMachine, metadata, accessControl, sqlParser, queryExplainer, warningCollector);
+            this.analysis = analyze(preparedQuery, stateMachine, metadata, groupProvider, accessControl, sqlParser, queryExplainer, warningCollector);
 
             stateMachine.addStateChangeListener(state -> {
                 if (!state.isDone()) {
@@ -237,6 +240,7 @@ private Analysis analyze(
             PreparedQuery preparedQuery,
             QueryStateMachine stateMachine,
             Metadata metadata,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             SqlParser sqlParser,
             QueryExplainer queryExplainer,
@@ -249,6 +253,7 @@ private Analysis analyze(
                 stateMachine.getSession(),
                 metadata,
                 sqlParser,
+                groupProvider,
                 accessControl,
                 Optional.of(queryExplainer),
                 preparedQuery.getParameters(),
@@ -679,6 +684,7 @@ public static class SqlQueryExecutionFactory
         private final int scheduleSplitBatchSize;
         private final Metadata metadata;
         private final TypeOperators typeOperators;
+        private final GroupProvider groupProvider;
         private final AccessControl accessControl;
         private final SqlParser sqlParser;
         private final SplitManager splitManager;
@@ -702,6 +708,7 @@ public static class SqlQueryExecutionFactory
                 QueryManagerConfig config,
                 Metadata metadata,
                 TypeOperators typeOperators,
+                GroupProvider groupProvider,
                 AccessControl accessControl,
                 SqlParser sqlParser,
                 SplitManager splitManager,
@@ -726,6 +733,7 @@ public static class SqlQueryExecutionFactory
             this.scheduleSplitBatchSize = config.getScheduleSplitBatchSize();
             this.metadata = requireNonNull(metadata, "metadata is null");
             this.typeOperators = requireNonNull(typeOperators, "typeOperators is null");
+            this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
             this.accessControl = requireNonNull(accessControl, "accessControl is null");
             this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
             this.splitManager = requireNonNull(splitManager, "splitManager is null");
@@ -762,6 +770,7 @@ public QueryExecution createQueryExecution(
                     slug,
                     metadata,
                     typeOperators,
+                    groupProvider,
                     accessControl,
                     sqlParser,
                     splitManager,
diff --git a/presto-main/src/main/java/io/prestosql/sql/analyzer/Analyzer.java b/presto-main/src/main/java/io/prestosql/sql/analyzer/Analyzer.java
index 71a7bfb339f8..9c2bd348b342 100644
--- a/presto-main/src/main/java/io/prestosql/sql/analyzer/Analyzer.java
+++ b/presto-main/src/main/java/io/prestosql/sql/analyzer/Analyzer.java
@@ -19,6 +19,7 @@
 import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
 import io.prestosql.security.AccessControl;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.sql.parser.SqlParser;
 import io.prestosql.sql.rewrite.StatementRewrite;
 import io.prestosql.sql.tree.Expression;
@@ -44,6 +45,7 @@ public class Analyzer
     private final Metadata metadata;
     private final SqlParser sqlParser;
     private final AccessControl accessControl;
+    private final GroupProvider groupProvider;
     private final Session session;
     private final Optional<QueryExplainer> queryExplainer;
     private final List<Expression> parameters;
@@ -54,6 +56,7 @@ public Analyzer(
             Session session,
             Metadata metadata,
             SqlParser sqlParser,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             Optional<QueryExplainer> queryExplainer,
             List<Expression> parameters,
@@ -63,6 +66,7 @@ public Analyzer(
         this.session = requireNonNull(session, "session is null");
         this.metadata = requireNonNull(metadata, "metadata is null");
         this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
+        this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
         this.accessControl = requireNonNull(accessControl, "accessControl is null");
         this.queryExplainer = requireNonNull(queryExplainer, "query explainer is null");
         this.parameters = parameters;
@@ -77,9 +81,9 @@ public Analysis analyze(Statement statement)
 
     public Analysis analyze(Statement statement, boolean isDescribe)
     {
-        Statement rewrittenStatement = StatementRewrite.rewrite(session, metadata, sqlParser, queryExplainer, statement, parameters, parameterLookup, accessControl, warningCollector);
+        Statement rewrittenStatement = StatementRewrite.rewrite(session, metadata, sqlParser, queryExplainer, statement, parameters, parameterLookup, groupProvider, accessControl, warningCollector);
         Analysis analysis = new Analysis(rewrittenStatement, parameterLookup, isDescribe);
-        StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
+        StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
         analyzer.analyze(rewrittenStatement, Optional.empty());
 
         // check column access permissions for each table
diff --git a/presto-main/src/main/java/io/prestosql/sql/analyzer/ExpressionAnalyzer.java b/presto-main/src/main/java/io/prestosql/sql/analyzer/ExpressionAnalyzer.java
index f4fe90337662..6c6544e72b1a 100644
--- a/presto-main/src/main/java/io/prestosql/sql/analyzer/ExpressionAnalyzer.java
+++ b/presto-main/src/main/java/io/prestosql/sql/analyzer/ExpressionAnalyzer.java
@@ -35,6 +35,7 @@
 import io.prestosql.spi.PrestoException;
 import io.prestosql.spi.PrestoWarning;
 import io.prestosql.spi.function.OperatorType;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.type.CharType;
 import io.prestosql.spi.type.DateType;
 import io.prestosql.spi.type.DecimalParseResult;
@@ -1868,6 +1869,7 @@ public List<Type> getFunctionInputTypes()
     public static ExpressionAnalysis analyzeExpressions(
             Session session,
             Metadata metadata,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             SqlParser sqlParser,
             TypeProvider types,
@@ -1877,7 +1879,7 @@ public static ExpressionAnalysis analyzeExpressions(
             boolean isDescribe)
     {
         Analysis analysis = new Analysis(null, parameters, isDescribe);
-        ExpressionAnalyzer analyzer = create(analysis, session, metadata, sqlParser, accessControl, types, warningCollector);
+        ExpressionAnalyzer analyzer = create(analysis, session, metadata, sqlParser, groupProvider, accessControl, types, warningCollector);
         for (Expression expression : expressions) {
             analyzer.analyze(
                     expression,
@@ -1901,6 +1903,7 @@ public static ExpressionAnalysis analyzeExpressions(
     public static ExpressionAnalysis analyzeExpression(
             Session session,
             Metadata metadata,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             SqlParser sqlParser,
             Scope scope,
@@ -1909,7 +1912,7 @@ public static ExpressionAnalysis analyzeExpression(
             WarningCollector warningCollector,
             CorrelationSupport correlationSupport)
     {
-        ExpressionAnalyzer analyzer = create(analysis, session, metadata, sqlParser, accessControl, TypeProvider.empty(), warningCollector, correlationSupport);
+        ExpressionAnalyzer analyzer = create(analysis, session, metadata, sqlParser, groupProvider, accessControl, TypeProvider.empty(), warningCollector, correlationSupport);
         analyzer.analyze(expression, scope);
 
         Map<NodeRef<Expression>, Type> expressionTypes = analyzer.getExpressionTypes();
@@ -1949,11 +1952,12 @@ public static ExpressionAnalyzer create(
             Session session,
             Metadata metadata,
             SqlParser sqlParser,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             TypeProvider types,
             WarningCollector warningCollector)
     {
-        return create(analysis, session, metadata, sqlParser, accessControl, types, warningCollector, CorrelationSupport.ALLOWED);
+        return create(analysis, session, metadata, sqlParser, groupProvider, accessControl, types, warningCollector, CorrelationSupport.ALLOWED);
     }
 
     public static ExpressionAnalyzer create(
@@ -1961,6 +1965,7 @@ public static ExpressionAnalyzer create(
             Session session,
             Metadata metadata,
             SqlParser sqlParser,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             TypeProvider types,
             WarningCollector warningCollector,
@@ -1969,7 +1974,7 @@ public static ExpressionAnalyzer create(
         return new ExpressionAnalyzer(
                 metadata,
                 accessControl,
-                node -> new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, correlationSupport),
+                node -> new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, accessControl, session, warningCollector, correlationSupport),
                 session,
                 types,
                 analysis.getParameters(),
diff --git a/presto-main/src/main/java/io/prestosql/sql/analyzer/QueryExplainer.java b/presto-main/src/main/java/io/prestosql/sql/analyzer/QueryExplainer.java
index 00191d8e9654..1963f32b6a19 100644
--- a/presto-main/src/main/java/io/prestosql/sql/analyzer/QueryExplainer.java
+++ b/presto-main/src/main/java/io/prestosql/sql/analyzer/QueryExplainer.java
@@ -22,6 +22,7 @@
 import io.prestosql.metadata.Metadata;
 import io.prestosql.security.AccessControl;
 import io.prestosql.spi.PrestoException;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.type.TypeOperators;
 import io.prestosql.sql.parser.SqlParser;
 import io.prestosql.sql.planner.LogicalPlanner;
@@ -57,6 +58,7 @@ public class QueryExplainer
     private final PlanFragmenter planFragmenter;
     private final Metadata metadata;
     private final TypeOperators typeOperators;
+    private final GroupProvider groupProvider;
     private final AccessControl accessControl;
     private final SqlParser sqlParser;
     private final StatsCalculator statsCalculator;
@@ -69,6 +71,7 @@ public QueryExplainer(
             PlanFragmenter planFragmenter,
             Metadata metadata,
             TypeOperators typeOperators,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             SqlParser sqlParser,
             StatsCalculator statsCalculator,
@@ -80,6 +83,7 @@ public QueryExplainer(
                 planFragmenter,
                 metadata,
                 typeOperators,
+                groupProvider,
                 accessControl,
                 sqlParser,
                 statsCalculator,
@@ -92,6 +96,7 @@ public QueryExplainer(
             PlanFragmenter planFragmenter,
             Metadata metadata,
             TypeOperators typeOperators,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             SqlParser sqlParser,
             StatsCalculator statsCalculator,
@@ -102,6 +107,7 @@ public QueryExplainer(
         this.planFragmenter = requireNonNull(planFragmenter, "planFragmenter is null");
         this.metadata = requireNonNull(metadata, "metadata is null");
         this.typeOperators = requireNonNull(typeOperators, "typeOperators is null");
+        this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
         this.accessControl = requireNonNull(accessControl, "accessControl is null");
         this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
         this.statsCalculator = requireNonNull(statsCalculator, "statsCalculator is null");
@@ -111,7 +117,7 @@ public QueryExplainer(
 
     public Analysis analyze(Session session, Statement statement, List<Expression> parameters, WarningCollector warningCollector)
     {
-        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.of(this), parameters, parameterExtractor(statement, parameters), warningCollector);
+        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, groupProvider, accessControl, Optional.of(this), parameters, parameterExtractor(statement, parameters), warningCollector);
         return analyzer.analyze(statement);
     }
 
diff --git a/presto-main/src/main/java/io/prestosql/sql/analyzer/StatementAnalyzer.java b/presto-main/src/main/java/io/prestosql/sql/analyzer/StatementAnalyzer.java
index 555fa8f553f8..5570c4e1ba77 100644
--- a/presto-main/src/main/java/io/prestosql/sql/analyzer/StatementAnalyzer.java
+++ b/presto-main/src/main/java/io/prestosql/sql/analyzer/StatementAnalyzer.java
@@ -46,6 +46,7 @@
 import io.prestosql.spi.connector.ConnectorViewDefinition.ViewColumn;
 import io.prestosql.spi.function.OperatorType;
 import io.prestosql.spi.security.AccessDeniedException;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.security.Identity;
 import io.prestosql.spi.security.ViewExpression;
 import io.prestosql.spi.type.ArrayType;
@@ -276,6 +277,7 @@ class StatementAnalyzer
     private final TypeCoercion typeCoercion;
     private final Session session;
     private final SqlParser sqlParser;
+    private final GroupProvider groupProvider;
     private final AccessControl accessControl;
     private final WarningCollector warningCollector;
     private final CorrelationSupport correlationSupport;
@@ -284,6 +286,7 @@ public StatementAnalyzer(
             Analysis analysis,
             Metadata metadata,
             SqlParser sqlParser,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             Session session,
             WarningCollector warningCollector,
@@ -293,6 +296,7 @@ public StatementAnalyzer(
         this.metadata = requireNonNull(metadata, "metadata is null");
         this.typeCoercion = new TypeCoercion(metadata::getType);
         this.sqlParser = requireNonNull(sqlParser, "sqlParser is null");
+        this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
         this.accessControl = requireNonNull(accessControl, "accessControl is null");
         this.session = requireNonNull(session, "session is null");
         this.warningCollector = requireNonNull(warningCollector, "warningCollector is null");
@@ -611,6 +615,7 @@ protected Scope visitDelete(Delete node, Optional<Scope> scope)
                     analysis,
                     metadata,
                     sqlParser,
+                    groupProvider,
                     new AllowAllAccessControl(),
                     session,
                     warningCollector,
@@ -770,7 +775,7 @@ protected Scope visitCreateView(CreateView node, Optional<Scope> scope)
             analysis.setUpdateType("CREATE VIEW", viewName);
 
             // analyze the query that creates the view
-            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
+            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
 
             Scope queryScope = analyzer.analyze(node.getQuery(), scope);
 
@@ -959,7 +964,7 @@ protected Scope visitCreateMaterializedView(CreateMaterializedView node, Optiona
             }
 
             // analyze the query that creates the view
-            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
+            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
 
             Scope queryScope = analyzer.analyze(node.getQuery(), scope);
 
@@ -1142,7 +1147,7 @@ else if (expressionType instanceof MapType) {
         @Override
         protected Scope visitLateral(Lateral node, Optional<Scope> scope)
         {
-            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
+            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
             Scope queryScope = analyzer.analyze(node.getQuery(), scope);
             return createAndAssignScope(node, scope, queryScope.getRelationType());
         }
@@ -1470,6 +1475,7 @@ protected Scope visitSampledRelation(SampledRelation relation, Optional<Scope> s
             Map<NodeRef<Expression>, Type> expressionTypes = ExpressionAnalyzer.analyzeExpressions(
                     session,
                     metadata,
+                    groupProvider,
                     accessControl,
                     sqlParser,
                     TypeProvider.empty(),
@@ -1518,7 +1524,7 @@ protected Scope visitSampledRelation(SampledRelation relation, Optional<Scope> s
         @Override
         protected Scope visitTableSubquery(TableSubquery node, Optional<Scope> scope)
         {
-            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
+            StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, accessControl, session, warningCollector, CorrelationSupport.ALLOWED);
             Scope queryScope = analyzer.analyze(node.getQuery(), scope);
             return createAndAssignScope(node, scope, queryScope.getRelationType());
         }
@@ -2568,7 +2574,9 @@ private RelationType analyzeView(Query query, QualifiedObjectName name, Optional
                 Identity identity;
                 AccessControl viewAccessControl;
                 if (owner.isPresent() && !owner.get().equals(session.getIdentity().getUser())) {
-                    identity = Identity.ofUser(owner.get());
+                    identity = Identity.forUser(owner.get())
+                            .withGroups(groupProvider.getGroups(owner.get()))
+                            .build();
                     viewAccessControl = new ViewAccessControl(accessControl, session.getIdentity());
                 }
                 else {
@@ -2579,7 +2587,7 @@ private RelationType analyzeView(Query query, QualifiedObjectName name, Optional
                 // TODO: record path in view definition (?) (check spec) and feed it into the session object we use to evaluate the query defined by the view
                 Session viewSession = createViewSession(catalog, schema, identity, session.getPath());
 
-                StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, viewAccessControl, viewSession, warningCollector, CorrelationSupport.ALLOWED);
+                StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, groupProvider, viewAccessControl, viewSession, warningCollector, CorrelationSupport.ALLOWED);
                 Scope queryScope = analyzer.analyze(query, Scope.create());
                 return queryScope.getRelationType().withAlias(name.getObjectName(), null);
             }
@@ -2657,6 +2665,7 @@ private ExpressionAnalysis analyzeExpression(Expression expression, Scope scope)
             return ExpressionAnalyzer.analyzeExpression(
                     session,
                     metadata,
+                    groupProvider,
                     accessControl,
                     sqlParser,
                     scope,
@@ -2671,6 +2680,7 @@ private ExpressionAnalysis analyzeExpression(Expression expression, Scope scope,
             return ExpressionAnalyzer.analyzeExpression(
                     session,
                     metadata,
+                    groupProvider,
                     accessControl,
                     sqlParser,
                     scope,
@@ -2700,6 +2710,7 @@ private void analyzeRowFilter(String currentIdentity, Table table, QualifiedObje
                 expressionAnalysis = ExpressionAnalyzer.analyzeExpression(
                         createViewSession(filter.getCatalog(), filter.getSchema(), Identity.forUser(filter.getIdentity()).build(), session.getPath()), // TODO: path should be included in row filter
                         metadata,
+                        groupProvider,
                         accessControl,
                         sqlParser,
                         scope,
@@ -2754,6 +2765,7 @@ private void analyzeColumnMask(String currentIdentity, Table table, QualifiedObj
                 expressionAnalysis = ExpressionAnalyzer.analyzeExpression(
                         createViewSession(mask.getCatalog(), mask.getSchema(), Identity.forUser(mask.getIdentity()).build(), session.getPath()), // TODO: path should be included in row filter
                         metadata,
+                        groupProvider,
                         accessControl,
                         sqlParser,
                         scope,
@@ -3173,6 +3185,7 @@ private List<Expression> analyzeOrderBy(Node node, List<SortItem> sortItems, Sco
 
                 ExpressionAnalysis expressionAnalysis = ExpressionAnalyzer.analyzeExpression(session,
                         metadata,
+                        groupProvider,
                         accessControl,
                         sqlParser,
                         orderByScope,
diff --git a/presto-main/src/main/java/io/prestosql/sql/planner/TypeAnalyzer.java b/presto-main/src/main/java/io/prestosql/sql/planner/TypeAnalyzer.java
index ee52b0aed961..9d5527e5ea5d 100644
--- a/presto-main/src/main/java/io/prestosql/sql/planner/TypeAnalyzer.java
+++ b/presto-main/src/main/java/io/prestosql/sql/planner/TypeAnalyzer.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import io.prestosql.Session;
 import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
@@ -49,7 +50,17 @@ public TypeAnalyzer(SqlParser parser, Metadata metadata)
 
     public Map<NodeRef<Expression>, Type> getTypes(Session session, TypeProvider inputTypes, Iterable<Expression> expressions)
     {
-        return analyzeExpressions(session, metadata, new AllowAllAccessControl(), parser, inputTypes, expressions, ImmutableMap.of(), WarningCollector.NOOP, false).getExpressionTypes();
+        return analyzeExpressions(session,
+                metadata,
+                user -> ImmutableSet.of(),
+                new AllowAllAccessControl(),
+                parser,
+                inputTypes,
+                expressions,
+                ImmutableMap.of(),
+                WarningCollector.NOOP,
+                false)
+                .getExpressionTypes();
     }
 
     public Map<NodeRef<Expression>, Type> getTypes(Session session, TypeProvider inputTypes, Expression expression)
diff --git a/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeInputRewrite.java b/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeInputRewrite.java
index f86a511cb085..8a9d06a9e943 100644
--- a/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeInputRewrite.java
+++ b/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeInputRewrite.java
@@ -18,6 +18,7 @@
 import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
 import io.prestosql.security.AccessControl;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.type.Type;
 import io.prestosql.sql.analyzer.Analysis;
 import io.prestosql.sql.analyzer.Analyzer;
@@ -67,10 +68,10 @@ public Statement rewrite(
             Statement node,
             List<Expression> parameters,
             Map<NodeRef<Parameter>, Expression> parameterLookup,
-            AccessControl accessControl,
+            GroupProvider groupProvider, AccessControl accessControl,
             WarningCollector warningCollector)
     {
-        return (Statement) new Visitor(session, parser, metadata, queryExplainer, parameters, parameterLookup, accessControl, warningCollector).process(node, null);
+        return (Statement) new Visitor(session, parser, metadata, queryExplainer, parameters, parameterLookup, groupProvider, accessControl, warningCollector).process(node, null);
     }
 
     private static final class Visitor
@@ -82,6 +83,7 @@ private static final class Visitor
         private final Optional<QueryExplainer> queryExplainer;
         private final List<Expression> parameters;
         private final Map<NodeRef<Parameter>, Expression> parameterLookup;
+        private final GroupProvider groupProvider;
         private final AccessControl accessControl;
         private final WarningCollector warningCollector;
 
@@ -92,6 +94,7 @@ public Visitor(
                 Optional<QueryExplainer> queryExplainer,
                 List<Expression> parameters,
                 Map<NodeRef<Parameter>, Expression> parameterLookup,
+                GroupProvider groupProvider,
                 AccessControl accessControl,
                 WarningCollector warningCollector)
         {
@@ -99,6 +102,7 @@ public Visitor(
             this.parser = parser;
             this.metadata = metadata;
             this.queryExplainer = queryExplainer;
+            this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
             this.accessControl = accessControl;
             this.parameters = parameters;
             this.parameterLookup = parameterLookup;
@@ -112,7 +116,7 @@ protected Node visitDescribeInput(DescribeInput node, Void context)
             Statement statement = parser.createStatement(sqlString, createParsingOptions(session));
 
             // create  analysis for the query we are describing.
-            Analyzer analyzer = new Analyzer(session, metadata, parser, accessControl, queryExplainer, parameters, parameterLookup, warningCollector);
+            Analyzer analyzer = new Analyzer(session, metadata, parser, groupProvider, accessControl, queryExplainer, parameters, parameterLookup, warningCollector);
             Analysis analysis = analyzer.analyze(statement, true);
 
             // get all parameters in query
diff --git a/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeOutputRewrite.java b/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeOutputRewrite.java
index c1180f30f753..8f2172ef5ace 100644
--- a/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeOutputRewrite.java
+++ b/presto-main/src/main/java/io/prestosql/sql/rewrite/DescribeOutputRewrite.java
@@ -19,6 +19,7 @@
 import io.prestosql.metadata.Metadata;
 import io.prestosql.metadata.QualifiedObjectName;
 import io.prestosql.security.AccessControl;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.type.FixedWidthType;
 import io.prestosql.sql.analyzer.Analysis;
 import io.prestosql.sql.analyzer.Analyzer;
@@ -66,10 +67,11 @@ public Statement rewrite(
             Statement node,
             List<Expression> parameters,
             Map<NodeRef<Parameter>, Expression> parameterLookup,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             WarningCollector warningCollector)
     {
-        return (Statement) new Visitor(session, parser, metadata, queryExplainer, parameters, parameterLookup, accessControl, warningCollector).process(node, null);
+        return (Statement) new Visitor(session, parser, metadata, queryExplainer, parameters, parameterLookup, groupProvider, accessControl, warningCollector).process(node, null);
     }
 
     private static final class Visitor
@@ -81,6 +83,7 @@ private static final class Visitor
         private final Optional<QueryExplainer> queryExplainer;
         private final List<Expression> parameters;
         private final Map<NodeRef<Parameter>, Expression> parameterLookup;
+        private final GroupProvider groupProvider;
         private final AccessControl accessControl;
         private final WarningCollector warningCollector;
 
@@ -91,6 +94,7 @@ public Visitor(
                 Optional<QueryExplainer> queryExplainer,
                 List<Expression> parameters,
                 Map<NodeRef<Parameter>, Expression> parameterLookup,
+                GroupProvider groupProvider,
                 AccessControl accessControl,
                 WarningCollector warningCollector)
         {
@@ -100,6 +104,7 @@ public Visitor(
             this.queryExplainer = queryExplainer;
             this.parameters = parameters;
             this.parameterLookup = parameterLookup;
+            this.groupProvider = requireNonNull(groupProvider, "groupProvider is null");
             this.accessControl = accessControl;
             this.warningCollector = requireNonNull(warningCollector, "warningCollector is null");
         }
@@ -110,7 +115,7 @@ protected Node visitDescribeOutput(DescribeOutput node, Void context)
             String sqlString = session.getPreparedStatement(node.getName().getValue());
             Statement statement = parser.createStatement(sqlString, createParsingOptions(session));
 
-            Analyzer analyzer = new Analyzer(session, metadata, parser, accessControl, queryExplainer, parameters, parameterLookup, warningCollector);
+            Analyzer analyzer = new Analyzer(session, metadata, parser, groupProvider, accessControl, queryExplainer, parameters, parameterLookup, warningCollector);
             Analysis analysis = analyzer.analyze(statement, true);
 
             Optional<Node> limit = Optional.empty();
diff --git a/presto-main/src/main/java/io/prestosql/sql/rewrite/ExplainRewrite.java b/presto-main/src/main/java/io/prestosql/sql/rewrite/ExplainRewrite.java
index 0a441d487f5a..95b5b25dcf94 100644
--- a/presto-main/src/main/java/io/prestosql/sql/rewrite/ExplainRewrite.java
+++ b/presto-main/src/main/java/io/prestosql/sql/rewrite/ExplainRewrite.java
@@ -19,6 +19,7 @@
 import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
 import io.prestosql.security.AccessControl;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.sql.analyzer.QueryExplainer;
 import io.prestosql.sql.parser.SqlParser;
 import io.prestosql.sql.tree.AstVisitor;
@@ -56,6 +57,7 @@ public Statement rewrite(
             Statement node,
             List<Expression> parameter,
             Map<NodeRef<Parameter>, Expression> parameterLookup,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             WarningCollector warningCollector)
     {
diff --git a/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowQueriesRewrite.java b/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowQueriesRewrite.java
index 35e8fc3aa151..7a641fb09023 100644
--- a/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowQueriesRewrite.java
+++ b/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowQueriesRewrite.java
@@ -37,6 +37,7 @@
 import io.prestosql.spi.connector.ConnectorTableMetadata;
 import io.prestosql.spi.connector.ConnectorViewDefinition;
 import io.prestosql.spi.connector.SchemaTableName;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.security.PrestoPrincipal;
 import io.prestosql.spi.security.PrincipalType;
 import io.prestosql.spi.session.PropertyMetadata;
@@ -155,6 +156,7 @@ public Statement rewrite(
             Statement node,
             List<Expression> parameters,
             Map<NodeRef<Parameter>, Expression> parameterLookup,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             WarningCollector warningCollector)
     {
diff --git a/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowStatsRewrite.java b/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowStatsRewrite.java
index 09a21ffeffc8..fb9bc3d146aa 100644
--- a/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowStatsRewrite.java
+++ b/presto-main/src/main/java/io/prestosql/sql/rewrite/ShowStatsRewrite.java
@@ -27,6 +27,7 @@
 import io.prestosql.spi.connector.ColumnMetadata;
 import io.prestosql.spi.connector.Constraint;
 import io.prestosql.spi.security.AccessDeniedException;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.spi.statistics.ColumnStatistics;
 import io.prestosql.spi.statistics.DoubleRange;
 import io.prestosql.spi.statistics.Estimate;
@@ -98,7 +99,17 @@ public class ShowStatsRewrite
     private static final Expression NULL_VARCHAR = new Cast(new NullLiteral(), toSqlType(VARCHAR));
 
     @Override
-    public Statement rewrite(Session session, Metadata metadata, SqlParser parser, Optional<QueryExplainer> queryExplainer, Statement node, List<Expression> parameters, Map<NodeRef<Parameter>, Expression> parameterLookup, AccessControl accessControl, WarningCollector warningCollector)
+    public Statement rewrite(
+            Session session,
+            Metadata metadata,
+            SqlParser parser,
+            Optional<QueryExplainer> queryExplainer,
+            Statement node,
+            List<Expression> parameters,
+            Map<NodeRef<Parameter>, Expression> parameterLookup,
+            GroupProvider groupProvider,
+            AccessControl accessControl,
+            WarningCollector warningCollector)
     {
         return (Statement) new Visitor(metadata, session, parameters, queryExplainer, accessControl, warningCollector).process(node, null);
     }
diff --git a/presto-main/src/main/java/io/prestosql/sql/rewrite/StatementRewrite.java b/presto-main/src/main/java/io/prestosql/sql/rewrite/StatementRewrite.java
index 1ee86288a461..9c7be66082d6 100644
--- a/presto-main/src/main/java/io/prestosql/sql/rewrite/StatementRewrite.java
+++ b/presto-main/src/main/java/io/prestosql/sql/rewrite/StatementRewrite.java
@@ -18,6 +18,7 @@
 import io.prestosql.execution.warnings.WarningCollector;
 import io.prestosql.metadata.Metadata;
 import io.prestosql.security.AccessControl;
+import io.prestosql.spi.security.GroupProvider;
 import io.prestosql.sql.analyzer.QueryExplainer;
 import io.prestosql.sql.parser.SqlParser;
 import io.prestosql.sql.tree.Expression;
@@ -50,11 +51,12 @@ public static Statement rewrite(
             Statement node,
             List<Expression> parameters,
             Map<NodeRef<Parameter>, Expression> parameterLookup,
+            GroupProvider groupProvider,
             AccessControl accessControl,
             WarningCollector warningCollector)
     {
         for (Rewrite rewrite : REWRITES) {
-            node = requireNonNull(rewrite.rewrite(session, metadata, parser, queryExplainer, node, parameters, parameterLookup, accessControl, warningCollector), "Statement rewrite returned null");
+            node = requireNonNull(rewrite.rewrite(session, metadata, parser, queryExplainer, node, parameters, parameterLookup, groupProvider, accessControl, warningCollector), "Statement rewrite returned null");
         }
         return node;
     }
@@ -69,7 +71,7 @@ Statement rewrite(
                 Statement node,
                 List<Expression> parameters,
                 Map<NodeRef<Parameter>, Expression> parameterLookup,
-                AccessControl accessControl,
+                GroupProvider groupProvider, AccessControl accessControl,
                 WarningCollector warningCollector);
     }
 }


Test patch:
diff --git a/presto-main/src/main/java/io/prestosql/server/testing/TestingPrestoServer.java b/presto-main/src/main/java/io/prestosql/server/testing/TestingPrestoServer.java
index 05700ae80442..6cc0a33abe33 100644
--- a/presto-main/src/main/java/io/prestosql/server/testing/TestingPrestoServer.java
+++ b/presto-main/src/main/java/io/prestosql/server/testing/TestingPrestoServer.java
@@ -17,7 +17,6 @@
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.io.Closer;
 import com.google.common.net.HostAndPort;
 import com.google.inject.Injector;
@@ -79,6 +78,7 @@
 import io.prestosql.testing.ProcedureTester;
 import io.prestosql.testing.TestingAccessControlManager;
 import io.prestosql.testing.TestingEventListenerManager;
+import io.prestosql.testing.TestingGroupProvider;
 import io.prestosql.testing.TestingWarningCollectorModule;
 import io.prestosql.transaction.TransactionManager;
 import org.weakref.jmx.guice.MBeanModule;
@@ -137,6 +137,7 @@ public static Builder builder()
     private final Metadata metadata;
     private final StatsCalculator statsCalculator;
     private final TestingAccessControlManager accessControl;
+    private final TestingGroupProvider groupProvider;
     private final ProcedureTester procedureTester;
     private final Optional<InternalResourceGroupManager<?>> resourceGroupManager;
     private final SessionPropertyDefaults sessionPropertyDefaults;
@@ -230,11 +231,12 @@ private TestingPrestoServer(
                 .add(binder -> {
                     binder.bind(EventListenerConfig.class).in(Scopes.SINGLETON);
                     binder.bind(TestingAccessControlManager.class).in(Scopes.SINGLETON);
+                    binder.bind(TestingGroupProvider.class).in(Scopes.SINGLETON);
                     binder.bind(TestingEventListenerManager.class).in(Scopes.SINGLETON);
                     binder.bind(AccessControlManager.class).to(TestingAccessControlManager.class).in(Scopes.SINGLETON);
                     binder.bind(EventListenerManager.class).to(TestingEventListenerManager.class).in(Scopes.SINGLETON);
                     binder.bind(GroupProviderManager.class).in(Scopes.SINGLETON);
-                    binder.bind(GroupProvider.class).toInstance(user -> ImmutableSet.of());
+                    binder.bind(GroupProvider.class).to(TestingGroupProvider.class).in(Scopes.SINGLETON);
                     binder.bind(AccessControl.class).to(AccessControlManager.class).in(Scopes.SINGLETON);
                     binder.bind(ShutdownAction.class).to(TestShutdownAction.class).in(Scopes.SINGLETON);
                     binder.bind(GracefulShutdownHandler.class).in(Scopes.SINGLETON);
@@ -278,6 +280,7 @@ private TestingPrestoServer(
         transactionManager = injector.getInstance(TransactionManager.class);
         metadata = injector.getInstance(Metadata.class);
         accessControl = injector.getInstance(TestingAccessControlManager.class);
+        groupProvider = injector.getInstance(TestingGroupProvider.class);
         procedureTester = injector.getInstance(ProcedureTester.class);
         splitManager = injector.getInstance(SplitManager.class);
         pageSourceManager = injector.getInstance(PageSourceManager.class);
@@ -429,6 +432,11 @@ public TestingAccessControlManager getAccessControl()
         return accessControl;
     }
 
+    public TestingGroupProvider getGroupProvider()
+    {
+        return groupProvider;
+    }
+
     public ProcedureTester getProcedureTester()
     {
         return procedureTester;
diff --git a/presto-main/src/main/java/io/prestosql/testing/LocalQueryRunner.java b/presto-main/src/main/java/io/prestosql/testing/LocalQueryRunner.java
index 59d83441f21e..6902847dcef8 100644
--- a/presto-main/src/main/java/io/prestosql/testing/LocalQueryRunner.java
+++ b/presto-main/src/main/java/io/prestosql/testing/LocalQueryRunner.java
@@ -240,6 +240,7 @@ public class LocalQueryRunner
     private final CostCalculator costCalculator;
     private final CostCalculator estimatedExchangesCostCalculator;
     private final TaskCountEstimator taskCountEstimator;
+    private final TestingGroupProvider groupProvider;
     private final TestingAccessControlManager accessControl;
     private final SplitManager splitManager;
     private final PageSourceManager pageSourceManager;
@@ -334,6 +335,7 @@ private LocalQueryRunner(
         this.taskCountEstimator = new TaskCountEstimator(() -> nodeCountForStats);
         this.costCalculator = new CostCalculatorUsingExchanges(taskCountEstimator);
         this.estimatedExchangesCostCalculator = new CostCalculatorWithEstimatedExchanges(costCalculator, taskCountEstimator);
+        this.groupProvider = new TestingGroupProvider();
         this.accessControl = new TestingAccessControlManager(transactionManager, eventListenerManager);
         accessControl.loadSystemAccessControl(AllowAllSystemAccessControl.NAME, ImmutableMap.of());
         this.pageSourceManager = new PageSourceManager();
@@ -421,7 +423,7 @@ private LocalQueryRunner(
 
         dataDefinitionTask = ImmutableMap.<Class<? extends Statement>, DataDefinitionTask<?>>builder()
                 .put(CreateTable.class, new CreateTableTask())
-                .put(CreateView.class, new CreateViewTask(sqlParser, featuresConfig))
+                .put(CreateView.class, new CreateViewTask(sqlParser, groupProvider))
                 .put(DropTable.class, new DropTableTask())
                 .put(DropView.class, new DropViewTask())
                 .put(RenameColumn.class, new RenameColumnTask())
@@ -526,6 +528,12 @@ public CostCalculator getEstimatedExchangesCostCalculator()
         return estimatedExchangesCostCalculator;
     }
 
+    @Override
+    public TestingGroupProvider getGroupProvider()
+    {
+        return groupProvider;
+    }
+
     @Override
     public TestingAccessControlManager getAccessControl()
     {
@@ -881,12 +889,13 @@ public Plan createPlan(Session session, @Language("SQL") String sql, List<PlanOp
                 planFragmenter,
                 metadata,
                 typeOperators,
+                groupProvider,
                 accessControl,
                 sqlParser,
                 statsCalculator,
                 costCalculator,
                 dataDefinitionTask);
-        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.of(queryExplainer), preparedQuery.getParameters(), parameterExtractor(preparedQuery.getStatement(), preparedQuery.getParameters()), warningCollector);
+        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, groupProvider, accessControl, Optional.of(queryExplainer), preparedQuery.getParameters(), parameterExtractor(preparedQuery.getStatement(), preparedQuery.getParameters()), warningCollector);
 
         LogicalPlanner logicalPlanner = new LogicalPlanner(
                 session,
diff --git a/presto-main/src/main/java/io/prestosql/testing/QueryRunner.java b/presto-main/src/main/java/io/prestosql/testing/QueryRunner.java
index 21033007e3bf..f5d3c8af8adf 100644
--- a/presto-main/src/main/java/io/prestosql/testing/QueryRunner.java
+++ b/presto-main/src/main/java/io/prestosql/testing/QueryRunner.java
@@ -54,6 +54,8 @@ public interface QueryRunner
 
     StatsCalculator getStatsCalculator();
 
+    TestingGroupProvider getGroupProvider();
+
     TestingAccessControlManager getAccessControl();
 
     MaterializedResult execute(@Language("SQL") String sql);
diff --git a/presto-main/src/main/java/io/prestosql/testing/TestingAccessControlManager.java b/presto-main/src/main/java/io/prestosql/testing/TestingAccessControlManager.java
index 3854d07c2559..68575a004bb0 100644
--- a/presto-main/src/main/java/io/prestosql/testing/TestingAccessControlManager.java
+++ b/presto-main/src/main/java/io/prestosql/testing/TestingAccessControlManager.java
@@ -39,6 +39,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.BiPredicate;
 import java.util.function.Predicate;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -105,11 +106,14 @@
 public class TestingAccessControlManager
         extends AccessControlManager
 {
+    private static final BiPredicate<Identity, String> IDENTITY_TABLE_TRUE = (identity, table) -> true;
+
     private final Set<TestingPrivilege> denyPrivileges = new HashSet<>();
     private final Map<RowFilterKey, List<ViewExpression>> rowFilters = new HashMap<>();
     private final Map<ColumnMaskKey, List<ViewExpression>> columnMasks = new HashMap<>();
     private Predicate<String> deniedCatalogs = s -> true;
     private Predicate<SchemaTableName> deniedTables = s -> true;
+    private BiPredicate<Identity, String> denyIdentityTable = IDENTITY_TABLE_TRUE;
 
     @Inject
     public TestingAccessControlManager(TransactionManager transactionManager, EventListenerManager eventListenerManager)
@@ -154,6 +158,7 @@ public void reset()
         denyPrivileges.clear();
         deniedCatalogs = s -> true;
         deniedTables = s -> true;
+        denyIdentityTable = IDENTITY_TABLE_TRUE;
         rowFilters.clear();
         columnMasks.clear();
     }
@@ -168,6 +173,11 @@ public void denyTables(Predicate<SchemaTableName> deniedTables)
         this.deniedTables = this.deniedTables.and(deniedTables);
     }
 
+    public void denyIdentityTable(BiPredicate<Identity, String> denyIdentityTable)
+    {
+        this.denyIdentityTable = requireNonNull(denyIdentityTable, "denyIdentityTable is null");
+    }
+
     @Override
     public Set<String> filterCatalogs(Identity identity, Set<String> catalogs)
     {
@@ -452,10 +462,13 @@ public void checkCanSetSystemSessionProperty(Identity identity, String propertyN
     @Override
     public void checkCanCreateViewWithSelectFromColumns(SecurityContext context, QualifiedObjectName tableName, Set<String> columnNames)
     {
+        if (!denyIdentityTable.test(context.getIdentity(), tableName.getObjectName())) {
+            denyCreateViewWithSelect(tableName.toString(), context.getIdentity());
+        }
         if (shouldDenyPrivilege(context.getIdentity().getUser(), tableName.getObjectName(), CREATE_VIEW_WITH_SELECT_COLUMNS)) {
             denyCreateViewWithSelect(tableName.toString(), context.getIdentity());
         }
-        if (denyPrivileges.isEmpty()) {
+        if (denyPrivileges.isEmpty() && denyIdentityTable.equals(IDENTITY_TABLE_TRUE)) {
             super.checkCanCreateViewWithSelectFromColumns(context, tableName, columnNames);
         }
     }
@@ -496,6 +509,9 @@ public void checkCanSetCatalogSessionProperty(SecurityContext context, String ca
     @Override
     public void checkCanSelectFromColumns(SecurityContext context, QualifiedObjectName tableName, Set<String> columns)
     {
+        if (!denyIdentityTable.test(context.getIdentity(), tableName.getObjectName())) {
+            denySelectColumns(tableName.toString(), columns);
+        }
         if (shouldDenyPrivilege(context.getIdentity().getUser(), tableName.getObjectName(), SELECT_COLUMN)) {
             denySelectColumns(tableName.toString(), columns);
         }
@@ -504,7 +520,7 @@ public void checkCanSelectFromColumns(SecurityContext context, QualifiedObjectNa
                 denySelectColumns(tableName.toString(), columns);
             }
         }
-        if (denyPrivileges.isEmpty()) {
+        if (denyPrivileges.isEmpty() && denyIdentityTable.equals(IDENTITY_TABLE_TRUE)) {
             super.checkCanSelectFromColumns(context, tableName, columns);
         }
     }
diff --git a/presto-main/src/main/java/io/prestosql/testing/TestingGroupProvider.java b/presto-main/src/main/java/io/prestosql/testing/TestingGroupProvider.java
new file mode 100644
index 000000000000..1a9c3aa83b8f
--- /dev/null
+++ b/presto-main/src/main/java/io/prestosql/testing/TestingGroupProvider.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed 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 io.prestosql.testing;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import io.prestosql.spi.security.GroupProvider;
+
+import java.util.Map;
+import java.util.Set;
+
+import static java.util.Objects.requireNonNull;
+
+public class TestingGroupProvider
+        implements GroupProvider
+{
+    private Map<String, Set<String>> userGroups = ImmutableMap.of();
+
+    public void reset()
+    {
+        setUserGroups(ImmutableMap.of());
+    }
+
+    public void setUserGroups(Map<String, Set<String>> userGroups)
+    {
+        this.userGroups = requireNonNull(userGroups, "userGroups is null");
+    }
+
+    @Override
+    public Set<String> getGroups(String user)
+    {
+        return userGroups.getOrDefault(user, ImmutableSet.of());
+    }
+}
diff --git a/presto-main/src/test/java/io/prestosql/sql/analyzer/TestAnalyzer.java b/presto-main/src/test/java/io/prestosql/sql/analyzer/TestAnalyzer.java
index 136c88216ef3..caec32454935 100644
--- a/presto-main/src/test/java/io/prestosql/sql/analyzer/TestAnalyzer.java
+++ b/presto-main/src/test/java/io/prestosql/sql/analyzer/TestAnalyzer.java
@@ -15,6 +15,7 @@
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import io.prestosql.Session;
 import io.prestosql.SystemSessionProperties;
 import io.prestosql.connector.CatalogName;
@@ -2841,6 +2842,7 @@ private static Analyzer createAnalyzer(Session session, Metadata metadata)
                 session,
                 metadata,
                 SQL_PARSER,
+                user -> ImmutableSet.of(),
                 new AllowAllAccessControl(),
                 Optional.empty(),
                 emptyList(),
diff --git a/presto-testing/src/main/java/io/prestosql/testing/AbstractTestDistributedQueries.java b/presto-testing/src/main/java/io/prestosql/testing/AbstractTestDistributedQueries.java
index 5caa8dbe3a88..ed8b1f166a70 100644
--- a/presto-testing/src/main/java/io/prestosql/testing/AbstractTestDistributedQueries.java
+++ b/presto-testing/src/main/java/io/prestosql/testing/AbstractTestDistributedQueries.java
@@ -1198,6 +1198,24 @@ public void testViewColumnAccessControl()
                 "Cannot select from columns \\[.*\\] in table .*.orders.*",
                 privilege(getSession().getUser(), "orders", SELECT_COLUMN));
 
+        // verify that groups are set inside access control
+        executeExclusively(() -> {
+            try {
+                // require view owner to be in a group to access table
+                getQueryRunner().getAccessControl().denyIdentityTable((identity, table) -> identity.getGroups().contains("testgroup") || !table.equals("orders"));
+                assertThatThrownBy(() -> getQueryRunner().execute(getSession(), "SELECT * FROM " + columnAccessViewName))
+                        .hasMessageMatching("Access Denied: View owner does not have sufficient privileges: View owner 'test_view_access_owner' cannot create view that selects from \\w+.\\w+.orders");
+
+                // verify view can be queried when owner is in group
+                getQueryRunner().getGroupProvider().setUserGroups(ImmutableMap.of(viewOwnerSession.getUser(), ImmutableSet.of("testgroup")));
+                getQueryRunner().execute(getSession(), "SELECT * FROM " + columnAccessViewName);
+            }
+            finally {
+                getQueryRunner().getAccessControl().reset();
+                getQueryRunner().getGroupProvider().reset();
+            }
+        });
+
         // change access denied exception to view
         assertAccessDenied("SHOW CREATE VIEW " + nestedViewName, "Cannot show create table for .*test_nested_view_column_access.*", privilege(nestedViewName, SHOW_CREATE_TABLE));
         assertAccessAllowed("SHOW CREATE VIEW " + nestedViewName, privilege("test_denied_access_view", SHOW_CREATE_TABLE));
diff --git a/presto-testing/src/main/java/io/prestosql/testing/AbstractTestQueryFramework.java b/presto-testing/src/main/java/io/prestosql/testing/AbstractTestQueryFramework.java
index ba178707f665..9cea70e107af 100644
--- a/presto-testing/src/main/java/io/prestosql/testing/AbstractTestQueryFramework.java
+++ b/presto-testing/src/main/java/io/prestosql/testing/AbstractTestQueryFramework.java
@@ -391,6 +391,7 @@ private QueryExplainer getQueryExplainer()
                 new PlanFragmenter(metadata, queryRunner.getNodePartitioningManager(), new QueryManagerConfig()),
                 metadata,
                 typeOperators,
+                queryRunner.getGroupProvider(),
                 queryRunner.getAccessControl(),
                 sqlParser,
                 queryRunner.getStatsCalculator(),
diff --git a/presto-testing/src/main/java/io/prestosql/testing/DistributedQueryRunner.java b/presto-testing/src/main/java/io/prestosql/testing/DistributedQueryRunner.java
index d97820577b18..2216d87d1528 100644
--- a/presto-testing/src/main/java/io/prestosql/testing/DistributedQueryRunner.java
+++ b/presto-testing/src/main/java/io/prestosql/testing/DistributedQueryRunner.java
@@ -335,6 +335,12 @@ public TestingAccessControlManager getAccessControl()
         return coordinator.getAccessControl();
     }
 
+    @Override
+    public TestingGroupProvider getGroupProvider()
+    {
+        return coordinator.getGroupProvider();
+    }
+
     public TestingPrestoServer getCoordinator()
     {
         return coordinator;
diff --git a/presto-testing/src/main/java/io/prestosql/testing/StandaloneQueryRunner.java b/presto-testing/src/main/java/io/prestosql/testing/StandaloneQueryRunner.java
index bacfd4b25b49..1d36a574fdde 100644
--- a/presto-testing/src/main/java/io/prestosql/testing/StandaloneQueryRunner.java
+++ b/presto-testing/src/main/java/io/prestosql/testing/StandaloneQueryRunner.java
@@ -153,6 +153,12 @@ public StatsCalculator getStatsCalculator()
         return server.getStatsCalculator();
     }
 
+    @Override
+    public TestingGroupProvider getGroupProvider()
+    {
+        return server.getGroupProvider();
+    }
+
     @Override
     public TestingAccessControlManager getAccessControl()
     {
diff --git a/presto-thrift/src/test/java/io/prestosql/plugin/thrift/integration/ThriftQueryRunner.java b/presto-thrift/src/test/java/io/prestosql/plugin/thrift/integration/ThriftQueryRunner.java
index 145a01dd9e7b..4e4f0d46b9eb 100644
--- a/presto-thrift/src/test/java/io/prestosql/plugin/thrift/integration/ThriftQueryRunner.java
+++ b/presto-thrift/src/test/java/io/prestosql/plugin/thrift/integration/ThriftQueryRunner.java
@@ -43,6 +43,7 @@
 import io.prestosql.testing.MaterializedResult;
 import io.prestosql.testing.QueryRunner;
 import io.prestosql.testing.TestingAccessControlManager;
+import io.prestosql.testing.TestingGroupProvider;
 import io.prestosql.transaction.TransactionManager;
 
 import java.io.IOException;
@@ -233,6 +234,12 @@ public StatsCalculator getStatsCalculator()
             return source.getStatsCalculator();
         }
 
+        @Override
+        public TestingGroupProvider getGroupProvider()
+        {
+            return source.getGroupProvider();
+        }
+
         @Override
         public TestingAccessControlManager getAccessControl()
         {