public void ClientCertificateOptions_InvalidArg_ThrowsException(ClientCertificateOption option)
 {
     using (var handler = new HttpClientHandler())
     {
         Assert.Throws<ArgumentOutOfRangeException>("value", () => handler.ClientCertificateOptions = option);
     }
 }
Example #2
0
        public HttpClientHandler()
        {
            _rtFilter        = new RTHttpBaseProtocolFilter();
            _handlerToFilter = new HttpHandlerToFilter(_rtFilter);
            _handlerToFilter.RequestMessageLookupKey             = RequestMessageLookupKey;
            _handlerToFilter.SavedExceptionDispatchInfoLookupKey = SavedExceptionDispatchInfoLookupKey;
            _diagnosticsPipeline = new DiagnosticsHandler(_handlerToFilter);

            _clientCertificateOptions = ClientCertificateOption.Manual;

            // Always turn off WinRT cookie processing if the WinRT API supports turning it off.
            // Use .NET CookieContainer handling only.
            if (RTCookieUsageBehaviorSupported)
            {
                _rtFilter.CookieUsageBehavior = RTHttpCookieUsageBehavior.NoCookies;
            }

            _useCookies      = true;                  // deal with cookies by default.
            _cookieContainer = new CookieContainer(); // default container used for dealing with auto-cookies.

            // Managed at this layer for granularity, but uses the desktop default.
            _rtFilter.AutomaticDecompression = false;
            _automaticDecompression          = DecompressionMethods.None;

            // We don't support using the UI model in HttpBaseProtocolFilter() especially for auto-handling 401 responses.
            _rtFilter.AllowUI = false;

            // The .NET Desktop System.Net Http APIs (based on HttpWebRequest/HttpClient) uses no caching by default.
            // To preserve app-compat, we turn off caching in the WinRT HttpClient APIs.
            _rtFilter.CacheControl.ReadBehavior = RTNoCacheSupported ?
                                                  RTHttpCacheReadBehavior.NoCache : RTHttpCacheReadBehavior.MostRecent;
            _rtFilter.CacheControl.WriteBehavior = RTHttpCacheWriteBehavior.NoCache;
        }
Example #3
0
        public HttpClientHandler()
        {
            _startRequest             = StartRequest;
            _getRequestStreamCallback = GetRequestStreamCallback;
            _getResponseCallback      = GetResponseCallback;

            _connectionGroupName = RuntimeHelpers.GetHashCode(this).ToString(NumberFormatInfo.InvariantInfo);

            // Set HWR default values
            _allowAutoRedirect           = true;
            _maxRequestContentBufferSize = HttpContent.MaxBufferSize;
            _automaticDecompression      = DecompressionMethods.None;
            _cookieContainer             = new CookieContainer(); // default container used for dealing with auto-cookies.
            _credentials = null;
            _maxAutomaticRedirections = 50;
            _preAuthenticate          = false;
            _proxy                 = null;
            _useProxy              = true;
            _useCookies            = true; // deal with cookies by default.
            _useDefaultCredentials = false;
            _clientCertOptions     = ClientCertificateOption.Manual;

            // New properties not in .NET Framework HttpClientHandler.
            _maxResponseHeadersLength = HttpWebRequest.DefaultMaximumResponseHeadersLength;
            _defaultProxyCredentials  = null;
            _clientCertificates       = null; // only create collection when required.
            _properties = null;               // only create collection when required.
            _maxConnectionsPerServer = ServicePointManager.DefaultConnectionLimit;
            _serverCertificateCustomValidationCallback = null;
        }
Example #4
0
        public HttpClientHandler()
        {
            _rtFilter            = new RTHttpBaseProtocolFilter();
            _handlerToFilter     = new HttpHandlerToFilter(_rtFilter);
            _diagnosticsPipeline = new DiagnosticsHandler(_handlerToFilter);

            _clientCertificateOptions = ClientCertificateOption.Manual;

            InitRTCookieUsageBehavior();

            _useCookies      = true;                  // deal with cookies by default.
            _cookieContainer = new CookieContainer(); // default container used for dealing with auto-cookies.

            // Managed at this layer for granularity, but uses the desktop default.
            _rtFilter.AutomaticDecompression = false;
            _automaticDecompression          = DecompressionMethods.None;

            // Set initial proxy credentials based on default system proxy.
            SetProxyCredential(null);

            // We don't support using the UI model in HttpBaseProtocolFilter() especially for auto-handling 401 responses.
            _rtFilter.AllowUI = false;

            // The .NET Desktop System.Net Http APIs (based on HttpWebRequest/HttpClient) uses no caching by default.
            // To preserve app-compat, we turn off caching (as much as possible) in the WinRT HttpClient APIs.
            // TODO (#7877): use RTHttpCacheReadBehavior.NoCache when available in the next version of WinRT HttpClient API.
            _rtFilter.CacheControl.ReadBehavior  = RTHttpCacheReadBehavior.MostRecent;
            _rtFilter.CacheControl.WriteBehavior = RTHttpCacheWriteBehavior.NoCache;
        }
Example #5
0
 public void ClientCertificateOptions_InvalidArg_ThrowsException(ClientCertificateOption option)
 {
     using (HttpClientHandler handler = CreateHttpClientHandler())
     {
         AssertExtensions.Throws <ArgumentOutOfRangeException>("value", () => handler.ClientCertificateOptions = option);
     }
 }
 public void ClientCertificateOptions_ValueArg_Roundtrips(ClientCertificateOption option)
 {
     using (var handler = new HttpClientHandler())
     {
         handler.ClientCertificateOptions = option;
         Assert.Equal(option, handler.ClientCertificateOptions);
     }
 }
Example #7
0
 public void ClientCertificateOptions_ValueArg_Roundtrips(ClientCertificateOption option)
 {
     using (HttpClientHandler handler = CreateHttpClientHandler())
     {
         handler.ClientCertificateOptions = option;
         Assert.Equal(option, handler.ClientCertificateOptions);
     }
 }
 /// <summary>Creates an instance of a <see cref="T:NMasters.Silverlight.Net.Http.Handlers.HttpClientHandler" /> class.</summary>
 public HttpClientHandler()
 {
     this.allowAutoRedirect = true;
     this.maxRequestContentBufferSize = 0x7fffffff;
     this.cookieContainer = new CookieContainer();
     this.credentials = null;
     this.maxAutomaticRedirections = 50;
     this.preAuthenticate = false;
     this.useCookies = true;
     this.useDefaultCredentials = false;
     this.clientCertOptions = ClientCertificateOption.Manual;
 }
Example #9
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                // Disable SSLv2/SSLv3, allow TLSv1.*
                easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSLVERSION, (long)Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1);

                IntPtr userPointer = IntPtr.Zero;

                if (clientCertOption == ClientCertificateOption.Automatic)
                {
                    ClientCertificateProvider certProvider = new ClientCertificateProvider();
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(),
                                           certProvider,
                                           CancellationToken.None,
                                           TaskContinuationOptions.ExecuteSynchronously,
                                           TaskScheduler.Default);
                }
                else
                {
                    Debug.Assert(clientCertOption == ClientCertificateOption.Manual, "ClientCertificateOption is manual or automatic");
                }

                CURLcode answer = easy.SetSslCtxCallback(s_sslCtxCallback, userPointer);

                switch (answer)
                {
                case CURLcode.CURLE_OK:
                    break;

                // Curl 7.38 and prior
                case CURLcode.CURLE_UNKNOWN_OPTION:
                // Curl 7.39 and later
                case CURLcode.CURLE_NOT_BUILT_IN:
                    EventSourceTrace("CURLOPT_SSL_CTX_FUNCTION not supported. Platform default HTTPS chain building in use");
                    if (clientCertOption == ClientCertificateOption.Automatic)
                    {
                        throw new PlatformNotSupportedException(SR.net_http_unix_invalid_client_cert_option);
                    }

                    break;

                default:
                    ThrowIfCURLEError(answer);
                    break;
                }
            }
Example #10
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                // Disable SSLv2/SSLv3, allow TLSv1.*
                easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSLVERSION, (long)Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1);

                IntPtr userPointer = IntPtr.Zero;
                if (clientCertOption == ClientCertificateOption.Automatic)
                {
                    ClientCertificateProvider certProvider = new ClientCertificateProvider();
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(),
                                           certProvider,
                                           CancellationToken.None,
                                           TaskContinuationOptions.ExecuteSynchronously,
                                           TaskScheduler.Default);
                }
                else
                {
                    Debug.Assert(clientCertOption == ClientCertificateOption.Manual, "ClientCertificateOption is manual or automatic");
                }

                CURLcode answer = easy.SetSslCtxCallback(s_sslCtxCallback, userPointer);

                switch (answer)
                {
                    case CURLcode.CURLE_OK:
                        break;
                    // Curl 7.38 and prior
                    case CURLcode.CURLE_UNKNOWN_OPTION:
                    // Curl 7.39 and later
                    case CURLcode.CURLE_NOT_BUILT_IN:
                        EventSourceTrace("CURLOPT_SSL_CTX_FUNCTION not supported. Platform default HTTPS chain building in use");
                        if (clientCertOption == ClientCertificateOption.Automatic)
                        {
                            throw new PlatformNotSupportedException(SR.net_http_unix_invalid_client_cert_option);
                        }

                        break;
                    default:
                        ThrowIfCURLEError(answer);
                        break;
                }
            }
        public HttpClientHandler()
        {
            _rtFilter = CreateFilter();

            _handlerToFilter = new HttpHandlerToFilter(_rtFilter, this);
            _handlerToFilter.RequestMessageLookupKey             = RequestMessageLookupKey;
            _handlerToFilter.SavedExceptionDispatchInfoLookupKey = SavedExceptionDispatchInfoLookupKey;
            _diagnosticsPipeline = new DiagnosticsHandler(_handlerToFilter);

            _clientCertificateOptions = ClientCertificateOption.Manual;

            _useCookies      = true;                  // deal with cookies by default.
            _cookieContainer = new CookieContainer(); // default container used for dealing with auto-cookies.

            _allowAutoRedirect        = true;
            _maxAutomaticRedirections = 50;

            _automaticDecompression = DecompressionMethods.None;
        }
Example #12
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                EventSourceTrace("ClientCertificateOption: {0}", clientCertOption, easy: easy);
                Debug.Assert(clientCertOption == ClientCertificateOption.Automatic || clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
                ClientCertificateProvider  certProvider       =
                    clientCertOption == ClientCertificateOption.Automatic ? new ClientCertificateProvider(null) : // automatic
                    clientCertificates?.Count > 0 ? new ClientCertificateProvider(clientCertificates) :           // manual with certs
                    null;                                                                                         // manual without certs
                IntPtr userPointer = IntPtr.Zero;

                if (certProvider != null)
                {
                    EventSourceTrace("Created certificate provider", easy: easy);

                    // The client cert provider needs to be passed through to the callback, and thus
                    // we create a GCHandle to keep it rooted.  This handle needs to be cleaned up
                    // when the request has completed, and a simple and pay-for-play way to do that
                    // is by cleaning it up in a continuation off of the request.
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(), certProvider,
                                           CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
                }

                // Configure the options.  Our best support is when targeting OpenSSL/1.0.  For other backends,
                // we fall back to a minimal amount of support, and may throw a PNSE based on the options requested.
                if (Interop.Http.HasMatchingOpenSslVersion)
                {
                    // Register the callback with libcurl.  We need to register even if there's no user-provided
                    // server callback and even if there are no client certificates, because we support verifying
                    // server certificates against more than those known to OpenSSL.
                    SetSslOptionsForSupportedBackend(easy, certProvider, userPointer);
                }
                else
                {
                    // Newer versions of OpenSSL, and other non-OpenSSL backends, do not currently support callbacks.
                    // That means we'll throw a PNSE if a callback is required.
                    SetSslOptionsForUnsupportedBackend(easy, certProvider);
                }
            }
Example #13
0
        private IResponse Invoke(UrlBuilder url, HttpMethod method, HttpContent content, IBindingSession session,
                                 long?offset, long?length, IDictionary <string, string> headers)
        {
            if (Logger.IsDebugEnabled)
            {
                Logger.Debug("HTTP: " + method.ToString() + " " + url.ToString());
            }

            IPortableAuthenticationProvider authProvider = session.GetAuthenticationProvider() as IPortableAuthenticationProvider;

            HttpClient httpClient = session.GetValue(InvokerHttpClient) as HttpClient;

            if (httpClient == null)
            {
                lock (invokerLock)
                {
                    httpClient = session.GetValue(InvokerHttpClient) as HttpClient;
                    if (httpClient == null)
                    {
                        // create a HTTP client handler
                        HttpClientHandler httpClientHandler = null;
                        if (authProvider != null)
                        {
                            httpClientHandler = authProvider.CreateHttpClientHandler();
                        }
                        if (httpClientHandler == null)
                        {
                            httpClientHandler = new HttpClientHandler();
                        }


                        // redirects
                        if (httpClientHandler.SupportsRedirectConfiguration)
                        {
                            httpClientHandler.AllowAutoRedirect = false;
                        }

                        // compression
                        if (httpClientHandler.SupportsAutomaticDecompression)
                        {
                            string compressionFlag = session.GetValue(SessionParameter.Compression) as string;
                            if (compressionFlag != null && compressionFlag.ToLowerInvariant().Equals("true"))
                            {
                                httpClientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                            }
                        }

                        // authentication
                        httpClientHandler.PreAuthenticate       = true;
                        httpClientHandler.UseDefaultCredentials = false;


                        // authentication provider
                        if (authProvider != null)
                        {
                            authProvider.PrepareHttpClientHandler(httpClientHandler);
                        }
                        string                  sslProtocols            = SessionParameterDefaults.SslProtocol;
                        string                  clientCertificateOption = SessionParameterDefaults.ClientCertificateOption;
                        SslProtocols            prot                       = SslProtocols.None;
                        ClientCertificateOption clientOption               = ClientCertificateOption.Manual;
                        object                  sslProtocolsobj            = session.GetValue(SessionParameter.SslProtocols, SessionParameterDefaults.SslProtocol);
                        object                  clientCertificateOptionObj = session.GetValue(SessionParameter.ClientCertificateOption, SessionParameterDefaults.ClientCertificateOption);
                        if (sslProtocolsobj != null)
                        {
                            sslProtocols = $"{sslProtocolsobj}";
                            if (!string.IsNullOrWhiteSpace(sslProtocols))
                            {
                                if (Enum.TryParse <SslProtocols>(sslProtocols, out SslProtocols result))
                                {
                                    prot = result;
                                }
                            }
                        }
                        if (clientCertificateOptionObj != null)
                        {
                            clientCertificateOption = $"{clientCertificateOptionObj}";
                            if (!string.IsNullOrWhiteSpace(clientCertificateOption))
                            {
                                if (Enum.TryParse <ClientCertificateOption>(clientCertificateOption, out ClientCertificateOption result))
                                {
                                    clientOption = result;
                                }
                            }
                        }
                        httpClientHandler.ClientCertificateOptions = clientOption;
                        httpClientHandler.SslProtocols             = prot;
                        httpClientHandler.ServerCertificateCustomValidationCallback =
                            (httpRequestMessage, cert, cetChain, policyErrors) =>
                        {
                            return(true);
                        };
                        // create HttpClient
                        httpClient = new HttpClient(httpClientHandler, true);

                        // timeouts
                        int connectTimeout = session.GetValue(SessionParameter.ConnectTimeout, -2);
                        if (connectTimeout >= -1)
                        {
                            httpClient.Timeout = TimeSpan.FromMilliseconds(connectTimeout);
                        }
                        session.PutValue(InvokerHttpClient, httpClient);
                    }
                }
            }

            HttpRequestMessage request = new HttpRequestMessage(method, url.ToString());

            try
            {
                // set additional headers
                string userAgent = session.GetValue(SessionParameter.UserAgent) as string;
                request.Headers.UserAgent.Add(ProductInfoHeaderValue.Parse(userAgent ?? ClientVersion.UserAgent));

                if (headers != null)
                {
                    foreach (KeyValuePair <string, string> header in headers)
                    {
                        request.Headers.TryAddWithoutValidation(header.Key, header.Value);
                    }
                }

                // range
                if (offset != null && length != null)
                {
                    long longOffset = offset.Value < 0 ? 0 : offset.Value;
                    if (length.Value > 0)
                    {
                        request.Headers.Range = new RangeHeaderValue(longOffset, longOffset + length.Value - 1);
                    }
                    else
                    {
                        request.Headers.Range = new RangeHeaderValue(longOffset, null);
                    }
                }
                else if (offset != null && offset.Value > 0)
                {
                    request.Headers.Range = new RangeHeaderValue(offset, null);
                }

                // content
                if (content != null)
                {
                    request.Headers.TransferEncodingChunked = true;
                    request.Content = content;
                }

                // authentication provider
                if (authProvider != null)
                {
                    authProvider.PrepareHttpRequestMessage(request);
                }

                Response response;
                try
                {
                    Task <HttpResponseMessage> task = Send(httpClient, request);
                    if (task.IsFaulted)
                    {
                        throw task.Exception;
                    }
                    else
                    {
                        HttpResponseMessage httpResponseMessage = task.Result;

                        if (authProvider != null)
                        {
                            authProvider.HandleResponse(httpResponseMessage);
                        }
                        response = new Response(httpResponseMessage);
                    }
                }
                catch (Exception e)
                {
                    throw new CmisConnectionException("Cannot access " + url + ": " + e.Message, e);
                }


                return(response);
            }
            finally
            {
                request.Dispose();
            }
        }
Example #14
0
        public async Task AutomaticOrManual_DoesntFailRegardlessOfWhetherClientCertsAreAvailable(ClientCertificateOption mode)
        {
            if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
            {
                _output.WriteLine($"Skipping {nameof(AutomaticOrManual_DoesntFailRegardlessOfWhetherClientCertsAreAvailable)}()");
                return;
            }

            using (HttpClientHandler handler = CreateHttpClientHandler())
                using (var client = new HttpClient(handler))
                {
                    handler.ServerCertificateCustomValidationCallback = delegate { return(true); };
                    handler.ClientCertificateOptions = mode;

                    await LoopbackServer.CreateServerAsync(async server =>
                    {
                        Task clientTask = client.GetStringAsync(server.Uri);
                        Task serverTask = server.AcceptConnectionAsync(async connection =>
                        {
                            SslStream sslStream = Assert.IsType <SslStream>(connection.Stream);
                            await connection.ReadRequestHeaderAndSendResponseAsync();
                        });

                        await new Task[] { clientTask, serverTask }.WhenAllOrAnyFailed();
                    }, new LoopbackServer.Options {
                        UseSsl = true
                    });
                }
        }
Example #15
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                Debug.Assert(
                    clientCertOption == ClientCertificateOption.Automatic ||
                    clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;

                if (clientCertOption != ClientCertificateOption.Manual || clientCertificates?.Count > 0)
                {
                    // libcurl does not have an option of accepting a SecIdentityRef via an input option,
                    // only via writing it to a file and letting it load the PFX.
                    // This would require that a) we write said file, and b) that it contaminate the default
                    // keychain (because their PFX loader loads to the default keychain).
                    throw new PlatformNotSupportedException(SR.net_http_libcurl_clientcerts_notsupported_os);
                }

                // Revocation checking is always on for darwinssl (SecureTransport).
                // If any other backend is used and revocation is requested, we can't guarantee
                // that assertion.
                if (easy._handler.CheckCertificateRevocationList &&
                    !CurlSslVersionDescription.Equals(Interop.Http.SecureTransportDescription))
                {
                    throw new PlatformNotSupportedException(
                              SR.Format(
                                  SR.net_http_libcurl_revocation_notsupported_sslbackend,
                                  CurlVersionDescription,
                                  CurlSslVersionDescription,
                                  Interop.Http.SecureTransportDescription));
                }

                if (easy._handler.ServerCertificateCustomValidationCallback != null)
                {
                    // libcurl (as of 7.49.1) does not have any callback which can be registered which fires
                    // between the time that a TLS/SSL handshake has offered up the server certificate and the
                    // time that the HTTP request headers are written.  Were there any callback, the option
                    // CURLINFO_TLS_SSL_PTR could be queried (and the backend identifier validated to be
                    // CURLSSLBACKEND_DARWINSSL). Then the SecTrustRef could be extracted to build the chain,
                    // a la SslStream.
                    //
                    // Without the callback the matrix looks like:
                    // * If default-trusted and callback-would-trust: No difference (except side effects, like logging).
                    // * If default-trusted and callback-would-block: Data would have been sent in violation of user trust.
                    // * If not-default-trusted and callback-would-not-trust: No difference (except side effects).
                    // * If not-default-trusted and callback-would-trust: No data sent, which doesn't match user desires.
                    //
                    // Of the two "different" cases, sending when we shouldn't is worse, so that's the direction we
                    // have to cater to. So we'll use default trust, and throw on any custom callback.
                    //
                    // The situation where system trust fails can be remedied by including the certificate into the
                    // user's keychain and setting the SSL policy trust for it to "Always Trust".
                    // Similarly, the "block this" could be attained by setting the SSL policy for a cert in the
                    // keychain to "Never Trust".
                    //
                    // However, one case we can support is when we know all certificates will pass validation.
                    // We can detect a key case of that: whether DangerousAcceptAnyServerCertificateValidator was used.
                    if (easy.ServerCertificateValidationCallbackAcceptsAll)
                    {
                        EventSourceTrace("Warning: Disabling peer verification per {0}", nameof(HttpClientHandler.DangerousAcceptAnyServerCertificateValidator), easy: easy);
                        easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYPEER, 0); // don't verify the peer

                        // Don't set CURLOPT_SSL_VERIFHOST to 0; doing so disables SNI with SecureTransport backend.
                        if (!CurlSslVersionDescription.Equals(Interop.Http.SecureTransportDescription))
                        {
                            easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0); // don't verify the hostname
                        }
                    }
                    else
                    {
                        throw new PlatformNotSupportedException(SR.net_http_libcurl_callback_notsupported_os);
                    }
                }

                SetSslVersion(easy);
            }
Example #16
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                Debug.Assert(clientCertOption == ClientCertificateOption.Automatic || clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
                ClientCertificateProvider certProvider =
                    clientCertOption == ClientCertificateOption.Automatic ? new ClientCertificateProvider(null) : // automatic
                    clientCertificates?.Count > 0 ? new ClientCertificateProvider(clientCertificates) : // manual with certs
                    null; // manual without certs
                IntPtr userPointer = IntPtr.Zero;
                if (certProvider != null)
                {
                    // The client cert provider needs to be passed through to the callback, and thus
                    // we create a GCHandle to keep it rooted.  This handle needs to be cleaned up
                    // when the request has completed, and a simple and pay-for-play way to do that
                    // is by cleaning it up in a continuation off of the request.
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(), certProvider,
                        CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
                }

                // Register the callback with libcurl.  We need to register even if there's no user-provided
                // server callback and even if there are no client certificates, because we support verifying
                // server certificates against more than those known to OpenSSL.
                CURLcode answer = easy.SetSslCtxCallback(s_sslCtxCallback, userPointer);
                switch (answer)
                {
                    case CURLcode.CURLE_OK:
                        // We successfully registered.  If we'll be invoking a user-provided callback to verify the server
                        // certificate as part of that, disable libcurl's verification of the host name.  The user's callback
                        // needs to be given the opportunity to examine the cert, and our logic will determine whether
                        // the host name matches and will inform the callback of that.
                        if (easy._handler.ServerCertificateValidationCallback != null)
                        {
                            easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0); // don't verify the peer cert's hostname
                            // We don't change the SSL_VERIFYPEER setting, as setting it to 0 will cause
                            // SSL and libcurl to ignore the result of the server callback.
                        }

                        // The allowed SSL protocols will be set in the configuration callback.
                        break;

                    case CURLcode.CURLE_UNKNOWN_OPTION: // Curl 7.38 and prior
                    case CURLcode.CURLE_NOT_BUILT_IN:   // Curl 7.39 and later
                        // It's ok if we failed to register the callback if all of the defaults are in play
                        // with relation to handling of certificates.  But if that's not the case, failing to 
                        // register the callback will result in those options not being factored in, which is
                        // a significant enough error that we need to fail.
                        EventSourceTrace("CURLOPT_SSL_CTX_FUNCTION not supported: {0}", answer, easy: easy);
                        if (certProvider != null ||
                            easy._handler.ServerCertificateValidationCallback != null ||
                            easy._handler.CheckCertificateRevocationList)
                        {
                            throw new PlatformNotSupportedException(
                                SR.Format(SR.net_http_unix_invalid_certcallback_option, CurlVersionDescription, CurlSslVersionDescription));
                        }

                        // Since there won't be a callback to configure the allowed SSL protocols, configure them here.
                        SetSslVersion(easy);

                        break;

                    default:
                        ThrowIfCURLEError(answer);
                        break;
                }
            }
        private async Task<HttpResponseMessage> SendGetRequest(OwinHttpListener listener, string address, ClientCertificateOption certOptions)
        {
            using (listener)
            {
                var handler = new WebRequestHandler();

                // Ignore server cert errors.
                handler.ServerCertificateValidationCallback = (a, b, c, d) => true;
                handler.ClientCertificateOptions = certOptions;

                var client = new HttpClient(handler);
                return await client.GetAsync(address);
            }
        }
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                Debug.Assert(clientCertOption == ClientCertificateOption.Automatic || clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
                ClientCertificateProvider  certProvider       =
                    clientCertOption == ClientCertificateOption.Automatic ? new ClientCertificateProvider(null) : // automatic
                    clientCertificates?.Count > 0 ? new ClientCertificateProvider(clientCertificates) :           // manual with certs
                    null;                                                                                         // manual without certs
                IntPtr userPointer = IntPtr.Zero;

                if (certProvider != null)
                {
                    // The client cert provider needs to be passed through to the callback, and thus
                    // we create a GCHandle to keep it rooted.  This handle needs to be cleaned up
                    // when the request has completed, and a simple and pay-for-play way to do that
                    // is by cleaning it up in a continuation off of the request.
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(), certProvider,
                                           CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
                }

                // Register the callback with libcurl.  We need to register even if there's no user-provided
                // server callback and even if there are no client certificates, because we support verifying
                // server certificates against more than those known to OpenSSL.
                CURLcode answer = easy.SetSslCtxCallback(s_sslCtxCallback, userPointer);

                switch (answer)
                {
                case CURLcode.CURLE_OK:
                    // We successfully registered.  If we'll be invoking a user-provided callback to verify the server
                    // certificate as part of that, disable libcurl's verification of the host name.  The user's callback
                    // needs to be given the opportunity to examine the cert, and our logic will determine whether
                    // the host name matches and will inform the callback of that.
                    if (easy._handler.ServerCertificateValidationCallback != null)
                    {
                        easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0);     // don't verify the peer cert's hostname
                        // We don't change the SSL_VERIFYPEER setting, as setting it to 0 will cause
                        // SSL and libcurl to ignore the result of the server callback.
                    }

                    // The allowed SSL protocols will be set in the configuration callback.
                    break;

                case CURLcode.CURLE_UNKNOWN_OPTION:     // Curl 7.38 and prior
                case CURLcode.CURLE_NOT_BUILT_IN:       // Curl 7.39 and later
                    // It's ok if we failed to register the callback if all of the defaults are in play
                    // with relation to handling of certificates.  But if that's not the case, failing to
                    // register the callback will result in those options not being factored in, which is
                    // a significant enough error that we need to fail.
                    EventSourceTrace("CURLOPT_SSL_CTX_FUNCTION not supported: {0}", answer);
                    if (certProvider != null ||
                        easy._handler.ServerCertificateValidationCallback != null ||
                        easy._handler.CheckCertificateRevocationList)
                    {
                        throw new PlatformNotSupportedException(
                                  SR.Format(SR.net_http_unix_invalid_certcallback_option, CurlVersionDescription, CurlSslVersionDescription));
                    }

                    // Since there won't be a callback to configure the allowed SSL protocols, configure them here.
                    SetSslVersion(easy);

                    break;

                default:
                    ThrowIfCURLEError(answer);
                    break;
                }
            }
 public static IHttpClientBuilder WithClientCertificateOptions(this IHttpClientBuilder builder, ClientCertificateOption options)
 {
     return(builder.WithConfiguration(s => s.ClientCertificateOptions = options));
 }
 private void SetClientCertificateOptions(ClientCertificateOption value) => InvokeNativeHandlerMethod("set_ClientCertificateOptions", value);
Example #21
0
        public HttpClientHandler()
        {
            this.rtFilter = new RTHttpBaseProtocolFilter();
            this.handlerToFilter = new HttpHandlerToFilter(this.rtFilter);

            this.clientCertificateOptions = ClientCertificateOption.Manual;

            InitRTCookieUsageBehavior();

            this.useCookies = true; // deal with cookies by default.
            this.cookieContainer = new CookieContainer(); // default container used for dealing with auto-cookies.

            // Managed at this layer for granularity, but uses the desktop default.
            this.rtFilter.AutomaticDecompression = false;
            this.automaticDecompression = DecompressionMethods.None;

            // Set initial proxy credentials based on default system proxy.
            SetProxyCredential(null);

            // We don't support using the UI model in HttpBaseProtocolFilter() especially for auto-handling 401 responses.
            this.rtFilter.AllowUI = false;
            
            // The .NET Desktop System.Net Http APIs (based on HttpWebRequest/HttpClient) uses no caching by default.
            // To preserve app-compat, we turn off caching (as much as possible) in the WinRT HttpClient APIs.
            // TODO (#7877): use RTHttpCacheReadBehavior.NoCache when available in the next version of WinRT HttpClient API.
            this.rtFilter.CacheControl.ReadBehavior = RTHttpCacheReadBehavior.MostRecent; 
            this.rtFilter.CacheControl.WriteBehavior = RTHttpCacheWriteBehavior.NoCache;
        }
        public async Task AutomaticOrManual_DoesntFailRegardlessOfWhetherClientCertsAreAvailable(ClientCertificateOption mode)
        {
            using (HttpClientHandler handler = CreateHttpClientHandler())
                using (HttpClient client = CreateHttpClient(handler))
                {
                    handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
                    handler.ClientCertificateOptions = mode;

                    await LoopbackServer.CreateServerAsync(async server =>
                    {
                        Task clientTask = client.GetStringAsync(server.Address);
                        Task serverTask = server.AcceptConnectionAsync(async connection =>
                        {
                            SslStream sslStream = Assert.IsType <SslStream>(connection.Stream);
                            await connection.ReadRequestHeaderAndSendResponseAsync();
                        });

                        await new Task[] { clientTask, serverTask }.WhenAllOrAnyFailed();
                    }, new LoopbackServer.Options {
                        UseSsl = true
                    });
                }
        }