Merge pull request #25 from Shabirmean/master

[MERGED from Shabir] Added SCEP Implementation for VirtualFireAlarm Sample with end to end encryption
application-manager-new
Shabir Mohamed 9 years ago
commit 66e4d99b57

@ -51,7 +51,15 @@
</context-param>
<context-param>
<param-name>managed-api-context</param-name>
<param-value>/firealarm</param-value>
<param-value>/firealarm</param-value>
</context-param>
<context-param>
<param-name>managed-api-context-template</param-name>
<param-value>/firealarm/{version}</param-value>
</context-param>
<context-param>
<param-name>managed-api-application</param-name>
<param-value>firealarm</param-value>
</context-param>
<context-param>
<param-name>managed-api-isSecured</param-name>

@ -36,6 +36,12 @@
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.analytics</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@ -185,11 +191,13 @@
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smack</artifactId>
<version>${smack.wso2.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smackx</artifactId>
<version>${smackx.wso2.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

@ -16,25 +16,15 @@
package org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.wso2.carbon.certificate.mgt.core.dto.SCEPResponse;
import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException;
import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException;
import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.iot.common.DeviceController;
import org.wso2.carbon.device.mgt.iot.common.DeviceManagement;
import org.wso2.carbon.device.mgt.iot.common.DeviceValidator;
import org.wso2.carbon.device.mgt.iot.common.apimgt.AccessTokenInfo;
@ -50,11 +40,12 @@ import org.wso2.carbon.device.mgt.iot.common.util.ZipArchive;
import org.wso2.carbon.device.mgt.iot.common.util.ZipUtil;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.dto.DeviceJSON;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception.VirtualFireAlarmEnrollmentException;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.ContentType;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.transport.VirtualFireAlarmMQTTSubscriber;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.transport.VirtualFireAlarmXMPPConnector;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VerificationManager;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.scep.ContentType;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.scep.SCEPOperation;
import javax.servlet.http.HttpServletRequest;
@ -63,7 +54,6 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
@ -73,15 +63,7 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@ -90,10 +72,8 @@ import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
//@Path("/VirtualFireAlarmDeviceManager")
public class VirtualFireAlarmService {
private static Log log = LogFactory.getLog(VirtualFireAlarmService.class);
@ -104,15 +84,21 @@ public class VirtualFireAlarmService {
@Context //injected response proxy supporting multiple thread
private HttpServletResponse response;
private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
public static final String XMPP_PROTOCOL = "XMPP";
public static final String HTTP_PROTOCOL = "HTTP";
public static final String MQTT_PROTOCOL = "MQTT";
private static VirtualFireAlarmMQTTSubscriber virtualFireAlarmMQTTSubscriber;
private static VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector;
private static ConcurrentHashMap<String, String> deviceToIpMap =
new ConcurrentHashMap<String, String>();
private VerificationManager verificationManager;
private VirtualFireAlarmMQTTSubscriber virtualFireAlarmMQTTSubscriber;
private VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector;
private ConcurrentHashMap<String, String> deviceToIpMap = new ConcurrentHashMap<>();
public void setVerificationManager(
VerificationManager verificationManager) {
this.verificationManager = verificationManager;
verificationManager.initVerificationManager();
}
public void setVirtualFireAlarmXMPPConnector(
final VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector) {
@ -148,6 +134,10 @@ public class VirtualFireAlarmService {
xmppStarterThread.start();
}
public VerificationManager getVerificationManager() {
return verificationManager;
}
public VirtualFireAlarmXMPPConnector getVirtualFireAlarmXMPPConnector() {
return virtualFireAlarmXMPPConnector;
}
@ -308,7 +298,7 @@ public class VirtualFireAlarmService {
List<Device> userDevices =
deviceManagement.getDeviceManagementService().getDevicesOfUser(
username);
ArrayList<Device> userDevicesforFirealarm = new ArrayList<Device>();
ArrayList<Device> userDevicesforFirealarm = new ArrayList<>();
for (Device device : userDevices) {
if (device.getType().equals(VirtualFireAlarmConstants.DEVICE_TYPE) &&
@ -336,9 +326,8 @@ public class VirtualFireAlarmService {
@QueryParam("deviceName") String customDeviceName,
@PathParam("sketch_type") String sketchType) {
//TODO:: null check customDeviceName at UI level
ZipArchive zipFile = null;
try {
zipFile = createDownloadFile(owner, customDeviceName, sketchType);
ZipArchive zipFile = createDownloadFile(owner, customDeviceName, sketchType);
Response.ResponseBuilder rb = Response.ok(zipFile.getZipFile());
rb.header("Content-Disposition",
"attachment; filename=\"" + zipFile.getFileName() + "\"");
@ -361,9 +350,8 @@ public class VirtualFireAlarmService {
@QueryParam("deviceName") String customDeviceName,
@PathParam("sketch_type") String sketchType) {
ZipArchive zipFile = null;
try {
zipFile = createDownloadFile(owner, customDeviceName, sketchType);
ZipArchive zipFile = createDownloadFile(owner, customDeviceName, sketchType);
Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId());
return rb.build();
} catch (IllegalArgumentException ex) {
@ -388,8 +376,7 @@ public class VirtualFireAlarmService {
String deviceId = shortUUID();
TokenClient accessTokenClient = new TokenClient(VirtualFireAlarmConstants.DEVICE_TYPE);
AccessTokenInfo accessTokenInfo = null;
accessTokenInfo = accessTokenClient.getAccessToken(owner, deviceId);
AccessTokenInfo accessTokenInfo = accessTokenClient.getAccessToken(owner, deviceId);
//create token
String accessToken = accessTokenInfo.getAccess_token();
@ -431,8 +418,7 @@ public class VirtualFireAlarmService {
ZipUtil ziputil = new ZipUtil();
ZipArchive zipFile = null;
zipFile = ziputil.downloadSketch(owner, SUPER_TENANT, sketchType, deviceId, deviceName,
ZipArchive zipFile = ziputil.downloadSketch(owner, SUPER_TENANT, sketchType, deviceId, deviceName,
accessToken, refreshToken);
zipFile.setDeviceId(deviceId);
return zipFile;
@ -489,7 +475,8 @@ public class VirtualFireAlarmService {
try {
DeviceValidator deviceValidator = new DeviceValidator();
if (!deviceValidator.isExist(owner, SUPER_TENANT, new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE))) {
VirtualFireAlarmConstants
.DEVICE_TYPE))) {
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
return;
}
@ -525,24 +512,23 @@ public class VirtualFireAlarmService {
return;
}
sendCommandViaHTTP(deviceHTTPEndpoint, callUrlPattern, true);
VirtualFireAlarmServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint, callUrlPattern, true);
break;
case MQTT_PROTOCOL:
sendCommandViaMQTT(owner, deviceId,
VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", ""),
switchToState);
String mqttMessage = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", "");
VirtualFireAlarmServiceUtils.sendCommandViaMQTT(owner, deviceId, mqttMessage, switchToState);
break;
case XMPP_PROTOCOL:
sendCommandViaXMPP(owner, deviceId, VirtualFireAlarmConstants.BULB_CONTEXT,
switchToState);
VirtualFireAlarmServiceUtils.sendCommandViaXMPP(owner, deviceId,
VirtualFireAlarmConstants.BULB_CONTEXT,
switchToState, virtualFireAlarmXMPPConnector);
break;
default:
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
return;
}
} catch (DeviceManagementException e) {
log.error("Failed to send switch-bulb request to device [" + deviceId + "] via " +
protocolString);
log.error("Failed to send switch-bulb request to device [" + deviceId + "] via " + protocolString);
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
return;
}
@ -562,7 +548,8 @@ public class VirtualFireAlarmService {
DeviceValidator deviceValidator = new DeviceValidator();
try {
if (!deviceValidator.isExist(owner, SUPER_TENANT, new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE))) {
VirtualFireAlarmConstants
.DEVICE_TYPE))) {
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
return "Unauthorized Access";
}
@ -590,19 +577,20 @@ public class VirtualFireAlarmService {
return replyMsg;
}
replyMsg = sendCommandViaHTTP(deviceHTTPEndpoint,
VirtualFireAlarmConstants.SONAR_CONTEXT, false);
replyMsg = VirtualFireAlarmServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint,
VirtualFireAlarmConstants.SONAR_CONTEXT,
false);
break;
case MQTT_PROTOCOL:
sendCommandViaMQTT(owner, deviceId,
VirtualFireAlarmConstants.SONAR_CONTEXT.replace("/", ""),
"");
String mqttMessage = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", "");
VirtualFireAlarmServiceUtils.sendCommandViaMQTT(owner, deviceId, mqttMessage, "");
break;
case XMPP_PROTOCOL:
sendCommandViaXMPP(owner, deviceId, VirtualFireAlarmConstants.SONAR_CONTEXT,
"");
VirtualFireAlarmServiceUtils.sendCommandViaXMPP(owner, deviceId,
VirtualFireAlarmConstants.SONAR_CONTEXT, "",
virtualFireAlarmXMPPConnector);
break;
default:
@ -635,7 +623,8 @@ public class VirtualFireAlarmService {
DeviceValidator deviceValidator = new DeviceValidator();
try {
if (!deviceValidator.isExist(owner, SUPER_TENANT, new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE))) {
VirtualFireAlarmConstants
.DEVICE_TYPE))) {
response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode());
}
} catch (DeviceManagementException e) {
@ -657,39 +646,35 @@ public class VirtualFireAlarmService {
if (deviceHTTPEndpoint == null) {
response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode());
}
String tString = sendCommandViaHTTP(deviceHTTPEndpoint,
VirtualFireAlarmConstants
.TEMPERATURE_CONTEXT,
false);
String temperatureValue = tString;
String temperatureValue = VirtualFireAlarmServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint,
VirtualFireAlarmConstants.TEMPERATURE_CONTEXT,
false);
SensorDataManager.getInstance().setSensorRecord(deviceId,
VirtualFireAlarmConstants
.SENSOR_TEMPERATURE,
VirtualFireAlarmConstants.SENSOR_TEMPERATURE,
temperatureValue,
Calendar.getInstance()
.getTimeInMillis());
Calendar.getInstance().getTimeInMillis());
break;
case MQTT_PROTOCOL:
sendCommandViaMQTT(owner, deviceId,
VirtualFireAlarmConstants.TEMPERATURE_CONTEXT.replace("/",
""),
"");
String mqttMessage = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", "");
VirtualFireAlarmServiceUtils.sendCommandViaMQTT(owner, deviceId, mqttMessage, "");
break;
case XMPP_PROTOCOL:
sendCommandViaXMPP(owner, deviceId, VirtualFireAlarmConstants
.TEMPERATURE_CONTEXT, "");
VirtualFireAlarmServiceUtils.sendCommandViaXMPP(owner, deviceId,
VirtualFireAlarmConstants.TEMPERATURE_CONTEXT, "",
virtualFireAlarmXMPPConnector);
break;
default:
response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode());
}
sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId,
VirtualFireAlarmConstants.SENSOR_TEMPERATURE);
} catch (DeviceManagementException e) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
} catch (DeviceControllerException e) {
VirtualFireAlarmConstants
.SENSOR_TEMPERATURE);
} catch (DeviceManagementException | DeviceControllerException e) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
}
@ -702,7 +687,6 @@ public class VirtualFireAlarmService {
@Consumes(MediaType.APPLICATION_JSON)
public void pushTemperatureData(final DeviceJSON dataMsg,
@Context HttpServletResponse response) {
boolean result;
String deviceId = dataMsg.deviceId;
String deviceIp = dataMsg.reply;
float temperature = dataMsg.value;
@ -724,252 +708,20 @@ public class VirtualFireAlarmService {
}
SensorDataManager.getInstance().setSensorRecord(deviceId,
VirtualFireAlarmConstants
.SENSOR_TEMPERATURE,
.SENSOR_TEMPERATURE,
String.valueOf(temperature),
Calendar.getInstance().getTimeInMillis());
if (!publishToDAS(dataMsg.owner, dataMsg.deviceId, dataMsg.value)) {
if (!VirtualFireAlarmServiceUtils.publishToDAS(dataMsg.owner, dataMsg.deviceId, dataMsg.value)) {
response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
}
}
private String sendCommandViaHTTP(final String deviceHTTPEndpoint, String urlContext,
boolean fireAndForgot) throws DeviceManagementException {
String responseMsg = "";
String urlString = VirtualFireAlarmConstants.URL_PREFIX + deviceHTTPEndpoint + urlContext;
if (log.isDebugEnabled()) {
log.debug(urlString);
}
if (!fireAndForgot) {
HttpURLConnection httpConnection = getHttpConnection(urlString);
try {
httpConnection.setRequestMethod(HttpMethod.GET);
} catch (ProtocolException e) {
String errorMsg =
"Protocol specific error occurred when trying to set method to GET" +
" for:" + urlString;
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
responseMsg = readResponseFromGetRequest(httpConnection);
} else {
CloseableHttpAsyncClient httpclient = null;
try {
httpclient = HttpAsyncClients.createDefault();
httpclient.start();
HttpGet request = new HttpGet(urlString);
final CountDownLatch latch = new CountDownLatch(1);
Future<HttpResponse> future = httpclient.execute(
request, new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse httpResponse) {
latch.countDown();
}
@Override
public void failed(Exception e) {
latch.countDown();
}
@Override
public void cancelled() {
latch.countDown();
}
});
latch.await();
} catch (InterruptedException e) {
if (log.isDebugEnabled()) {
log.debug("Sync Interrupted");
}
} finally {
try {
if (httpclient != null) {
httpclient.close();
}
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug("Failed on close");
}
}
}
}
return responseMsg;
}
private boolean sendCommandViaMQTT(String deviceOwner, String deviceId, String resource,
String state) throws DeviceManagementException {
boolean result = false;
DeviceController deviceController = new DeviceController();
try {
result = deviceController.publishMqttControl(deviceOwner,
VirtualFireAlarmConstants.DEVICE_TYPE,
deviceId, resource, state);
} catch (DeviceControllerException e) {
String errorMsg = "Error whilst trying to publish to MQTT Queue";
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
return result;
}
private void sendCommandViaXMPP(String deviceOwner, String deviceId, String resource,
String state) throws DeviceManagementException {
String xmppServerDomain = XmppConfig.getInstance().getXmppEndpoint();
int indexOfChar = xmppServerDomain.lastIndexOf(File.separator);
if (indexOfChar != -1) {
xmppServerDomain = xmppServerDomain.substring((indexOfChar + 1),
xmppServerDomain.length());
}
indexOfChar = xmppServerDomain.indexOf(":");
if (indexOfChar != -1) {
xmppServerDomain = xmppServerDomain.substring(0, indexOfChar);
}
String clientToConnect = deviceId + "@" + xmppServerDomain + File.separator + deviceOwner;
String message = resource.replace("/", "") + ":" + state;
virtualFireAlarmXMPPConnector.sendXMPPMessage(clientToConnect, message, "CONTROL-REQUEST");
}
/* ---------------------------------------------------------------------------------------
Utility methods relevant to creating and sending http requests
--------------------------------------------------------------------------------------- */
/* This methods creates and returns a http connection object */
private HttpURLConnection getHttpConnection(String urlString) throws
DeviceManagementException {
URL connectionUrl = null;
HttpURLConnection httpConnection = null;
try {
connectionUrl = new URL(urlString);
httpConnection = (HttpURLConnection) connectionUrl.openConnection();
} catch (MalformedURLException e) {
String errorMsg =
"Error occured whilst trying to form HTTP-URL from string: " + urlString;
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
} catch (IOException e) {
String errorMsg = "Error occured whilst trying to open a connection to: " +
connectionUrl.toString();
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
return httpConnection;
}
/* This methods reads and returns the response from the connection */
private String readResponseFromGetRequest(HttpURLConnection httpConnection)
throws DeviceManagementException {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(
httpConnection.getInputStream()));
} catch (IOException e) {
String errorMsg =
"There is an issue with connecting the reader to the input stream at: " +
httpConnection.getURL();
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
String responseLine;
StringBuffer completeResponse = new StringBuffer();
try {
while ((responseLine = bufferedReader.readLine()) != null) {
completeResponse.append(responseLine);
}
} catch (IOException e) {
String errorMsg =
"Error occured whilst trying read from the connection stream at: " +
httpConnection.getURL();
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
try {
bufferedReader.close();
} catch (IOException e) {
log.error(
"Could not succesfully close the bufferedReader to the connection at: " +
httpConnection.getURL());
}
return completeResponse.toString();
}
public static boolean publishToDAS(String owner, String deviceId, float temperature) {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
ctx.setTenantDomain(SUPER_TENANT, true);
DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService(
DeviceAnalyticsService.class, null);
Object metdaData[] = {owner, VirtualFireAlarmConstants.DEVICE_TYPE, deviceId,
System.currentTimeMillis()};
Object payloadData[] = {temperature};
try {
deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData,
new Object[0], payloadData);
} catch (DataPublisherConfigurationException e) {
return false;
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
return true;
}
// @GET
// @Path("/enrol")
// public Response scepRequest(String certificateSignRequest) {
//
// Base64 base64Encoder = new Base64();
// String signedCertEncodedString = "";
//
//
// CertificateManagementService certificateManagementService = null;
// try {
// certificateManagementService = VirtualFireAlarmServiceUtils.getCertificateManagementService();
// X509Certificate signedCeritficate = certificateManagementService.getSignedCertificateFromCSR(certificateSignRequest);
// signedCertEncodedString = base64Encoder.encodeAsString(signedCeritficate.getEncoded());
// } catch (VirtualFireAlarmEnrollmentException e) {
// e.printStackTrace();
// } catch (KeystoreException e) {
// e.printStackTrace();
// } catch (CertificateEncodingException e) {
// e.printStackTrace();
// }
//
//
// Response.ResponseBuilder responseBuilder = Response.ok(signedCertEncodedString, ContentType.X_X509_CA_CERT);;
// return responseBuilder.build();
// }
@GET
@Path("/scep")
public Response scepRequest(@QueryParam("operation") String operation) {
@Path("controller/scep")
public Response scepRequest(@QueryParam("operation") String operation, @QueryParam("message") String message) {
if (log.isDebugEnabled()) {
log.debug("Invoking SCEP operation " + operation);
@ -1016,11 +768,8 @@ public class VirtualFireAlarmService {
break;
}
return responseBuilder.build();
} catch (VirtualFireAlarmEnrollmentException e) {
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the iOS device", e);
} catch (KeystoreException e) {
log.error("Keystore error occurred while enrolling the iOS device", e);
@ -1038,8 +787,9 @@ public class VirtualFireAlarmService {
byte caCaps[] = certificateManagementService.getCACapsSCEP();
return Response.ok(caCaps, MediaType.TEXT_PLAIN).build();
} catch (VirtualFireAlarmEnrollmentException e) {
log.error("Error occurred while enrolling the iOS device", e);
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the device", e);
}
} else {
@ -1050,10 +800,8 @@ public class VirtualFireAlarmService {
}
@POST
@Consumes({ContentType.X_PKI_MESSAGE})
@Path("/scep")
public Response scepRequestPost(@QueryParam("operation") String operation,
InputStream inputStream) {
@Path("controller/scep")
public Response scepRequestPost(@QueryParam("operation") String operation, InputStream inputStream) {
if (log.isDebugEnabled()) {
log.debug("Invoking SCEP operation " + operation);
@ -1071,14 +819,13 @@ public class VirtualFireAlarmService {
byte pkiMessage[] = certificateManagementService.getPKIMessageSCEP(inputStream);
return Response.ok(pkiMessage, ContentType.X_PKI_MESSAGE).build();
} catch (VirtualFireAlarmEnrollmentException e) {
log.error("Error occurred while enrolling the iOS device", e);
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the device", e);
} catch (KeystoreException e) {
log.error("Keystore error occurred while enrolling the iOS device", e);
log.error("Keystore error occurred while enrolling the device", e);
}
}
return Response.serverError().build();
}
}

@ -1,13 +1,13 @@
package org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception;
public class VirtualFireAlarmEnrollmentException extends Exception {
public class VirtualFireAlarmException extends Exception {
private static final long serialVersionUID = 118512086957330189L;
public VirtualFireAlarmEnrollmentException(String errorMessage) {
public VirtualFireAlarmException(String errorMessage) {
super(errorMessage);
}
public VirtualFireAlarmEnrollmentException(String errorMessage, Throwable throwable) {
public VirtualFireAlarmException(String errorMessage, Throwable throwable) {
super(errorMessage, throwable);
}
}

@ -8,103 +8,129 @@ import org.wso2.carbon.device.mgt.iot.common.controlqueue.mqtt.MqttConfig;
import org.wso2.carbon.device.mgt.iot.common.controlqueue.mqtt.MqttSubscriber;
import org.wso2.carbon.device.mgt.iot.common.sensormgt.SensorDataManager;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.VirtualFireAlarmService;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VerificationManager;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Calendar;
import java.util.UUID;
public class VirtualFireAlarmMQTTSubscriber extends MqttSubscriber {
private static Log log = LogFactory.getLog(VirtualFireAlarmMQTTSubscriber.class);
private static final String subscribeTopic =
"wso2" + File.separator + "iot" + File.separator + "+" + File.separator +
VirtualFireAlarmConstants.DEVICE_TYPE + File.separator + "+" + File.separator +
"publisher";
private static final String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5);
private static String mqttEndpoint;
private VirtualFireAlarmMQTTSubscriber() {
super(iotServerSubscriber, VirtualFireAlarmConstants.DEVICE_TYPE,
MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic);
}
public void initConnector() {
mqttEndpoint = MqttConfig.getInstance().getMqttQueueEndpoint();
}
public void connectAndSubscribe() {
try {
super.connectAndSubscribe();
} catch (DeviceManagementException e) {
log.error("Subscription to MQTT Broker at: " + mqttEndpoint + " failed");
retryMQTTSubscription();
}
}
@Override
protected void postMessageArrived(String topic, MqttMessage message) {
String ownerAndId = topic.replace("wso2" + File.separator + "iot" + File.separator, "");
ownerAndId = ownerAndId.replace(File.separator + VirtualFireAlarmConstants.DEVICE_TYPE + File.separator, ":");
ownerAndId = ownerAndId.replace(File.separator + "publisher", "");
String owner = ownerAndId.split(":")[0];
String deviceId = ownerAndId.split(":")[1];
log.info("Received MQTT message for: {OWNER-" + owner + "} & {DEVICE.ID-" + deviceId + "}");
if (message.toString().contains("PUBLISHER")) {
log.info("MQTT: Publisher Message [" + message.toString() + "] topic: [" + topic + "]");
float temperature = Float.parseFloat(message.toString().split(":")[2]);
if(!VirtualFireAlarmService.publishToDAS(owner, deviceId, temperature)) {
log.error("MQTT Subscriber: Publishing data to DAS failed.");
}
if(log.isDebugEnabled()) {
log.debug("MQTT Subscriber: Published data to DAS successfully.");
}
} else if (message.toString().contains("TEMPERATURE")) {
log.info("MQTT: Reply Message [" + message.toString() + "] topic: [" + topic + "]");
String temperatureValue = message.toString().split(":")[1];
SensorDataManager.getInstance().setSensorRecord(deviceId, VirtualFireAlarmConstants.SENSOR_TEMPERATURE, temperatureValue, Calendar.getInstance().getTimeInMillis());
} else {
log.info("MQTT: Message [" + message.toString() + "] topic: [" + topic + "]");
private static Log log = LogFactory.getLog(VirtualFireAlarmMQTTSubscriber.class);
private static final String subscribeTopic =
"wso22" + File.separator + "iot" + File.separator + "+" + File.separator +
VirtualFireAlarmConstants.DEVICE_TYPE + File.separator + "+" + File.separator +
"publisher";
private static final String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5);
private static String mqttEndpoint;
private VirtualFireAlarmMQTTSubscriber() {
super(iotServerSubscriber, VirtualFireAlarmConstants.DEVICE_TYPE,
MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic);
}
public void initConnector() {
mqttEndpoint = MqttConfig.getInstance().getMqttQueueEndpoint();
}
public void connectAndSubscribe() {
try {
super.connectAndSubscribe();
} catch (DeviceManagementException e) {
log.error("Subscription to MQTT Broker at: " + mqttEndpoint + " failed");
retryMQTTSubscription();
}
}
private void retryMQTTSubscription() {
Thread retryToSubscribe = new Thread() {
@Override
public void run() {
while (true) {
if (!isConnected()) {
if (log.isDebugEnabled()) {
log.debug("Subscriber re-trying to reach MQTT queue....");
}
try {
VirtualFireAlarmMQTTSubscriber.super.connectAndSubscribe();
} catch (DeviceManagementException e1) {
if (log.isDebugEnabled()) {
log.debug("Attempt to re-connect to MQTT-Queue failed");
}
}
} else {
break;
}
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
log.error("MQTT: Thread S;eep Interrupt Exception");
}
}
}
};
retryToSubscribe.setDaemon(true);
retryToSubscribe.start();
}
@Override
protected void postMessageArrived(String topic, MqttMessage mqttMessage) {
String ownerAndId = topic.replace("wso2" + File.separator + "iot" + File.separator, "");
ownerAndId = ownerAndId.replace(File.separator + VirtualFireAlarmConstants.DEVICE_TYPE + File.separator, ":");
ownerAndId = ownerAndId.replace(File.separator + "publisher", "");
String owner = ownerAndId.split(":")[0];
String deviceId = ownerAndId.split(":")[1];
if (log.isDebugEnabled()) {
log.debug("Received MQTT message for: {OWNER-" + owner + "} & {DEVICE.ID-" + deviceId + "}");
}
String actualMessage = "";
try {
PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
PrivateKey serverPrivateKey = VerificationManager.getServerPrivateKey();
actualMessage = VirtualFireAlarmServiceUtils.extractMessageFromPayload(mqttMessage.toString(),
serverPrivateKey, clientPublicKey);
if (log.isDebugEnabled()) {
log.debug("MQTT: Received Message [" + actualMessage + "] topic: [" + topic + "]");
}
if (actualMessage.contains("PUBLISHER")) {
float temperature = Float.parseFloat(actualMessage.split(":")[2]);
if (!VirtualFireAlarmServiceUtils.publishToDAS(owner, deviceId, temperature)) {
log.error("MQTT Subscriber: Publishing data to DAS failed.");
}
if (log.isDebugEnabled()) {
log.debug("MQTT Subscriber: Published data to DAS successfully.");
}
} else if (actualMessage.contains("TEMPERATURE")) {
String temperatureValue = actualMessage.split(":")[1];
SensorDataManager.getInstance().setSensorRecord(deviceId, VirtualFireAlarmConstants.SENSOR_TEMPERATURE,
temperatureValue,
Calendar.getInstance().getTimeInMillis());
} else {
if (log.isDebugEnabled()) {
log.debug("MQTT: Random Message [" + actualMessage + "] topic: [" + topic + "]");
}
}
} catch (VirtualFireAlarmException e) {
String errorMsg =
"CertificateManagementService failure oo Signature-Verification/Decryption was unsuccessful.";
log.error(errorMsg, e);
}
}
private void retryMQTTSubscription() {
Thread retryToSubscribe = new Thread() {
@Override
public void run() {
while (true) {
if (!isConnected()) {
if (log.isDebugEnabled()) {
log.debug("Subscriber re-trying to reach MQTT queue....");
}
try {
VirtualFireAlarmMQTTSubscriber.super.connectAndSubscribe();
} catch (DeviceManagementException e1) {
if (log.isDebugEnabled()) {
log.debug("Attempt to re-connect to MQTT-Queue failed");
}
}
} else {
break;
}
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
log.error("MQTT: Thread S;eep Interrupt Exception");
}
}
}
};
retryToSubscribe.setDaemon(true);
retryToSubscribe.start();
}
}

@ -9,7 +9,7 @@ import org.wso2.carbon.device.mgt.iot.common.controlqueue.xmpp.XmppConnector;
import org.wso2.carbon.device.mgt.iot.common.sensormgt.SensorDataManager;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.plugin.constants
.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.VirtualFireAlarmService;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import java.util.Calendar;
@ -62,7 +62,7 @@ public class VirtualFireAlarmXMPPConnector extends XmppConnector {
log.info("XMPP: Publisher Message [" + message + "] from [" + from + "]");
float temperature = Float.parseFloat(message.split(":")[1]);
if(!VirtualFireAlarmService.publishToDAS(owner, deviceId, temperature)) {
if(!VirtualFireAlarmServiceUtils.publishToDAS(owner, deviceId, temperature)) {
log.error("XMPP Connector: Publishing data to DAS failed.");
}

@ -0,0 +1,236 @@
package org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException;
import org.wso2.carbon.certificate.mgt.core.util.ConfigurationUtil;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception.VirtualFireAlarmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
public class VerificationManager {
private static final Log log = LogFactory.getLog(VerificationManager.class);
private static PrivateKey serverPrivateKey;
private static final String SIGNATURE_ALG = "SHA1withRSA";
private static final String CIPHER_PADDING = "RSA/ECB/PKCS1Padding";
private VerificationManager() {
}
public void initVerificationManager() {
serverPrivateKey = retrievePrivateKey(ConfigurationUtil.CA_CERT_ALIAS,
ConfigurationUtil.KEYSTORE_CA_CERT_PRIV_PASSWORD);
}
public static PrivateKey retrievePrivateKey(String alias, String password){
PrivateKey privateKey = null;
InputStream inputStream = null;
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(ConfigurationUtil.getConfigEntry(ConfigurationUtil.CERTIFICATE_KEYSTORE));
inputStream = new FileInputStream(ConfigurationUtil.getConfigEntry(
ConfigurationUtil.PATH_CERTIFICATE_KEYSTORE));
keyStore.load(inputStream, ConfigurationUtil.getConfigEntry(ConfigurationUtil.CERTIFICATE_KEYSTORE_PASSWORD)
.toCharArray());
privateKey = (PrivateKey) (keyStore.getKey(ConfigurationUtil.getConfigEntry(alias),
ConfigurationUtil.getConfigEntry(password).toCharArray()));
} catch (KeyStoreException e) {
String errorMsg = "Could not load KeyStore of given type in [certificate-config.xml] file." ;
log.error(errorMsg, e);
} catch (FileNotFoundException e) {
String errorMsg = "KeyStore file could not be loaded from path given in [certificate-config.xml] file.";
log.error(errorMsg, e);
} catch (NoSuchAlgorithmException e) {
String errorMsg = "Algorithm not found when loading KeyStore";
log.error(errorMsg, e);
} catch (CertificateException e) {
String errorMsg = "CertificateException when loading KeyStore";
log.error(errorMsg, e);
} catch (IOException e) {
String errorMsg = "Input output issue occurred when loading KeyStore";
log.error(errorMsg, e);
} catch (KeystoreException e) {
String errorMsg = "An error occurred whilst trying load Configs for KeyStoreReader";
log.error(errorMsg, e);
} catch (UnrecoverableKeyException e) {
String errorMsg = "Key is unrecoverable when retrieving CA private key";
log.error(errorMsg, e);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
log.error("Error closing KeyStore input stream", e);
}
}
return privateKey;
}
public static PrivateKey getServerPrivateKey() {
return serverPrivateKey;
}
public static String encryptMessage(String message, Key encryptionKey) throws VirtualFireAlarmException {
Cipher encrypter;
byte[] cipherData;
try {
encrypter = Cipher.getInstance(CIPHER_PADDING);
encrypter.init(Cipher.ENCRYPT_MODE, encryptionKey);
cipherData = encrypter.doFinal(message.getBytes(StandardCharsets.UTF_8));
} catch (NoSuchAlgorithmException e) {
String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (NoSuchPaddingException e) {
String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (InvalidKeyException e) {
String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + encryptionKey + "\n]\n";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (BadPaddingException e) {
String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (IllegalBlockSizeException e) {
String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
}
return Base64.encodeBase64String(cipherData);
}
public static String signMessage(String encryptedData, PrivateKey signatureKey) throws VirtualFireAlarmException {
Signature signature;
String signedEncodedString;
try {
signature = Signature.getInstance(SIGNATURE_ALG);
signature.initSign(signatureKey);
signature.update(Base64.decodeBase64(encryptedData));
byte[] signatureBytes = signature.sign();
signedEncodedString = Base64.encodeBase64String(signatureBytes);
} catch (NoSuchAlgorithmException e) {
String errorMsg = "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (SignatureException e) {
String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (InvalidKeyException e) {
String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + signatureKey + "\n]\n";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
}
return signedEncodedString;
}
public static boolean verifySignature(String data, String signedData, PublicKey verificationKey)
throws VirtualFireAlarmException {
Signature signature;
boolean verified;
try {
signature = Signature.getInstance(SIGNATURE_ALG);
signature.initVerify(verificationKey);
signature.update(Base64.decodeBase64(data));
verified = signature.verify(Base64.decodeBase64(signedData));
} catch (NoSuchAlgorithmException e) {
String errorMsg = "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (SignatureException e) {
String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (InvalidKeyException e) {
String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + verificationKey + "\n]\n";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
}
return verified;
}
public static String decryptMessage(String encryptedMessage, Key decryptKey) throws VirtualFireAlarmException {
Cipher decrypter;
String decryptedMessage;
try {
decrypter = Cipher.getInstance(CIPHER_PADDING);
decrypter.init(Cipher.DECRYPT_MODE, decryptKey);
decryptedMessage = new String(decrypter.doFinal(Base64.decodeBase64(encryptedMessage)), StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException e) {
String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (NoSuchPaddingException e) {
String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (InvalidKeyException e) {
String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + decryptKey + "\n]\n";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (BadPaddingException e) {
String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (IllegalBlockSizeException e) {
String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
}
return decryptedMessage;
}
}

@ -2,16 +2,52 @@ package org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.uti
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.json.JSONObject;
import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException;
import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception
.VirtualFireAlarmEnrollmentException;
import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException;
import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.iot.common.DeviceController;
import org.wso2.carbon.device.mgt.iot.common.controlqueue.xmpp.XmppConfig;
import org.wso2.carbon.device.mgt.iot.common.exception.DeviceControllerException;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.transport.VirtualFireAlarmXMPPConnector;
import javax.ws.rs.HttpMethod;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
public class VirtualFireAlarmServiceUtils {
private static final Log log = LogFactory.getLog(VirtualFireAlarmServiceUtils.class);
//TODO; replace this tenant domain
private static final String SUPER_TENANT = "carbon.super";
private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature";
private static final String JSON_MESSAGE_KEY = "Msg";
private static final String JSON_SIGNATURE_KEY = "Sig";
public static CertificateManagementService getCertificateManagementService() throws
VirtualFireAlarmEnrollmentException {
VirtualFireAlarmException {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
CertificateManagementService certificateManagementService = (CertificateManagementService)
@ -20,10 +56,284 @@ public class VirtualFireAlarmServiceUtils {
if (certificateManagementService == null) {
String msg = "EnrollmentService is not initialized";
log.error(msg);
throw new VirtualFireAlarmEnrollmentException(msg);
throw new VirtualFireAlarmException(msg);
}
return certificateManagementService;
}
public static String sendCommandViaHTTP(final String deviceHTTPEndpoint, String urlContext,
boolean fireAndForgot) throws DeviceManagementException {
String responseMsg = "";
String urlString = VirtualFireAlarmConstants.URL_PREFIX + deviceHTTPEndpoint + urlContext;
if (log.isDebugEnabled()) {
log.debug(urlString);
}
if (!fireAndForgot) {
HttpURLConnection httpConnection = getHttpConnection(urlString);
try {
httpConnection.setRequestMethod(HttpMethod.GET);
} catch (ProtocolException e) {
String errorMsg =
"Protocol specific error occurred when trying to set method to GET" +
" for:" + urlString;
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
responseMsg = readResponseFromGetRequest(httpConnection);
} else {
CloseableHttpAsyncClient httpclient = null;
try {
httpclient = HttpAsyncClients.createDefault();
httpclient.start();
HttpGet request = new HttpGet(urlString);
final CountDownLatch latch = new CountDownLatch(1);
Future<HttpResponse> future = httpclient.execute(
request, new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse httpResponse) {
latch.countDown();
}
@Override
public void failed(Exception e) {
latch.countDown();
}
@Override
public void cancelled() {
latch.countDown();
}
});
latch.await();
} catch (InterruptedException e) {
if (log.isDebugEnabled()) {
log.debug("Sync Interrupted");
}
} finally {
try {
if (httpclient != null) {
httpclient.close();
}
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug("Failed on close");
}
}
}
}
return responseMsg;
}
public static boolean sendCommandViaMQTT(String deviceOwner, String deviceId, String resource,
String state) throws DeviceManagementException {
boolean result;
DeviceController deviceController = new DeviceController();
try {
PublicKey devicePublicKey = getDevicePublicKey(deviceId);
PrivateKey serverPrivateKey = VerificationManager.getServerPrivateKey();
String message = prepareSecurePayLoad(resource, devicePublicKey, serverPrivateKey);
result = deviceController.publishMqttControl(deviceOwner,
VirtualFireAlarmConstants.DEVICE_TYPE,
deviceId, message, state);
} catch (DeviceControllerException e) {
String errorMsg = "Error whilst trying to publish to MQTT Queue";
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
} catch (VirtualFireAlarmException e) {
throw new DeviceManagementException(e);
}
return result;
}
public static void sendCommandViaXMPP(String deviceOwner, String deviceId, String resource,
String state, VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector)
throws DeviceManagementException {
String xmppServerDomain = XmppConfig.getInstance().getXmppEndpoint();
int indexOfChar = xmppServerDomain.lastIndexOf(File.separator);
if (indexOfChar != -1) {
xmppServerDomain = xmppServerDomain.substring((indexOfChar + 1),
xmppServerDomain.length());
}
indexOfChar = xmppServerDomain.indexOf(":");
if (indexOfChar != -1) {
xmppServerDomain = xmppServerDomain.substring(0, indexOfChar);
}
String clientToConnect = deviceId + "@" + xmppServerDomain + File.separator + deviceOwner;
String message = resource.replace("/", "") + ":" + state;
virtualFireAlarmXMPPConnector.sendXMPPMessage(clientToConnect, message, "CONTROL-REQUEST");
}
/* ---------------------------------------------------------------------------------------
Utility methods relevant to creating and sending http requests
--------------------------------------------------------------------------------------- */
/* This methods creates and returns a http connection object */
public static HttpURLConnection getHttpConnection(String urlString) throws
DeviceManagementException {
URL connectionUrl = null;
HttpURLConnection httpConnection;
try {
connectionUrl = new URL(urlString);
httpConnection = (HttpURLConnection) connectionUrl.openConnection();
} catch (MalformedURLException e) {
String errorMsg =
"Error occured whilst trying to form HTTP-URL from string: " + urlString;
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
} catch (IOException e) {
String errorMsg = "Error occured whilst trying to open a connection to: " +
connectionUrl.toString();
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
return httpConnection;
}
/* This methods reads and returns the response from the connection */
public static String readResponseFromGetRequest(HttpURLConnection httpConnection)
throws DeviceManagementException {
BufferedReader bufferedReader;
try {
bufferedReader = new BufferedReader(new InputStreamReader(
httpConnection.getInputStream()));
} catch (IOException e) {
String errorMsg =
"There is an issue with connecting the reader to the input stream at: " +
httpConnection.getURL();
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
String responseLine;
StringBuilder completeResponse = new StringBuilder();
try {
while ((responseLine = bufferedReader.readLine()) != null) {
completeResponse.append(responseLine);
}
} catch (IOException e) {
String errorMsg =
"Error occured whilst trying read from the connection stream at: " +
httpConnection.getURL();
log.error(errorMsg);
throw new DeviceManagementException(errorMsg, e);
}
try {
bufferedReader.close();
} catch (IOException e) {
log.error(
"Could not succesfully close the bufferedReader to the connection at: " +
httpConnection.getURL());
}
return completeResponse.toString();
}
public static boolean publishToDAS(String owner, String deviceId, float temperature) {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
ctx.setTenantDomain(SUPER_TENANT, true);
DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService(
DeviceAnalyticsService.class, null);
Object metdaData[] = {owner, VirtualFireAlarmConstants.DEVICE_TYPE, deviceId,
System.currentTimeMillis()};
Object payloadData[] = {temperature};
try {
deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData,
new Object[0], payloadData);
} catch (DataPublisherConfigurationException e) {
return false;
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
return true;
}
public static String prepareSecurePayLoad(String message, Key encryptionKey, PrivateKey signatureKey)
throws VirtualFireAlarmException {
String encryptedMsg = VerificationManager.encryptMessage(message, encryptionKey);
String signedPayload = VerificationManager.signMessage(encryptedMsg, signatureKey);
JSONObject jsonPayload = new JSONObject();
jsonPayload.append(JSON_MESSAGE_KEY, encryptedMsg);
jsonPayload.append(JSON_SIGNATURE_KEY, signedPayload);
return jsonPayload.toString();
}
public static String extractMessageFromPayload(String message, Key decryptionKey, PublicKey verifySignatureKey)
throws VirtualFireAlarmException {
String actualMessage;
JSONObject jsonPayload = new JSONObject(message);
String encryptedMessage = jsonPayload.getString(JSON_MESSAGE_KEY);
String signedPayload = jsonPayload.getString(JSON_SIGNATURE_KEY);
if (VerificationManager.verifySignature(encryptedMessage, signedPayload, verifySignatureKey)) {
actualMessage = VerificationManager.decryptMessage(encryptedMessage, decryptionKey);
} else {
String errorMsg = "The message was not signed by a valid client. Could not verify signature on payload";
throw new VirtualFireAlarmException(errorMsg);
}
return actualMessage;
}
public static PublicKey getDevicePublicKey(String deviceId) throws VirtualFireAlarmException {
PublicKey clientPublicKey;
String alias = "";
try {
alias += deviceId.hashCode();
CertificateManagementService certificateManagementService =
VirtualFireAlarmServiceUtils.getCertificateManagementService();
X509Certificate clientCertificate = (X509Certificate) certificateManagementService.getCertificateByAlias(
alias);
clientPublicKey = clientCertificate.getPublicKey();
} catch (VirtualFireAlarmException e) {
String errorMsg = "Could not retrieve CertificateManagementService from the runtime.";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
} catch (KeystoreException e) {
String errorMsg = "An error occurred whilst trying to retrieve certificate for deviceId [" + deviceId +
"] with alias: [" + alias + "]";
log.error(errorMsg);
throw new VirtualFireAlarmException(errorMsg, e);
}
return clientPublicKey;
}
}

@ -40,6 +40,7 @@
<jaxrs:serviceBeans>
<bean id="VirtualFireAlarmService"
class="org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.VirtualFireAlarmService">
<property name="verificationManager" ref="verificationManagerBean"/>
<property name="virtualFireAlarmMQTTSubscriber" ref="mqttSubscriberBean"/>
<property name="virtualFireAlarmXMPPConnector" ref="xmppConnectorBean"/>
</bean>
@ -49,7 +50,9 @@
</jaxrs:providers>
</jaxrs:server>
<bean id="verificationManagerBean"
class="org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.util.VerificationManager">
</bean>
<bean id="mqttSubscriberBean"
class="org.wso2.carbon.device.mgt.iot.sample.virtual.firealarm.service.impl.transport.VirtualFireAlarmMQTTSubscriber">
</bean>

Loading…
Cancel
Save