pact-foundation / pact-net

.NET version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://pact.io
MIT License
823 stars 225 forks source link

'WithSslVerificationDisabled' doesnt disable ssl verification #488

Open bulat30 opened 4 months ago

bulat30 commented 4 months ago

I'm trying to implement a simple provider test using pact-broker as the pact source. But I get a certificate verification error when connecting to the broker, although I use WithSslVerificationDisabled. I also tried using the PACT_DISABLE_SSL_VERIFICATION and PACT_BROKER_DISABLE_SSL_VERIFICATION variables, but the error persists Package - "PactNet" Version="4.5.0", OS - windows, framework - net7.0

Environment.SetEnvironmentVariable("PACT_DISABLE_SSL_VERIFICATION", "true");
Environment.SetEnvironmentVariable("PACT_BROKER_DISABLE_SSL_VERIFICATION", "true");
var pactVerifier = new PactVerifier(new PactVerifierConfig() { Outputters = new[] { new XunitOutput(testOutputHelper) }, LogLevel = PactLogLevel.Debug });
pactVerifier
               .ServiceProvider("my_service", new Uri("http://localhost:5000"))
               .WithPactBrokerSource(new Uri("https://myhost"), opt =>
                   {
                       opt.PublishResults(Guid.NewGuid().ToString());
                   })
               .WithSslVerificationDisabled()
               .Verify();

Verifier Logs: reqwest::async_impl::client: rustls failed to parse DER certificate MissingOrMalformedExtensions Certificate pact_verifier::pact_broker: Fetching path '/' from pact broker rustls::conn: Sending fatal alert BadCertificate pact_verifier: Failed to load pact - \x1b[31mCould not load pacts from the pact broker.

adamrodger commented 4 months ago

@mefellows this looks like an FFI error similar to the one I found a while ago about falling to parse certs.

It looks like it still tries to load the cert bundle when when SSL verification is disabled, and it's the parsing that fails.

bulat30 commented 4 months ago

@adamrodger Could you tell please when i can expect a fix? And is there any way to temporarily bypass this bug?

adamrodger commented 4 months ago

The defect is in a different library, not in PactNet. Pull requests are gratefully expected if this is urgent.

Alternatively your quickest option will be to identify and remove and invalid certificate on your machine so that it doesn't fail to parse.

mefellows commented 4 months ago

@bulat30 the issue is an underlying dependency attempts to load all certificates from the host into a trust store, so that when outbound https calls are made, it can compare the presented certificate to those chains that are trusted.

There is a certificate on your host somewhere that is invalid, and that's the issue that we're seeing. I thought we had found the library that caused the issue, but that was actually a different problem.

I'll create a tracking issue upstream to fix this.

See also the original upstream issue.

bulat30 commented 4 months ago

@mefellows thanks! i tried to load all certificates chain from the broker host into a trust store on client side using a browser, and also tried to specify the path to these certificates using the SSL_CERT_DIR variable and the path to each of the certificates using SSL_CERT_FILE, but, unfortunately, every time I get BadCertificate error (rustls::conn: Sending fatal alert BadCertificate)

mefellows commented 4 months ago

No worries. Unfortunately none of those options would circumvent the issue described above.

You could use the repro Adam created here to potentially find and understand which certificate is causing the problem. It might be the one presented in the pact broker (presumably it's a self-signed cert?) so you might start there.

adamrodger commented 4 months ago

I was just trying to remember where that sample app was 😂

I thought the native TLS lib had changed so that you can handle parsing errors in user code, but perhaps not? Or is it a dependency of a dependency so we don't get the chance to handle the error?

mefellows commented 4 months ago

I thought the native TLS lib had changed so that you can handle parsing errors in user code, but perhaps not? Or is it a dependency of a dependency so we don't get the chance to handle the error?

Yeah it was, but that was handled in a dependency of a dependency. This error looks related but I think is slightly different.

In the linked issue above, I actually think the disabling of certificate checking is behind a rust feature that doesn't apply to the rust feature of the TLS library we use. That is, in my reading at least, the method is a no-op which is why we are getting this error.

bulat30 commented 4 months ago

I found invalid certificates only on clientside and the errors "reqwest::async_impl::client: rustls failed to parse DER certificate MissingOrMalformedExtensions Certificate" disappeared. But I still get the BadCertificate error :( Logs: INFO ThreadId(01) pact_verifier::pact_broker: Fetching path '/' from pact broker DEBUG ThreadId(01) reqwest::connect: starting new connection: https:// DEBUG ThreadId(01) hyper::client::connect::http: connecting to DEBUG ThreadId(01) rustls::client::hs: No cached session for DnsName(DnsName(DnsName("")))
DEBUG ThreadId(01) rustls::client::hs: Not resuming any session WARN ThreadId(01) rustls::conn: Sending fatal alert BadCertificate
ERROR ThreadId(01) pact_verifier: Failed to load pact - \x1b[31mCould not load pacts from the pact broker

adamrodger commented 4 months ago

That looks more like the certificate of the broker you're using is invalid to me. I'm not sure if you're using a self hosted broker or Pactflow though.

bulat30 commented 4 months ago

Im using self hosted broker with self signed certificate. rustls-native-certs didn't find invalid certs on the broker host

adamrodger commented 4 months ago

Yeah so that means that the host where you're running the tests doesn't trust the cert being used by the broker.

I can't really help you with that because that depends if/how you configure those certs, and PactNet is behaving as expected in the scenario where that's not configured properly.

Your best bet is to try and use something like curl -v https://broker.example.org to connect to the broker from the machine running the tests, and that will allow you to confirm when the certificate is properly trusted by the OS without needing PactNet in the loop at all. Once that works then PactNet will also.