diff --git a/README.md b/README.md index c9eea801..6bce71f7 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,13 @@ A third option is to get an id_token - get Id Token via `com.here.account.oauth2.HereAccount`'s `TokenEndpoint.requestToken(..)` approach by setting the scope field in the request. +You can also use one of the proxy options to getAccessToken +- use `HereAccessTokenProvider.builder().setProxy(, ).build();` (Uses https by default) +- use `HereAccessTokenProvider.builder().setProxy(, , ).build();` (Can be used to set http/https scheme) +- use `HereAccessTokenProvider.builder().setProxy(, , ).setProxyAuthentication(, ).build();` + +If you want move advanced options, you can provide your own HttpProvider `HereAccessTokenProvider.builder().setHttpProvider().build();` + # License Copyright (C) 2016-2019 HERE Europe B.V. diff --git a/examples/here-oauth-client-example/dependency-reduced-pom.xml b/examples/here-oauth-client-example/dependency-reduced-pom.xml index 5c639816..6130d03f 100644 --- a/examples/here-oauth-client-example/dependency-reduced-pom.xml +++ b/examples/here-oauth-client-example/dependency-reduced-pom.xml @@ -61,6 +61,16 @@ com.here.account.oauth2.tutorial.HereAccessTokenProviderTutorial + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + diff --git a/examples/here-oauth-client-example/pom.xml b/examples/here-oauth-client-example/pom.xml index 27c424c8..71c8f4a3 100644 --- a/examples/here-oauth-client-example/pom.xml +++ b/examples/here-oauth-client-example/pom.xml @@ -72,6 +72,16 @@ com.here.account.oauth2.tutorial.HereAccessTokenProviderTutorial + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + @@ -94,6 +104,10 @@ org.apache.httpcomponents httpclient + + net.lightbody.bmp + browsermob-core + diff --git a/examples/here-oauth-client-example/src/main/java/com/here/account/oauth2/tutorial/HereAccessTokenProviderTutorial.java b/examples/here-oauth-client-example/src/main/java/com/here/account/oauth2/tutorial/HereAccessTokenProviderTutorial.java index eb3601e8..b06ea7ed 100644 --- a/examples/here-oauth-client-example/src/main/java/com/here/account/oauth2/tutorial/HereAccessTokenProviderTutorial.java +++ b/examples/here-oauth-client-example/src/main/java/com/here/account/oauth2/tutorial/HereAccessTokenProviderTutorial.java @@ -15,13 +15,15 @@ */ package com.here.account.oauth2.tutorial; -import java.util.List; -import java.util.Map; - -import com.here.account.auth.OAuth2Authorizer; -import com.here.account.http.HttpProvider; -import com.here.account.http.HttpProvider.HttpRequest; +import com.here.account.http.apache.ApacheHttpClientProvider; import com.here.account.oauth2.HereAccessTokenProvider; +import net.lightbody.bmp.BrowserMobProxy; +import net.lightbody.bmp.BrowserMobProxyServer; +import net.lightbody.bmp.proxy.auth.AuthType; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; /** * A simple tutorial demonstrating how to get a HERE Access Token. @@ -33,6 +35,8 @@ public class HereAccessTokenProviderTutorial { public static void main(String[] argv) { HereAccessTokenProviderTutorial t = new HereAccessTokenProviderTutorial(argv); t.doGetAccessToken(); + t.doGetAccessTokenViaProxy(); + t.doGetAccessTokenViaProxyAndAuth(); } private final Args args; @@ -62,6 +66,87 @@ protected void doGetAccessToken() { } } + + /** + * A simple method that builds a HereAccessTokenProvider via a proxy, + * gets one Access Token, + * and if successful outputs the first few characters of the valid token. + */ + protected void doGetAccessTokenViaProxy() { + try { + // Creating custom httpClient for test purposes as real server will require SSL verification certificates + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + // Create a proxy + BrowserMobProxy proxy = new BrowserMobProxyServer(); + // Start proxy + proxy.start(0); + try ( + // use your provided System properties, ~/.here/credentials.ini, or credentials.properties file + HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder() + .setHttpProvider(ApacheHttpClientProvider.builder().setHttpClient(httpClient).build()) + .setProxy("localhost", proxy.getPort(), "http") + .build() + ) { + // call accessTokens.getAccessToken(); every time one is needed, it will always be fresh + String accessToken = accessTokens.getAccessToken(); + // use accessToken on a request... + useAccessToken(accessToken); + } catch (Exception e) { + trouble(e); + } + finally { + // Stop proxy + proxy.stop(); + } + } catch (Exception e) { + trouble(e); + } + } + + /** + * A simple method that builds a HereAccessTokenProvider via a proxy and Auth, + * gets one Access Token, + * and if successful outputs the first few characters of the valid token. + */ + protected void doGetAccessTokenViaProxyAndAuth() { + try { + // Creating custom httpClient for test purposes as real server will require SSL verification certificates + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + // Create a proxy + BrowserMobProxy proxy = new BrowserMobProxyServer(); + // Start proxy + proxy.start(0); + String proxyUsername = "yourUsername"; + String proxyPassword = "yourPassword"; + proxy.autoAuthorization("localhost:" + proxy.getPort(), proxyUsername, proxyPassword, AuthType.BASIC); + try ( + // use your provided System properties, ~/.here/credentials.ini, or credentials.properties file + HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder() + .setHttpProvider(ApacheHttpClientProvider.builder().setHttpClient(httpClient).build()) + .setProxy("localhost", proxy.getPort()) // uses https as default scheme + .setProxyAuthentication(proxyUsername, proxyPassword) + .build() + ) { + // call accessTokens.getAccessToken(); every time one is needed, it will always be fresh + String accessToken = accessTokens.getAccessToken(); + // use accessToken on a request... + useAccessToken(accessToken); + } catch (Exception e) { + trouble(e); + } finally { + // Stop proxy + proxy.stop(); + } + } catch (Exception e) { + trouble(e); + } + } protected void useAccessToken(String accessToken) { if (args.isVerbose()) { diff --git a/here-oauth-client/pom.xml b/here-oauth-client/pom.xml index ad514a84..5b8ae2f2 100644 --- a/here-oauth-client/pom.xml +++ b/here-oauth-client/pom.xml @@ -109,5 +109,11 @@ async-http-client test + + net.lightbody.bmp + browsermob-core + test + + diff --git a/here-oauth-client/src/main/java/com/here/account/http/apache/ApacheHttpClientProvider.java b/here-oauth-client/src/main/java/com/here/account/http/apache/ApacheHttpClientProvider.java index a486113d..88521d05 100644 --- a/here-oauth-client/src/main/java/com/here/account/http/apache/ApacheHttpClientProvider.java +++ b/here-oauth-client/src/main/java/com/here/account/http/apache/ApacheHttpClientProvider.java @@ -25,7 +25,10 @@ import org.apache.http.Header; import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; import org.apache.http.NameValuePair; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; @@ -40,8 +43,10 @@ import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpTrace; import org.apache.http.entity.BasicHttpEntity; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpContext; @@ -92,6 +97,11 @@ public static class Builder { private RequestConfig.Builder apacheConfigBuilder; private CloseableHttpClient httpClient; private boolean doCloseHttpClient = true; + private String proxyHost; + private int proxyPort; + private String scheme = "https"; + private String proxyUsername; + private String proxyPassword; private Builder() { apacheConfigBuilder = RequestConfig.custom(); @@ -134,19 +144,38 @@ public Builder setConnectionTimeoutInMs(int connectionTimeoutInMs) { return this; } + public Builder setProxy(String proxyHost, int proxyPort, String scheme) { + this.proxyHost = proxyHost; + this.proxyPort = proxyPort; + this.scheme = scheme; + return this; + } + + public Builder setProxyAuthentication(String proxyUsername, String proxyPassword) { + this.proxyUsername = proxyUsername; + this.proxyPassword = proxyPassword; + return this; + } + /** * Build using builders, builders, and more builders. * * @return the built HttpProvider implementation for Apache httpclient. */ public HttpProvider build() { - - CloseableHttpClient client = this.httpClient != null ? this.httpClient : - // uses PoolingHttpClientConnectionManager by default - HttpClientBuilder.create().setDefaultRequestConfig(apacheConfigBuilder.build()).build(); - + HttpClientBuilder clientBuilder = HttpClientBuilder.create() + .setDefaultRequestConfig(apacheConfigBuilder.build()); + if (null != proxyHost && proxyPort > 0) { + clientBuilder.setRoutePlanner(new DefaultProxyRoutePlanner(new HttpHost(proxyHost, proxyPort, scheme))); + if (null != proxyUsername && null != proxyPassword) { + BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxyHost, proxyPort), + new UsernamePasswordCredentials(proxyUsername, proxyPassword)); + clientBuilder.setDefaultCredentialsProvider(credentialsProvider); + } + } + CloseableHttpClient client = null != this.httpClient ? this.httpClient : clientBuilder.build(); return new ApacheHttpClientProvider(client, this.doCloseHttpClient); - } } diff --git a/here-oauth-client/src/main/java/com/here/account/oauth2/HereAccessTokenProvider.java b/here-oauth-client/src/main/java/com/here/account/oauth2/HereAccessTokenProvider.java index e408d755..cffee23c 100644 --- a/here-oauth-client/src/main/java/com/here/account/oauth2/HereAccessTokenProvider.java +++ b/here-oauth-client/src/main/java/com/here/account/oauth2/HereAccessTokenProvider.java @@ -28,6 +28,7 @@ import com.here.account.util.JacksonSerializer; import com.here.account.util.Serializer; import com.here.account.util.SettableSystemClock; +import org.apache.http.HttpHost; /** * An implementation that provides HERE Access Tokens, by accessing HERE Account @@ -108,6 +109,11 @@ public static class Builder { private boolean alwaysRequestNewToken = false; private Serializer serializer; private RetryPolicy retryPolicy; + private String proxyHost; + private int proxyPort; + private String scheme; + private String proxyUsername; + private String proxyPassword; private Builder() { } @@ -177,6 +183,45 @@ public Builder setRetryPolicy(RetryPolicy retryPolicy) { return this; } + /** + * Optionally set proxy endpoint configurations (https by default) + * @param proxyHost proxy host + * @param proxyPort proxy port + * @return this Builder + */ + public Builder setProxy(String proxyHost, int proxyPort) { + this.proxyHost = proxyHost; + this.proxyPort = proxyPort; + this.scheme = "https"; + return this; + } + + /** + * Optionally set proxy endpoint configurations (https by default) + * @param proxyHost proxy host + * @param proxyPort proxy port + * @param scheme "http" or "https" + * + * @return this Builder + */ + public Builder setProxy(String proxyHost, int proxyPort, String scheme) { + this.proxyHost = proxyHost; + this.proxyPort = proxyPort; + this.scheme = scheme; + return this; + } + + /** + * Optionally set proxy authentication configurations + * @param proxyUsername proxy username + * @param proxyPassword proxy password + * @return this Builder + */ + public Builder setProxyAuthentication(String proxyUsername, String proxyPassword) { + this.proxyUsername = proxyUsername; + this.proxyPassword = proxyPassword; + return this; + } /** * Build using builders, builders, and more builders. @@ -194,8 +239,15 @@ public HereAccessTokenProvider build() { boolean doCloseHttpProvider = false; if (null == httpProvider) { + ApacheHttpClientProvider.Builder apacheHttpClientProvider = ApacheHttpClientProvider.builder(); + if (null != proxyHost && proxyPort > 0) { + apacheHttpClientProvider = apacheHttpClientProvider.setProxy(proxyHost, proxyPort, scheme); + if (null != proxyUsername && null != proxyPassword) { + apacheHttpClientProvider = apacheHttpClientProvider.setProxyAuthentication(proxyUsername, proxyPassword); + } + } // uses PoolingHttpClientConnectionManager by default - this.httpProvider = ApacheHttpClientProvider.builder().build(); + this.httpProvider = apacheHttpClientProvider.build(); // because the httpProvider was not injected, we should close it doCloseHttpProvider = true; } diff --git a/here-oauth-client/src/main/javadoc/overview.html b/here-oauth-client/src/main/javadoc/overview.html index bc8ae9e3..94ac2651 100644 --- a/here-oauth-client/src/main/javadoc/overview.html +++ b/here-oauth-client/src/main/javadoc/overview.html @@ -29,7 +29,39 @@ } + +

+ To use proxy server to get access token: +

+            {@code
+                HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder()
+                            .setProxy(proxyHost, proxyHost) // uses https as default scheme
+                            .build();
+            }
+
+            {@code
+                HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder()
+                            .setProxy(proxyHost, proxyPort, scheme) // scheme can be http or https
+                            .build();
+            }
+
+            {@code
+                HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder()
+                            .setProxy(proxyHost, proxyPort, scheme)
+                            .setProxyAuthentication(proxyUsername, proxyPassword)
+                            .build();
+            }
+        
+

- See the {@link com.here.account.oauth2.HereAccessTokenProvider} entry point class for detailed usage instructions. + If you want move advanced options, you can provide your own custom HttpProvider +

+            {@code
+                HereAccessTokenProvider.builder().setHttpProvider(httpProvider).build();
+            }
+        
+ +

+ See the {@link com.here.account.oauth2.HereAccessTokenProvider} entry point class for detailed usage instructions.} \ No newline at end of file diff --git a/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderIT.java b/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderIT.java index c8327da3..e0be62ff 100644 --- a/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderIT.java +++ b/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderIT.java @@ -23,8 +23,16 @@ import com.here.account.auth.provider.FromHereCredentialsIniFile; import com.here.account.auth.provider.FromHereCredentialsIniStream; import com.here.account.http.HttpProvider; +import com.here.account.http.apache.ApacheHttpClientProvider; import com.here.account.util.Clock; import com.here.account.util.SettableSystemClock; +import net.lightbody.bmp.BrowserMobProxy; +import net.lightbody.bmp.BrowserMobProxyServer; +import net.lightbody.bmp.proxy.auth.AuthType; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; @@ -34,8 +42,7 @@ import java.util.Map.Entry; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * @author kmccrack @@ -57,6 +64,66 @@ public void test_builder_basic() throws IOException { } } + @Ignore // We don't want to create and run a server each time + @Test + public void test_builder_proxy() throws Exception { + // Creating custom httpClient for testing purposes as real server will require SSL verification certificates + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + // Create a proxy + BrowserMobProxy proxy = new BrowserMobProxyServer(); + // Start proxy + proxy.start(0); + try ( + HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder() + .setHttpProvider(ApacheHttpClientProvider.builder().setHttpClient(httpClient).build()) + .setProxy("localhost", proxy.getPort(), "http") + .build() + ) { + String accessToken = accessTokens.getAccessToken(); + assertNotNull("accessToken was null", accessToken); + assertFalse("accessToken was blank", accessToken.trim().isEmpty()); + AccessTokenResponse accessTokenResponse = accessTokens.getAccessTokenResponse(); + assertNotNull("accessTokenResponse was null", accessTokenResponse); + assertEquals("tokenType invalid", "bearer", accessTokenResponse.getTokenType()); + } + proxy.stop(); + } + + @Ignore // We don't want to create and run a server each time + @Test + public void test_builder_proxy_and_auth() throws Exception { + // Creating custom httpClient for testing purposes as real server will require SSL verification certificates + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLContext(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + // Create a proxy + BrowserMobProxy proxy = new BrowserMobProxyServer(); + // Start proxy + proxy.start(0); + String proxyUsername = "yourUsername"; + String proxyPassword = "yourPassword"; + proxy.autoAuthorization("localhost:" + proxy.getPort(), proxyUsername, proxyPassword, AuthType.BASIC); + try ( + HereAccessTokenProvider accessTokens = HereAccessTokenProvider.builder() + .setHttpProvider(ApacheHttpClientProvider.builder().setHttpClient(httpClient).build()) + .setProxy("localhost", proxy.getPort()) + .setProxyAuthentication(proxyUsername, proxyPassword) + .build() + ) { + String accessToken = accessTokens.getAccessToken(); + assertNotNull("accessToken was null", accessToken); + assertFalse("accessToken was blank", accessToken.trim().isEmpty()); + AccessTokenResponse accessTokenResponse = accessTokens.getAccessTokenResponse(); + assertNotNull("accessTokenResponse was null", accessTokenResponse); + assertEquals("tokenType invalid", "bearer", accessTokenResponse.getTokenType()); + } + proxy.stop(); + } + private static final int ONE_HOUR_SKEW_MILLIS = 60 * 60 * 1000; @Test diff --git a/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderTest.java b/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderTest.java index 4b9aaeea..2dd1ba2b 100644 --- a/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderTest.java +++ b/here-oauth-client/src/test/java/com/here/account/oauth2/HereAccessTokenProviderTest.java @@ -15,6 +15,8 @@ */ package com.here.account.oauth2; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -265,6 +267,60 @@ public void test_HereAccessTokenProvider_defaultHttpProvider() throws IOExceptio } } + @Test + public void test_HereAccessTokenProvider_withProxy() throws IOException, HttpException { + HttpProvider mockHttpProvider = Mockito.mock(HttpProvider.class); + HttpProvider.HttpResponse mockHttpResponse = Mockito.mock(HttpProvider.HttpResponse.class); + String responseBody = HereAccountTest.getResponseBody(expectedAccessToken, expectedScope); + byte[] bytes = responseBody.getBytes(StandardCharsets.UTF_8); + Mockito.when(mockHttpResponse.getStatusCode()).thenReturn(200); + Mockito.when(mockHttpResponse.getResponseBody()).thenReturn(new ByteArrayInputStream(bytes)); + Mockito.when(mockHttpProvider.execute(Mockito.any(HttpProvider.HttpRequest.class))) + .thenReturn(mockHttpResponse); + try ( + HereAccessTokenProvider hereAccessTokenProvider = HereAccessTokenProvider.builder() + .setHttpProvider(mockHttpProvider) + .setClientAuthorizationRequestProvider(clientAuthorizationRequestProvider) + .setProxy("localhost", 8000, "http") + .build() + ) { + AccessTokenResponse accessTokenResponse = hereAccessTokenProvider.getAccessTokenResponse(); + assertNotNull("accessTokenResponse was null", accessTokenResponse); + String accessToken = accessTokenResponse.getAccessToken(); + assertEquals("expected accessToken " + expectedAccessToken + ", actual " + accessToken, + expectedAccessToken, accessToken); + String scope = accessTokenResponse.getScope(); + assertEquals("expected scope " + expectedScope + ", actual " + scope, expectedScope, scope); + } + } + @Test + public void test_HereAccessTokenProvider_withProxyAuthentication() throws IOException, HttpException { + HttpProvider mockHttpProvider = Mockito.mock(HttpProvider.class); + HttpProvider.HttpResponse mockHttpResponse = Mockito.mock(HttpProvider.HttpResponse.class); + String responseBody = HereAccountTest.getResponseBody(expectedAccessToken, expectedScope); + byte[] bytes = responseBody.getBytes(StandardCharsets.UTF_8); + Mockito.when(mockHttpResponse.getStatusCode()).thenReturn(200); + Mockito.when(mockHttpResponse.getResponseBody()).thenReturn(new ByteArrayInputStream(bytes)); + Mockito.when(mockHttpProvider.execute(Mockito.any(HttpProvider.HttpRequest.class))) + .thenReturn(mockHttpResponse); + try ( + HereAccessTokenProvider hereAccessTokenProvider + = HereAccessTokenProvider.builder() + .setHttpProvider(mockHttpProvider) + .setClientAuthorizationRequestProvider(clientAuthorizationRequestProvider) + .setProxy("localhost", 8000) + .setProxyAuthentication("myUsername", "myPassword") + .build() + ) { + AccessTokenResponse accessTokenResponse = hereAccessTokenProvider.getAccessTokenResponse(); + assertNotNull("accessTokenResponse was null", accessTokenResponse); + String accessToken = accessTokenResponse.getAccessToken(); + assertEquals("expected accessToken " + expectedAccessToken + ", actual " + accessToken, + expectedAccessToken, accessToken); + String scope = accessTokenResponse.getScope(); + assertEquals("expected scope " + expectedScope + ", actual " + scope, expectedScope, scope); + } + } } diff --git a/here-oauth-client/src/test/java/com/here/account/oauth2/SignInWithClientCredentialsIT.java b/here-oauth-client/src/test/java/com/here/account/oauth2/SignInWithClientCredentialsIT.java index 1b21d0fd..e09fdd50 100644 --- a/here-oauth-client/src/test/java/com/here/account/oauth2/SignInWithClientCredentialsIT.java +++ b/here-oauth-client/src/test/java/com/here/account/oauth2/SignInWithClientCredentialsIT.java @@ -149,7 +149,7 @@ public void test_signIn_wrongClock() throws Exception { String error = errorResponse.getError(); String expectedError = "invalid_request"; assertTrue("expected error " + expectedError + ", actual " + error, expectedError.equals(error)); - String expectedErrorDescriptionContains = "timestamp"; + String expectedErrorDescriptionContains = "offset"; String errorDescription = errorResponse.getErrorDescription(); assertTrue("expected error_description to contain " + errorDescription + ", actual " + errorDescription, null != errorDescription && errorDescription.contains(expectedErrorDescriptionContains)); diff --git a/pom.xml b/pom.xml index 318a1c45..ad30d1dc 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,7 @@ 4.13.1 1.10.19 1.8.17 + 2.1.5 @@ -118,6 +119,11 @@ httpclient ${apache.httpclient.version} + + net.lightbody.bmp + browsermob-core + ${browsermob.version} +