testcontainers / testcontainers-java

Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
https://testcontainers.org
MIT License
8.03k stars 1.65k forks source link

[Enhancement]: Alternative waiting strategy for MockServer #6647

Closed nils-christian closed 1 year ago

nils-christian commented 1 year ago

Module

MockServer

Proposal

Hi,

Currently the MockServer uses the waiting strategy

waitingFor(Wait.forHttp("/mockserver/status").withMethod("PUT").forStatusCode(200));

While this might work for the default case, it breaks as soon as SSL is enabled (which might not be an unusual scenario for testing with mockserver). In this case, at least forHttps would have to be used. It gets worse when you use certificates to authenticate the access, as you cannot easily use forHttps with a trust store.

I suggest to change the waiting strategy to something like

Wait.forLogMessage( ".*started on port: 1080.*", 1 )

I assume this would work in other scenarios as well.

eddumelendez commented 1 year ago

Hi @nils-christian, thanks for raising this issue. Would you like to contribute with this and adding some tests?

nils-christian commented 1 year ago

Hi @eddumelendez,

Sure. I added a PR for the issue.

nils-christian commented 1 year ago

Hi @eddumelendez,

I am sorry, but I have withdrawn the PR. Frankly speaking: Implementing the additional suggestions is a little bit more time than I wanted to invest in this single line (as this would require creating a certificate etc.). Additionaly, I have trouble importing the project into my IDE without errors.

vcvitaly commented 1 year ago

I can take it.

eddumelendez commented 1 year ago

@vcvitaly all yours! 😄

vcvitaly commented 1 year ago

@nils-christian Could you point me to some example or documentation on enabling SSL for Mockserver by any chance? I read the docs a bit and got the impression that HTTP and HTTPS are enabled by default, but I might've misunderstood it. I would be really grateful.

nils-christian commented 1 year ago

Hi @vcvitaly,

Unfortunately I cannot. Configuring SSL correctly with a certificate (which has yet to be generated) and all the other parts are (as far as I can see) a little bit more work and exactly the reasons why I dropped the PR. I am sorry.

DenilssonMontoya commented 1 year ago

Hi @vcvitaly,

This enhancement caught my eye as I am learning about testcontainers. Although I am aware that you are already working on it, I would like to offer some information that might be of help.

As you mentioned before, HTTPS is enabled by default in Mockserver using the same port as HTTP. https://www.mock-server.com/mock_server/HTTPS_TLS.html

Mockserver will automatically load a default Certificate Authority certificate to be used on secure communications, hence the related CertificateAuthority could be included in the HTTP client when hitting the mock endpoint.

Mockserver also lets us dynamically create a Certificate Authority instead of using a default one but I think the default one is good enough to test a successful HTTPS communication which is the main purpose of this enhancement.

Having said that, we just need to hit the mock endpoint using “https” in the URL and we also need to make Mockserver certificates trusted in the HTTP client. The default Mockserver CertificateAuthority(PEM file) can be found in the following link at Mockserver Github repo. https://github.com/mock-server/mockserver/blob/master/mockserver-core/src/main/resources/org/mockserver/socket/CertificateAuthorityCertificate.pem

Here is an example on how to add the CertificateAuthority certificate as part of the java HTTP Client https://bhanuchander210.github.io/HttpsUrlConnection-SSLSocketFactory-Configuration-With-SSLCertificates/. There are also examples on how to accomplish this in other Testcontainer modules, for instance Elasticasearch, https://github.com/testcontainers/testcontainers-java/blob/main/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java

I hope it helps.

vcvitaly commented 1 year ago

hi @DenilssonMontoya Actually, if you want - you can take this :), I don't have any experience with Mockserver and due to that hasn't been working on it lately.

DenilssonMontoya commented 1 year ago

Hi @vcvitaly , sure, I would love to contribute to this enhancement :).

Hi @eddumelendez, if it's okay for me to take this one, please let me know.

bedla commented 1 year ago

Just a question. If I get it correctly, this one is not about changing wait strategy (it is already working with HTTPS on same port), but more about exposing HTTPS certificate of started mockserver to be used in some HttpClients, right?

DenilssonMontoya commented 1 year ago

Hi @bedla,

It is true that Mockserver enables HTTPS by default in the same port as HTTP, so in theory we should be able to validate the Mockserver status either using HTTP(currently used for Wait strategy) or HTTPS.

It is important to note that Mockserver supports TLS and mTLS when talking about secure communication to Mockserver. https://www.mock-server.com/mock_server/HTTPS_TLS.html

When using TLS we authenticate the server in the client by including the CA certificate in the HTTP client, here we can use HTTP to validate status of Mockserver and HTTPS to make a request to the mocked endpoint, hence there should be no need to change the Wait Strategy.

However when using mTLS (Mutual TLS) and making it required, any communication to Mockserver will not be possible via HTTP. Trying to use HTTP will get us the following response.

returning response:

  {
    "statusCode" : 426,
    "headers" : {
      "Upgrade" : [ "TLS/1.2, HTTP/1.1" ],
      "Connection" : [ "Upgrade" ]
    }
  }
 //The HTTP 426 Upgrade Required client error response code indicates that the server refuses to perform the request 
 //using the current protocol but might be willing to do so after the client upgrades to a different protocol.

mTLS means that there is a mutual authentication between the server and the client, to make it required we need to change the value of this environment variable “MOCKSERVER_TLS_MUTUAL_AUTHENTICATION_REQUIRED” to “true”. https://www.mock-server.com/mock_server/HTTPS_TLS.html#button_configuration_require_mtls_for_all_tls_connections

Therefore, as far as I can tell, it would be needed to update the Wait Strategy for MockserverContainer as proposed by @nils-christian due to the possibility of making mTLS required for all communication.

bedla commented 1 year ago

ahh, now I get it. Thx for clarifying it @DenilssonMontoya