protected void ApplyTableSecurity()

in Arriba/Arriba.Client/Model/SecureDatabase.cs [101:209]


        protected void ApplyTableSecurity<T>(IQuery<T> query, Func<SecurityIdentity, bool> isCurrentUserIn, ExecutionDetails details)
        {
            SecurityPermissions security = this.Security(query.TableName);

            // If table has row restrictions and one matches, restrict rows and allow
            // NOTE: If restricted rows are returned, columns are NOT restricted.
            foreach (var rowRestriction in security.RowRestrictedUsers)
            {
                if (isCurrentUserIn(rowRestriction.Key))
                {
                    query.Where = new AndExpression(QueryParser.Parse(rowRestriction.Value), query.Where);
                    return;
                }
            }

            // If table has column restrictions, build a list of excluded columns
            IList<string> restrictedColumns = GetRestrictedColumns(query.TableName, isCurrentUserIn);

            // If no columns were restricted, return query as-is
            if (restrictedColumns == null) return;

            // Exclude disallowed columns from where clauses
            // If a disallowed column is requested specifically, block the query and return an error
            ColumnSecurityCorrector c = new ColumnSecurityCorrector(restrictedColumns);
            try
            {
                query.Correct(c);
            }
            catch (ArribaColumnAccessDeniedException e)
            {
                query.Where = new EmptyExpression();
                details.AddDeniedColumn(e.Message);
                details.AddError(ExecutionDetails.DisallowedColumnQuery, e.Message);
            }

            // If columns are excluded, remove those from the select list
            IQuery<T> primaryQuery = query;
            if (query is JoinQuery<T>) primaryQuery = ((JoinQuery<T>)query).PrimaryQuery;

            if (primaryQuery.GetType().Equals(typeof(SelectQuery)))
            {
                SelectQuery sq = (SelectQuery)primaryQuery;
                List<string> filteredColumns = null;

                if (sq.Columns.Count == 1 && sq.Columns[0] == "*")
                {
                    filteredColumns = new List<string>();
                    foreach (ColumnDetails column in this[sq.TableName].ColumnDetails)
                    {
                        if (restrictedColumns.Contains(column.Name))
                        {
                            details.AddDeniedColumn(column.Name);
                        }
                        else
                        {
                            filteredColumns.Add(column.Name);
                        }
                    }
                }
                else
                {
                    foreach (string columnName in sq.Columns)
                    {
                        if (restrictedColumns.Contains(columnName))
                        {
                            if (filteredColumns == null) filteredColumns = new List<string>(sq.Columns);
                            filteredColumns.Remove(columnName);

                            details.AddDeniedColumn(columnName);
                        }
                    }
                }

                if (filteredColumns != null) sq.Columns = filteredColumns;
            }
            else if (primaryQuery.GetType().Equals(typeof(AggregationQuery)))
            {
                AggregationQuery aq = (AggregationQuery)primaryQuery;
                if (aq.AggregationColumns != null)
                {
                    foreach (string columnName in aq.AggregationColumns)
                    {
                        if (restrictedColumns.Contains(columnName))
                        {
                            details.AddDeniedColumn(columnName);
                            details.AddError(ExecutionDetails.DisallowedColumnQuery, columnName);
                            aq.Where = new EmptyExpression();
                        }
                    }
                }
            }
            else if (primaryQuery.GetType().Equals(typeof(DistinctQuery)))
            {
                DistinctQuery dq = (DistinctQuery)primaryQuery;
                if (restrictedColumns.Contains(dq.Column))
                {
                    details.AddDeniedColumn(dq.Column);
                    details.AddError(ExecutionDetails.DisallowedColumnQuery, dq.Column);
                    dq.Where = new EmptyExpression();
                }
            }
            else
            {
                // IQuery is extensible; there's no way to ensure that user-implemented
                // queries respect security rules.
                details.AddError(ExecutionDetails.DisallowedQuery, primaryQuery.GetType().Name);
                primaryQuery.Where = new EmptyExpression();
            }
        }