/// <summary> /// Get a policy decision for a particular securable /// </summary> public PolicyGrantType GetPolicyDecision(IPrincipal principal, object securable) { if (principal == null) { throw new ArgumentNullException(nameof(principal)); } else if (securable == null) { throw new ArgumentNullException(nameof(securable)); } // Get the user object from the principal var pip = ApplicationContext.Current.PolicyInformationService; // Policies var securablePolicies = pip.GetActivePolicies(securable); // Most restrictive PolicyGrantType decision = PolicyGrantType.Grant; foreach (var pol in securablePolicies) { var securablePdp = this.GetPolicyOutcome(principal, pol.Policy.Oid); if (securablePdp < decision) { decision = securablePdp; } } return(decision); }
/// <summary> /// Demand the permission /// </summary> public void Demand() { var pdp = ApplicationContext.Current.PolicyDecisionService; // Non system principals must be authenticated if (this.m_principal?.Identity?.IsAuthenticated == false || this.m_principal == null) { throw new PolicyViolationException(this.m_policyId, PolicyGrantType.Deny); } PolicyGrantType action = PolicyGrantType.Deny; if (pdp == null) // No way to verify { action = PolicyGrantType.Deny; } else if (pdp != null) { action = pdp.GetPolicyOutcome(this.m_principal, this.m_policyId); } this.m_traceSource.TraceInfo("Policy Enforce: {0}({1}) = {2}", this.m_principal?.Identity?.Name, this.m_policyId, action); if (action != PolicyGrantType.Grant) { throw new PolicyViolationException(this.m_policyId, action); } }
/// <summary> /// Throws a <see cref="T:System.Security.SecurityException" /> at run time if the security requirement is not met. /// </summary> /// <exception cref="System.UnauthorizedAccessException"> /// </exception> public void Demand() { // PDP is different here, it is local off the claims identity if (this.principal?.Identity?.IsAuthenticated == false || this.principal == null) { throw new UnauthorizedAccessException($"Policy {this.policyId} was denied"); } PolicyGrantType action = PolicyGrantType.Deny; var claimsPrincipal = this.principal as ClaimsPrincipal; if (claimsPrincipal == null) // No way to verify { action = PolicyGrantType.Deny; } else if (claimsPrincipal is ClaimsPrincipal && claimsPrincipal.HasClaim(c => c.Type == Constants.OpenIzGrantedPolicyClaim && c.Value == this.policyId || this.policyId.StartsWith(String.Format("{0}.", c.Value)))) { action = PolicyGrantType.Grant; } this.traceSource.TraceInfo("Policy Enforce: {0}({1}) = {2}", this.principal?.Identity?.Name, this.policyId, action); if (action != PolicyGrantType.Grant) { throw new UnauthorizedAccessException($"Policy {this.policyId} was denied with reason : {action}"); } }
/// <summary> /// Initializes a new instance of the <see cref="PolicyViolationException"/> class. /// </summary> /// <param name="policyId">Policy identifier.</param> /// <param name="outcome">Outcome.</param> /// <param name="principal">The principal that the action was attempted as</param> public PolicyViolationException(IPrincipal principal, string policyId, PolicyGrantType outcome) { this.PolicyId = policyId; this.PolicyDecision = principal.Identity.Name == "ANONYMOUS" ? PolicyGrantType.Elevate : outcome; this.Principal = principal; try { this.m_policyName = ApplicationServiceContext.Current.GetService <IPolicyInformationService>()?.GetPolicy(policyId)?.Name; } catch { } }
/// <summary> /// Note supported /// </summary> public void AddPolicies(object securable, PolicyGrantType rule, IPrincipal principal, params string[] policyOids) { try { using (var client = this.GetClient()) foreach (var itm in policyOids) { client.Client.Post <SecurityPolicyInfo, SecurityPolicyInfo>($"{securable.GetType().Name}/{(securable as IIdentifiedEntity).Key}/policy", new SecurityPolicyInfo() { Oid = itm, Grant = rule }); } } catch (Exception e) { throw new RemoteOperationException($"Error attaching policy {String.Join(";", policyOids)} to {securable}", e); } }
/// <summary> /// Get a policy decision /// </summary> public PolicyDecision GetPolicyDecision(IPrincipal principal, object securable) { if (principal == null) { throw new ArgumentNullException(nameof(principal)); } else if (securable == null) { throw new ArgumentNullException(nameof(securable)); } // We need to get the active policies for this var pip = ApplicationServiceContext.Current.GetService <IPolicyInformationService>(); IEnumerable <IPolicyInstance> securablePolicies = pip.GetActivePolicies(securable), principalPolicies = pip.GetActivePolicies(principal); List <PolicyDecisionDetail> details = new List <PolicyDecisionDetail>(); var retVal = new PolicyDecision(securable, details); foreach (var pol in securablePolicies) { // Get most restrictive from principal var rules = principalPolicies.Where(p => p.Policy.Oid.StartsWith(pol.Policy.Oid)).Select(o => o.Rule); PolicyGrantType rule = PolicyGrantType.Deny; if (rules.Any()) { rule = rules.Min(); } // Rule for elevate can only be made when the policy allows for it & the principal is allowed if (rule == PolicyGrantType.Elevate && (!pol.Policy.CanOverride || principalPolicies.Any(o => o.Policy.Oid == PermissionPolicyIdentifiers.ElevateClinicalData && o.Rule == PolicyGrantType.Grant))) { rule = PolicyGrantType.Deny; } details.Add(new PolicyDecisionDetail(pol.Policy.Oid, rule)); } return(retVal); }
/// <summary> /// Creates a new policy instance with the specified policy and grant /// </summary> public SecurityPolicyInstance(SecurityPolicy policy, PolicyGrantType grantType) { this.Policy = policy; this.GrantType = grantType; }
/// <summary> /// Adds the specified policies to the specified object /// </summary> /// <param name="securable">The securible to which the policy is to be added</param> /// <param name="rule">The rule to apply to the securable</param> /// <param name="policyOids">The policy OIDs to apply</param> public void AddPolicies(object securable, PolicyGrantType rule, IPrincipal principal, params string[] policyOids) { using (DataContext context = this.m_configuration.Provider.GetWriteConnection()) { IDbTransaction tx = null; try { context.Open(); tx = context.BeginTransaction(); foreach (var oid in policyOids) { var policy = context.FirstOrDefault <DbSecurityPolicy>(p => p.Oid == oid); if (policy == null) { throw new KeyNotFoundException($"Policy {oid} not found"); } // Add if (securable is SecurityRole) { var sr = securable as SecurityRole; new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.AssignPolicy, principal).Demand(); // Delete the existing role context.Delete <DbSecurityRolePolicy>(o => o.PolicyKey == policy.Key && o.SourceKey == sr.Key); context.Insert(new DbSecurityRolePolicy() { SourceKey = sr.Key.Value, GrantType = (int)rule, PolicyKey = policy.Key }); } else if (securable is SecurityApplication) { var sa = securable as SecurityApplication; new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.AssignPolicy, principal).Demand(); // Delete the existing role context.Delete <DbSecurityApplicationPolicy>(o => o.PolicyKey == policy.Key && o.SourceKey == sa.Key); context.Insert(new DbSecurityApplicationPolicy() { SourceKey = sa.Key.Value, GrantType = (int)rule, PolicyKey = policy.Key }); } else if (securable is SecurityDevice) { var sd = securable as SecurityDevice; // Delete the existing role new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.AssignPolicy, principal).Demand(); context.Delete <DbSecurityDevicePolicy>(o => o.PolicyKey == policy.Key && o.SourceKey == sd.Key); context.Insert(new DbSecurityDevicePolicy() { SourceKey = sd.Key.Value, GrantType = (int)rule, PolicyKey = policy.Key }); } else if (securable is Entity) { // Must either have write, must be the patient or must be their dedicated provider if (securable is Patient) { new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.WriteClinicalData, principal).Demand(); } else if (securable is Material || securable is ManufacturedMaterial) { new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.WriteMaterials, principal).Demand(); } else if (securable is Place || securable is Organization || securable is Provider) { new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.WritePlacesAndOrgs, principal).Demand(); } else { new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.AssignPolicy, principal).Demand(); } var ent = securable as Entity; var existing = context.FirstOrDefault <DbEntitySecurityPolicy>(e => e.SourceKey == ent.Key && e.PolicyKey == policy.Key && e.ObsoleteVersionSequenceId == null); if (existing != null) { // Set obsolete to null if rule is DENY existing.ObsoleteVersionSequenceId = null; context.Update(existing); } context.Insert(new DbEntitySecurityPolicy() { EffectiveVersionSequenceId = ent.VersionSequence.Value, PolicyKey = policy.Key, SourceKey = ent.Key.Value }); } else if (securable is Act) { new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.WriteClinicalData, principal).Demand(); var act = securable as Act; var existing = context.FirstOrDefault <DbActSecurityPolicy>(e => e.SourceKey == act.Key && e.PolicyKey == policy.Key && e.ObsoleteVersionSequenceId == null); if (existing != null) { // Set obsolete to null if rule is DENY existing.ObsoleteVersionSequenceId = null; context.Update(existing); } context.Insert(new DbActSecurityPolicy() { EffectiveVersionSequenceId = act.VersionSequence.Value, PolicyKey = policy.Key, SourceKey = act.Key.Value }); } else { throw new NotSupportedException($"Policies are not supported for {securable}"); } } tx.Commit(); } catch (Exception e) { tx.Rollback(); this.m_traceSource.TraceEvent(EventLevel.Error, "Error adding policies to {0}: {1}", securable, e); throw; } } }
internal static void AssignPolicy(PolicyAssignParms parms) { // Identify the grant type PolicyGrantType grant = PolicyGrantType.Deny; if (!String.IsNullOrEmpty(parms.GrantType)) { if (Int32.TryParse(parms.GrantType, out int grantParm)) { grant = (PolicyGrantType)grantParm; } else if (!Enum.TryParse <PolicyGrantType>(parms.GrantType, out grant)) { throw new InvalidOperationException($"Can't understand {parms.GrantType}"); } } List <SecurityPolicyInfo> policies = null; if (parms.Policy?.Count > 0) { policies = parms.Policy.OfType <String>().Select(o => m_client.GetPolicies(r => r.Oid == o).CollectionItem.FirstOrDefault()).OfType <SecurityPolicy>().Select(o => new SecurityPolicyInfo() { CanOverride = false, Grant = grant, Oid = o.Oid, Name = o.Name, Policy = o }).ToList(); } if (parms.Policy == null || policies.Count() != parms.Policy.Count) { throw new InvalidOperationException("Could not find one or more policies"); } var policyGrant = String.Join(";", policies.Select(o => o.Name)); // Apply to roles? if (parms.Role != null) { foreach (var r in parms.Role) { var role = m_client.Query <SecurityRole>(o => o.Name == r, 0, 1, out int _).CollectionItem.FirstOrDefault() as SecurityRoleInfo; if (role == null) { throw new KeyNotFoundException($"Role {r} not found"); } policies.ForEach(o => m_client.Client.Post <SecurityPolicyInfo, SecurityPolicyInfo>($"SecurityRole/{role.Entity.Key}/policy", o)); Console.WriteLine("{2}: {1} TO {0}", r, policyGrant, grant); } } // Apply to devices? if (parms.Device != null) { foreach (var d in parms.Device) { var device = m_client.Query <SecurityDevice>(o => o.Name == d, 0, 1, out int _).CollectionItem.FirstOrDefault() as SecurityDeviceInfo; if (device == null) { throw new KeyNotFoundException($"Device {d} not found"); } policies.ForEach(o => m_client.Client.Post <SecurityPolicyInfo, SecurityPolicyInfo>($"SecurityDevice/{device.Entity.Key}/policy", o)); Console.WriteLine("{2}: {1} TO {0}", d, policyGrant, grant); } } // Apply to devices? if (parms.Application != null) { foreach (var a in parms.Application) { var application = m_client.Query <SecurityApplication>(o => o.Name == a, 0, 1, out int _).CollectionItem.FirstOrDefault() as SecurityApplicationInfo; if (application == null) { throw new KeyNotFoundException($"Application {a} not found"); } policies.ForEach(o => m_client.Client.Post <SecurityPolicyInfo, SecurityPolicyInfo>($"SecurityApplication/{application.Entity.Key}/policy", o)); Console.WriteLine("{2}: {1} TO {0}", a, policyGrant, grant); } } }
/// <summary> /// Initializes a new instance of the <see cref="OpenIZ.Mobile.Core.Exceptions.PolicyViolationException"/> class. /// </summary> /// <param name="policy">Policy.</param> /// <param name="outcome">Outcome.</param> public PolicyViolationException(IPolicy policy, PolicyGrantType outcome) { this.Policy = policy; this.PolicyId = policy.Oid; this.PolicyDecision = outcome; }
/// <summary> /// Initializes a new instance of the <see cref="OpenIZ.Mobile.Core.Exceptions.PolicyViolationException"/> class. /// </summary> /// <param name="policyId">Policy identifier.</param> /// <param name="outcome">Outcome.</param> public PolicyViolationException(string policyId, PolicyGrantType outcome) { this.PolicyId = policyId; this.PolicyDecision = outcome; }
/// <summary> /// Constructs a new instance of the policy instance /// </summary> public GenericPolicyInstance(IPolicy policy, PolicyGrantType rule) { this.Policy = policy; this.Rule = rule; }
/// <summary> /// Creates a new policy decision outcome /// </summary> public PolicyDecisionDetail(String policyId, PolicyGrantType outcome) { this.PolicyId = policyId; this.Outcome = outcome; }
/// <summary> /// Effective policy instance /// </summary> public EffectivePolicyInstance(IPolicy policy, PolicyGrantType rule, IPrincipal forPrincipal) { this.Policy = new EffectivePolicy(policy.Key, policy.Oid, policy.Name, policy.CanOverride); this.Rule = rule; this.m_securable = forPrincipal; }
/// <summary> /// Create a policy from policy instance /// </summary> public AdoSecurityPolicyInstance(IPolicy policyInstance, PolicyGrantType rule) { this.Policy = policyInstance; this.Rule = rule; }
/// <summary> /// Add the specified policies to the specified securable /// </summary> public void AddPolicies(object securable, PolicyGrantType rule, IPrincipal principal, params string[] policyOids) { var conn = this.CreateConnection(); using (conn.Lock()) { // First resolve identities if (securable is IDeviceIdentity) { var did = securable as IDeviceIdentity; var dbd = conn.Table <DbSecurityDevice>().Where(o => o.PublicId == did.Name).ToList(); securable = dbd.Select(o => new SecurityDevice() { Key = o.Key, Name = o.PublicId }).FirstOrDefault(); if (securable == null) { throw new KeyNotFoundException($"Device identity {did.Name} not found"); } } else if (securable is Act) { throw new NotSupportedException("Policies should be assigned to ACTS via the IRepositoryService<Act>"); } else if (securable is Entity) { throw new NotSupportedException("Policies should be assigned to ENTITIES via the IRepositoryService<Entity>"); } byte[] key = (securable as IdentifiedData)?.Key.Value.ToByteArray(); // Delete existing policy oids foreach (var oid in policyOids) { // Get the policy var policy = conn.Table <DbSecurityPolicy>().Where(p => p.Oid == oid).ToList().FirstOrDefault(); if (policy == null) { throw new KeyNotFoundException($"Policy {oid} not found"); } if (securable is SecurityDevice) { conn.Table <DbSecurityDevicePolicy>().Delete(o => o.DeviceId == key && o.PolicyId == policy.Uuid); } else if (securable is SecurityRole) { conn.Table <DbSecurityRolePolicy>().Delete(o => o.RoleId == key && o.PolicyId == policy.Uuid); } else { throw new ArgumentOutOfRangeException("Invalid type", nameof(securable)); } if (securable is SecurityDevice) { conn.Insert(new DbSecurityDevicePolicy() { DeviceId = key, GrantType = (int)rule, PolicyId = policy.Key.ToByteArray(), Key = Guid.NewGuid() }); } else if (securable is SecurityRole) { conn.Insert(new DbSecurityRolePolicy() { RoleId = key, GrantType = (int)rule, PolicyId = policy.Key.ToByteArray(), Key = Guid.NewGuid() }); } } } }