// Check create, update or delete authorizations on all the entities of a dataset. // dataset : the dataset to check // claims : user claims to check upon // entitiesToIgnore : for these entities, the check should be skipped // mode : define if an entity not authorized should be removed from the dataset or an exception thrown public PermissionLevel CheckWriteAuthorizationsOnDataSet(IObjectsDataSet saveset, UserClaims claims, Parameters parameters, out string message) { // Work on a clone of the dataset so as not to mess with the original (causes save problems otherwise, e.g. if main entity !IsDirty) var dataset = saveset.CloneDirtyObjects(); message = null; SecurityPredicate predicate = null; foreach (var entity in dataset.GetAllObjects()) { // get the instance of the entity authorizations class var entityAuthorizations = GetEntityAuthorizations(entity); // case delete if (entity.IsMarkedForDeletion) { var permissionLevel = CanDelete(entity, claims, out message, out predicate); if (permissionLevel != PermissionLevel.Authorized) { string explanation = Explain(EntityAccessEnum.DELETE, entityAuthorizations.EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); return(PermissionLevel.Denied); } } // case create / update else { PermissionLevel permissionLevel; if (entity.IsNew) { permissionLevel = CanCreate(entity, claims, out message, out predicate); } else if (entity.IsDirty) { permissionLevel = CanUpdate(entity, claims, out message, out predicate); if (permissionLevel != PermissionLevel.Authorized && AppSettings.Get <bool>("DataSetAuthorizationCheckModeRemoveFromDataSet")) { saveset.RemoveObject(entity); continue; } } else { continue; } if (permissionLevel != PermissionLevel.Authorized) { string explanation = Explain(entity.IsNew ? EntityAccessEnum.CREATE : EntityAccessEnum.UPDATE, entityAuthorizations.EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); return(PermissionLevel.Denied); } } } return(PermissionLevel.Authorized); }
private string FormatAccessDeniedMessage(string explanation, SecurityPredicate predicate) { if (predicate == null) { return(explanation); } return($"{explanation}{(String.IsNullOrEmpty(predicate.Message) || predicate.Message.Contains(explanation) ? String.Empty : $": {predicate.Message}")}"); }
// Check read authorization on all the entities of a dataset. usefull when a get, getcollection or save action is configured with includes, to make sure related objects can be read for the given user claims. // dataset : the dataset to check // entitiesToIgnore : for these entities, the check should be skipped // mode : define if an entity not authorized should be removed from the dataset or an exception thrown public PermissionLevel CheckReadAuthorizationsOnDataSet(IObjectsDataSet dataset, UserClaims claims, IEnumerable <IDataObject> entitiesToIgnore, DataSetAuthorizationCheckMode mode, Parameters parameters, out string message) { message = null; SecurityPredicate predicate = null; // Work on a clone of the dataset so as not to mess with the original (causes save problems otherwise, e.g. if main entity !IsDirty) dataset = dataset.Clone(); foreach (var entity in dataset.GetAllObjects()) { var permissionLevel = CanRead(entity, claims, out message, out predicate); if (permissionLevel != PermissionLevel.Authorized) { if (mode == DataSetAuthorizationCheckMode.RemoveFromDataSet) { dataset.RemoveObject(entity); continue; } else { string explanation = Explain(EntityAccessEnum.READ, GetEntityAuthorizations(entity).EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); return(PermissionLevel.Denied); } } if (predicate != null) { // If the security filter needs related data, load it first: if (!String.IsNullOrEmpty(predicate.Includes)) { DataObjectHelper.RecurseLoadIncludes(entity, parameters, predicate.Includes, skipSecurity: true); } if (!DoesPredicateAccept(entity, predicate.Filter, predicate.Includes, EntityAccessEnum.READ)) { if (mode == DataSetAuthorizationCheckMode.RemoveFromDataSet) { dataset.RemoveObject(entity); continue; } else { string explanation = Explain(EntityAccessEnum.READ, GetEntityAuthorizations(entity).EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); return(PermissionLevel.Denied); } } } } return(PermissionLevel.Authorized); }
public bool IsAuthorized( IDataObject entity, SecurityPredicate predicate, EntityAccessEnum action, ref string message, Parameters parameters = null) { if (parameters == null) { // connect to existing transaction by using the existing parameters var transaction = ApplicationSettings.Resolve <ITransactionProvider>().GetTransaction(parameters) as DatabaseDataProviderTransaction; parameters = transaction.Parameters; // this following line is probably no necessary. just for safety parameters = parameters ?? new Parameters(); } var entityAuthorizations = GetEntityAuthorizations(entity); // If the security filter needs related data, load related data first: if (!String.IsNullOrEmpty(predicate.Includes)) { DataObjectHelper.RecurseLoadIncludes(entity, parameters, predicate.Includes, skipSecurity: true); } // First check the submitted data : is submitted data authorized? if (predicate.IsEvaluateDataset) { if (!DoesPredicateAccept(entity, predicate.DatasetFilter, predicate.Includes, action)) { string explanation = Explain(action, entityAuthorizations.EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); return(false); } } // Then check existing data in database if (predicate.IsEvaluateDatabase && !entity.IsNew) { // Important: We fetch a fresh copy (including the includes) to eliminate possibility of hacker messing with the dataset dynamic provider = ApplicationSettings.Container.Resolve <IEntityDataProvider>().GetDataProviderForEntity(entity); var existingEntity = provider.Get(entity, null, includes: String.IsNullOrEmpty(predicate.Includes) ? null : predicate.Includes.Split(',').ToList(), parameters: parameters, skipSecurity: true); if (!DoesPredicateAccept(existingEntity, predicate.DatasetFilter, predicate.Includes, action)) { string explanation = Explain(action, entityAuthorizations.EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); return(false); } } return(true); }
public PermissionLevel CanDelete(IDataObject entity, UserClaims claims, out string message, out SecurityPredicate predicate) { message = null; predicate = null; return(PermissionLevel.NotSet); }
public PermissionLevel CanCreate(IDataObject entity, UserClaims claims, out string message, out SecurityPredicate predicate) { message = null; predicate = null; // If not authenticated and no role assigned to anonymous users if (claims.IsAuthenticated == false && claims.Roles.Count == 0) { return(PermissionLevel.Denied); } PermissionLevel result = PermissionLevel.NotSet; // get the per-entity authorizations class so we can check for entity-specific permissions overrides var entityAuthorizations = GetEntityAuthorizations(entity); // Check override access rule first if (entityAuthorizations != null) { result = entityAuthorizations.CanCreate(entity, claims, out message, out predicate); if (result == PermissionLevel.Denied) { string explanation = Explain(EntityAccessEnum.CREATE, entityAuthorizations.EntityDisplayName); message = FormatAccessDeniedMessage(explanation, predicate); result = PermissionLevel.Denied; } } // If no override rule found, check default entity rules for an authorized role if (result == PermissionLevel.NotSet) { // Roles "Administrator", "User" have default authorized CREATE access to all entities if (claims.Roles.Intersect(new List <string> { "Administrator", "User" }).Any()) { result = PermissionLevel.Authorized; } else { message = Explain(EntityAccessEnum.CREATE, entityAuthorizations.EntityDisplayName); result = PermissionLevel.Denied; } } return(result); }