File: system\security\principal\windowsprincipal.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// <OWNER>Microsoft</OWNER>
// 
 
//
// WindowsPrincipal.cs
//
// Group membership checks.
//
 
namespace System.Security.Principal
{
    using System.Diagnostics.Contracts;
    using System.Runtime.InteropServices;
#if !FEATURE_CORECLR
    using System.Runtime.Serialization;
    using System.Security.Claims;
    using System.Collections.Generic;
#endif
    using System.Security.Permissions;
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles;
    using Hashtable = System.Collections.Hashtable;
 
 
    [Serializable]
    [ComVisible(true)]
    public enum WindowsBuiltInRole {
        Administrator   = 0x220,
        User            = 0x221,
        Guest           = 0x222,
        PowerUser       = 0x223,
        AccountOperator = 0x224,
        SystemOperator  = 0x225,
        PrintOperator   = 0x226,
        BackupOperator  = 0x227,
        Replicator      = 0x228
    }
 
    [Serializable]
    [HostProtection(SecurityInfrastructure=true)]
    [ComVisible(true)]
 
#if !FEATURE_CORECLR
    public class WindowsPrincipal : ClaimsPrincipal {
#else
    public class WindowsPrincipal : IPrincipal {
#endif
        private WindowsIdentity m_identity = null;
 
        // Following 3 fields are present purely for serialization compatability with Everett: not used in Whidbey        
#pragma warning disable 169
        private String[] m_roles;
        private Hashtable m_rolesTable;
        private bool m_rolesLoaded;
#pragma warning restore 169
 
        //
        // Constructors.
        //
 
        private WindowsPrincipal () {}
 
        public WindowsPrincipal (WindowsIdentity ntIdentity) 
 
#if !FEATURE_CORECLR
            : base (ntIdentity) 
#endif
        {
            if (ntIdentity == null)
                throw new ArgumentNullException("ntIdentity");
            Contract.EndContractBlock();
 
            m_identity = ntIdentity;
        }
 
#if !FEATURE_CORECLR
        [OnDeserialized()]
        [SecuritySafeCritical]
        private void OnDeserializedMethod(StreamingContext context)
        {
            // Here it the matrix of possible serializations
            //
            // Version From  |  Version To | ClaimsIdentities | Roles
            // ============     ==========   ================   ========================================================
            // 4.0               4.5         None               We always need to add a ClaimsIdentity
            //
            // 4.5               4.5         Yes                There should be a ClaimsIdentity
 
            ClaimsIdentity firstNonNullIdentity = null;
            foreach (var identity in base.Identities)
            {
                if (identity != null)
                {
                    firstNonNullIdentity = identity;
                    break;
                }
            }
 
            if (firstNonNullIdentity == null)
            {
                base.AddIdentity(m_identity);
            }
        }
#endif //!FEATURE_CORECLR
 
        //
        // Properties.
        //
#if !FEATURE_CORECLR
        public override IIdentity Identity {
#else
        public virtual IIdentity Identity {
#endif
            get {
                return m_identity;
            }
        }
 
        //
        // Public methods.
        //
 
        [SecuritySafeCritical]
        [SecurityPermission(SecurityAction.Demand, ControlPrincipal = true)]
#if !FEATURE_CORECLR
        public override bool IsInRole (string role) {
#else
        public virtual bool IsInRole (string role) {
#endif
            if (role == null || role.Length == 0)
                return false;
 
            NTAccount ntAccount = new NTAccount(role);
            IdentityReferenceCollection source = new IdentityReferenceCollection(1);
            source.Add(ntAccount);
            IdentityReferenceCollection target = NTAccount.Translate(source, typeof(SecurityIdentifier), false);
 
            SecurityIdentifier sid = target[0] as SecurityIdentifier;
 
#if !FEATURE_CORECLR
            if (sid != null) {
                if ( IsInRole(sid) ) {
                    return true;
                }
            }
 
            // possible that identity has other role claims that match
            return base.IsInRole(role);
#else
            if (sid == null)
                return false;
 
            return IsInRole(sid);
#endif
        }
 
#if !FEATURE_CORECLR
        // <summary
        // Returns all of the claims from all of the identities that are windows user claims
        // found in the NT token.
        // </summary>
        public virtual IEnumerable<Claim> UserClaims
        {
            get
            {
                foreach (ClaimsIdentity identity in Identities)
                {
                    WindowsIdentity wi = identity as WindowsIdentity;
                    if ( wi!=null)
                    {
                        foreach (Claim claim in wi.UserClaims)
                        {
                            yield return claim;
                        }
                    }   
                }
            }
        }
 
        // <summary
        // Returns all of the claims from all of the identities that are windows device claims
        // found in the NT token.
        // </summary>
        public virtual IEnumerable<Claim> DeviceClaims
        {
            get
            {
                foreach (ClaimsIdentity identity in Identities)
                {
                    WindowsIdentity wi = identity as WindowsIdentity;
                    if (wi != null)
                    {
                        foreach (Claim claim in wi.DeviceClaims)
                        {
                            yield return claim;
                        }
                    }
                }
            }
        }
#endif
        public virtual bool IsInRole (WindowsBuiltInRole role) {
            if (role < WindowsBuiltInRole.Administrator || role > WindowsBuiltInRole.Replicator)
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)role), "role");
            Contract.EndContractBlock();
 
            return IsInRole((int) role);
        }
 
        public virtual bool IsInRole (int rid) {
            SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority, 
                                                            new int[] {Win32Native.SECURITY_BUILTIN_DOMAIN_RID, rid});
 
            return IsInRole(sid);
        }
 
        // This methods (with a SID parameter) is more general than the 2 overloads that accept a WindowsBuiltInRole or
        // a rid (as an int). It is also better from a performance standpoint than the overload that accepts a string.
        // The aformentioned overloads remain in this class since we do not want to introduce a
        // breaking change. However, this method should be used in all new applications and we should document this.
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ComVisible(false)]
        public virtual bool IsInRole (SecurityIdentifier sid) {
            if (sid == null)
                throw new ArgumentNullException("sid");
            Contract.EndContractBlock();
 
            // special case the anonymous identity.
            if (m_identity.AccessToken.IsInvalid)
                return false;
 
            // CheckTokenMembership expects an impersonation token
            SafeAccessTokenHandle token = SafeAccessTokenHandle.InvalidHandle;
            if (m_identity.ImpersonationLevel == TokenImpersonationLevel.None) {
                if (!Win32Native.DuplicateTokenEx(m_identity.AccessToken,
                                                  (uint) TokenAccessLevels.Query,
                                                  IntPtr.Zero,
                                                  (uint) TokenImpersonationLevel.Identification,
                                                  (uint) TokenType.TokenImpersonation,
                                                  ref token))
                    throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
            }
 
            bool isMember = false;
            // CheckTokenMembership will check if the SID is both present and enabled in the access token.
            if (!Win32Native.CheckTokenMembership((m_identity.ImpersonationLevel != TokenImpersonationLevel.None ? m_identity.AccessToken : token),
                                                  sid.BinaryForm,
                                                  ref isMember))
                throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
 
            token.Dispose();
            return isMember;
        }
    }
}