示例#1
0
        /// <summary>
        /// Initializes the static elements of a 'WebTransactionProtocol' connection.
        /// </summary>
        static HttpBatchProcessor()
        {
            // We need to reference the user preferences in this static constructor.
            UserPreferences userPreferences = new UserPreferences();

            // Use a default timout for the Http Request if one was specified in the application configuration file.
            string timeoutText = ConfigurationManager.AppSettings["httpTimeout"];

            HttpBatchProcessor.Timeout = timeoutText == null ? defaultTimeout : Convert.ToInt32(timeoutText);

            // Initially, the decision about prompting for a URL is decided by whether there is a recently saved URL to try.
            // After the first WebException, we'll prompt them until a good one is entered.
            HttpBatchProcessor.Url           = (string)UserPreferences.LocalSettings[webServiceMru0Key];
            HttpBatchProcessor.IsUrlPrompted = HttpBatchProcessor.Url == string.Empty;

            // Initially the decision to prompt the user for credentials is made by whether a complete set of information for
            // establishing a session can be collected from the local settings.  If there isn't enough information, the user will
            // be prompted.  After the first time, a 401 error will indicate that the user should be prompted for their credentials
            // again.
            HttpBatchProcessor.IsCredentialPrompted = false;

            // Select the method for authenticating the user when they connect to the web transaction server.  The default is to
            // use certificates.  This can be overridden by configuration settings.
            HttpBatchProcessor.AuthenticationMode = AuthenticationMode.Certificate;
            string authenticationModeText = ConfigurationManager.AppSettings["authenticationMode"];

            if (authenticationModeText != null)
            {
                HttpBatchProcessor.AuthenticationMode = (AuthenticationMode)Enum.Parse(typeof(AuthenticationMode),
                                                                                       authenticationModeText);
            }

            // Set up the details of authentication based on the selected authentication mode.
            switch (HttpBatchProcessor.AuthenticationMode)
            {
            case AuthenticationMode.Certificate:

                // This is a collection of cached certificates used for SSL security.
                HttpBatchProcessor.clientCertificates = new X509CertificateCollection();

                // If a certificate name was stored in the user preferences, then attempt to match it up against the personal
                // certificate store.  If a previosly used certificate was found, then put it in the cache where it can be used the
                // next time a connection is established.
                string certificateName = (string)UserPreferences.LocalSettings[certificateNameKey];
                if (certificateName != null)
                {
                    foreach (X509Certificate x509Certificate in Crypt.GetCertificateStore(myStoreName))
                    {
                        if (x509Certificate.Subject == certificateName)
                        {
                            HttpBatchProcessor.clientCertificates.Add(x509Certificate);
                        }
                    }
                }

                // If the user preferences has a valid certificate, then the prompting can be bypassed.  Otherwise, the first time
                // a request is sent, the user will be asked for a URL and a certificate.
                HttpBatchProcessor.IsCredentialPrompted = HttpBatchProcessor.clientCertificates.Count == 0;

                break;

            case AuthenticationMode.WindowsIntegrated:

                // Integrated Mode uses the current user's security context, there is nothing for which to prompt the user.
                HttpBatchProcessor.IsCredentialPrompted = false;

                break;

            case AuthenticationMode.Basic:

                // Basic authorization over SSL can be used for the web request. See if the user has some saved credentials.
                HttpBatchProcessor.networkCredential          = new NetworkCredential();
                HttpBatchProcessor.networkCredential.UserName = (string)UserPreferences.LocalSettings[usernameKey];
                HttpBatchProcessor.networkCredential.Domain   = (string)UserPreferences.LocalSettings[domainKey];

                // The user must always be prompted for the password in Basic Mode due to an inability to secure the password
                // on the local machine.
                HttpBatchProcessor.IsCredentialPrompted = true;

                break;
            }

            // Since the UserPreferences were used by a static non-component, the resources need to be cleaned up explicitly.  This
            // should balance the books on the UserPreferences component.
            userPreferences.Dispose();
        }
示例#2
0
        /// <summary>
        /// Constructs an HttpWebRequest specifically destined for the transaction server.
        /// </summary>
        private static HttpWebRequest CreateCertificateRequest()
        {
            // This section of code is thread safe.  Since the user can modify the URL or the credentials of other threads that
            // want to use this class, the class itself is locked while the user is prompted (if prompting is necessary).
            lock (typeof(HttpBatchProcessor))
            {
                // Get the URL.
                GetUrl();

                // If the WebTransactionProtocol has successfully connected once, then try to use the URL and Certificate from the
                // previous connection for this request.
                if (HttpBatchProcessor.IsCredentialPrompted)
                {
                    // A Certificate is also required for SSL communication.  A cache of certificates is kept by this class to speed up
                    // the task of connecting to the server.  Since the URL has changed at this point, none of the previous
                    // certificates that were selected by the user should be used.
                    HttpBatchProcessor.clientCertificates.Clear();

                    // The design goal of the certificate selection sequence is to limit the number of decisions that the user has to
                    // make.  The personal certficate store is used to select a certificate for the session.  If the name on the
                    // certificate matches the name stored in the user preferences, then that certificate is used.
                    X509CertificateCollection x509CertificateCollection = Crypt.GetCertificateStore(myStoreName);

                    // If there is only one certificate in the personal store, then use it without any prompting. Otherwise, ask the
                    // user to select a certificate.
                    if (x509CertificateCollection.Count == 1)
                    {
                        HttpBatchProcessor.clientCertificates.Add(x509CertificateCollection[0]);
                    }
                    else
                    {
                        // Only prompt for a certificate if there are more than one to choose from.
                        if (x509CertificateCollection.Count != 0)
                        {
                            // Prompt the user for a certificate.  Note that if they don't select a certificate an exception is throw
                            // that will terminate the application if not caught.  Generally, the application should be allowed to exit
                            // if a secure connection with the server can't be established.
                            FormSelectCertificate formSelectCertificate = new FormSelectCertificate();
                            formSelectCertificate.ShowDialog();
                            if (formSelectCertificate.DialogResult != DialogResult.OK)
                            {
                                throw new UserAbortException("User cancelled the operation");
                            }

                            // Add this certificate to the client's collection.
                            HttpBatchProcessor.clientCertificates.Add(formSelectCertificate.SelectedCertificate);

                            // There's no need to prompt again until some error forces the user back here.
                            HttpBatchProcessor.IsCredentialPrompted = false;

                            // The form must be destroyed explicitly or the components will hang around until the garbage is collected.
                            formSelectCertificate.Dispose();
                        }
                    }
                }
            }

            // Create and initialize an HttpWebRequest to handle the conversation between the client and server.  All Batch
            // operations are handled using the 'POST' verb.  The timeout is specified above though the configuration file or a
            // programtic setting.  Also note that the Stream Buffering is disabled as it appears to have a negative impact on
            // throughput.  Finally, the chosen certificate is tacked onto the outgoing request for authentication.
            HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(HttpBatchProcessor.Url);

            httpWebRequest.Method  = "POST";
            httpWebRequest.Timeout = HttpBatchProcessor.Timeout;
            httpWebRequest.AllowWriteStreamBuffering = true;
            httpWebRequest.ClientCertificates.AddRange(HttpBatchProcessor.clientCertificates);

            // This request can be used to send a 'Batch' object to the Web Transaction server.
            return(httpWebRequest);
        }