Created
February 26, 2014 19:54
-
-
Save anonymous/9237151 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class AuthorizationQueryValidator : ODataQueryValidator | |
{ | |
public override void Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) | |
{ | |
base.Validate(options, validationSettings); | |
CanAccess(options.Request.GetODataPath().EntitySet); | |
SelectExpandClause selectExpandClause = options.SelectExpand.SelectExpandClause; | |
IList<ExpandedNavigationSelectItem> expandedItems = GetExpandedProperties(selectExpandClause); | |
foreach (ExpandedNavigationSelectItem item in expandedItems) | |
{ | |
ValidatePath(item); | |
} | |
} | |
private void ValidatePath(ExpandedNavigationSelectItem item) | |
{ | |
if (CanAccess(item.EntitySet)) | |
{ | |
foreach (var element in GetExpandedProperties(item.SelectAndExpand)) | |
{ | |
ValidatePath(element); | |
} | |
} | |
else | |
{ | |
throw new InvalidOperationException(string.Format("Can't access the entitySet {0}", item.EntitySet.Name)); | |
} | |
} | |
Up to here is the interesting part | |
private static IEdmNavigationProperty GetNavigationProperty(ExpandedNavigationSelectItem item) | |
{ | |
return item.PathToNavigationProperty.OfType<NavigationPropertySegment>().Last().NavigationProperty; | |
} | |
public abstract bool CanAccess(IEdmNavigationSource navigationSource); | |
private static IList<ExpandedNavigationSelectItem> GetExpandedProperties(SelectExpandClause clause) | |
{ | |
Contract.Assert(clause != null); | |
return clause.SelectedItems.OfType<ExpandedNavigationSelectItem>().ToList(); | |
} | |
} | |
That is the abstract class that I defined just to try several options. This could be a way to do it: | |
public class AuthorizationAnnotation | |
{ | |
public string[] AllowedRoles { get; private set; } | |
public AuthorizationAnnotation(params string[] allowedRoles) | |
{ | |
AllowedRoles = allowedRoles; | |
} | |
} | |
public class StaticAuthorizationQueryValidator : AuthorizationQueryValidator | |
{ | |
private HttpRequestMessage _request; | |
public StaticAuthorizationQueryValidator(HttpRequestMessage request) | |
{ | |
_request = request; | |
} | |
public override bool CanAccess(IEdmNavigationSource edmEntitySetBase) | |
{ | |
IEdmModel model = _request.GetEdmModel(); | |
AuthorizationAnnotation authorizedRoles = model.GetAnnotationValue<AuthorizationAnnotation>(edmEntitySetBase); | |
return authorizedRoles == null || | |
authorizedRoles.AllowedRoles.Any(rol => rol == "*" || _request.GetRequestContext().Principal.IsInRole(rol)); | |
} | |
} | |
Here is how you would configure the model: | |
public static IEdmModel GetModel() | |
{ | |
ODataModelBuilder builder = new ODataConventionModelBuilder(); | |
builder.EntitySet<Customer>("Customers"); | |
builder.EntitySet<Order>("Orders"); | |
builder.EntitySet<Address>("Addresses"); | |
builder.EntitySet<OrderLine>("OrdersLines"); | |
IEdmModel model = builder.GetEdmModel(); | |
SetRoles(model, "Customers", "*"); | |
SetRoles(model, "Orders", "Administrator"); | |
SetRoles(model, "Addresses", "EspecialRole"); | |
return model; | |
} | |
private static void SetRoles(IEdmModel model, string navigationSourceName, params string[] roles) | |
{ | |
IEdmNavigationSource navigationSource = model.EntityContainer.FindEntitySet(navigationSourceName); | |
if (navigationSource == null) | |
{ | |
navigationSource = model.EntityContainer.FindSingleton(navigationSourceName); | |
} | |
if (navigationSource == null) | |
{ | |
throw new ArgumentException("The given entity set or singleton doesn't exist", "navigationSourceName"); | |
} | |
model.SetAnnotationValue(navigationSource, new AuthorizationAnnotation(roles)); | |
} | |
Plumbing through the QueryableAttribute: | |
public class ValidatingQueryableAttribute : QueryableAttribute | |
{ | |
public override void ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions) | |
{ | |
queryOptions.Validator = new StaticAuthorizationQueryValidator(request); | |
base.ValidateQuery(request, queryOptions); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment