File: System\Security\Permissions\PrincipalPermission.cs
Web Access
Project: src\src\libraries\System.Security.Permissions\src\System.Security.Permissions.csproj (System.Security.Permissions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Generic;
using System.Security.Principal;
using System.Threading;
 
namespace System.Security.Permissions
{
#if NET
    [Obsolete(Obsoletions.CodeAccessSecurityMessage, DiagnosticId = Obsoletions.CodeAccessSecurityDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
#endif
    public sealed class PrincipalPermission : IPermission, ISecurityEncodable, IUnrestrictedPermission
    {
        private IDRole[] _idArray;
 
        public PrincipalPermission(PermissionState state)
        {
            if (state == PermissionState.Unrestricted)
            {
                _idArray = new IDRole[] { new IDRole(true, null, null) };
            }
            else if (state == PermissionState.None)
            {
                _idArray = new IDRole[] { new IDRole(false, string.Empty, string.Empty) };
            }
            else
            {
                throw new ArgumentException(SR.Argument_InvalidPermissionState);
            }
        }
 
        public PrincipalPermission(string name, string role)
        {
            _idArray = new IDRole[] { new IDRole(true, name, role) };
        }
 
        public PrincipalPermission(string name, string role, bool isAuthenticated)
        {
            _idArray = new IDRole[] { new IDRole(isAuthenticated, name, role) };
        }
 
        private PrincipalPermission(IDRole[] array)
        {
            _idArray = array;
        }
 
        private bool IsEmpty()
        {
            foreach (IDRole idRole in _idArray)
            {
                if (idRole.ID == null || idRole.ID.Length != 0 || idRole.Role == null || idRole.Role.Length != 0 || idRole.Authenticated)
                    return false;
            }
            return true;
        }
 
        private bool VerifyType(IPermission perm)
        {
            // if perm is null, then obviously not of the same type
            return (perm != null) && (perm.GetType() == GetType());
        }
 
        public bool IsUnrestricted()
        {
            foreach (IDRole idRole in _idArray)
            {
                if (idRole.ID != null || idRole.Role != null || !idRole.Authenticated)
                    return false;
            }
            return true;
        }
 
        public bool IsSubsetOf(IPermission target)
        {
            if (target == null)
            {
                return IsEmpty();
            }
            else if (!VerifyType(target))
            {
                throw new ArgumentException(SR.Format(SR.Argument_WrongType, GetType().FullName), nameof(target));
            }
 
            PrincipalPermission operand = (PrincipalPermission)target;
 
            if (operand.IsUnrestricted())
            {
                return true;
            }
            else if (IsUnrestricted())
            {
                return false;
            }
 
            foreach (IDRole idRole in _idArray)
            {
                bool foundMatch = false;
                foreach (IDRole operandIdRole in operand._idArray)
                {
                    if ((operandIdRole.Authenticated == idRole.Authenticated) &&
                        (operandIdRole.ID == null || (idRole.ID != null && idRole.ID.Equals(operandIdRole.ID))) &&
                        (operandIdRole.Role == null || (idRole.Role != null && idRole.Role.Equals(operandIdRole.Role))))
                    {
                        foundMatch = true;
                        break;
                    }
                }
 
                if (!foundMatch)
                    return false;
            }
 
            return true;
        }
 
        public IPermission Intersect(IPermission target)
        {
            if (target == null)
            {
                return null;
            }
            else if (!VerifyType(target))
            {
                throw new ArgumentException(SR.Format(SR.Argument_WrongType, GetType().FullName), nameof(target));
            }
            else if (IsUnrestricted())
            {
                return target.Copy();
            }
 
            PrincipalPermission operand = (PrincipalPermission)target;
 
            if (operand.IsUnrestricted())
            {
                return Copy();
            }
 
            List<IDRole> idroles = null;
            foreach (IDRole idRole in _idArray)
            {
                foreach (IDRole operandIdRole in operand._idArray)
                {
                    if (operandIdRole.Authenticated == idRole.Authenticated)
                    {
                        string newID = string.Empty;
                        string newRole = string.Empty;
                        bool newAuthenticated = operandIdRole.Authenticated;
                        bool addToNewIDRoles = false;
 
                        if (operandIdRole.ID == null || idRole.ID == null || idRole.ID.Equals(operandIdRole.ID))
                        {
                            newID = operandIdRole.ID ?? idRole.ID;
                            addToNewIDRoles = true;
                        }
                        if (operandIdRole.Role == null || idRole.Role == null || idRole.Role.Equals(operandIdRole.Role))
                        {
                            newRole = operandIdRole.Role ?? idRole.Role;
                            addToNewIDRoles = true;
                        }
                        if (addToNewIDRoles)
                        {
                            idroles ??= new List<IDRole>();
                            idroles.Add(new IDRole(newAuthenticated, newID, newRole));
                        }
                    }
                }
            }
 
            return (idroles == null) ? null : new PrincipalPermission(idroles.ToArray());
        }
 
        public IPermission Union(IPermission other)
        {
            if (other == null)
            {
                return Copy();
            }
            else if (!VerifyType(other))
            {
                throw new ArgumentException(SR.Format(SR.Argument_WrongType, GetType().FullName), nameof(other));
            }
 
            PrincipalPermission operand = (PrincipalPermission)other;
 
            if (IsUnrestricted() || operand.IsUnrestricted())
            {
                return new PrincipalPermission(PermissionState.Unrestricted);
            }
 
            IDRole[] idrolesArray = new IDRole[_idArray.Length + operand._idArray.Length];
            Array.Copy(_idArray, idrolesArray, _idArray.Length);
            Array.Copy(operand._idArray, 0, idrolesArray, _idArray.Length, operand._idArray.Length);
 
            return new PrincipalPermission(idrolesArray);
        }
 
        public override bool Equals(object obj)
        {
            IPermission perm = obj as IPermission;
            if (obj != null && perm == null)
                return false;
            if (!IsSubsetOf(perm))
                return false;
            if (perm != null && !perm.IsSubsetOf(this))
                return false;
            return true;
        }
 
        public override int GetHashCode()
        {
            int hash = 0;
            foreach (IDRole idRole in _idArray)
                hash += idRole.GetHashCode();
            return hash;
        }
 
        public IPermission Copy()
        {
            return new PrincipalPermission(_idArray);
        }
 
        public void Demand()
        {
            IPrincipal principal = Thread.CurrentPrincipal;
            if (principal == null)
                throw new SecurityException(SR.Security_PrincipalPermission);
            if (_idArray == null)
                return;
 
            // A demand passes when the grant satisfies all entries.
            foreach (IDRole idRole in _idArray)
            {
                // If the demand is authenticated, we need to check the identity and role
                if (!idRole.Authenticated)
                {
                    return;
                }
                else if (principal.Identity.IsAuthenticated &&
                         (idRole.ID == null || string.Equals(principal.Identity.Name, idRole.ID, StringComparison.OrdinalIgnoreCase)))
                {
                    if (idRole.Role == null || principal.IsInRole(idRole.Role))
                        return;
                }
            }
 
            throw new SecurityException(SR.Security_PrincipalPermission);
        }
 
        public SecurityElement ToXml()
        {
            SecurityElement root = new SecurityElement("IPermission");
 
            string typename = "System.Security.Permissions.PrincipalPermission";
            root.AddAttribute("class", typename + ", " + GetType().Module.Assembly.FullName.Replace('\"', '\''));
            root.AddAttribute("version", "1");
 
            if (_idArray != null)
            {
                foreach (IDRole idRole in _idArray)
                {
                    root.AddChild(idRole.ToXml());
                }
            }
 
            return root;
        }
 
        public void FromXml(SecurityElement elem)
        {
            if (elem is null)
            {
                throw new ArgumentNullException(nameof(elem));
            }
 
            if (elem.Tag == null || !elem.Tag.Equals("Permission") && !elem.Tag.Equals("IPermission"))
                throw new ArgumentException(SR.Argument_NotAPermissionElement);
 
            string version = elem.Attribute("version");
 
            if (version == null || (version != null && !version.Equals("1")))
                throw new ArgumentException(SR.Argument_InvalidXMLBadVersion);
 
            if (elem.Children != null && elem.Children.Count != 0)
            {
                int numChildren = elem.Children.Count;
                int count = 0;
 
                _idArray = new IDRole[numChildren];
                foreach (object curr in elem.Children)
                {
                    _idArray[count++] = new IDRole((SecurityElement)curr);
                }
            }
            else
                _idArray = Array.Empty<IDRole>();
        }
 
        public override string ToString()
        {
            return ToXml().ToString();
        }
    }
}