WsatConfiguration.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 / Tools / WSATConfig / Configuration / WsatConfiguration.cs / 2 / WsatConfiguration.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace Microsoft.Tools.ServiceModel.WsatConfig 
{
    using System; 
    using System.Text; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Principal; 
    using System.Globalization;
    using System.Diagnostics;
    using System.Security.Permissions;
    using System.Security.Cryptography; 
    using System.Security.AccessControl;
    using Microsoft.Win32; 
 
    // In theory we could abstract this class out and provide concrete implementation for config from different
    // sources, in practice we didn't do that for historical code reasons 
    class WsatConfiguration
    {
        const string TransactionBridgeRegistryValue = "{EEC5DCCA-05DC-4B46-8AF7-2881C1635AEA}";
 
        internal const bool DefaultNetworkSupport = false;
        internal const uint DefaultHttpsPort = 443; 
        internal const SourceLevels DefaultTraceLevel = SourceLevels.Warning; 
        internal const bool DefaultActivityPropagation = false;
        internal const bool DefaultActivityTracing = false; 
        internal const uint DefaultDefaultTimeout = 60;
        internal const uint DefaultMaxTimeout = 3600;
        internal const bool DefaultTracingPii = false;
        internal string[] DefaultX509GlobalAcl = { string.Empty }; 
        internal string[] DefaultKerberosGlobalAcl = { @"NT AUTHORITY\Authenticated Users" };
        const X509Certificate2 DefaultX509CertificateIdentity = null; 
 
        WsatConfiguration previousConfig;
        FirewallWrapper firewallWrapper; 
        string machineName;
        string virtualServer;
        ConfigurationProvider wsatConfigProvider;
        ConfigurationProvider msdtcConfigProvider; 

        bool isClusterRemoteNode = false; 
        uint httpsPort = DefaultHttpsPort; 
        uint defaultTimeout = DefaultDefaultTimeout;
        uint maxTimeout = DefaultMaxTimeout; 
        SourceLevels diagnosticTraceLevel = DefaultTraceLevel;
        bool activityPropagation = DefaultActivityPropagation;
        bool activityTracing = DefaultActivityTracing;
        bool tracePii = DefaultTracingPii; 
        bool transactionBridgeEnabled = false;
        X509Certificate2 certificate = DefaultX509CertificateIdentity; 
        string[] allowedCertificates = null; 
        string[] kerberosGlobalAcl = null;
        bool minimalWrite = false; 
        string[] clusterNodes = null;

        SafeHResource hClusterDtcResource;
 
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        internal WsatConfiguration(string machineName, string virtualServer, WsatConfiguration previousConfig, bool minimalWrite) 
        { 
            this.MachineName = machineName;
            this.minimalWrite = minimalWrite; 
            this.firewallWrapper = new FirewallWrapper();
            this.previousConfig = previousConfig;
            this.virtualServer = virtualServer;
            if (previousConfig == null) 
            {
                this.allowedCertificates = DefaultX509GlobalAcl; 
                this.kerberosGlobalAcl = DefaultKerberosGlobalAcl; 
            }
            else 
            {
                CopyConfigurationData(previousConfig, this);
            }
 
            if (MsdtcClusterUtils.IsClusterServer(MachineName))
            { 
                this.hClusterDtcResource = MsdtcClusterUtils.GetTransactionManagerClusterResource(VirtualServer, out clusterNodes); 
                if (hClusterDtcResource == null || hClusterDtcResource.IsInvalid)
                { 
                    if (!string.IsNullOrEmpty(VirtualServer))
                    {
                        throw new WsatAdminException(WsatAdminErrorCode.CANNOT_FIND_CLUSTER_VIRTUAL_SERVER, SR.GetString(SR.ErrorCanNotFindVirtualServer));
                    } 
                }
            } 
            InitializeConfigurationProvider(); 
        }
 
        void CopyConfigurationData(WsatConfiguration src, WsatConfiguration dest)
        {
            dest.TransactionBridgeEnabled = src.TransactionBridgeEnabled;
            dest.HttpsPort = src.HttpsPort; 
            dest.X509Certificate = src.X509Certificate;
            dest.KerberosGlobalAcl = src.KerberosGlobalAcl; 
            dest.X509GlobalAcl = src.X509GlobalAcl; 
            dest.DefaultTimeout = src.DefaultTimeout;
            dest.MaxTimeout = src.MaxTimeout; 
            dest.TraceLevel = src.TraceLevel;
            dest.ActivityPropagation = src.ActivityPropagation;
            dest.ActivityTracing = src.ActivityTracing;
            dest.TracePii = src.TracePii; 
            dest.MachineName = src.MachineName;
            dest.IsClusterRemoteNode = src.IsClusterRemoteNode; 
            dest.VirtualServer = src.VirtualServer; 
        }
 
        internal MsdtcWrapper GetMsdtcWrapper()
        {
            return MsdtcWrapper.GetWrapper(MachineName, VirtualServer, this.msdtcConfigProvider);
        } 

        // A cluster node can spawn remote processes to setup other nodes. 
        // Is this a node of cluster, but not the originating one? 
        internal bool IsClusterRemoteNode
        { 
            get { return this.isClusterRemoteNode; }
            set { this.isClusterRemoteNode = value; }
        }
 
        internal bool IsClustered
        { 
            get 
            {
                return (hClusterDtcResource != null && !hClusterDtcResource.IsInvalid); 
            }
        }

        internal string MachineName 
        {
            get { return string.IsNullOrEmpty(this.machineName) ? string.Empty : machineName; } 
            set { this.machineName = value; } 
        }
 
        internal string VirtualServer
        {
            get { return this.virtualServer; }
            set { this.virtualServer = value; } 
        }
 
        internal bool TransactionBridgeEnabled 
        {
            get { return this.transactionBridgeEnabled; } 
            set { this.transactionBridgeEnabled = value; }
        }

        internal uint HttpsPort 
        {
            get { return this.httpsPort; } 
            set { this.httpsPort = value; } 
        }
 
        internal SourceLevels TraceLevel
        {
            get { return this.diagnosticTraceLevel; }
            set { this.diagnosticTraceLevel = value; } 
        }
 
        internal uint DefaultTimeout 
        {
            get { return this.defaultTimeout; } 
            set { this.defaultTimeout = value; }
        }

        internal uint MaxTimeout 
        {
            get { return this.maxTimeout; } 
            set { this.maxTimeout = value; } 
        }
 
        internal bool ActivityTracing
        {
            get { return this.activityTracing; }
            set { this.activityTracing = value; } 
        }
 
        internal bool ActivityPropagation 
        {
            get { return this.activityPropagation; } 
            set { this.activityPropagation = value; }
        }

        internal bool TracePii 
        {
            get { return this.tracePii; } 
            set { this.tracePii = value; } 
        }
 
        internal string[] X509GlobalAcl
        {
            get { return this.allowedCertificates; }
            set 
            {
                if (value == null) 
                { 
                    this.allowedCertificates = new string[] {};
                } 
                else
                {
                    this.allowedCertificates = value;
                } 
            }
        } 
 
        internal string[] KerberosGlobalAcl
        { 
            get { return kerberosGlobalAcl; }
            set
            {
                if (value == null) 
                {
                    this.kerberosGlobalAcl = new string[] {}; 
                } 
                else
                { 
                    this.kerberosGlobalAcl = value;
                }
            }
        } 

        internal X509Certificate2 X509Certificate 
        { 
            get { return this.certificate; }
            set { this.certificate = value; } 
        }

        internal void ValidateThrow()
        { 
            if (this.TransactionBridgeEnabled)
            { 
                // rule: WS-AT network support requires MSDTC network transaction to be enabled 

                // GetNetworkTransactionAccess fails if current remote cluster node does not take ownership 
                if (!IsClusterRemoteNode)
                {
                    MsdtcWrapper wrapper = this.GetMsdtcWrapper();
                    if (!wrapper.GetNetworkTransactionAccess()) 
                    {
                        throw new WsatAdminException(WsatAdminErrorCode.MSDTC_NETWORK_ACCESS_DISABLED, 
                                                        SR.GetString(SR.ErrorMsdtcNetworkAccessDisabled)); 
                    }
                } 

                // rule: HTTPS port must be in range 1-65535
                if (this.HttpsPort < 1)
                { 
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_HTTPS_PORT,
                                                    SR.GetString(SR.ErrorHttpsPortRange)); 
                } 

                // rule: local endpoint certificate must be specified and valid 
                ValidateIdentityCertificateThrow(this.X509Certificate, !Utilities.IsLocalMachineName(MachineName));

                // rule: default timeout should be in range 1-3600
                if (this.DefaultTimeout < 1 || this.DefaultTimeout > 3600) 
                {
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_DEFTIMEOUT_ARGUMENT, 
                                                    SR.GetString(SR.ErrorDefaultTimeoutRange)); 
                }
 
                // rule: max timeout be in range 0-3600
                if (this.MaxTimeout > 3600)
                {
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_MAXTIMEOUT_ARGUMENT, 
                                                    SR.GetString(SR.ErrorMaximumTimeoutRange));
                } 
            } 
        }
 
        void InitializeConfigurationProvider()
        {
            if (IsClustered)
            { 
                this.msdtcConfigProvider = new ClusterRegistryConfigurationProvider(this.hClusterDtcResource, GetClusterMstdcRegistryKey());
                this.wsatConfigProvider = new ClusterRegistryConfigurationProvider(this.hClusterDtcResource, WsatKeys.WsatClusterRegKey); 
            } 
            else
            { 
                this.msdtcConfigProvider = new RegistryConfigurationProvider(RegistryHive.LocalMachine, WsatKeys.MsdtcRegKey, MachineName);
                this.wsatConfigProvider = new RegistryConfigurationProvider(RegistryHive.LocalMachine, WsatKeys.WsatRegKey, MachineName);
            }
        } 

        // 
        // LH: Cluster\Resources\GUID_OF_DTC\MSDTCPrivate\MSDTC 
        // W2k3: Cluster\Resources\GUID_OF_DTC\SOME_GUID\, here SOME_GUID is the default value of GUID_OF_DTC\DataPointer\
        // 
        string GetClusterMstdcRegistryKey()
        {
            Debug.Assert(IsClustered);
 
            if (Utilities.OSMajor > 5)
            { 
                return WsatKeys.MsdtcClusterRegKey_OS6; 
            }
            ClusterRegistryConfigurationProvider clusterReg = new ClusterRegistryConfigurationProvider(this.hClusterDtcResource, WsatKeys.MsdtcClusterDataPointerRegKey_OS5); 
            using (clusterReg)
            {
                //the default value
                string subKey = clusterReg.ReadString(string.Empty, string.Empty); 
                if (!string.IsNullOrEmpty(subKey))
                { 
                    return subKey; 
                }
            } 
            RegistryExceptionHelper registryExceptionHelper = new RegistryExceptionHelper(WsatKeys.MsdtcClusterDataPointerRegKey_OS5);
            throw registryExceptionHelper.CreateRegistryAccessException(null);
        }
 
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        internal void LoadFromRegistry() 
        { 
            string value = msdtcConfigProvider.ReadString(WsatKeys.TransactionBridgeRegKey, null);
            TransactionBridgeEnabled = Utilities.SafeCompare(value, TransactionBridgeRegistryValue); 

            HttpsPort = wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryHttpsPort, DefaultHttpsPort);
            X509Certificate = CertificateManager.GetCertificateFromThumbprint(
                wsatConfigProvider.ReadString(WsatKeys.RegistryEntryX509CertificateIdentity, string.Empty), 
                MachineName);
            KerberosGlobalAcl = wsatConfigProvider.ReadMultiString(WsatKeys.RegistryEntryKerberosGlobalAcl, DefaultKerberosGlobalAcl); 
            X509GlobalAcl = wsatConfigProvider.ReadMultiString(WsatKeys.RegistryEntryX509GlobalAcl, DefaultX509GlobalAcl); 
            TraceLevel = (SourceLevels)wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryTraceLevel, (uint)DefaultTraceLevel);
#pragma warning disable 429 
            ActivityTracing = wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryActivityTracing, (DefaultActivityTracing ? 1 : 0)) != 0;
            ActivityPropagation = wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryPropagateActivity, (DefaultActivityPropagation ? 1 : 0)) != 0;
            TracePii = wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryTracingPii, (DefaultTracingPii ? 1 : 0)) != 0;
#pragma warning restore 429 
            DefaultTimeout = wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryDefTimeout, DefaultDefaultTimeout);
            MaxTimeout = wsatConfigProvider.ReadUInt32(WsatKeys.RegistryEntryMaxTimeout, DefaultMaxTimeout); 
        } 

        internal bool IsLocalMachine 
        {
            get { return !IsClustered && Utilities.IsLocalMachineName(this.MachineName); }
        }
 
        // The code should align with the ValidateIdentityCertificate implementation in
        // src\TransactionBridge\Microsoft\Transactions\Wsat\protocol\Configuration.cs 
        internal static void ValidateIdentityCertificateThrow(X509Certificate2 cert, bool remoteCert) 
        {
            // I wish we had system-defined constants for these. We don't. 
            const string KeyUsage = "2.5.29.15";
            const string EnhancedKeyUsage = "2.5.29.37";
            const string ClientAuthentication = "1.3.6.1.5.5.7.3.2";
            const string ServerAuthentication = "1.3.6.1.5.5.7.3.1"; 

            X509Certificate2 identity = cert; 
 
            // 0) The certificate should be present
            if (identity == null) 
            {
                throw new WsatAdminException(WsatAdminErrorCode.INVALID_OR_MISSING_SSL_CERTIFICATE,
                                                              SR.GetString(SR.ErrorMissingSSLCert));
            } 

            if (remoteCert) 
            { 
                return; // the following info is not accurate for remote cert, so we do not bother to check them
            } 

            // 1) A certificate identity must have a private key
            if (!identity.HasPrivateKey)
            { 
                throw new WsatAdminException(WsatAdminErrorCode.INVALID_OR_MISSING_SSL_CERTIFICATE,
                                                                SR.GetString(SR.ErrorSSLCertHasNoPrivateKey)); 
            } 

            // 2) A certificate identity must have an accessible private key 
            try
            {
                // Yes, this property throws on error...
                AsymmetricAlgorithm privateKey = identity.PrivateKey; 
            }
            catch (CryptographicException e) 
            { 
                throw new WsatAdminException(WsatAdminErrorCode.INVALID_OR_MISSING_SSL_CERTIFICATE,
                                                                SR.GetString(SR.ErrorSSLCertCanNotAccessPrivateKey), e); 
            }

            // 3) If a "Key Usage" extension is present, it must allow "Key Encipherment"
            // 4) If a "Key Usage" extension is present, it must allow "Digital Signature" 
            X509KeyUsageExtension keyUsage = (X509KeyUsageExtension)identity.Extensions[KeyUsage];
            if (keyUsage != null) 
            { 
                const X509KeyUsageFlags required = X509KeyUsageFlags.KeyEncipherment |
                                                   X509KeyUsageFlags.DigitalSignature; 

                if ((keyUsage.KeyUsages & required) != required)
                {
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_OR_MISSING_SSL_CERTIFICATE, 
                                                                    SR.GetString(SR.ErrorSSLCertDoesNotSupportKeyEnciphermentOrDsig));
                } 
            } 

            X509EnhancedKeyUsageExtension enhancedKeyUsage = (X509EnhancedKeyUsageExtension)identity.Extensions[EnhancedKeyUsage]; 
            if (enhancedKeyUsage != null)
            {
                // 5) If an "Enhanced Key Usage" extension is present, it must allow "Client Authentication"
                if (enhancedKeyUsage.EnhancedKeyUsages[ClientAuthentication] == null) 
                {
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_OR_MISSING_SSL_CERTIFICATE, 
                                                                    SR.GetString(SR.ErrorSSLCertDoesNotSupportClientAuthentication)); 
                }
 
                // 6) If an "Enhanced Key Usage" extension is present, it must allow "Server Authentication"
                if (enhancedKeyUsage.EnhancedKeyUsages[ServerAuthentication] == null)
                {
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_OR_MISSING_SSL_CERTIFICATE, 
                                                                    SR.GetString(SR.ErrorSSLCertDoesNotSupportServerAuthentication));                }
            } 
        } 

        void UpdateClusterNodesPorts(bool restart) 
        {
            if (clusterNodes != null)
            {
                foreach (string node in clusterNodes) 
                {
                    if (Utilities.SafeCompare(node, Utilities.LocalHostName)) 
                    { 
                        UpdatePorts();
                        UpdateCertificatePrivateKeyAccess(); 
                    }
                    else
                    {
                        //Explicitly not to restart DTC on remote cluster node, actually restart will be ignored anyway. 
                        SaveRemote(node, false, true);
                    } 
                } 
            }
        } 

        void RestartHelper(bool restart)
        {
            if (restart) 
            {
                try 
                { 
                    MsdtcWrapper msdtc = this.GetMsdtcWrapper();
                    msdtc.RestartDtcService(); 
                }
                catch (WsatAdminException)
                {
                    throw; 
                }
#pragma warning suppress 56500 
                catch (Exception e) 
                {
                    if (Utilities.IsCriticalException(e)) 
                    {
                        throw;
                    }
                    throw new WsatAdminException(WsatAdminErrorCode.DTC_RESTART_ERROR, SR.GetString(SR.ErrorRestartMSDTC), e); 
                }
            } 
        } 

        internal void Save(bool restart) 
        {
            if (IsLocalMachine)
            {
                Utilities.Log("Save - LocalMachine"); 
                // Single local machine:
                //   1. Update local SSL binding 
                //   2. Update URL ACL 
                //   3. Update firewall port status
                //   4. Update the endpoint cert's private key permission 
                //   5. Save to local registry
                UpdatePorts();
                UpdateCertificatePrivateKeyAccess();
                SaveToRegistry(); 
                RestartHelper(restart);
            } 
            else if (IsClusterRemoteNode) 
            {
                Utilities.Log("Save - Cluster Remote Node"); 
                // Cluster remote node machine:
                //   DO NOT save to cluster registry, DO NOT restart DTC
                //   1. Update SSL binding on the node
                //   2. Update URL ACL on the node 
                //   3. Update firewall port status on the node
                //   4. Update the endpoint cert's private key permission 
                UpdatePorts(); 
                UpdateCertificatePrivateKeyAccess();
            } 
            else if (IsClustered) // the orignating cluster node
            {
                Utilities.Log("Save - Cluster");
                // Cluster originating node machine: 
                //   1. Update SSL binding on each node
                //   2. Update URL ACL on each node 
                //   3. Update firewall port status on each remote node 
                //   4. Update the endpoint cert's private key permission on each remote node
                //   5. Save to cluster registry 
                UpdateClusterNodesPorts(restart);
                SaveToRegistry();
                RestartHelper(restart);
            } 
            else
            { 
                Utilities.Log("Save - Remote"); 
                // Remote machine:
                //   1. Save to remote registry 
                //   2. Update SSL binding on remote machine
                //   3. Update URL ACL on remote machine
                //   4. Update firewall port status on remote machine
                //   5. Update the endpoint cert's private key permission on remote machine 
                SaveRemote(restart, false);
            } 
            CopyConfigurationData(this, previousConfig); 
        }
 
        void SaveRemote(bool restart, bool clusterRemoteNode)
        {
            System.Diagnostics.Debug.Assert(!(IsLocalMachine || IsClustered));
            SaveRemote(MachineName, restart, clusterRemoteNode); 
        }
 
        void SaveRemote(string machineName, bool restart, bool clusterRemoteNode) 
        {
            string portString = null; 
            string endpointCertString = null;
            string accountsString = null;
            string accountsCertsString = null;
            string defaultTimeoutString = null; 
            string maxTimeoutString = null;
            string traceLevelString = null; 
            string traceActivityString = null; 
            string tracePropString = null;
            string tracePiiString = null; 

            // Performance is not a concern here so we just do plain string concatenation
            string networkEnabledString = " -" + CommandLineOption.Network + ":" +
                            (this.TransactionBridgeEnabled ? CommandLineOption.Enable : CommandLineOption.Disable); 
            string virtualServerString = null;
            if (!string.IsNullOrEmpty(VirtualServer)) 
            { 
                virtualServerString = " -" + CommandLineOption.ClusterVirtualServer + ":" + "\"" + VirtualServer + "\"";
            } 

            if (this.TransactionBridgeEnabled)
            {
                portString = " -" + CommandLineOption.Port + ":" + this.HttpsPort; 
                endpointCertString = this.X509Certificate == null ? "" : " -" + CommandLineOption.EndpointCert + ":" + this.X509Certificate.Thumbprint;
                accountsString = " -" + CommandLineOption.Accounts + ":" + BuildAccountsArgument(); 
                accountsCertsString = " -" + CommandLineOption.AccountsCerts + ":" + BuildAccountsCertsArgument(); 
                defaultTimeoutString = " -" + CommandLineOption.DefaultTimeout + ":" + this.DefaultTimeout.ToString(CultureInfo.InvariantCulture);
                traceLevelString = " -" + CommandLineOption.TraceLevel + ":" + ((uint)this.TraceLevel).ToString(CultureInfo.InvariantCulture); 
                traceActivityString = " -" + CommandLineOption.TraceActivity + ":" + (this.ActivityTracing ? CommandLineOption.Enable : CommandLineOption.Disable);
                tracePropString = " -" + CommandLineOption.TraceProp + ":" + (this.ActivityPropagation ? CommandLineOption.Enable : CommandLineOption.Disable);
                tracePiiString = " -" + CommandLineOption.TracePii + ":" + (this.TracePii ? CommandLineOption.Enable : CommandLineOption.Disable);
                maxTimeoutString = " -" + CommandLineOption.MaxTimeout + ":" + this.MaxTimeout.ToString(CultureInfo.InvariantCulture); 
            }
 
            string arguments = networkEnabledString + virtualServerString + portString + endpointCertString + accountsString + 
                                accountsCertsString + defaultTimeoutString + maxTimeoutString +
                                traceLevelString + traceActivityString + tracePropString + tracePiiString; 

            if (clusterRemoteNode)
            {
                arguments += " -" + CommandLineOption.ClusterRemoteNode + ":" + CommandLineOption.Enable; 
            }
 
            if (restart) 
            {
                arguments += " -" + CommandLineOption.Restart; 
            }

            Utilities.Log("Remote command arguments: " + arguments);
 
            RemoteHelper remote = new RemoteHelper(machineName);
            remote.ExecuteWsatProcess(arguments); 
        } 

        string BuildAccountsCertsArgument() 
        {
            string result = string.Empty;
            if (this.X509GlobalAcl != null && this.X509GlobalAcl.Length > 0)
            { 
                result += "\"" + this.X509GlobalAcl[0] + "\"";
                for (int i = 1; i < this.X509GlobalAcl.Length; ++i) 
                { 
                    result += ",\"" + this.X509GlobalAcl[i] + "\"";
                } 
            }
            return result;
        }
 
        string BuildAccountsArgument()
        { 
            string result = string.Empty; 
            if (this.KerberosGlobalAcl != null && this.KerberosGlobalAcl.Length > 0)
            { 
                result += "\"" + this.KerberosGlobalAcl[0] + "\"";
                for (int i = 1; i < this.KerberosGlobalAcl.Length; ++i)
                {
                    result += ",\"" + this.KerberosGlobalAcl[i] + "\""; 
                }
            } 
            return result; 
        }
 
        void UpdateCertificatePrivateKeyAccess()
        {
            if (previousConfig == null)
            { 
                AddCertificatePrivateKeyAccess(X509Certificate);
            } 
            else if (X509Certificate != previousConfig.X509Certificate) 
            {
                RemoveCertificatePrivateKeyAccess(previousConfig.X509Certificate); 
                AddCertificatePrivateKeyAccess(X509Certificate);
            }
        }
 
        // This method could throw any exception, because RSACryptoServiceProvider ctor could do so
        // We will escalate the exceptions to the callers who will be more sensible on how to deal with them 
        void CommitCryptoKeySecurity(CspKeyContainerInfo info, CryptoKeySecurity keySec) 
        {
            CspParameters cspParams = new CspParameters( 
                info.ProviderType, info.ProviderName,
                info.KeyContainerName);
            cspParams.CryptoKeySecurity = keySec;
            // Important flag, or the security setting will silently fail 
            cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
 
            // The RSACryptoServiceProvider ctor will automatically apply DACLs set in CSP's securtiy info 
            new RSACryptoServiceProvider(cspParams);
        } 

        void RemoveCertificatePrivateKeyAccess(X509Certificate2 cert)
        {
            if (cert != null && cert.HasPrivateKey) 
            {
                try 
                { 
                    AsymmetricAlgorithm key = cert.PrivateKey;
 
                    // Only RSA provider is supported here
                    if (key is RSACryptoServiceProvider)
                    {
                        RSACryptoServiceProvider prov = key as RSACryptoServiceProvider; 
                        CspKeyContainerInfo info = prov.CspKeyContainerInfo;
                        CryptoKeySecurity keySec = info.CryptoKeySecurity; 
 
                        SecurityIdentifier ns = new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null);
                        AuthorizationRuleCollection rules = keySec.GetAccessRules(true, false, typeof(SecurityIdentifier)); 
                        foreach (AuthorizationRule rule in rules)
                        {
                            CryptoKeyAccessRule keyAccessRule = (CryptoKeyAccessRule)rule;
 
                            if (keyAccessRule.AccessControlType == AccessControlType.Allow &&
                                (int)(keyAccessRule.CryptoKeyRights & CryptoKeyRights.GenericRead) != 0) 
                            { 
                                SecurityIdentifier sid = keyAccessRule.IdentityReference as SecurityIdentifier;
                                if (ns.Equals(sid)) 
                                {
                                    CryptoKeyAccessRule nsReadRule = new CryptoKeyAccessRule(ns,
                                            CryptoKeyRights.GenericRead,
                                            AccessControlType.Allow); 
                                    keySec.RemoveAccessRule(nsReadRule);
 
                                    CommitCryptoKeySecurity(info, keySec); 
                                    break;
                                } 
                            }
                        }
                    }
                } 
#pragma warning suppress 56500
                catch (Exception e) 
                { 
                    // CommitCryptoKeySecurity can actually throw any exception,
                    // so the safest way here is to catch a generic exception while throw on critical ones 
                    if (Utilities.IsCriticalException(e))
                    {
                        throw;
                    } 
                    throw new WsatAdminException(WsatAdminErrorCode.CANNOT_UPDATE_PRIVATE_KEY_PERM,
                                           SR.GetString(SR.ErrorUpdateCertPrivateKeyPerm), e); 
                } 
            }
        } 

        void AddCertificatePrivateKeyAccess(X509Certificate2 cert)
        {
            if (cert != null && cert.HasPrivateKey) 
            {
                try 
                { 
                    AsymmetricAlgorithm key = cert.PrivateKey;
 
                    // Only RSA provider is supported here
                    if (key is RSACryptoServiceProvider)
                    {
                        RSACryptoServiceProvider prov = key as RSACryptoServiceProvider; 
                        CspKeyContainerInfo info = prov.CspKeyContainerInfo;
                        CryptoKeySecurity keySec = info.CryptoKeySecurity; 
 
                        SecurityIdentifier ns = new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null);
                        // Just add a rule, exisitng settings will be merged 
                        CryptoKeyAccessRule rule = new CryptoKeyAccessRule(ns,
                                    CryptoKeyRights.GenericRead,
                                    AccessControlType.Allow);
                        keySec.AddAccessRule(rule); 

                        CommitCryptoKeySecurity(info, keySec); 
                    } 
                }
#pragma warning suppress 56500 
                catch (Exception e)
                {
                    // CommitCryptoKeySecurity can actually throw any exception,
                    // so the safest way here is to catch a generic exception while throw on critical ones 
                    if (Utilities.IsCriticalException(e))
                    { 
                        throw; 
                    }
                    throw new WsatAdminException(WsatAdminErrorCode.CANNOT_UPDATE_PRIVATE_KEY_PERM, 
                                           SR.GetString(SR.ErrorUpdateCertPrivateKeyPerm), e);
                }

            } 
        }
 
        void SaveToRegistry() 
        {
            if (!this.minimalWrite || this.previousConfig == null || this.TransactionBridgeEnabled != this.previousConfig.TransactionBridgeEnabled) 
            {
                msdtcConfigProvider.WriteString(
                    WsatKeys.TransactionBridgeRegKey,
                    this.TransactionBridgeEnabled ? TransactionBridgeRegistryValue : string.Empty); 
            }
 
            if (!this.minimalWrite || this.previousConfig == null || this.TraceLevel != this.previousConfig.TraceLevel) 
            {
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryTraceLevel, (uint)this.TraceLevel); 
            }

            if (!this.minimalWrite || this.previousConfig == null || this.ActivityTracing != this.previousConfig.ActivityTracing)
            { 
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryActivityTracing, (this.ActivityTracing ? 1u : 0));
            } 
 
            if (!this.minimalWrite || this.previousConfig == null || this.ActivityPropagation != this.previousConfig.ActivityPropagation)
            { 
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryPropagateActivity, (this.ActivityPropagation ? 1u : 0));
            }

            if (!this.minimalWrite || this.previousConfig == null || this.TracePii != this.previousConfig.TracePii) 
            {
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryTracingPii, (this.TracePii ? 1u : 0)); 
            } 

            if (!this.minimalWrite || this.previousConfig == null || this.DefaultTimeout != this.previousConfig.DefaultTimeout) 
            {
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryDefTimeout, (uint)this.DefaultTimeout);
            }
 
            if (!this.minimalWrite || this.previousConfig == null || this.MaxTimeout != this.previousConfig.MaxTimeout)
            { 
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryMaxTimeout, (uint)this.MaxTimeout); 
            }
 
            if (!this.minimalWrite || this.previousConfig == null || this.X509GlobalAcl != this.previousConfig.X509GlobalAcl)
            {
                wsatConfigProvider.WriteMultiString(WsatKeys.RegistryEntryX509GlobalAcl, this.X509GlobalAcl);
            } 

            if (!this.minimalWrite || this.previousConfig == null || this.X509Certificate != this.previousConfig.X509Certificate) 
            { 
                wsatConfigProvider.WriteString(WsatKeys.RegistryEntryX509CertificateIdentity, (this.X509Certificate == null ? string.Empty : this.X509Certificate.Thumbprint));
            } 

            if (!this.minimalWrite || this.previousConfig == null || this.HttpsPort != this.previousConfig.HttpsPort)
            {
                wsatConfigProvider.WriteUInt32(WsatKeys.RegistryEntryHttpsPort, this.HttpsPort); 
            }
 
            if (!this.minimalWrite || this.previousConfig == null || this.KerberosGlobalAcl != this.previousConfig.KerberosGlobalAcl) 
            {
                wsatConfigProvider.WriteMultiString(WsatKeys.RegistryEntryKerberosGlobalAcl, this.KerberosGlobalAcl); 
            }

            if (IsClustered || IsLocalMachine)
            { 
                wsatConfigProvider.AdjustRegKeyPermission();
            } 
        } 

        void UpdateUrlAclReservation() 
        {
            WsatServiceAddress wsatServiceAddress;

            if (this.previousConfig != null) 
            {
                wsatServiceAddress = new WsatServiceAddress(this.previousConfig.HttpsPort); 
                wsatServiceAddress.FreeWsatServiceAddress(); 
            }
 
            if(this.TransactionBridgeEnabled)
            {
                wsatServiceAddress = new WsatServiceAddress(this.HttpsPort);
                wsatServiceAddress.ReserveWsatServiceAddress(); 
            }
        } 
 
        void UpdateSSLBinding()
        { 
            WsatServiceCertificate wsatServiceCertificate;

            if (this.previousConfig != null && this.previousConfig.X509Certificate != null)
            { 
                wsatServiceCertificate = new WsatServiceCertificate(this.previousConfig.X509Certificate, previousConfig.HttpsPort);
                wsatServiceCertificate.UnbindSSLCertificate(); 
            } 
            if(this.TransactionBridgeEnabled && this.X509Certificate != null)
            { 
                wsatServiceCertificate = new WsatServiceCertificate(this.X509Certificate, HttpsPort);
                wsatServiceCertificate.BindSSLCertificate();
            }
        } 

        void UpdateFirewallPort() 
        { 
            FirewallWrapper firewallWrapper = new FirewallWrapper();
            firewallWrapper.RemoveHttpsPort((int)this.previousConfig.HttpsPort); 

            if(this.TransactionBridgeEnabled)
            {
                firewallWrapper.AddHttpsPort((int)this.HttpsPort); 
            }
        } 
 
        // update the ports for the SSL Binding, URL ACL Reservation and Firewall
        void UpdatePorts() 
        {
            UpdateFirewallPort();
            UpdateUrlAclReservation();
            UpdateSSLBinding(); 
        }
 
#if WSAT_CMDLINE 
        public override string ToString()
        { 
            StringBuilder sb = new StringBuilder();
            sb.Append(SR.GetString(SR.ConfigNetworkSupport, Utilities.GetEnabledStatusString(this.TransactionBridgeEnabled)));

            if (this.TransactionBridgeEnabled) 
            {
                sb.Append(SR.GetString(SR.ConfigHTTPSPort, this.HttpsPort)); 
                sb.Append(SR.GetString(SR.ConfigIdentityCertificate, 
                                       this.X509Certificate == null ? SR.GetString(SR.ConfigNone) : this.X509Certificate.Thumbprint));
                sb.Append(SR.GetString(SR.ConfigKerberosGACL)); 
                if (this.KerberosGlobalAcl == null || this.KerberosGlobalAcl.Length < 1)
                {
                    sb.AppendLine(SR.GetString(SR.ConfigNone));
                } 
                else
                { 
                    int i = 0; 
                    foreach (string ace in this.KerberosGlobalAcl)
                    { 
                        if (i++ > 0)
                        {
                            sb.Append(SR.GetString(SR.ConfigACEPrefix));
                        } 
                        sb.AppendLine(ace);
                    } 
                } 

                sb.Append(SR.GetString(SR.ConfigAcceptedCertificates)); 
                if (this.X509GlobalAcl == null || this.X509GlobalAcl.Length < 1)
                {
                    sb.AppendLine(SR.GetString(SR.ConfigNone));
                } 
                else
                { 
                    int i = 0; 
                    foreach (string cert in this.X509GlobalAcl)
                    { 
                        if (i++ > 0)
                        {
                            sb.Append(SR.GetString(SR.ConfigAcceptedCertPrefix));
                        } 
                        sb.AppendLine(cert);
                    } 
                } 

                sb.Append(SR.GetString(SR.ConfigDefaultTimeout, this.DefaultTimeout)); 
                sb.Append(SR.GetString(SR.ConfigMaximumTimeout, this.MaxTimeout));

                SourceLevels level = this.TraceLevel;
                if(level != SourceLevels.All) 
                {
                    level = level & ~SourceLevels.ActivityTracing; 
                } 
                sb.Append(SR.GetString(SR.ConfigTraceLevel, level));
                sb.Append(SR.GetString(SR.ConfigActivityTracing, Utilities.GetEnabledStatusString(this.ActivityTracing))); 
                sb.Append(SR.GetString(SR.ConfigActivityProp, Utilities.GetEnabledStatusString(this.ActivityPropagation)));
                sb.Append(SR.GetString(SR.ConfigPiiTracing, Utilities.GetEnabledStatusString(this.TracePii)));

                MsdtcWrapper msdtc = this.GetMsdtcWrapper(); 
                if (!msdtc.GetNetworkTransactionAccess())
                { 
                    sb.Append(Environment.NewLine); 
                    sb.Append(SR.GetString(SR.ConfigWarningNetworkDTCAccessIsDisabled));
                } 
            }
            else
            {
                // When network support is disabled, the only setting that still matters is the MaxTimeout 
                sb.Append(SR.GetString(SR.ConfigMaximumTimeoutWhenNetworkDisabled, this.MaxTimeout));
            } 
 
            return sb.ToString();
        } 
#endif
    }
}

// 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