betamaxteam / betamax

Betamax is a tool for mocking external HTTP resources such as web services and REST APIs in your tests. The project was inspired by the VCR library for Ruby.
http://betamax.software
Apache License 2.0
469 stars 131 forks source link

Possible to use custom SSL Context with HttpClient? #72

Closed abethell closed 11 years ago

abethell commented 11 years ago

A RESTful service I use requires SSL authentication - I use the SSLSocketFactory as shown in this example - http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java.

However - when using the SystemDefaultHttpClient, or BetamaxRoutePlanner - I always receive:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

there is also a warning immediately before this:

javax.net.ssl.SSLException: Received fatal alert: certificate_unknown

Is there something I am missing - or is this not supported yet?

Heres my full test-source - it works fine if I remove the @Betamax annotation, or get from a http address:

import java.security.KeyStore;
...

public class BetamaxTest {

    private Logger log = LoggerFactory.getLogger(CountryRepositoryTest.class);

    @Resource
    private RepositoryConfigImpl repositoryConfig;

    @Rule
    public Recorder recorder = new Recorder();

    @Before
    public void setup() {
        recorder.setSslSupport(true);
    }

    @Betamax(tape="thing tape")
    @Test
    public void testGetThingy() throws Exception {

        KeyStore keyStore = repositoryConfig.getKeyStore();
        KeyStore trustStore = repositoryConfig.getTrustStore();

        DefaultHttpClient httpClient = new SystemDefaultHttpClient();

        SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, "changeit", trustStore);
        Scheme sch = new Scheme("https", 443, socketFactory);
     //   BetamaxRoutePlanner.configure(httpClient);
        httpClient.getConnectionManager().getSchemeRegistry().register(sch);
        HttpGet httpGet = new HttpGet("https://myresthost/REST/account_attribute/97487/");
        HttpResponse response1 = httpClient.execute(httpGet);

        try {
            System.out.println(response1.getStatusLine());
            HttpEntity entity1 = response1.getEntity();
            EntityUtils.consume(entity1);
        } finally {
            httpGet.releaseConnection();
        }
    }
}

Thanks

robfletcher commented 11 years ago

Not supported yet but it's a very good idea

robfletcher commented 11 years ago

Would it make sense to be able to set the SSLSocketFactory instance on the Recorder? It could then be used by the proxy to make the real connection to the target. I'm not sure if it's necessary to set it on the client in your test since Betamax is breaking the certificate chain anyway in order to record traffic. I think this should be simple to implement.

robfletcher commented 11 years ago

Fixed. This will be in the next release.

abethell commented 11 years ago

Hi Rob - thanks for adding support for this; I was looking at the 1.2 (multimodule) branch to see if I could test this, but I am a little lost...

If I use the BetamaxHttpClient - it saves the yaml tape files, but only on https://www.google.co.uk - on my secure host I get SSLPeerUnverifiedExceptions.

If I use the DefaultHttpClient then my http GET is successful, but no tapes are recorded.

Any ideas?

Thanks

@ContextConfiguration(locations = {"classpath:test-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class BetamaxTest {

    private Logger log = LoggerFactory.getLogger(BetamaxTest.class);

    @Resource
    private RepositoryConfigImpl repositoryConfig;

    @Rule
    public Recorder recorder = new ProxyRecorder();

    @Betamax(tape="test tape")
    @Test
    public void testGetCountry() throws Exception {

        SSLSocketFactory socketFactory = new SSLSocketFactory(repositoryConfig.getKeyStore(),
                "asdfoi2j34",
                repositoryConfig.getTrustStore());

        ((ProxyRecorder)recorder).setSslSupport(true);
        ((ProxyRecorder)recorder).setSslSocketFactory(socketFactory);

        //HttpClient httpClient = new BetamaxHttpClient(recorder);
        HttpClient httpClient = new DefaultHttpClient();

        Scheme sch = new Scheme("https", 443, socketFactory);
        httpClient.getConnectionManager().getSchemeRegistry().register(sch);

        HttpGet httpGet = new HttpGet("https://api-test-host/REST/country/gb");
        //HttpGet httpGet = new HttpGet("https://www.google.com/");
        HttpResponse response1 = httpClient.execute(httpGet);

        try {
            System.out.println(response1.getStatusLine());
            HttpEntity entity1 = response1.getEntity();
            FileCopyUtils.copy(entity1.getContent(),System.out);
            EntityUtils.consume(entity1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpGet.releaseConnection();
        }
    }

}

My maven pom:

        <dependency>
            <groupId>co.freeside</groupId>
            <artifactId>betamax-core</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>co.freeside</groupId>
            <artifactId>betamax-httpclient</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>co.freeside</groupId>
            <artifactId>betamax-proxy</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
monksy commented 9 years ago

When will the next release be? 1.1.2 is still the "stable" version.

rschmitt commented 9 years ago

Under 20 commits in the last year and a half? It might be time for a fork. You're not the only one tired of waiting.