Skip to content

Commit

Permalink
added Service Fabric Certificate Auth support
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelenglert committed Mar 23, 2018
1 parent 3a8271a commit b284181
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/target
/.idea
*.iml
src/test/resources/conf/integration-*-config.yml
src/test/resources/conf/integration-*-config.yml
src/test/resources/cert/integration-*.pfx
4 changes: 4 additions & 0 deletions CHANGES.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### Version 1.1.9.3 (Beta)

* Added Service Fabric Certificate Authentication

### Version 1.1.9.2 (Beta)

* Added Azure Key Vault Support
Expand Down
9 changes: 9 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ To achieve this the following configuration in `config.yml` is required:
```
The **Key Vault Client Key** can also be encrypted just as the normal **Client Key**.

## Service Fabric Authentication

Currently the Extension support Certificate based Authentication to gather the Health Status of your Service Fabric Clusters. To use this those properties in `config.yml` have to be used:

```
serviceFabricCert: 'monitors/AzureMonitor/your-cert.pfx'
serviceFabricPassphrase: ''
```

## Password Encryption Support

To avoid setting the clear text password in the config.yml. Please follow the process to encrypt the password and set the encrypted password and the key in the config.yml
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.appdynamics.monitors</groupId>
<artifactId>azure-monitoring-extension</artifactId>
<version>1.1.9.2</version>
<version>1.1.9.3</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
import com.microsoft.aad.adal4j.AuthenticationResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.*;

class AzureRestOperation {
private static final Logger logger = LoggerFactory.getLogger(AzureRestOperation.class);
Expand Down Expand Up @@ -67,4 +65,47 @@ static JsonNode doPost(URL url, String body) {
return null;
}
}

static JsonNode doSecurePost(URL url, String body, String cert, String passphrase) {
JsonNode responseJson = null;
try {
KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream(cert);
ks.load(fis, passphrase.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // PKIX
tmf.init(ks);
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn)
.setSSLSocketFactory(sc.getSocketFactory());
((HttpsURLConnection)conn)
.setHostnameVerifier(allHostsValid);
}
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
OutputStream output = conn.getOutputStream();
output.write(body.getBytes("UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String response = "";
//noinspection StatementWithEmptyBody
for (String line; (line = br.readLine()) != null; response += line);
conn.disconnect();
ObjectMapper objectMapper = new ObjectMapper();
responseJson = objectMapper.readTree(response);
} catch (Exception e) {
logger.error("Error while processing POST on URL {} with Body {}", url, body, e);
}
return responseJson;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import java.util.Map;

class ServiceFabricTask implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(AzureMonitorTask.class);
private static final Logger logger = LoggerFactory.getLogger(ServiceFabricTask.class);
private final MonitorConfiguration configuration;
private final JsonNode node;
private final String metric;
Expand All @@ -41,16 +41,21 @@ public void run() {
}

private void runTask() throws IOException {
String serviceFabricBody = configuration.getConfigYml().get(Globals.serviceFabricBody).toString();
String serviceFabricCert = configuration.getConfigYml().get(Globals.serviceFabricCert).toString();
String serviceFabricPassphrase = configuration.getConfigYml().get(Globals.serviceFabricPassphrase).toString();

if (logger.isDebugEnabled()) {logger.debug("JSON Node: " + Utilities.prettifyJson(node));}
URL url = new URL(node.get("properties").get("managementEndpoint").asText() + Globals.serviceFabricGetClusterHealthChunk +
"?" + Globals.azureApiVersion + "=" + configuration.getConfigYml().get(Globals.serviceFabricApiVersion));
if (logger.isDebugEnabled()) {logger.debug("Get Metrics REST API Request: " + url.toString());}
if (url.toString().matches("https://.*")){
logger.info("Skipping Service Fabric Cluster {} because the Authentication Method is currently not supported",
node.get("properties").get("managementEndpoint").asText());
if (url.toString().matches("https://.*") && !serviceFabricCert.isEmpty()){
//logger.info("Skipping Service Fabric Cluster {} because the Authentication Method is currently not supported",
// node.get("properties").get("managementEndpoint").asText());
extractMetrics(AzureRestOperation.doSecurePost(url, serviceFabricBody, serviceFabricCert, serviceFabricPassphrase));
}
else {
extractMetrics(AzureRestOperation.doPost(url, configuration.getConfigYml().get(Globals.serviceFabricBody).toString()));
extractMetrics(AzureRestOperation.doPost(url, serviceFabricBody));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class Globals {
public static final int timeOffset = -2;
public static final String serviceFabricGetClusterHealthChunk = "/$/GetClusterHealthChunk";
public static final String serviceFabricBody = "serviceFabricBody";
public static final String serviceFabricCert = "serviceFabricCert";
public static final String serviceFabricPassphrase = "serviceFabricPassphrase";
public static final String serviceFabricApiVersion = "serviceFabricApiVersion";
public static final String serviceFabricResourceApiVersion = "serviceFabricResourceApiVersion";
public static final String serviceFabricHealthStates = "serviceFabricHealthStates";
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/conf/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ serviceFabricApiVersion: "3.0"
serviceFabricResourceApiVersion: "2016-09-01"
serviceFabricBody: '{"ApplicationFilters":[{"HealthStateFilter":65535}],"NodeFilters":[{"HealthStateFilter":65535}]}'

# Certificate Authentication will be used if the Service Fabric Management Endpoint is https://...
serviceFabricCert: 'monitors/AzureMonitor/your-cert.pfx'
serviceFabricPassphrase: ''

# Service Fabric Health States. These States will be translated to numbers according to the table below
# The Defaults are derived from here https://docs.microsoft.com/en-us/rest/api/servicefabric/sfclient-model-healthinformation
serviceFabricHealthStates:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileReader;
import java.io.*;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
Expand Down

0 comments on commit b284181

Please sign in to comment.