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