From faabeccc310706a364c77519e7d24d51589c17bf Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 27 Sep 2017 17:11:52 +0530 Subject: [PATCH] cloudian: have pre-emptive basic http/s auth Signed-off-by: Rohit Yadav --- .../com/cloudian/client/CloudianClient.java | 35 ++++++++++++------- .../cloudstack/CloudianConnector.java | 2 +- .../cloudstack/CloudianConnectorImpl.java | 2 +- .../cloudian/client/CloudianClientTest.java | 12 ++++--- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java index 50165c983f9..4b21c1dfb10 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java +++ b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java @@ -31,10 +31,12 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; @@ -42,10 +44,13 @@ import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.log4j.Logger; @@ -59,14 +64,20 @@ public class CloudianClient { private static final Logger LOG = Logger.getLogger(CloudianClient.class); private final HttpClient httpClient; - private final String baseUrl; + private final HttpClientContext httpContext; + private final String adminApiUrl; - public CloudianClient(final String baseUrl, final String username, final String password, final boolean validateSSlCertificate, final int timeout) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { - this.baseUrl = baseUrl; - - final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password); + public CloudianClient(final String host, final Integer port, final String scheme, final String username, final String password, final boolean validateSSlCertificate, final int timeout) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { final CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials(AuthScope.ANY, credentials); + provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); + final HttpHost adminHost = new HttpHost(host, port, scheme); + final AuthCache authCache = new BasicAuthCache(); + authCache.put(adminHost, new BasicScheme()); + + this.adminApiUrl = adminHost.toURI(); + this.httpContext = HttpClientContext.create(); + this.httpContext.setCredentialsProvider(provider); + this.httpContext.setAuthCache(authCache); final RequestConfig config = RequestConfig.custom() .setConnectTimeout(timeout * 1000) @@ -92,31 +103,31 @@ public class CloudianClient { } private HttpResponse delete(final String path) throws IOException { - return httpClient.execute(new HttpDelete(baseUrl + path)); + return httpClient.execute(new HttpDelete(adminApiUrl + path), httpContext); } private HttpResponse get(final String path) throws IOException { - return httpClient.execute(new HttpGet(baseUrl + path)); + return httpClient.execute(new HttpGet(adminApiUrl + path), httpContext); } private HttpResponse post(final String path, final Object item) throws IOException { final ObjectMapper mapper = new ObjectMapper(); final String json = mapper.writeValueAsString(item); final StringEntity entity = new StringEntity(json); - final HttpPost request = new HttpPost(baseUrl + path); + final HttpPost request = new HttpPost(adminApiUrl + path); request.setHeader("Content-type", "application/json"); request.setEntity(entity); - return httpClient.execute(request); + return httpClient.execute(request, httpContext); } private HttpResponse put(final String path, final Object item) throws IOException { final ObjectMapper mapper = new ObjectMapper(); final String json = mapper.writeValueAsString(item); final StringEntity entity = new StringEntity(json); - final HttpPut request = new HttpPut(baseUrl + path); + final HttpPut request = new HttpPut(adminApiUrl + path); request.setHeader("Content-type", "application/json"); request.setEntity(entity); - return httpClient.execute(request); + return httpClient.execute(request, httpContext); } //////////////////////////////////////////////////////// diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java index 8b936ada024..acad054e326 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java @@ -29,7 +29,7 @@ public interface CloudianConnector extends PluggableService { ConfigKey CloudianAdminHost = new ConfigKey<>("Advanced", String.class, "cloudian.admin.host", "s3-admin.cloudian.com", "The hostname of the Cloudian Admin server.", true); - ConfigKey CloudianAdminPort = new ConfigKey<>("Advanced", String.class, "cloudian.admin.port", "19443", + ConfigKey CloudianAdminPort = new ConfigKey<>("Advanced", Integer.class, "cloudian.admin.port", "19443", "The port of the Cloudian Admin server.", true); ConfigKey CloudianAdminProtocol = new ConfigKey<>("Advanced", String.class, "cloudian.admin.protocol", "https", diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java index 9a1f861feb5..acc401fe045 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java @@ -73,7 +73,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo private CloudianClient getClient() { try { - return new CloudianClient(getAdminUrl(), + return new CloudianClient(CloudianAdminHost.value(), CloudianAdminPort.value(), CloudianAdminProtocol.value(), CloudianAdminUser.value(), CloudianAdminPassword.value(), CloudianValidateSSLSecurity.value(), CloudianAdminApiRequestTimeout.value()); } catch (final KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) { diff --git a/plugins/integrations/cloudian/test/com/cloudian/client/CloudianClientTest.java b/plugins/integrations/cloudian/test/com/cloudian/client/CloudianClientTest.java index 38f75b40874..a0b2b844e4b 100644 --- a/plugins/integrations/cloudian/test/com/cloudian/client/CloudianClientTest.java +++ b/plugins/integrations/cloudian/test/com/cloudian/client/CloudianClientTest.java @@ -23,17 +23,19 @@ import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit.WireMockRule; public class CloudianClientTest { - @Rule - public WireMockRule wireMockRule = new WireMockRule(14333); + private final int port = 14333; private final int timeout = 2; private final String adminUsername = "admin"; private final String adminPassword = "public"; private CloudianClient client; + @Rule + public WireMockRule wireMockRule = new WireMockRule(port); + @Before public void setUp() throws Exception { - client = new CloudianClient("http://localhost:14333", adminUsername, adminPassword, false, timeout); + client = new CloudianClient("localhost", port, "http", adminUsername, adminPassword, false, timeout); } @After @@ -73,12 +75,12 @@ public class CloudianClientTest { client.listGroups(); } - @Test(expected = CloudRuntimeException.class) + @Test public void testBasicAuth() { wireMockRule.stubFor(WireMock.get(urlEqualTo("/group/list")) .willReturn(WireMock.aResponse() .withStatus(200) - .withBody(""))); + .withBody("[]"))); client.listGroups(); WireMock.verify(getRequestedFor(urlEqualTo("/group/list")) .withBasicAuth(new BasicCredentials(adminUsername, adminPassword)));