/// <summary>
        /// Creates and returns a permission that is the intersection of the current permission and the specified permission.
        /// </summary>
        /// <param name="target">A permission to intersect with the current permission. It must be of the same type as the current
        /// permission.</param>
        /// <returns>A new permission that represents the intersection of the current permission and the specified permission. This
        /// new permission is null if the intersection is empty.</returns>
        public IPermission Intersect(IPermission target)
        {
            // An intersection operation isn't possible unless both operands employ the same permissioning scheme.
            if (target is ClaimsPrincipalPermission)
            {
                // This is the source Permission scheme for the operation.
                ClaimsPrincipalPermission targetPermission = target as ClaimsPrincipalPermission;

                // If this permission scheme allows unrestricted access, then it has nothing it can add to the intersection of the
                // two schemes.
                if (this.IsUnrestricted())
                {
                    return(target.Copy());
                }

                // If the other permission scheme is unrestricted, it has nothing to add to the intersection of the two schemes.
                if (targetPermission.IsUnrestricted())
                {
                    return(this.Copy());
                }

                // Both permission schemes must share the requirement that the user is authenticated and both issuers must be the
                // same for the claims to be merged.
                if (this.isAuthenticated == targetPermission.IsAuthenticated && IsExactIssuerMatch(targetPermission.Issuer))
                {
                    // This creates a list that is the intersection of the claims in the two permission schemes.
                    List <Claim> claims = new List <Claim>();
                    foreach (Claim claim in this.requiredClaims)
                    {
                        if (targetPermission.RequiredClaims.ContainsClaim(claim))
                        {
                            claims.Add(claim);
                        }
                    }

                    // Once the set of interesecting claims is created, the permission scheme can be created.  It is known at this
                    // point that the authenticated state of the user and the issuer are equivalent.
                    return(new ClaimsPrincipalPermission(this.isAuthenticated, new DefaultClaimSet(this.requiredClaims.Issuer,
                                                                                                   claims)));
                }
            }

            // An intersection of the two permission schemes could not be constructed at this point.
            return(null);
        }
        /// <summary>
        /// Determines whether the current permission is a subset of the specified permission.
        /// </summary>
        /// <param name="target">A permission that is to be tested for the subset relationship. This permission must be of the same
        /// type as the current permission.</param>
        /// <returns>true if the current permission is a subset of the specified permission; otherwise, false.</returns>
        public bool IsSubsetOf(IPermission target)
        {
            // A subset operation isn't possible unless both operands employ the same permissioning scheme.
            if (target is ClaimsPrincipalPermission)
            {
                // This is the source Permission scheme for the operation.
                ClaimsPrincipalPermission targetPermission = target as ClaimsPrincipalPermission;

                // Unrestricted permission sets are basically the set of every claim, so this permission set, no matter what is in
                // it, is a subset of everything.
                if (targetPermission.IsUnrestricted())
                {
                    return(true);
                }

                // At this point we know that the target set contains a finite number of claims.  If this permission set contains
                // an inifinite number of claims, it can't be a subset of the target.
                if (this.IsUnrestricted())
                {
                    return(false);
                }

                // The two sets of permissions can only be compared if they require the same authentication state for the two
                // Principals and the issuers of both sets are exactly the same.
                if (this.isAuthenticated == targetPermission.IsAuthenticated && IsExactIssuerMatch(targetPermission.Issuer))
                {
                    // Any claim in the required set that doesn't belong to the target set of permissions will disqualify the
                    // required ClaimSet as a subset of the target.
                    foreach (Claim claim in this.requiredClaims)
                    {
                        if (!targetPermission.RequiredClaims.ContainsClaim(claim))
                        {
                            return(false);
                        }
                    }

                    // At this point, the required ClaimSet is a subset of the target set of permissions.
                    return(true);
                }
            }

            // The required ClaimSet is not a subset of the target at this point.
            return(false);
        }
        /// <summary>
        /// Creates a permission that is the union of the current permission and the specified permission.
        /// </summary>
        /// <param name="target">A permission to combine with the current permission. It must be of the same type as the
        /// current permission.</param>
        /// <returns>A new permission that represents the union of the current permission and the specified permission.</returns>
        public IPermission Union(IPermission target)
        {
            // A union operation isn't possible unless both operands employ the same permissioning scheme.
            if (target is ClaimsPrincipalPermission)
            {
                // This is the source Permission scheme for the operation.
                ClaimsPrincipalPermission targetPermission = target as ClaimsPrincipalPermission;

                // If either premission contains an infinite set of claims, the union is an infinite (unrestricted) permission set.
                if (targetPermission.IsUnrestricted() || this.IsUnrestricted())
                {
                    return(new ClaimsPrincipalPermission(PermissionState.Unrestricted));
                }

                // The two sets of permissions can only be merged if they require the same authentication state for the two
                // Principals and the issuers of both sets are exactly the same.
                if (this.isAuthenticated == targetPermission.IsAuthenticated && IsExactIssuerMatch(targetPermission.Issuer))
                {
                    // This creates a list of claims that is the union between the two sets of permissions.
                    List <Claim> claims = new List <Claim>();
                    foreach (Claim claim in this.requiredClaims)
                    {
                        claims.Add(claim);
                    }
                    foreach (Claim claim in targetPermission.RequiredClaims)
                    {
                        if (!claims.Contains(claim))
                        {
                            claims.Add(claim);
                        }
                    }

                    // The state of authentication and the issuer are the same at this point.  This will create and return a
                    // permission that is the union of the claims of the two permissions.
                    return(new ClaimsPrincipalPermission(this.isAuthenticated, new DefaultClaimSet(this.requiredClaims.Issuer,
                                                                                                   claims)));
                }
            }

            // At this point, the two premissions couldn't be merged.
            return(null);
        }