Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example Code for calling HTTPS Serivice with Client Cert Authentication ... #371

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions microsoft-azure-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.13</version>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
Expand Down Expand Up @@ -87,7 +87,7 @@
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.13</version>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
Expand All @@ -110,6 +110,13 @@
<version>1.46</version>
<scope>test</scope>
</dependency>
<!-- can replace with apache commons-io or write something from scratch -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-io</artifactId>
<version>r03</version>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
*
* The author contributes this code to the public domain,
* retaining no rights and incurring no responsibilities for its use in whole or in part.
*/

package com.microsoft.windowsazure.services.management;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.text.MessageFormat;

import javax.net.ssl.SSLContext;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;

public class APICall {

private final String url;

private final SSLContext sslContext;

public static final String SERIVICE_VERSION_HEADER_KEY = "x-ms-version";

public static final String SERIVICE_VERSION_HEADER_VALUE = "2013-03-01";

public static final String SERVICE_CONTENT_TYPE_HEADER_KEY = "Content-Type";

public static final String SERVICE_CONTENT_TYPE_HEADER_VALUE = "application/xml";

public APICall(String subscription, SSLContext context) {
// make this changeable in whatever way suits you.....
url = MessageFormat.format("https://management.core.windows.net/{0}/services/hostedservices", subscription);
sslContext = context;
}

public APICall(String subscription, ConnectionCredential cred) throws GeneralSecurityException, IOException {
this(subscription, SSLContextFactory.createSSLContext(cred));
}

public String get() throws IOException, GeneralSecurityException {
Builder b = prepWebResourceBuilder();
ClientResponse response = b.get(ClientResponse.class);
checkBadResponse(response);
return response.getEntity(String.class);
}

public String post(String body) throws IOException, GeneralSecurityException {
Builder b = prepWebResourceBuilder();
ClientResponse response = b.post(ClientResponse.class, body);
checkBadResponse(response);
return response.getEntity(String.class);
}

private Builder prepWebResourceBuilder() throws IOException, GeneralSecurityException {
Client client = createClient();
WebResource wr = client.resource(url);
return wr.header(SERVICE_CONTENT_TYPE_HEADER_KEY, SERVICE_CONTENT_TYPE_HEADER_VALUE).header(
SERIVICE_VERSION_HEADER_KEY, SERIVICE_VERSION_HEADER_VALUE);
}

private Client createClient() throws IOException, GeneralSecurityException {
ClientConfig config = new DefaultClientConfig();
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(null, sslContext));
Client client = Client.create(config);
return client;
}

void checkBadResponse(ClientResponse response) {
if (response.getStatus() == 404) {
System.out.println("Entity doesn't Exist");
}
else if (response.getStatus() != 200) {
System.out.println("Something went wrong....");
System.out.println(response.getEntity(String.class));
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
*
*
* The author contributes this code to the public domain,
* retaining no rights and incurring no responsibilities for its use in whole or in part.
*/

package com.microsoft.windowsazure.services.management;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import com.google.common.io.ByteStreams;

public class ConnectionCredential {
private final byte[] keyStore;

private final String keyPasswd;

private final KeyStoreType keyStoreType;

/**
* Creates a Credential from a keyStore.
*
* @param keyPass
* - keyStore password, key for store and the internal private key must be
* symmetric
* @param keys
* - an InputStream probably a FileInputStream from a keyStore, the jks containing
* your management cert
* @throws IOException
*/
ConnectionCredential(InputStream keys, String keyPass, KeyStoreType type) throws IOException {
keyPasswd = keyPass;
// Apache IOUtils could be used instead of google.common.io,
// or do a brute force read into List and then into an array.
keyStore = ByteStreams.toByteArray(keys);
keyStoreType = type;
}

public KeyStoreType getKeyStoreType() {
return keyStoreType;
}

public InputStream getKeyStore() {
return new ByteArrayInputStream(keyStore);
}

public String getKeyPasswd() {
return keyPasswd;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
*
* The author contributes this code to the public domain,
* retaining no rights and incurring no responsibilities for its use in whole or in part.
*/
package com.microsoft.windowsazure.services.management;

import java.io.FileInputStream;

public class Example {
public static void main(String[] args) throws Exception {
ConnectionCredential cred = new ConnectionCredential(
// the .jks file (or other jks stream) containing your management cert bytes
new FileInputStream("../test.jks"),
// the password to the cert file and the private key inside it
"I won't tell you", KeyStoreType.jks);
APICall call = new APICall("my-subscription", cred);
System.out.println(call.get());
//or... call.post(someBodyText);

cred = new ConnectionCredential(
// the .pfx file (or other pfx stream) containing your management cert bytes
new FileInputStream("../test.pfx"),
// the password to the cert file and the private key inside it
"I won't tell you", KeyStoreType.pkcs12);
call = new APICall("my-subscription", cred);
System.out.println(call.get());

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
*
*
* The author contributes this code to the public domain,
* retaining no rights and incurring no responsibilities for its use in whole or in part.
*/

package com.microsoft.windowsazure.services.management;

public enum KeyStoreType {
jks, pkcs12
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
*
* The author contributes this code to the public domain,
* retaining no rights and incurring no responsibilities for its use in whole or in part.
*/
package com.microsoft.windowsazure.services.management;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;

/**
* Note: as it stands this provides a TLS SSLContext from jks and pfx stores. It could be modified to
* support other protocols (SSLv3, SSLv2, etc) and different key stores...
*
* Note that older .pfx files may need to be updated to pkcs12 format....
*
*/
public class SSLContextFactory {

public static SSLContext createSSLContext(ConnectionCredential cred) throws GeneralSecurityException, IOException {
return createSSLContext(cred.getKeyStore(), cred.getKeyPasswd(), cred.getKeyStoreType());
}

public static SSLContext createSSLContext(InputStream keyStoreStream, String keyStreamPasswd, KeyStoreType type)
throws GeneralSecurityException, IOException {
// Could Proxy KeyManagers to include only those with a specific alias for multi-cert file....
KeyManager[] keyManagers = getKeyManagers(keyStoreStream, keyStreamPasswd, type.name());
// note: may want to broaden this to SSLv3, SSLv2, SSL, etc...
SSLContext context = SSLContext.getInstance("TLS");
// use default TrustManager and SecureRandom
context.init(keyManagers, null, null);
return context;
}

private static KeyManager[] getKeyManagers(InputStream keyStoreStream, String keyStreamPasswd, String type)
throws IOException, GeneralSecurityException {

KeyStore ks = KeyStore.getInstance(type);
ks.load(keyStoreStream, keyStreamPasswd.toCharArray());
keyStoreStream.close();

String alg = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmFact = KeyManagerFactory.getInstance(alg);
kmFact.init(ks, keyStreamPasswd.toCharArray());

return kmFact.getKeyManagers();
}

}