Get selenium to work with proxy authentication
The problem at hand is to get Selenium working with an application, that is only reachable via a proxy that requires authentication. I thought that this is a very common setting, as most websites should be hidden until the day of the launch but it is not very well supported by selenium.
It was suprisingly hard to get up and running, so I”ll outline the solution here in order to save my fellow software writers / testers a couple of hours. I used the FirefoxDriver & Java for this one, but it should be applicable for other Drivers as well as Selenium APIs as well.
In short we will start up a proxy server on the machine where the test runs and make the FirefoxDriver use it. In order to make this all self-contained we need the browsermob-proxy and – of course – selenium. So in Maven this means:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>biz.neustar</groupId>
<artifactId>browsermob-proxy</artifactId>
<version>2.0-beta-3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.2</version>
</dependency>
</dependencies>
</dependencyManagement> |
Configuring the proxy server takes a few lines, as we have to rely on reflection in order to configure the proxy to use the proxy
:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/**
*
* @param internalPort Port of the local proxy (listening on localhost).
* @param proxyHost The (external) proxy to use.
* @param credentials The credentials needed for the external proxy.
* @return The created proxy server.
* @throws Exception
*/
private ProxyServer createAndConfigureProxyServer(int internalPort,
HttpHost proxyHost, UsernamePasswordCredentials credentials)
throws Exception{
// Set up the internal proxy server and start it, because otherwise the
// http client is not started and we end up with a NP.
ProxyServer server = new ProxyServer(internalPort);
server.start();
DefaultHttpClient httpClient = extract();
AuthScope authScope = new AuthScope(proxyHost.getHostName(),
proxyHost.getPort());
httpClient.getCredentialsProvider().setCredentials(authScope,
credentials);
HttpHost proxy = new HttpHost(proxyHost.getHostName(),
proxyHost.getPort());
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
proxy);
return server;
}
private DefaultHttpClient extract() throws NoSuchFieldException,
IllegalAccessException {
// The httpclient has to be manipulated in order to be configured
// to use the proxy is private, so we have to rely on reflection.
Field clientField = ProxyServer.class.getDeclaredField("client");
setFieldAccessible(clientField);
BrowserMobHttpClient client = (BrowserMobHttpClient) clientField
.get(server);
Field httpClientfield = BrowserMobHttpClient.class
.getDeclaredField("httpClient");
setFieldAccessible(httpClientfield);
DefaultHttpClient httpClient = (DefaultHttpClient) httpClientfield
.get(client);
return httpClient;
}
private void setFieldAccessible(Field clientField) {
if (!clientField.isAccessible()) {
clientField.setAccessible(true);
}
} |
Ok, almost there – just a few lines to start up selenium and use the proxy on localhost:
|
1 2 3 4 |
ProxyServer server = createAndConfigureProxyServer();
FirefoxProfile firefoxProfile = new FirefoxProfile();
firefoxProfile.setProxyPreferences(server.seleniumProxy());
FirefoxDriver driver = new FirefoxDriver(firefoxProfile); |
So, happy testing!
PS: If you have a question or comments feel free to contact me or to post below.