ComPlusAuthorization.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / ComIntegration / ComPlusAuthorization.cs / 1 / ComPlusAuthorization.cs

                            //---------------------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------------------
namespace System.ServiceModel.ComIntegration
{ 
    using System;
    using System.ServiceModel; 
    using System.ServiceModel.Diagnostics; 
    using System.Security;
    using System.Net.Security; 
    using System.Security.AccessControl;
    using System.Security.Principal;
    using System.ServiceModel.Security;
    using System.Runtime.InteropServices; 
    using System.ComponentModel;
    using System.Collections.Generic; 
    using System.Threading; 

    using SafeCloseHandle = System.IdentityModel.SafeCloseHandle; 
    using SafeHGlobalHandle = System.IdentityModel.SafeHGlobalHandle;


    internal static class SecurityUtils 
    {
        static WindowsIdentity anonymousIdentity; 
        static WindowsIdentity processIdentity; 
        static object lockObject = new object();
 
        public static SafeHandle GetTokenInformation(SafeCloseHandle token, TOKEN_INFORMATION_CLASS infoClass)
        {
            uint length;
            if (!SafeNativeMethods.GetTokenInformation(token, infoClass, SafeHGlobalHandle.InvalidHandle, 0, out length)) 
            {
                int error = Marshal.GetLastWin32Error(); 
                if (error != (int)Win32Error.ERROR_INSUFFICIENT_BUFFER) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.GetTokenInfoFailed, error))); 
                }
            }
            SafeHandle buffer = SafeHGlobalHandle.AllocHGlobal(length);
            try 
            {
                if (!SafeNativeMethods.GetTokenInformation(token, infoClass, buffer, length, out length)) 
                { 
                    int error = Marshal.GetLastWin32Error();
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.GetTokenInfoFailed, error))); 
                }
            }
            catch
            { 
                buffer.Dispose();
                throw; 
            } 
            return buffer;
        } 

        internal static bool IsAtleastImpersonationToken(SafeCloseHandle token)
        {
            using (SafeHandle buffer = 
                GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenImpersonationLevel))
            { 
                int level = Marshal.ReadInt32(buffer.DangerousGetHandle()); 
                if (level < (int)SecurityImpersonationLevel.Impersonation)
                    return false; 
                else
                    return true;
            }
        } 

        internal static bool IsPrimaryToken(SafeCloseHandle token) 
        { 
            using (SafeHandle buffer =
                GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenType)) 
            {
                int level = Marshal.ReadInt32(buffer.DangerousGetHandle());
                return (level == (int)TokenType.TokenPrimary);
            } 
        }
 
        internal static LUID GetModifiedIDLUID(SafeCloseHandle token) 
        {
            using (SafeHandle buffer = 
                GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenStatistics))
            {
                TOKEN_STATISTICS tokenStats = (TOKEN_STATISTICS)
                    Marshal.PtrToStructure(buffer.DangerousGetHandle(), typeof(TOKEN_STATISTICS)); 
                return tokenStats.ModifiedId;
            } 
        } 

        public static WindowsIdentity GetAnonymousIdentity() 
        {
            SafeCloseHandle tokenHandle = null;
            bool isImpersonating = false;
 
            lock (lockObject)
            { 
                if (anonymousIdentity == null) 
                {
                    try 
                    {
                        try
                        {
                            if (!SafeNativeMethods.ImpersonateAnonymousUserOnCurrentThread(SafeNativeMethods.GetCurrentThread())) 
                            {
                                int error = Marshal.GetLastWin32Error(); 
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.ImpersonateAnonymousTokenFailed, error))); 
                            }
                            isImpersonating = true; 
                            bool revertSuccess;
                            bool isSuccess = SafeNativeMethods.OpenCurrentThreadToken(SafeNativeMethods.GetCurrentThread(), TokenAccessLevels.Query, true, out tokenHandle);
                            if (!isSuccess)
                            { 
                                int error = Marshal.GetLastWin32Error();
 
                                revertSuccess = SafeNativeMethods.RevertToSelf(); 
                                if (false == revertSuccess)
                                { 
                                    error = Marshal.GetLastWin32Error();

                                    //this requires a failfast since failure to revert impersonation compromises security
                                    DiagnosticUtility.FailFast("RevertToSelf() failed with " + error); 
                                }
                                isImpersonating = false; 
 
                                Utility.CloseInvalidOutSafeHandle(tokenHandle);
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.OpenThreadTokenFailed, error))); 
                            }

                            revertSuccess = SafeNativeMethods.RevertToSelf();
                            if (false == revertSuccess) 
                            {
                                int error = Marshal.GetLastWin32Error(); 
 
                                //this requires a failfast since failure to revert impersonation compromises security
                                DiagnosticUtility.FailFast("RevertToSelf() failed with " + error); 
                            }
                            isImpersonating = false;

                            using (tokenHandle) 
                            {
                                anonymousIdentity = new WindowsIdentity(tokenHandle.DangerousGetHandle()); 
                            } 
                        }
                        finally 
                        {
                            if (isImpersonating)
                            {
                                bool revertSuccess = SafeNativeMethods.RevertToSelf(); 
                                if (false == revertSuccess)
                                { 
                                    int error = Marshal.GetLastWin32Error(); 

                                    //this requires a failfast since failure to revert impersonation compromises security 
                                    DiagnosticUtility.FailFast("RevertToSelf() failed with " + error);
                                }
                            }
                        } 
                    }
                    catch 
                    { 
                        // Force the finally to run before leaving the method.
                        throw; 
                    }
                }
            }
            return anonymousIdentity; 
        }
 
        public static WindowsIdentity GetProcessIdentity() 
        {
 
            SafeCloseHandle tokenHandle = null;
            lock (lockObject)
            {
 
                try
                { 
                    bool isSuccess = SafeNativeMethods.GetCurrentProcessToken(SafeNativeMethods.GetCurrentProcess(), TokenAccessLevels.Query, out tokenHandle); 
                    if (!isSuccess)
                    { 
                        int error = Marshal.GetLastWin32Error();
                        Utility.CloseInvalidOutSafeHandle(tokenHandle);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.OpenProcessTokenFailed, error)));
                    } 
                    processIdentity = new WindowsIdentity(tokenHandle.DangerousGetHandle());
                } 
                finally 
                {
                    if (tokenHandle != null) 
                        tokenHandle.Dispose();
                }
            }
            return processIdentity; 
        }
    } 
 
    internal sealed class ComPlusAuthorization
    { 

        string[] serviceRoleMembers = null;
        string[] contractRoleMembers = null;
        string[] operationRoleMembers = null; 
        CommonSecurityDescriptor securityDescriptor = null;
        static SecurityIdentifier sidAdministrators = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null); 
        Dictionary accessCheckCache = new Dictionary(); 

        public ComPlusAuthorization(string[] serviceRoleMembers, string[] contractRoleMembers, string[] operationRoleMembers) 
        {
            this.serviceRoleMembers = serviceRoleMembers;
            this.contractRoleMembers = contractRoleMembers;
            this.operationRoleMembers = operationRoleMembers; 
        }
 
        private void BuildSecurityDescriptor() 
        {
            DiagnosticUtility.DebugAssert((null == securityDescriptor), "SecurityDescriptor must be NULL"); 

            NTAccount name;
            SecurityIdentifier sid;
            CommonAce ace; 
            RawAcl acl = new RawAcl(GenericAcl.AclRevision, 1);
            int index = 0; 
            if (operationRoleMembers != null) 
            {
                foreach (string userName in operationRoleMembers) 
                {
                    name = new NTAccount(userName);
                    sid = (SecurityIdentifier)name.Translate(typeof(SecurityIdentifier));
                    ace = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, (int)ComRights.EXECUTE, sid, false, null); 
                    acl.InsertAce(index, ace);
                    index++; 
                } 
            }
            if (contractRoleMembers != null) 
            {
                foreach (string userName in contractRoleMembers)
                {
                    name = new NTAccount(userName); 
                    sid = (SecurityIdentifier)name.Translate(typeof(SecurityIdentifier));
                    ace = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, (int)ComRights.EXECUTE, sid, false, null); 
                    acl.InsertAce(index, ace); 
                    index++;
                } 
            }
            if (serviceRoleMembers != null)
            {
                foreach (string userName in serviceRoleMembers) 
                {
                    name = new NTAccount(userName); 
                    sid = (SecurityIdentifier)name.Translate(typeof(SecurityIdentifier)); 
                    ace = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, (int)ComRights.EXECUTE, sid, false, null);
                    acl.InsertAce(index, ace); 
                    index++;
                }
            }
            DiscretionaryAcl dacl = new DiscretionaryAcl(true, false, acl); 
            securityDescriptor = new CommonSecurityDescriptor(true, false, ControlFlags.DiscretionaryAclPresent, sidAdministrators, sidAdministrators, null, dacl);
 
        } 

        private bool IsAccessCached(LUID luidModifiedID, out bool isAccessAllowed) 
        {
            if (null == accessCheckCache)
            {
                DiagnosticUtility.DebugAssert("AcessCheckCache must not be NULL"); 

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(true); 
            } 

            bool retValue = false; 

            lock(this)
            {
                retValue = accessCheckCache.TryGetValue(luidModifiedID, out isAccessAllowed); 
            }
 
            return retValue; 
        }
 
        private void CacheAccessCheck(LUID luidModifiedID, bool isAccessAllowed)
        {
            if (null == accessCheckCache)
            { 
                DiagnosticUtility.DebugAssert("AcessCheckCache must not be NULL");
 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(true); 
            }
 
            lock (this)
            {
                accessCheckCache[luidModifiedID] = isAccessAllowed;
            } 
        }
        private void CheckAccess(WindowsIdentity clientIdentity, out bool IsAccessAllowed) 
        { 
            if (null == securityDescriptor)
            { 
                DiagnosticUtility.DebugAssert("Security Descriptor must not be NULL");

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(true);
            } 

            IsAccessAllowed = false; 
            byte[] BinaryForm = new byte[securityDescriptor.BinaryLength]; 
            securityDescriptor.GetBinaryForm(BinaryForm, 0);
            SafeCloseHandle ImpersonationToken = null; 
            SafeCloseHandle clientIdentityToken = new SafeCloseHandle(clientIdentity.Token, false);
            try
            {
                if (SecurityUtils.IsPrimaryToken(clientIdentityToken)) 
                {
                    if (!SafeNativeMethods.DuplicateTokenEx(clientIdentityToken, 
                                                                        TokenAccessLevels.Query, 
                                                                        IntPtr.Zero,
                                                                        SecurityImpersonationLevel.Identification, 
                                                                        TokenType.TokenImpersonation,
                                                                        out ImpersonationToken))
                    {
                        int error = Marshal.GetLastWin32Error(); 
                        Utility.CloseInvalidOutSafeHandle(ImpersonationToken);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.DuplicateTokenExFailed, error))); 
                    } 
                }
                GENERIC_MAPPING GenericMapping = new GENERIC_MAPPING(); 
                PRIVILEGE_SET PrivilegeSet = new PRIVILEGE_SET();
                uint PrivilegeSetLength = (uint)Marshal.SizeOf(PrivilegeSet);
                uint GrantedAccess = 0;
                if (!SafeNativeMethods.AccessCheck(BinaryForm, (ImpersonationToken != null) ? ImpersonationToken : clientIdentityToken, 
                    (int)ComRights.EXECUTE, GenericMapping, out PrivilegeSet,
                    ref PrivilegeSetLength, out GrantedAccess, out IsAccessAllowed)) 
                { 
                    int error = Marshal.GetLastWin32Error();
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error, SR.GetString(SR.AccessCheckFailed, error))); 
                }

            }
            finally 
            {
                if (ImpersonationToken != null) 
                    ImpersonationToken.Dispose(); 
            }
        } 

        public string[] ServiceRoleMembers
        {
            get 
            {
                return serviceRoleMembers; 
            } 
        }
        public string[] ContractRoleMembers 
        {
            get
            {
                return contractRoleMembers; 
            }
        } 
        public string[] OperationRoleMembers 
        {
            get 
            {
                return operationRoleMembers;
            }
        } 
        public CommonSecurityDescriptor SecurityDescriptor
        { 
            get 
            {
                return securityDescriptor; 
            }
        }
        public bool IsAuthorizedForOperation(WindowsIdentity clientIdentity)
        { 

            bool IsAccessAllowed = false; 
 
            if (null == clientIdentity)
            { 
                DiagnosticUtility.DebugAssert("NULL Identity");

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            } 
            if (IntPtr.Zero == clientIdentity.Token)
            { 
                DiagnosticUtility.DebugAssert("Token handle cannot be zero"); 

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }

            lock (this)
            { 
                if (securityDescriptor == null)
                { 
                    BuildSecurityDescriptor(); 
                }
            } 

            LUID luidModified = SecurityUtils.GetModifiedIDLUID(new SafeCloseHandle(clientIdentity.Token, false));

            if (IsAccessCached(luidModified, out IsAccessAllowed)) 
                return IsAccessAllowed;
 
            CheckAccess(clientIdentity, out IsAccessAllowed); 

            CacheAccessCheck(luidModified, IsAccessAllowed); 

            return IsAccessAllowed;
        }
 
    }
 
    internal sealed class ComPlusServerSecurity : IContextSecurityPerimeter, IServerSecurity, IDisposable 
    {
        WindowsIdentity clientIdentity = null; 
        IntPtr oldSecurityObject = IntPtr.Zero;
        WindowsImpersonationContext impersonateContext = null;
        bool isImpersonating = false;
        bool shouldUseCallContext = false; 

        const uint RPC_C_AUTHN_GSS_NEGOTIATE = 9; 
        const uint RPC_C_AUTHN_WINNT = 10; 
        const uint RPC_C_AUTHN_GSS_KERBEROS = 16;
        const uint RPC_C_AUTHN_DEFAULT = unchecked((uint)0xFFFFFFFF); 

        const uint RPC_C_AUTHZ_NONE = 0;

        const uint RPC_C_AUTHN_LEVEL_DEFAULT = 0; 
        const uint RPC_C_AUTHN_LEVEL_NONE = 1;
        const uint RPC_C_AUTHN_LEVEL_CONNECT = 2; 
        const uint RPC_C_AUTHN_LEVEL_CALL = 3; 
        const uint RPC_C_AUTHN_LEVEL_PKT = 4;
        const uint RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5; 
        const uint RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6;

        public ComPlusServerSecurity(WindowsIdentity clientIdentity, bool shouldUseCallContext)
        { 
            if (null == clientIdentity)
            { 
                DiagnosticUtility.DebugAssert("NULL Identity"); 

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }
            if (IntPtr.Zero == clientIdentity.Token)
            {
                DiagnosticUtility.DebugAssert("Token handle cannot be zero"); 

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            } 

            this.shouldUseCallContext = shouldUseCallContext; 
            this.clientIdentity = clientIdentity;
            IntPtr secCtx = Marshal.GetIUnknownForObject(this);
            try
            { 
                oldSecurityObject = SafeNativeMethods.CoSwitchCallContext(secCtx);
            } 
            catch 
            {
                Marshal.Release(secCtx); 

                throw;
            }
        } 
        ~ComPlusServerSecurity()
        { 
            Dispose(false); 
        }
        public bool GetPerimeterFlag() 
        {
            return shouldUseCallContext;
        }
 
        public void SetPerimeterFlag(bool flag)
        { 
            shouldUseCallContext = flag; 
        }
 
        public void QueryBlanket
        (
            IntPtr authnSvc,
            IntPtr authzSvc, 
            IntPtr serverPrincipalName,
            IntPtr authnLevel, 
            IntPtr impLevel, 
            IntPtr clientPrincipalName,
            IntPtr Capabilities 
        )
        {
            // Convert to RPC'isms.
 
            if (authnSvc != IntPtr.Zero)
            { 
                uint tempAuthnSvc = RPC_C_AUTHN_DEFAULT; 

                // Try to convert the clientIdentity.AuthenticationType to an RPC constant. 
                // This is a best case attempt.
                string authenticationType = clientIdentity.AuthenticationType;
                if (authenticationType.ToUpperInvariant() == "NTLM")
                    tempAuthnSvc = RPC_C_AUTHN_WINNT; 
                else if (authenticationType.ToUpperInvariant() == "KERBEROS")
                    tempAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS; 
                else if (authenticationType.ToUpperInvariant() == "NEGOTIATE") 
                    tempAuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE;
 
                Marshal.WriteInt32(authnSvc, (int)tempAuthnSvc);
            }

            if (authzSvc != IntPtr.Zero) 
            {
                Marshal.WriteInt32(authzSvc, (int)RPC_C_AUTHZ_NONE); 
            } 

            if (serverPrincipalName != IntPtr.Zero) 
            {
                IntPtr str = Marshal.StringToCoTaskMemUni(SecurityUtils.GetProcessIdentity().Name);

                Marshal.WriteIntPtr(serverPrincipalName, str); 
            }
 
            // There is no equivalent for the RPC authn level. It can only be 
            // approximated, in the best case. Use default.
 
            if (authnLevel != IntPtr.Zero)
            {
                Marshal.WriteInt32(authnLevel, (int)RPC_C_AUTHN_LEVEL_DEFAULT);
            } 

            if (impLevel != IntPtr.Zero) 
            { 
                Marshal.WriteInt32(impLevel, 0);
            } 

            if (clientPrincipalName != IntPtr.Zero)
            {
                IntPtr str = Marshal.StringToCoTaskMemUni(clientIdentity.Name); 

                Marshal.WriteIntPtr(clientPrincipalName, str); 
            } 

            if (Capabilities != IntPtr.Zero) 
            {
                Marshal.WriteInt32(Capabilities, 0);
            }
        } 

        public int ImpersonateClient() 
        { 
            // We want to return known COM hresults here rather than random CLR-Exception mapped HRESULTS.  Also,
            // we don't want CLR to set the ErrorInfo object. 

            int hresult = HR.E_FAIL;
            try
            { 
                impersonateContext = WindowsIdentity.Impersonate(clientIdentity.Token);
                isImpersonating = true; 
                hresult = HR.S_OK; 
            }
            catch (SecurityException) 
            {
                // Special case anonymous impersonation failure.
                // Unmanaged callers to ImpersonateClient expect this hresult.
                hresult = HR.RPC_NT_BINDING_HAS_NO_AUTH; 
            }
            catch(Exception e) 
            { 
                if(DiagnosticUtility.IsFatal(e))
                    throw; 
            }
            return hresult;
        }
        public int RevertToSelf() 
        {
            // We want to return known COM hresults here rather than random CLR-Exception mapped HRESULTS.  Also, 
            // we don't want CLR to set the ErrorInfo object. 

            int hresult = HR.E_FAIL; 
            if (isImpersonating)
            {
                try
                { 
                    impersonateContext.Undo();
                    isImpersonating = false; 
                    hresult = HR.S_OK; 
                }
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e))
                        throw;
                } 
            }
            return hresult; 
        } 
        public bool IsImpersonating()
        { 
            return isImpersonating;
        }
        void IDisposable.Dispose()
        { 
            Dispose(true);
            GC.SuppressFinalize(this); 
        } 

        public void Dispose(bool disposing) 
        {
            RevertToSelf();
            IntPtr secCtx = SafeNativeMethods.CoSwitchCallContext(oldSecurityObject);
 
            if (IntPtr.Zero == secCtx)
            { 
                // this has to be a failfast since not having a security context can compromise security 
                DiagnosticUtility.FailFast("Security Context was should not be null");
            } 

            if (Marshal.GetObjectForIUnknown(secCtx) != this)
            {
                // this has to be a failfast since being in the wrong security context can compromise security 
                DiagnosticUtility.FailFast("Security Context was modified from underneath us");
            } 
            Marshal.Release(secCtx); 
            if (disposing)
            { 
                clientIdentity = null;
                if (impersonateContext != null)
                    impersonateContext.Dispose();
            } 
        }
 
    } 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK