/// <summary> /// Returns whether this Credential has Privilege among his Roles for /// the Feature or whether any of his Memberships has the Privilege. /// </summary> /// <param name="feature"></param> /// <param name="strategy"></param> /// <param name="until"></param> /// <returns></returns> public virtual bool?CanAccess(Feature feature, AccessControlStrategy strategy, DateTime?until = null) { //TODO: None? NotSet? //TODO: yes, this is roughly loosely analog to TFS 2013 security //TODO: also borrowing from a couple other role-based models... const bool opt = true; //opt-imistic const bool pes = false; //pes-simistic //Credentials having access is ruled out here. if (!Expiry.HasAccess(until)) { return(null); } while (feature != null) { // Focus on just this feature and its branch (later on). var featuredRoles = Permissions.Where(r => r.Expiry.HasAccess(until) && r.Feature.Equals(feature)).ToArray(); // Return the desired response when privilege is met. // ReSharper disable once SwitchStatementMissingSomeCases switch (strategy) { case Optimistic: if (featuredRoles.HasPermission(Allow)) { return(opt); } break; case Pessimistic: if (featuredRoles.HasPermission(Deny)) { return(pes); } break; } // See above re: ruling out Credentials HasAccess concerns. // ReSharper disable once SwitchStatementMissingSomeCases switch (strategy) { case Optimistic: if (MemberOf.Any(m => m.Group.CanAccess(feature, strategy, until) == opt)) { return(opt); } break; case Pessimistic: if (MemberOf.Any(m => m.Group.CanAccess(feature, strategy, until) == pes)) { return(pes); } break; } // Break when we are not talking about an inherited permission. if (featuredRoles.DoesNotHavePermission(Inherited)) { break; } // Get the next one or Null when there are no parents. feature = feature.Branch.Skip(1).FirstOrDefault(); } return(null); }