cjstehno / ersatz

🤖 A simulated HTTP server for testing client code with configurable responses.
https://cjstehno.github.io/ersatz
Apache License 2.0
47 stars 5 forks source link

Issue with https certificate and localhost #189

Open frieder opened 7 months ago

frieder commented 7 months ago

Hi

I'm using the library to unit test a custom HTTP client implementation (based on Apache HttpClient 4.5) and while doing so I'm getting an exception with the OOTB certificate.

javax.net.ssl.SSLPeerUnverifiedException: Certificate for <localhost> doesn't match any of the subject alternative names: []

The only way to work around this issue is to create my own certificate and add localhost to it.

keytool -genkey -alias ersatz \
    -keyalg RSA \
    -dname "CN=Ersatz,OU=Ersatz,O=Ersatz,L=Nowhere,ST=Nowhere,C=US" \
    -ext "SAN:c=DNS:localhost,IP:127.0.0.1" \
    -validity 3650 \
    -keystore ./src/test/resources/ersatz/cert.jks \
    -storepass ersatz -keypass ersatz

The same test with a self-signed cert on nginx does not result in such an exception so I think the issue is with the OOTB Ersatz certificate. Shouldn't localhost be part of the certificate already or am I doing something wrong here? Following is some example code I'm using for the unit test. Without the last two lines of code in #enableHttps(ServerConfig) I get the aforementioned exception.

@ExtendWith(ErsatzServerExtension.class)
class CustomTest {
    void enableHttps(ServerConfig config) {
        config.https();
        var url = getClass().getClassLoader().getResource("ersatz/cert.jks");
        config.keystore(url, "ersatz");
    }

    @Test
    @DisplayName("HTTPS OK")
    @ApplyServerConfig("enableHttps")
    void httpsOK(ErsatzServer server) throws Exception {
        server.expectations(expect -> expect.GET("/").responds().body(PAYLOAD));
        var request = new HttpGet(server.httpsUrl("/"));

        try (var client = CustomHttpClientBuilder.create().ignoreSsl(true).buildClient()) {
            try (var response = client.execute(request)) {
                int statusCode = response.getStatusLine().getStatusCode();
                assertThat(statusCode).isEqualTo(200);
            }
        }
    }
}

It's working for me but I'd prefer if this would work OOTB without the need to create a custom certificate.

Aside from this issue I really enjoy using the library. Thank you very much for creating such a great lib. ;)

cjstehno commented 6 months ago

Considering how important SSL is, I am always amazed at how horrible it is to work with. I should be able to take a look at with sometime over the next couple weeks.

cjstehno commented 6 months ago

I probably didn't have localhost explicitly added to the old keystore - I used your version of the keytool command to build a new one (and changed the name). The tests pass, but if you can I would suggest you pull the keystore-issue branch and run your test against it (without applying your own keystore. Let me know if that fixes your issue and I will cut a new release soon.

cjstehno commented 6 months ago

Since this seems to have become a non-issue, I will keep this around and merge the branch into the next full release, probably near the end of 2024.

frieder commented 6 months ago

Sorry I didn't have time to look at it yet. I'll try to have a look at it this or next week and give you some feedback. But it's also true that it's not a pressing issue for me so I don't mind if you wait with a new release as you suggested. Thx.

frieder commented 5 months ago

Hi

I just gave it a try with the code from the branch you suggested and it seems to work just fine now. Thank you very much.

When you release a new version, would it also be possible to issue a new version for 2.0.0 as well or is it too much work? We have one project that is stuck on Java 11. It not that's not an issue, we have a workaround for it.

Thx & have a nice day.

cjstehno commented 5 months ago

I generally do not back-patch fixes, but I will see if I have the time to do it when I make that release. Glad the fix worked.