WsatConfiguration.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / Tools / WSATConfig / Configuration / WsatConfiguration.cs / 1305376 / 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 = "{BFFECCA7-4069-49F9-B5AB-7CCBB078ED91}";
        const string TransactionBridge30RegistryValue = "{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; 
        bool transactionBridge30Enabled = 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.TransactionBridge30Enabled = src.TransactionBridge30Enabled; 
            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 bool TransactionBridge30Enabled 
        {
            get { return this.transactionBridge30Enabled; } 
            set { this.transactionBridge30Enabled = 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); 

            TransactionBridge30Enabled = Utilities.SafeCompare(value, TransactionBridge30RegistryValue);

            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 || (this.previousConfig.TransactionBridge30Enabled && !this.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 || this.TransactionBridge30Enabled))); 

            if (this.TransactionBridgeEnabled || this.TransactionBridge30Enabled) 
            { 
                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.


                        

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