Changes after testing with virtual firealarm and android sense

merge-requests/1/head
ayyoob 9 years ago
parent 5f43cc47e8
commit 16fb54d463

@ -140,6 +140,7 @@ public class RegisterActivity extends Activity {
});
if (registerStatus.isRegistered()) {
LocalRegistry.setEnrolled(getApplicationContext(), true);
LocalRegistry.addUsername(getApplicationContext(), username);
LocalRegistry.addDeviceId(getApplicationContext(), deviceId);
LocalRegistry.addMqttPort(getApplicationContext(), mqttPortNo);

@ -143,7 +143,7 @@ public class DataPublisherService extends Service {
}
SenseDataHolder.resetWordDataHolder();
//publish the data
if (events.size() > 0) {
if (events.size() > 0 && LocalRegistry.isEnrolled(context)) {
String user = LocalRegistry.getUsername(context);
String deviceId = LocalRegistry.getDeviceId(context);
JSONArray jsonArray = new JSONArray();

@ -176,7 +176,7 @@ public class ActivitySelectSensor extends AppCompatActivity
Intent activity = new Intent(getApplicationContext(), RegisterActivity.class);
startActivity(activity);
}
LocalRegistry.setEnrolled(getApplicationContext(), false);
LocalRegistry.removeUsername(getApplicationContext());
LocalRegistry.removeDeviceId(getApplicationContext());
LocalRegistry.removeServerURL(getApplicationContext());

@ -35,6 +35,7 @@ public class LocalRegistry {
private static final String ACCESS_TOKEN_KEY = "accessTokenKey";
private static final String REFRESH_TOKEN_KEY = "refreshTokenKey";
private static final String MQTT_PORT_KEY = "mqttPort";
private static final String IS_ENROLLED_KEY = "enrolled";
private static boolean exists = false;
private static String username;
private static String deviceId;
@ -43,6 +44,7 @@ public class LocalRegistry {
private static String accessToken;
private static String refreshToken;
private static int mqttPort;
private static boolean enrolled;
public static boolean isExist(Context context) {
if (!exists) {
@ -209,6 +211,22 @@ public class LocalRegistry {
return LocalRegistry.mqttPort;
}
public static void setEnrolled(Context context, boolean enrolled) {
SharedPreferences sharedpreferences = context.getSharedPreferences(SENSE_SHARED_PREFERENCES, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(IS_ENROLLED_KEY, enrolled);
editor.commit();
LocalRegistry.enrolled = enrolled;
}
public static boolean isEnrolled(Context context) {
if (!LocalRegistry.enrolled) {
SharedPreferences sharedpreferences = context.getSharedPreferences(SENSE_SHARED_PREFERENCES, Context.MODE_PRIVATE);
return LocalRegistry.enrolled = sharedpreferences.getBoolean(IS_ENROLLED_KEY, false);
}
return LocalRegistry.enrolled;
}
public static String getServerHost(Context context) {
URL url = null;

@ -27,13 +27,13 @@
android:id="@+id/username"
android:inputType="text"
android:maxLines="1" android:singleLine="true"
android:text="admin"/>
/>
<EditText android:id="@+id/password" android:layout_width="match_parent"
android:layout_height="wrap_content" android:hint="@string/prompt_password"
android:inputType="textPassword"
android:maxLines="1" android:singleLine="true"
android:text="admin"/>
/>
<EditText
android:layout_width="match_parent"

@ -19,13 +19,13 @@
<eventReceiver name="EventReceiver_AndroidSense" statistics="disable" trace="disable" xmlns="http://wso2.org/carbon/eventreceiver">
<from eventAdapterType="oauth-mqtt">
<property name="topic">wso2/android_sense/#</property>
<property name="topic">wso2/android_sense/+/data</property>
<property name="username">admin</property>
<property name="contentValidationParams">device_id_json_path:event.metaData.deviceId,device_id_topic_hierarchy_index:2</property>
<property name="contentValidation">default</property>
<property name="dcrUrl">https://localhost:9443/dynamic-client-web/register</property>
<property name="url">tcp://localhost:1883</property>
<property name="cleanSession">false</property>
<property name="cleanSession">true</property>
</from>
<mapping customMapping="disable" type="json"/>
<to streamName="org.wso2.iot.android.sense" version="1.0.0"/>

@ -46,9 +46,8 @@ public interface AndroidSenseControllerService {
*/
@Path("device/{deviceId}/words")
@POST
@Feature(code = "keywords", name = "Add Keywords", description = "Send keywords to the device",
type = "operation")
Response sendKeyWords(@PathParam("deviceId") String deviceId, @FormParam("keywords") String keywords);
@Feature(code = "keywords", name = "Add Keywords", description = "Send keywords to the device", type = "operation")
Response sendKeyWords(@PathParam("deviceId") String deviceId, @QueryParam("keywords") String keywords);
/**
* End point to send the key words to the device
@ -60,7 +59,7 @@ public interface AndroidSenseControllerService {
@POST
@Feature(code = "threshold", name = "Add a Threshold", description = "Set a threshold for word in the device",
type = "operation")
Response sendThreshold(@PathParam("deviceId") String deviceId, @FormParam("threshold") String threshold);
Response sendThreshold(@PathParam("deviceId") String deviceId, @QueryParam("threshold") String threshold);
@Path("device/{deviceId}/words")
@DELETE
@ -71,7 +70,6 @@ public interface AndroidSenseControllerService {
/**
* Retrieve Sensor data for the device type
*/
@Path("stats/{deviceId}/sensors/{sensorName}")
@GET
@Consumes("application/json")

@ -24,6 +24,8 @@ import org.wso2.carbon.analytics.dataservice.commons.SORT;
import org.wso2.carbon.analytics.dataservice.commons.SortByField;
import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.transport.AndroidSenseMQTTConnector;
import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.APIUtil;
import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.SensorRecord;
@ -57,9 +59,17 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController
@POST
public Response sendKeyWords(@PathParam("deviceId") String deviceId, @QueryParam("keywords") String keywords) {
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
AndroidSenseConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
androidSenseMQTTConnector.publishDeviceData(deviceId, "add", keywords);
return Response.ok().build();
} catch (TransportHandlerException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@ -68,9 +78,16 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController
@POST
public Response sendThreshold(@PathParam("deviceId") String deviceId, @QueryParam("threshold") String threshold) {
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
AndroidSenseConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
androidSenseMQTTConnector.publishDeviceData(deviceId, "threshold", threshold);
return Response.ok().build();
} catch (TransportHandlerException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@ -79,9 +96,17 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController
@DELETE
public Response removeKeyWords(@PathParam("deviceId") String deviceId, @QueryParam("words") String words) {
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
AndroidSenseConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
androidSenseMQTTConnector.publishDeviceData(deviceId, "remove", words);
return Response.ok().build();
} catch (TransportHandlerException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@ -96,13 +121,18 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController
String toDate = String.valueOf(to);
String user = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" +
AndroidSenseConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]";
AndroidSenseConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]";
if (sensor.equals(AndroidSenseConstants.SENSOR_WORDCOUNT)) {
query = "owner:" + user + " AND deviceId:" + deviceId;
}
String sensorTableName = getSensorEventTableName(sensor);
List<SensorRecord> sensorDatas;
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
AndroidSenseConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
List<SensorRecord> sensorDatas;
if (sensor.equals(AndroidSenseConstants.SENSOR_WORDCOUNT)) {
List<SortByField> sortByFields = new ArrayList<>();
SortByField sortByField = new SortByField("time", SORT.ASC, false);
@ -116,6 +146,9 @@ public class AndroidSenseControllerServiceImpl implements AndroidSenseController
String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query;
log.error(errorMsg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}

@ -31,7 +31,6 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
@Path("enrollment")
@DeviceType(value = "android_sense")
@API(name = "android_sense_mgt", version = "1.0.0", context = "/android_sense_mgt", tags = {"android_sense"})
public interface AndroidSenseManagerService {
@ -53,10 +52,5 @@ public interface AndroidSenseManagerService {
@Produces("application/json")
Response getDevice(@PathParam("device_id") String deviceId);
@Path("/devices/download")
@GET
@Produces("application/octet-stream")
Response downloadSketch();
}

@ -24,9 +24,9 @@ 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.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util.APIUtil;
import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants;
import org.wso2.carbon.utils.CarbonUtils;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@ -38,7 +38,6 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.File;
import java.util.Date;
@Path("enrollment")
@ -56,7 +55,6 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) {
return Response.status(Response.Status.CONFLICT.getStatusCode()).build();
}
Device device = new Device();
device.setDeviceIdentifier(deviceId);
EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
@ -76,6 +74,7 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).entity(false).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(false).build();
}
}
@ -87,6 +86,9 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(AndroidSenseConstants.DEVICE_TYPE);
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
boolean removed = APIUtil.getDeviceManagementService().disenrollDevice(deviceIdentifier);
if (removed) {
return Response.ok().build();
@ -94,6 +96,10 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@ -105,6 +111,9 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(AndroidSenseConstants.DEVICE_TYPE);
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier);
device.setDeviceIdentifier(deviceId);
device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime());
@ -117,6 +126,10 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@ -130,26 +143,17 @@ public class AndroidSenseManagerServiceImpl implements AndroidSenseManagerServic
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(AndroidSenseConstants.DEVICE_TYPE);
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier);
return Response.ok().entity(device).build();
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@Path("/devices/download")
@GET
@Produces("application/octet-stream")
public Response downloadSketch() {
try {
String sep = File.separator;
String sketchFolder = "repository" + sep + "resources" + sep + "sketches" + sep + "android_sense" + sep;
String archivesPath = CarbonUtils.getCarbonHome() + sep + sketchFolder;
Response.ResponseBuilder rb = Response.ok(new File(archivesPath + sep + "androidsense.apk"));
rb.header("Content-Disposition", "attachment; filename=\"" + "androidsense.apk" + "\"");
return rb.build();
} catch (IllegalArgumentException ex) {
return Response.status(Response.Status.BAD_REQUEST).entity(ex.getMessage()).build();
}
}

@ -45,7 +45,7 @@ public class AndroidSenseMQTTConnector extends MQTTTransportHandler {
private static String subscribeTopic = AndroidSenseConstants.MQTT_SUBSCRIBE_WORDS_TOPIC;
private static String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5);
private static final String KEY_TYPE = "PRODUCTION";
private static final String EMPTY_STRING = "";
private static final String DEFAULT_PASSWORD = "";
private AndroidSenseMQTTConnector() {
super(iotServerSubscriber, AndroidSenseConstants.DEVICE_TYPE,
@ -75,9 +75,8 @@ public class AndroidSenseMQTTConnector extends MQTTTransportHandler {
apiApplicationKey.getConsumerSecret(), applicationUsername, scopes);
//create token
String accessToken = accessTokenInfo.getAccessToken();
setUsernameAndPassword(accessToken, EMPTY_STRING);
setUsernameAndPassword(accessToken, DEFAULT_PASSWORD);
connectToQueue();
subscribeToQueue();
} catch (TransportHandlerException e) {
log.warn("Connection/Subscription to MQTT Broker at: " + mqttBrokerEndPoint + " failed");
try {

@ -13,8 +13,14 @@ import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
import org.wso2.carbon.device.mgt.core.permission.mgt.PermissionUtils;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import org.wso2.carbon.registry.api.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.service.RealmService;
@ -30,7 +36,6 @@ import java.util.Map;
public class APIUtil {
private static Log log = LogFactory.getLog(APIUtil.class);
private static Object lock = new Object();
public static String getAuthenticatedUser() {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
@ -66,7 +71,8 @@ public class APIUtil {
return analyticsDataAPI;
}
public static List<SensorRecord> getAllEventsForDevice(String tableName, String query, List<SortByField> sortByFields) throws AnalyticsException {
public static List<SensorRecord> getAllEventsForDevice(String tableName, String query,
List<SortByField> sortByFields) throws AnalyticsException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI();
int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query);
@ -158,37 +164,52 @@ public class APIUtil {
return jwtClientManagerService;
}
public static DeviceAccessAuthorizationService getDeviceAccessAuthorizationService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceAccessAuthorizationService deviceAccessAuthorizationService =
(DeviceAccessAuthorizationService) ctx.getOSGiService(DeviceAccessAuthorizationService.class, null);
if (deviceAccessAuthorizationService == null) {
String msg = "Device Authorization service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceAccessAuthorizationService;
}
public static void registerApiAccessRoles(String user) {
UserStoreManager userStoreManager = null;
try {
userStoreManager = getUserStoreManager();
if (userStoreManager != null) {
synchronized (lock) {
String[] userList = new String[]{user};
if (!userStoreManager.isExistingRole(Constants.DEFAULT_ROLE_NAME)) {
userStoreManager.addRole(Constants.DEFAULT_ROLE_NAME, userList, Constants.DEFAULT_PERMISSION);
}
String[] userList = new String[]{user};
if (!userStoreManager.isExistingRole(Constants.DEFAULT_ROLE_NAME)) {
userStoreManager.addRole(Constants.DEFAULT_ROLE_NAME, userList, Constants.DEFAULT_PERMISSION);
}
}
} catch (UserStoreException e) {
log.error("error on wso2 user component");
log.error("Error while creating a role and adding a user for android_sense.", e);
}
}
private static UserStoreManager getUserStoreManager() throws UserStoreException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
return getRealmService().getTenantUserRealm(tenantId).getUserStoreManager();
}
public static RealmService getRealmService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
RealmService realmService =
(RealmService) ctx.getOSGiService(RealmService.class, null);
if (realmService == null) {
String msg = "JWT Client manager service has not initialized.";
log.error(msg);
public static UserStoreManager getUserStoreManager() {
RealmService realmService;
UserStoreManager userStoreManager;
try {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
realmService = (RealmService) ctx.getOSGiService(RealmService.class, null);
if (realmService == null) {
String msg = "Realm service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
int tenantId = ctx.getTenantId();
userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager();
} catch (UserStoreException e) {
String msg = "Error occurred while retrieving current user store manager";
log.error(msg, e);
throw new IllegalStateException(msg);
}
return realmService;
return userStoreManager;
}
}

@ -19,15 +19,14 @@
package org.wso2.carbon.device.mgt.iot.androidsense.service.impl.util;
import org.wso2.carbon.user.core.Permission;
import org.wso2.carbon.user.core.authorization.TreeNode;
/**
* This hold the constants related to android sense.
* This hold the constants related to the device type.
*/
public class Constants {
private static final String DEFAULT_PERMISSION_RESOURCE = "/_system/governance/permission/admin/device-mgt/android_sense/user";
public static final String DEFAULT_PERMISSION_RESOURCE = "/permission/admin/device-mgt/android_sense/user";
public static final String DEFAULT_ROLE_NAME = "android_sense_user";
public static final Permission DEFAULT_PERMISSION[] = new Permission[]{new Permission(Constants.DEFAULT_PERMISSION_RESOURCE,
TreeNode.Permission.UI_EXECUTE.toString())};
"ui.execute")};
}

@ -77,13 +77,6 @@
<method>DELETE</method>
<scope>android_sense_user</scope>
</Permission>
<Permission>
<name>Download device</name>
<path>/device-mgt/android_sense/user</path>
<url>/enrollment/devices/download</url>
<method>GET</method>
<scope>android_sense_user</scope>
</Permission>
<Permission>
<name>Update device</name>
<path>/device-mgt/android_sense/user</path>

@ -1,68 +1,230 @@
<div class="col-lg-12 margin-top-double">
<h1 class="grey ">Android Mobile</h1>
<h1 class="grey ">Android Sense</h1>
<hr>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 padding-top">
<img src="{{@unit.publicUri}}/images/android-icon.png" class="img-responsive">
<img src="{{@unit.publicUri}}/images/android-sense-icon.png" class="img-responsive">
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 padding-top">
<h4 class="doc-link">Click <a href="https://docs.wso2.com/display/IoTS100/Android"
target="_blank">[ here ]</a> for latest instructions and troubleshooting.</h4>
<h4 class="doc-link">Click <a href="https://docs.wso2.com/display/IoTS100/Android+Sense"
target="_blank">[ here ]</a> for latest instructions and
troubleshooting.</h4>
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 padding-top">
<h3 class="uppercase">What it Does</h3>
<hr>
<p class="grey margin-top">Connect and manage your Android device with WSO2 IoT Server.</p>
<p class="grey margin-top">Connect an Android device to WSO2 IoT Server and visualize sensor
data.</p>
<br>
<h3 class="uppercase">What You Need</h3>
<hr>
<p class="grey margin-top">You should have an Android Device to get started.</p>
<ul class="list-unstyled">
<li class="padding-top-double"><span class="circle">STEP 01</span>&nbsp;&nbsp;&nbsp;Android
Mobile.
<li class="padding-top-double">
<span class="circle">STEP 01</span>
&nbsp;&nbsp;&nbsp;Go ahead and click [Enroll Device].
</li>
<li class="padding-top-double"><span class="circle">STEP 02</span>&nbsp;&nbsp;&nbsp;Go ahead
and click [Enroll Device].
<li class="padding-top-double">
<span class="circle">STEP 02</span>
&nbsp;&nbsp;&nbsp;You can either scan the QR code or directly download Android agent.
</li>
<li class="padding-top-double"><span class="circle">STEP 03</span>&nbsp;&nbsp;&nbsp;Proceed
to the [Prepare] section.
<li class="padding-top-double">
<span class="circle">STEP 03</span>
&nbsp;&nbsp;&nbsp;Install Android agent into your Android Device.
</li>
<li class="padding-top-double"><span class="circle">STEP 04</span>
&nbsp;&nbsp;&nbsp;Proceed to [Prepare] section.
</ul>
<br>
<a href="#" class="download-link btn-operations">
<i class="fw fw-mobile fw-inverse fw-lg"></i> Enroll Device</a>
<br/><br/>
<a href="#" class="download-link btn-operations"><i class="fw fw-mobile fw-inverse fw-lg"></i> Enroll Device</a>
<div id="download-device-modal-content-links" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Please download the file from following link(Press CTRL+C).</h3>
<br/>
<div>
<input id="download-device-url" style="color:#3f3f3f;padding:5px"
type="text" value="" placeholder="Type here" size="60">
</div>
</div>
</div>
</div>
</div>
<div id="device-400-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Exception at backend. Try Later.</h3>
<div class="buttons">
<a href="#" id="device-400-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-401-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>You have to log in first.</h3><br/>
<div class="buttons">
<a href="#" id="device-401-link" class="blue-button">
Goto Login Page
</a>&nbsp;&nbsp;
<a href="#" onclick="hidePopup();" class="btn-operations">
Cancel
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-403-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Action not permitted.</h3><br/>
<div class="buttons">
<a href="#" id="device-403-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-409-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Device Sketch does not exist.</h3><br/>
<div class="buttons">
<a href="#" id="device-409-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<div id="device-unexpected-error-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Unexpected error.</h3><br/>
<div class="buttons">
<a href="#" id="device-unexpected-error-link" class="btn-operations">
OK
</a>
</div>
</div>
</div>
</div>
</div>
<br/><br/>
</div>
<div class="col-xs-12 col-sm-12 col-md-8 col-lg-12 padding-double grey-bg">
<h3 class="uppercase">Prepare</h3><hr>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 padding-double grey-bg">
<h3 class="uppercase">Prepare</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double"><span class="circle">01</span> Download Device Agent into your Android Mobile.</li>
<li class="padding-top-double"><span class="circle">02</span> Install Agent APK file.</li>
<li class="padding-top-double"><span class="circle">03</span> Configure Agent App</li>
<li class="padding-top-double">
<span class="circle">01</span>
&nbsp;&nbsp;&nbsp;Connect Android device to network.
</li>
<li class="padding-top-double">
<span class="circle">02</span>
&nbsp;&nbsp;&nbsp;Start Android Sense app in your device.
</li>
<li class="padding-top-double">
<span class="circle">03</span>
&nbsp;&nbsp;&nbsp;Fill login form with the credentials.
<i>(Use server URL as [&nbsp;https://&lt;WSO2_IoT_SERVER_HOST&gt;:&lt;
HTTPS_SERVER_PORT&gt;&nbsp;] and click on
<strong>Register Device</strong> button.)</i>
</li>
<li>
<a href="{{@unit.publicUri}}/images/registerView.png" target="_blank"
class="padding-top-double">
<img src="{{@unit.publicUri}}/images/registerView.png" class="img-responsive">
</a>
</li>
<li class="padding-top-double">
<span class="circle">04</span>
&nbsp;&nbsp;&nbsp;Once the device is enrolled, click on <strong>[+]</strong> button to
select the sensors.
<a href="{{@unit.publicUri}}/images/selectSensorView.png" target="_blank"
class="padding-top-double">
<img src="{{@unit.publicUri}}/images/selectSensorView.png" class="img-responsive">
</a>
</li>
<li class="padding-top-double">
<span class="circle">05</span>
&nbsp;&nbsp;&nbsp;Click on <i>[Publish data]</i> button to publish sensor readings to
IoT server.
<a href="{{@unit.publicUri}}/images/publishDataView.png" target="_blank"
class="padding-top-double">
<img src="{{@unit.publicUri}}/images/publishDataView.png" class="img-responsive">
</a>
</li>
</ul>
<br>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 padding-double">
<h3 class="uppercase">Try Out</h3>
<hr>
<ul class="list-unstyled">
<li class="padding-top-double">
<span class="fw-stack fw-lg margin-right">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-right-arrow fw-stack-1x"></i>
</span>
&nbsp;&nbsp;&nbsp;You can view all your connected devices
<a href="{{@app.context}}/devices">[Device Management]</a> page.
</li>
<li class="padding-top-double">
<span class="fw-stack fw-lg margin-right">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-right-arrow fw-stack-1x"></i>
</span>
&nbsp;&nbsp;&nbsp;You can select any one of your connected devices for available
operations and Real-Time data monitoring.
</li>
<li class="padding-top-double">
<span class="fw-stack fw-lg margin-right">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-right-arrow fw-stack-1x"></i>
</span>&nbsp;&nbsp;&nbsp;For historical analytics of sensor data navigate to device
analytics page.
</li>
</ul>
<br/>
<p class="grey margin-top">Click on the image to zoom</p>
<center>
<a href="{{@unit.publicUri}}/images/android_device.png" target="_blank">
<img src="{{@unit.publicUri}}/images/android_device.png" class="img-responsive">
<a href="{{@unit.publicUri}}/images/myDevices_analytics.png" target="_blank">
<img src="{{@unit.publicUri}}/images/myDevices_analytics.png" class="img-responsive">
</a>
</center>
</div>
<br/>
<div id="qr-code-modal"
data-enrollment-url="{{hostName}}{{@unit.publicUri}}/asset/android-agent.apk" class="hidden">
<div id="qr-code-modal" data-enrollment-url="{{hostName}}{{@unit.publicUri}}/asset/androidsense.apk" class="hidden">
<div class="content">
<div class="row">
<div class="col-lg-5 col-md-6 col-centered">
@ -73,74 +235,94 @@
<div class="qr-code"></div>
</div>
</div>
<form id="downloadForm" method="GET"
action="{{hostName}}{{@unit.publicUri}}/asset/androidsense.apk">
<div class="buttons" style="padding-bottom: 0px">
<input class="btn btn-operations" type="submit" value="Download Now">
</div>
</form>
</div>
</div>
</div>
<div id="device-agent-downloading-content" class="hide">
<div class="modal-content">
<div class="row">
<div class="col-md-7 col-centered center-container">
<h3>Device Agent will downloading shortly.</h3>
</div>
</div>
</div>
</div>
</div>
{{#zone "topCss"}}
<style type="text/css">
.circle {
background: none repeat scroll 0 0 #191919;
border-radius: 50px;
height: 50px;
padding: 10px;
width: 50px;
color: #fff;
}
.padding-top-double {
padding-top: 20px;
}
.padding-double {
padding: 20px;
}
.grey {
color: #333;
}
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #7f7f7f;
margin: 1em 0;
padding: 0;
opacity: 0.2;
}
.light-grey {
color: #7c7c7c;
}
.uppercase {
text-transform: uppercase;
}
.grey-bg {
background-color: #f6f4f4;
}
<style type="text/css">
.circle {
background: none repeat scroll 0 0 #191919;
border-radius: 50px;
height: 50px;
padding: 10px;
width: 50px;
color: #fff;
}
.doc-link {
background: #11375B;
padding: 20px;
color: white;
margin-top: 0;
}
.padding-top-double {
padding-top: 20px;
}
.doc-link a {
color: white;
}
</style>
{{/zone}}
.padding-double {
padding: 20px;
}
.grey {
color: #333;
}
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #7f7f7f;
margin: 1em 0;
padding: 0;
opacity: 0.2;
}
.light-grey {
color: #7c7c7c;
}
.uppercase {
text-transform: uppercase;
}
.grey-bg {
background-color: #f6f4f4;
}
.doc-link {
background: #11375B;
padding: 20px;
color: white;
margin-top: 0;
}
.doc-link a {
color: white;
}
</style>
{{#zone "bottomJs"}}
{{js "/js/download.js"}}
<script type="text/javascript">
$(".download-link").click(function(){
$(".download-link").click(function () {
toggleEnrollment();
});
function toggleEnrollment(){
function toggleEnrollment() {
$(".modalpopup-content").html($("#qr-code-modal").html());
generateQRCode(".modalpopup-content .qr-code");
showPopup();
}
</script>
{{/zone}}
{{js "/js/jquery.validate.js"}}
{{/zone}}

@ -69,6 +69,7 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
public void run() {
while (!isConnected()) {
try {
connectToQueue();
agentManager.updateAgentStatus("Connected to MQTT Queue");
} catch (TransportHandlerException e) {
@ -142,8 +143,7 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
String replyTemperature = "Current temperature was read as: '" + currentTemperature + "C'";
log.info(AgentConstants.LOG_APPENDER + replyTemperature);
String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC,
serverName, deviceOwner, deviceID);
String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, deviceID);
replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature;
securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
@ -157,7 +157,7 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
log.info(AgentConstants.LOG_APPENDER + replyHumidity);
String humidPublishTopic = String.format(
AgentConstants.MQTT_PUBLISH_TOPIC, serverName, deviceOwner, deviceID);
AgentConstants.MQTT_PUBLISH_TOPIC, deviceID);
replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity;
securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
@ -202,8 +202,6 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
pushMessage.setRetained(false);
String topic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC,
agentManager.getAgentConfigs().getServerName(),
agentManager.getAgentConfigs().getDeviceOwner(),
agentManager.getAgentConfigs().getDeviceId());
publishToQueue(topic, pushMessage);

@ -29,6 +29,7 @@ public class AgentConfiguration {
private String deviceId;
private String deviceName;
private String controllerContext;
private String scepContext;
private String HTTPS_ServerEndpoint;
private String HTTP_ServerEndpoint;
private String apimGatewayEndpoint;
@ -150,6 +151,14 @@ public class AgentConfiguration {
public void setDataPushInterval(int dataPushInterval) {
this.dataPushInterval = dataPushInterval;
}
public String getScepContext() {
return scepContext;
}
public void setScepContext(String scepContext) {
this.scepContext = scepContext;
}
}

@ -26,7 +26,8 @@ public class AgentConstants {
/* ---------------------------------------------------------------------------------------
IoT-Server specific information
--------------------------------------------------------------------------------------- */
public static final String DEVICE_CONTROLLER_API_EP = "/virtual_firealarm/controller";
public static final String DEVICE_CONTROLLER_API_EP = "/virtual_firealarm/device";
public static final String DEVICE_SCEP_API_EP = "/virtual_firealarm_scep";
public static final String DEVICE_ENROLLMENT_API_EP = "/scep";
public static final String DEVICE_REGISTER_API_EP = "/register";
public static final String DEVICE_PUSH_TEMPERATURE_API_EP = "/push_temperature";
@ -56,8 +57,8 @@ public class AgentConstants {
--------------------------------------------------------------------------------------- */
public static final int DEFAULT_MQTT_RECONNECTION_INTERVAL = 2; // time in seconds
public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0;
public static final String MQTT_SUBSCRIBE_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s";
public static final String MQTT_PUBLISH_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s/publisher";
public static final String MQTT_SUBSCRIBE_TOPIC = "wso2/" + DEVICE_TYPE + "/%s";
public static final String MQTT_PUBLISH_TOPIC = "wso2/" + DEVICE_TYPE + "/%s/publisher";
/* ---------------------------------------------------------------------------------------
XMPP Connection specific information
--------------------------------------------------------------------------------------- */
@ -71,6 +72,7 @@ public class AgentConstants {
public static final String DEVICE_ID_PROPERTY = "deviceId";
public static final String DEVICE_NAME_PROPERTY = "device-name";
public static final String DEVICE_CONTROLLER_CONTEXT_PROPERTY = "controller-context";
public static final String DEVICE_SCEP_CONTEXT_PROPERTY = "scep-context";
public static final String SERVER_HTTPS_EP_PROPERTY = "https-ep";
public static final String SERVER_HTTP_EP_PROPERTY = "http-ep";
public static final String APIM_GATEWAY_EP_PROPERTY = "apim-ep";

@ -133,10 +133,7 @@ public class AgentManager {
log.error("XMPP Endpoint String - " + agentConfigs.getXmppServerEndpoint() +
", provided in the configuration file is invalid.");
}
String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC,
agentConfigs.getServerName(),
agentConfigs.getDeviceOwner(),
agentConfigs.getDeviceId());
String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC, agentConfigs.getDeviceId());
// TransportHandler httpCommunicator = new FireAlarmHTTPCommunicator();
TransportHandler mqttCommunicator = new FireAlarmMQTTCommunicator(agentConfigs.getDeviceOwner(),

@ -18,6 +18,7 @@
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;
@ -45,6 +46,8 @@ public class AgentUtilOperations {
private static final Log log = LogFactory.getLog(AgentUtilOperations.class);
private static final String JSON_MESSAGE_KEY = "Msg";
private static final String JSON_SIGNATURE_KEY = "Sig";
private static final String JSON_SERIAL_KEY = "SerialNumber";
private static final String JSON_TENANT_KEY = "Tenant";
/**
* This method reads the agent specific configurations for the device from the
@ -88,6 +91,8 @@ public class AgentUtilOperations {
AgentConstants.DEVICE_NAME_PROPERTY));
iotServerConfigs.setControllerContext(properties.getProperty(
AgentConstants.DEVICE_CONTROLLER_CONTEXT_PROPERTY));
iotServerConfigs.setScepContext(properties.getProperty(
AgentConstants.DEVICE_SCEP_CONTEXT_PROPERTY));
iotServerConfigs.setHTTPS_ServerEndpoint(properties.getProperty(
AgentConstants.SERVER_HTTPS_EP_PROPERTY));
iotServerConfigs.setHTTP_ServerEndpoint(properties.getProperty(
@ -176,6 +181,7 @@ public class AgentUtilOperations {
iotServerConfigs.setDeviceId(AgentConstants.DEFAULT_DEVICE_ID);
iotServerConfigs.setDeviceName(AgentConstants.DEFAULT_DEVICE_NAME);
iotServerConfigs.setControllerContext(AgentConstants.DEVICE_CONTROLLER_API_EP);
iotServerConfigs.setScepContext(AgentConstants.DEVICE_SCEP_API_EP);
iotServerConfigs.setHTTPS_ServerEndpoint(AgentConstants.DEFAULT_HTTPS_SERVER_EP);
iotServerConfigs.setHTTP_ServerEndpoint(AgentConstants.DEFAULT_HTTP_SERVER_EP);
iotServerConfigs.setApimGatewayEndpoint(AgentConstants.DEFAULT_APIM_GATEWAY_EP);
@ -203,11 +209,11 @@ public class AgentUtilOperations {
String serverSecureEndpoint = agentManager.getAgentConfigs().getHTTPS_ServerEndpoint();
String serverUnSecureEndpoint = agentManager.getAgentConfigs().getHTTP_ServerEndpoint();
String backEndContext = agentManager.getAgentConfigs().getControllerContext();
String scepBackEndContext = agentManager.getAgentConfigs().getScepContext();
String deviceControllerAPIEndpoint = serverSecureEndpoint + backEndContext;
String deviceEnrollmentEndpoint =
serverUnSecureEndpoint + backEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP;
serverUnSecureEndpoint + scepBackEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP;
agentManager.setEnrollmentEP(deviceEnrollmentEndpoint);
String registerEndpointURL =
@ -229,21 +235,11 @@ public class AgentUtilOperations {
public static String prepareSecurePayLoad(String message) throws AgentCoreOperationException {
PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey();
PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey();
String encryptedMsg;
try {
encryptedMsg = CommunicationUtils.encryptMessage(message, serverPublicKey);
} catch (TransportHandlerException e) {
String errorMsg = "Error occurred whilst trying to encryptMessage: [" + message + "]";
log.error(errorMsg);
throw new AgentCoreOperationException(errorMsg, e);
}
String encodedMessage = Base64.encodeBase64String(message.getBytes());
String signedPayload;
try {
signedPayload = CommunicationUtils.signMessage(encryptedMsg, devicePrivateKey);
signedPayload = CommunicationUtils.signMessage(encodedMessage, devicePrivateKey);
} catch (TransportHandlerException e) {
String errorMsg = "Error occurred whilst trying to sign encrypted message of: [" + message + "]";
log.error(errorMsg);
@ -251,8 +247,11 @@ public class AgentUtilOperations {
}
JSONObject jsonPayload = new JSONObject();
jsonPayload.put(JSON_MESSAGE_KEY, encryptedMsg);
jsonPayload.put(JSON_MESSAGE_KEY, encodedMessage);
jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload);
//below statements are temporary fix.
jsonPayload.put(JSON_SERIAL_KEY, EnrollmentManager.getInstance().getSCEPCertificate().getSerialNumber());
jsonPayload.put(JSON_TENANT_KEY, "carbon.super");
return jsonPayload.toString();
}
@ -262,17 +261,15 @@ public class AgentUtilOperations {
String actualMessage;
PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey();
PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey();
JSONObject jsonPayload = new JSONObject(message);
Object encryptedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
Object encodedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY);
boolean verification;
if (encryptedMessage != null && signedPayload != null) {
if (encodedMessage != null && signedPayload != null) {
try {
verification = CommunicationUtils.verifySignature(
encryptedMessage.toString(), signedPayload.toString(), serverPublicKey);
encodedMessage.toString(), signedPayload.toString(), serverPublicKey);
} catch (TransportHandlerException e) {
String errorMsg =
"Error occurred whilst trying to verify signature on received message: [" + message + "]";
@ -284,21 +281,13 @@ public class AgentUtilOperations {
"Need to be JSON - {\"Msg\":\"<ENCRYPTED_MSG>\", \"Sig\":\"<SIGNED_MSG>\"}.";
throw new AgentCoreOperationException(errorMsg);
}
try {
if (verification) {
actualMessage = CommunicationUtils.decryptMessage(encryptedMessage.toString(), devicePrivateKey);
} else {
String errorMsg = "Could not verify payload signature. The message was not signed by a valid client";
log.error(errorMsg);
throw new AgentCoreOperationException(errorMsg);
}
} catch (TransportHandlerException e) {
String errorMsg = "Error occurred whilst trying to decrypt received message: [" + encryptedMessage + "]";
if (verification) {
actualMessage = new String(Base64.decodeBase64(encodedMessage.toString()), StandardCharsets.UTF_8);
} else {
String errorMsg = "Could not verify payload signature. The message was not signed by a valid client";
log.error(errorMsg);
throw new AgentCoreOperationException(errorMsg, e);
throw new AgentCoreOperationException(errorMsg);
}
return actualMessage;
}

@ -27,6 +27,7 @@ import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandler;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException;
@ -53,6 +54,7 @@ public abstract class MQTTTransportHandler
private static final Log log = LogFactory.getLog(MQTTTransportHandler.class);
public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0;
private static final String DEFAULT_PASSWORD = "";
private MqttClient client;
private String clientId;
@ -81,6 +83,8 @@ public abstract class MQTTTransportHandler
this.mqttBrokerEndPoint = mqttBrokerEndPoint;
this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
this.initSubscriber();
options.setUserName(AgentManager.getInstance().getAgentConfigs().getAuthToken());
options.setPassword(DEFAULT_PASSWORD.toCharArray());
}
/**
@ -105,6 +109,8 @@ public abstract class MQTTTransportHandler
this.mqttBrokerEndPoint = mqttBrokerEndPoint;
this.timeoutInterval = intervalInMillis;
this.initSubscriber();
options.setUserName(AgentManager.getInstance().getAgentConfigs().getAuthToken());
options.setPassword(DEFAULT_PASSWORD.toCharArray());
}
public void setTimeoutInterval(int timeoutInterval) {

@ -20,7 +20,8 @@ server-name=WSO2IoTServer
owner=shabirmean
deviceId=t4ctwq8qfl11
device-name=SMEAN_t4ctwq8qfl11
controller-context=/virtual_firealarm/controller
controller-context=/virtual_firealarm/device
scep-context=/virtual_firealarm_scep
https-ep=https://localhost:9443
http-ep=http://localhost:9763
apim-ep=http://192.168.67.21:8281

@ -137,8 +137,7 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
String replyTemperature = "Current temperature was read as: '" + currentTemperature + "C'";
log.info(AgentConstants.LOG_APPENDER + replyTemperature);
String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC,
serverName, deviceOwner, deviceID);
String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, deviceID);
replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature;
securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
@ -152,7 +151,7 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
log.info(AgentConstants.LOG_APPENDER + replyHumidity);
String humidPublishTopic = String.format(
AgentConstants.MQTT_PUBLISH_TOPIC, serverName, deviceOwner, deviceID);
AgentConstants.MQTT_PUBLISH_TOPIC, deviceID);
replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity;
securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage);
@ -193,8 +192,6 @@ public class FireAlarmMQTTCommunicator extends MQTTTransportHandler {
pushMessage.setRetained(false);
String topic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC,
agentManager.getAgentConfigs().getServerName(),
agentManager.getAgentConfigs().getDeviceOwner(),
agentManager.getAgentConfigs().getDeviceId());
publishToQueue(topic, pushMessage);

@ -29,6 +29,7 @@ public class AgentConfiguration {
private String deviceId;
private String deviceName;
private String controllerContext;
private String scepContext;
private String HTTPS_ServerEndpoint;
private String HTTP_ServerEndpoint;
private String apimGatewayEndpoint;
@ -150,6 +151,14 @@ public class AgentConfiguration {
public void setDataPushInterval(int dataPushInterval) {
this.dataPushInterval = dataPushInterval;
}
public String getScepContext() {
return scepContext;
}
public void setScepContext(String scepContext) {
this.scepContext = scepContext;
}
}

@ -56,8 +56,8 @@ public class AgentConstants {
--------------------------------------------------------------------------------------- */
public static final int DEFAULT_MQTT_RECONNECTION_INTERVAL = 2; // time in seconds
public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0;
public static final String MQTT_SUBSCRIBE_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s";
public static final String MQTT_PUBLISH_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s/publisher";
public static final String MQTT_SUBSCRIBE_TOPIC = "wso2/" + DEVICE_TYPE + "/%s";
public static final String MQTT_PUBLISH_TOPIC = "wso2/" + DEVICE_TYPE + "/%s/publisher";
/* ---------------------------------------------------------------------------------------
XMPP Connection specific information
--------------------------------------------------------------------------------------- */
@ -71,6 +71,7 @@ public class AgentConstants {
public static final String DEVICE_ID_PROPERTY = "deviceId";
public static final String DEVICE_NAME_PROPERTY = "device-name";
public static final String DEVICE_CONTROLLER_CONTEXT_PROPERTY = "controller-context";
public static final String DEVICE_SCEP_CONTEXT_PROPERTY = "scep-context";
public static final String SERVER_HTTPS_EP_PROPERTY = "https-ep";
public static final String SERVER_HTTP_EP_PROPERTY = "http-ep";
public static final String APIM_GATEWAY_EP_PROPERTY = "apim-ep";

@ -121,10 +121,7 @@ public class AgentManager {
log.error("XMPP Endpoint String - " + agentConfigs.getXmppServerEndpoint() +
", provided in the configuration file is invalid.");
}
String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC,
agentConfigs.getServerName(),
agentConfigs.getDeviceOwner(),
agentConfigs.getDeviceId());
String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC, agentConfigs.getDeviceId());
// TransportHandler httpCommunicator = new FireAlarmHTTPCommunicator();
TransportHandler mqttCommunicator = new FireAlarmMQTTCommunicator(agentConfigs.getDeviceOwner(),

@ -18,6 +18,7 @@
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;
@ -49,6 +50,8 @@ public class AgentUtilOperations {
private static final Log log = LogFactory.getLog(AgentUtilOperations.class);
private static final String JSON_MESSAGE_KEY = "Msg";
private static final String JSON_SIGNATURE_KEY = "Sig";
private static final String JSON_SERIAL_KEY = "SerialNumber";
private static final String JSON_TENANT_KEY = "Tenant";
/**
* This method reads the agent specific configurations for the device from the
@ -92,6 +95,8 @@ public class AgentUtilOperations {
AgentConstants.DEVICE_NAME_PROPERTY));
iotServerConfigs.setControllerContext(properties.getProperty(
AgentConstants.DEVICE_CONTROLLER_CONTEXT_PROPERTY));
iotServerConfigs.setScepContext(properties.getProperty(
AgentConstants.DEVICE_SCEP_CONTEXT_PROPERTY));
iotServerConfigs.setHTTPS_ServerEndpoint(properties.getProperty(
AgentConstants.SERVER_HTTPS_EP_PROPERTY));
iotServerConfigs.setHTTP_ServerEndpoint(properties.getProperty(
@ -176,11 +181,12 @@ public class AgentUtilOperations {
String serverSecureEndpoint = agentManager.getAgentConfigs().getHTTPS_ServerEndpoint();
String serverUnSecureEndpoint = agentManager.getAgentConfigs().getHTTP_ServerEndpoint();
String backEndContext = agentManager.getAgentConfigs().getControllerContext();
String scepBackEndContext = agentManager.getAgentConfigs().getScepContext();
String deviceControllerAPIEndpoint = serverSecureEndpoint + backEndContext;
String deviceEnrollmentEndpoint =
serverUnSecureEndpoint + backEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP;
serverUnSecureEndpoint + scepBackEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP;
agentManager.setEnrollmentEP(deviceEnrollmentEndpoint);
String registerEndpointURL =
@ -202,21 +208,11 @@ public class AgentUtilOperations {
public static String prepareSecurePayLoad(String message) throws AgentCoreOperationException {
PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey();
PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey();
String encryptedMsg;
try {
encryptedMsg = CommunicationUtils.encryptMessage(message, serverPublicKey);
} catch (TransportHandlerException e) {
String errorMsg = "Error occurred whilst trying to encryptMessage: [" + message + "]";
log.error(errorMsg);
throw new AgentCoreOperationException(errorMsg, e);
}
String encodedMessage = Base64.encodeBase64String(message.getBytes());
String signedPayload;
try {
signedPayload = CommunicationUtils.signMessage(encryptedMsg, devicePrivateKey);
signedPayload = CommunicationUtils.signMessage(encodedMessage, devicePrivateKey);
} catch (TransportHandlerException e) {
String errorMsg = "Error occurred whilst trying to sign encrypted message of: [" + message + "]";
log.error(errorMsg);
@ -224,28 +220,28 @@ public class AgentUtilOperations {
}
JSONObject jsonPayload = new JSONObject();
jsonPayload.put(JSON_MESSAGE_KEY, encryptedMsg);
jsonPayload.put(JSON_MESSAGE_KEY, encodedMessage);
jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload);
//below statements are temporary fix.
jsonPayload.put(JSON_SERIAL_KEY, EnrollmentManager.getInstance().getSCEPCertificate().getSerialNumber());
jsonPayload.put(JSON_TENANT_KEY, "carbon.super");
return jsonPayload.toString();
}
public static String extractMessageFromPayload(String message) throws AgentCoreOperationException {
String actualMessage;
PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey();
PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey();
JSONObject jsonPayload = new JSONObject(message);
Object encryptedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
Object encodedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY);
boolean verification;
if (encryptedMessage != null && signedPayload != null) {
if (encodedMessage != null && signedPayload != null) {
try {
verification = CommunicationUtils.verifySignature(
encryptedMessage.toString(), signedPayload.toString(), serverPublicKey);
encodedMessage.toString(), signedPayload.toString(), serverPublicKey);
} catch (TransportHandlerException e) {
String errorMsg =
"Error occurred whilst trying to verify signature on received message: [" + message + "]";
@ -257,21 +253,13 @@ public class AgentUtilOperations {
"Need to be JSON - {\"Msg\":\"<ENCRYPTED_MSG>\", \"Sig\":\"<SIGNED_MSG>\"}.";
throw new AgentCoreOperationException(errorMsg);
}
try {
if (verification) {
actualMessage = CommunicationUtils.decryptMessage(encryptedMessage.toString(), devicePrivateKey);
} else {
String errorMsg = "Could not verify payload signature. The message was not signed by a valid client";
log.error(errorMsg);
throw new AgentCoreOperationException(errorMsg);
}
} catch (TransportHandlerException e) {
String errorMsg = "Error occurred whilst trying to decrypt received message: [" + encryptedMessage + "]";
if (verification) {
actualMessage = new String(Base64.decodeBase64(encodedMessage.toString()), StandardCharsets.UTF_8);
} else {
String errorMsg = "Could not verify payload signature. The message was not signed by a valid client";
log.error(errorMsg);
throw new AgentCoreOperationException(errorMsg, e);
throw new AgentCoreOperationException(errorMsg);
}
return actualMessage;
}

@ -27,6 +27,7 @@ import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException;
@ -51,7 +52,7 @@ import java.nio.charset.StandardCharsets;
public abstract class MQTTTransportHandler
implements MqttCallback, TransportHandler<MqttMessage> {
private static final Log log = LogFactory.getLog(MQTTTransportHandler.class);
private static final String DEFAULT_PASSWORD = "";
public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0;
private MqttClient client;
@ -81,6 +82,8 @@ public abstract class MQTTTransportHandler
this.mqttBrokerEndPoint = mqttBrokerEndPoint;
this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL;
this.initSubscriber();
options.setUserName(AgentManager.getInstance().getAgentConfigs().getAuthToken());
options.setPassword(DEFAULT_PASSWORD.toCharArray());
}
/**
@ -105,6 +108,8 @@ public abstract class MQTTTransportHandler
this.mqttBrokerEndPoint = mqttBrokerEndPoint;
this.timeoutInterval = intervalInMillis;
this.initSubscriber();
options.setUserName(AgentManager.getInstance().getAgentConfigs().getAuthToken());
options.setPassword(DEFAULT_PASSWORD.toCharArray());
}
public void setTimeoutInterval(int timeoutInterval) {

@ -20,7 +20,8 @@ server-name=WSO2IoTServer
owner=shabirmean
deviceId=t4ctwq8qfl11
device-name=SMEAN_t4ctwq8qfl11
controller-context=/virtual_firealarm/controller
controller-context=/virtual_firealarm/device
scep-context=/virtual_firealarm_scep
https-ep=https://localhost:9443
http-ep=http://localhost:9763
apim-ep=http://192.168.67.21:8281

@ -37,6 +37,13 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
/**
* This class consists the functions/APIs specific to the "actions" of the VirtualFirealarm device-type. These APIs
* include the ones that are used by the [Device] to contact the server (i.e: Enrollment & Publishing Data) and the
* ones used by the [Server/Owner] to contact the [Device] (i.e: sending control signals). This class also initializes
* the transport 'Connectors' [XMPP & MQTT] specific to the VirtualFirealarm device-type in order to communicate with
* such devices and to receive messages form it.
*/
@API(name = "virtual_firealarm", version = "1.0.0", context = "/virtual_firealarm", tags = "virtual_firealarm")
@DeviceType(value = "virtual_firealarm")
public interface VirtualFireAlarmControllerService {
@ -89,40 +96,7 @@ public interface VirtualFireAlarmControllerService {
@Path("device/temperature")
@Consumes(MediaType.APPLICATION_JSON)
Response pushTemperatureData(final DeviceData dataMsg);
/**
* This is an API called/used by the SCEP Client of the VirtualFirealarm device in its SCEP enrollment process.
* This acts as the endpoint exposed as part of the SCEP-Server for use by a SCEP Client. This is one of the two
* method-signatures that takes different parameters according to the SCEP-Operation executed by the SCEP-Client
* of the enrolling device. The API supports 2 SCEP Operations [GetCACert] and [GetCACaps].
* <p/>
* Operation [GetCACert] returns the CA cert of the SCEP-Server for the device to verify its authenticity.
* Operation [GetCACaps] returns the CA Capabilities of the SCEP-Server.
*
* @param operation the SCEP operation requested by the client. [GetCACert] or [GetCACaps]
* @param message any messages pertaining to the requested SCEP Operation.
* @return an HTTP Response object with either the CA-Cert or the CA-Capabilities according to the operation.
*/
@GET
@Path("device/scep")
Response scepRequest(@QueryParam("operation") String operation, @QueryParam("message") String message);
/**
* This is an API called/used by the SCEP Client of the VirtualFirealarm device in its SCEP enrollment process.
* This acts as the endpoint exposed as part of the SCEP-Server for use by a SCEP Client. This is one of the two
* method-signatures that takes different parameters according to the SCEP-Operation executed by the SCEP-Client
* of the enrolling device. This API supports the SCEP Operation [PKIOperation].
* <p/>
* Operation [PKIOperation] returns a certificate generated by the SCEP-Server for the enrolling device.
*
* @param operation the final SCEP operation executed in the enrollment process - which is [PKIOperation]
* @param inputStream an input stream consisting of the Certificate-Signing-Request (CSR) from the device.
* @return an HTTP Response object with the signed certificate for the device by the CA of the SCEP Server.
*/
@POST
@Path("device/scep")
Response scepRequestPost(@QueryParam("operation") String operation, InputStream inputStream);
/**
* Retrieve Sensor data for the device type

@ -26,21 +26,23 @@ import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException
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.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig;
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig;
import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener;
import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.DeviceData;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmXMPPConnector;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.scep.ContentType;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.scep.SCEPOperation;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmMQTTConnector;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport.VirtualFireAlarmXMPPConnector;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.APIUtil;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.scep.ContentType;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.scep.SCEPOperation;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants;
import javax.servlet.http.HttpServletRequest;
@ -60,13 +62,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* This class consists the functions/APIs specific to the "actions" of the VirtualFirealarm device-type. These APIs
* include the ones that are used by the [Device] to contact the server (i.e: Enrollment & Publishing Data) and the
* ones used by the [Server/Owner] to contact the [Device] (i.e: sending control signals). This class also initializes
* the transport 'Connectors' [XMPP & MQTT] specific to the VirtualFirealarm device-type in order to communicate with
* such devices and to receive messages form it.
*/
@SuppressWarnings("Non-Annoted WebService")
public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmControllerService {
@ -75,7 +70,7 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
private static final String MQTT_PROTOCOL = "MQTT";
private static Log log = LogFactory.getLog(VirtualFireAlarmControllerServiceImpl.class);
// consists of utility methods related to encrypting and decrypting messages
private SecurityManager securityManager;
private org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager securityManager;
// connects to the given MQTT broker and handles MQTT communication
private VirtualFireAlarmMQTTConnector virtualFireAlarmMQTTConnector;
// connects to the given XMPP server and handles XMPP communication
@ -117,6 +112,10 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
protocolString);
}
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
switch (protocolString) {
case HTTP_PROTOCOL:
String deviceHTTPEndpoint = deviceToIpMap.get(deviceId);
@ -138,6 +137,9 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
} catch (DeviceManagementException | TransportHandlerException e) {
log.error("Failed to send switch-bulb request to device [" + deviceId + "] via " + protocolString);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
@ -147,7 +149,6 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
public Response pushTemperatureData(final DeviceData dataMsg) {
String deviceId = dataMsg.deviceId;
String deviceIp = dataMsg.reply;
float temperature = dataMsg.value;
String registeredIp = deviceToIpMap.get(deviceId);
if (registeredIp == null) {
log.warn("Unregistered IP: Temperature Data Received from an un-registered IP " +
@ -158,102 +159,19 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
" is already registered under some other IP. Re-registration required");
return Response.status(Response.Status.CONFLICT).build();
}
if (!VirtualFireAlarmServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.ok().build();
}
@GET
@Path("device/scep")
public Response scepRequest(@QueryParam("operation") String operation, @QueryParam("message") String message) {
if (log.isDebugEnabled()) {
log.debug("Invoking SCEP operation " + operation);
}
if (SCEPOperation.GET_CA_CERT.getValue().equals(operation)) {
if (log.isDebugEnabled()) {
log.debug("Invoking GetCACert");
}
try {
CertificateManagementService certificateManagementService =
VirtualFireAlarmServiceUtils.getCertificateManagementService();
SCEPResponse scepResponse = certificateManagementService.getCACertSCEP();
Response.ResponseBuilder responseBuilder;
switch (scepResponse.getResultCriteria()) {
case CA_CERT_FAILED:
log.error("CA cert failed");
responseBuilder = Response.serverError();
break;
case CA_CERT_RECEIVED:
if (log.isDebugEnabled()) {
log.debug("CA certificate received in GetCACert");
}
responseBuilder = Response.ok(scepResponse.getEncodedResponse(),
ContentType.X_X509_CA_CERT);
break;
case CA_RA_CERT_RECEIVED:
if (log.isDebugEnabled()) {
log.debug("CA and RA certificates received in GetCACert");
}
responseBuilder = Response.ok(scepResponse.getEncodedResponse(),
ContentType.X_X509_CA_RA_CERT);
break;
default:
log.error("Invalid SCEP request");
responseBuilder = Response.serverError();
break;
}
return responseBuilder.build();
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the VirtualFireAlarm device", e);
} catch (KeystoreException e) {
log.error("Keystore error occurred while enrolling the VirtualFireAlarm device", e);
}
} else if (SCEPOperation.GET_CA_CAPS.getValue().equals(operation)) {
if (log.isDebugEnabled()) {
log.debug("Invoking GetCACaps");
}
try {
CertificateManagementService certificateManagementService = VirtualFireAlarmServiceUtils.
getCertificateManagementService();
byte caCaps[] = certificateManagementService.getCACapsSCEP();
return Response.ok(caCaps, MediaType.TEXT_PLAIN).build();
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the device", e);
}
} else {
log.error("Invalid SCEP operation " + operation);
}
return Response.serverError().build();
}
@POST
@Path("device/scep")
public Response scepRequestPost(@QueryParam("operation") String operation, InputStream inputStream) {
if (log.isDebugEnabled()) {
log.debug("Invoking SCEP operation " + operation);
}
if (SCEPOperation.PKI_OPERATION.getValue().equals(operation)) {
if (log.isDebugEnabled()) {
log.debug("Invoking PKIOperation");
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
try {
CertificateManagementService certificateManagementService = VirtualFireAlarmServiceUtils.
getCertificateManagementService();
byte pkiMessage[] = certificateManagementService.getPKIMessageSCEP(inputStream);
return Response.ok(pkiMessage, ContentType.X_PKI_MESSAGE).build();
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the device", e);
} catch (KeystoreException e) {
log.error("Keystore error occurred while enrolling the device", e);
if (!VirtualFireAlarmServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.ok().build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.serverError().build();
}
@Path("device/stats/{deviceId}/sensors/{sensorName}")
@ -270,6 +188,10 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
VirtualFireAlarmConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]";
String sensorTableName = getSensorEventTableName(sensor);
try {
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE))) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
if (sensorTableName != null) {
List<SortByField> sortByFields = new ArrayList<>();
SortByField sortByField = new SortByField("time", SORT.ASC, false);
@ -281,6 +203,9 @@ public class VirtualFireAlarmControllerServiceImpl implements VirtualFireAlarmCo
String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query;
log.error(errorMsg);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(errorMsg).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response.status(Response.Status.BAD_REQUEST).build();
}

@ -34,39 +34,32 @@ import javax.ws.rs.core.Response;
@Path("enrollment")
@API(name = "virtual_firealarm_mgt", version = "1.0.0", context = "/virtual_firealarm_mgt", tags = "virtual_firealarm")
@DeviceType(value = "virtual_firealarm")
public interface VirtualFireAlarmManagerService {
@Path("devices/{device_id}")
@Path("/devices/{device_id}")
@DELETE
Response removeDevice(@PathParam("device_id") String deviceId);
@Path("devices/{device_id}")
@Path("/devices/{device_id}")
@PUT
Response updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name);
@Path("devices/{device_id}")
@Path("/devices/{device_id}")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Response getDevice(@PathParam("device_id") String deviceId);
@Path("devices")
@Path("/devices")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
Response getFirealarmDevices();
@Path("devices/download")
@Path("/devices/download")
@GET
@Produces(MediaType.APPLICATION_JSON)
@Produces("application/zip")
Response downloadSketch(@QueryParam("deviceName") String deviceName, @QueryParam("sketchType") String sketchType);
@Path("devices/generate_link")
@GET
Response generateSketchLink(@QueryParam("deviceName") String deviceName,
@QueryParam("sketchType") String sketchType);
}

@ -19,6 +19,8 @@
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
@ -27,6 +29,7 @@ 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.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppAccount;
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig;
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient;
@ -63,14 +66,18 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
private static final String KEY_TYPE = "PRODUCTION";
private static ApiApplicationKey apiApplicationKey;
private static Log log = LogFactory.getLog(VirtualFireAlarmManagerServiceImpl.class);
@Path("devices/{device_id}")
@Path("/devices/{device_id}")
@DELETE
public Response removeDevice(@PathParam("device_id") String deviceId) {
try {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE);
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
boolean removed = APIUtil.getDeviceManagementService().disenrollDevice(
deviceIdentifier);
if (removed) {
@ -79,17 +86,24 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@Path("devices/{device_id}")
@Path("/devices/{device_id}")
@PUT
public Response updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name) {
try {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE);
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier);
device.setDeviceIdentifier(deviceId);
device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime());
@ -102,11 +116,15 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
return Response.status(Response.Status.NOT_ACCEPTABLE.getStatusCode()).build();
}
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@Path("devices/{device_id}")
@Path("/devices/{device_id}")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ -115,14 +133,21 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE);
if (!APIUtil.getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier)) {
return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
}
Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier);
return Response.ok().entity(device).build();
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
} catch (DeviceAccessAuthorizationException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@Path("devices")
@Path("/devices")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ -140,57 +165,44 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
Device[] devices = userDevicesforFirealarm.toArray(new Device[]{});
return Response.ok().entity(devices).build();
} catch (DeviceManagementException e) {
log.error(e.getErrorMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build();
}
}
@Path("devices/download")
@Path("/devices/download")
@GET
@Produces(MediaType.APPLICATION_JSON)
@Produces("application/zip")
public Response downloadSketch(@QueryParam("deviceName") String deviceName,
@QueryParam("sketchType") String sketchType) {
try {
ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName, sketchType);
Response.ResponseBuilder response = Response.ok(FileUtils.readFileToByteArray(zipFile.getZipFile()));
response.status(Response.Status.OK);
response.type("application/zip");
response.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\"");
return response.build();
Response resp = response.build();
zipFile.getZipFile().delete();
return resp;
} catch (IllegalArgumentException ex) {
return Response.status(400).entity(ex.getMessage()).build();//bad request
} catch (DeviceManagementException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (JWTClientException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (APIManagerException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (DeviceControllerException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
} catch (UserStoreException ex) {
return Response.status(500).entity(ex.getMessage()).build();
}
}
@Path("devices/generate_link")
@GET
public Response generateSketchLink(@QueryParam("deviceName") String deviceName,
@QueryParam("sketchType") String sketchType) {
try {
ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName, sketchType);
Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId());
return rb.build();
} catch (IllegalArgumentException ex) {
return Response.status(400).entity(ex.getMessage()).build();//bad request
} catch (DeviceManagementException ex) {
return Response.status(500).entity(ex.getMessage()).build();
} catch (JWTClientException ex) {
return Response.status(500).entity(ex.getMessage()).build();
} catch (APIManagerException ex) {
return Response.status(500).entity(ex.getMessage()).build();
} catch (DeviceControllerException ex) {
return Response.status(500).entity(ex.getMessage()).build();
} catch (UserStoreException ex) {
log.error(ex.getMessage(), ex);
return Response.status(500).entity(ex.getMessage()).build();
}
}
@ -215,8 +227,12 @@ public class VirtualFireAlarmManagerServiceImpl implements VirtualFireAlarmManag
enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser());
device.setEnrolmentInfo(enrolmentInfo);
boolean added = APIUtil.getDeviceManagementService().enrollDevice(device);
if (added) {
APIUtil.registerApiAccessRoles(APIUtil.getAuthenticatedUser());
}
return added;
} catch (DeviceManagementException e) {
log.error(e.getMessage(), e);
return false;
}
}

@ -22,6 +22,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
@ -33,9 +34,9 @@ import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig;
import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException;
import org.wso2.carbon.device.mgt.iot.transport.mqtt.MQTTTransportHandler;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.APIUtil;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.identity.jwt.client.extension.JWTClient;
@ -47,7 +48,6 @@ import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Calendar;
import java.util.UUID;
/**
@ -73,6 +73,8 @@ public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler {
private static String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5);
private static final String KEY_TYPE = "PRODUCTION";
private static final String EMPTY_STRING = "";
private static final String JSON_SERIAL_KEY = "SerialNumber";
private static final String JSON_TENANT_KEY = "Tenant";
/**
* Default constructor for the VirtualFirealarmMQTTConnector.
@ -99,7 +101,8 @@ public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler {
String applicationUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm()
.getRealmConfiguration().getAdminUserName();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(applicationUsername);
APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService();
APIManagementProviderService apiManagementProviderService = APIUtil
.getAPIManagementProviderService();
String[] tags = {VirtualFireAlarmConstants.DEVICE_TYPE};
ApiApplicationKey apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys(
VirtualFireAlarmConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true);
@ -156,17 +159,34 @@ public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler {
if (log.isDebugEnabled()) {
log.debug("Received MQTT message for: [DEVICE.ID-" + deviceId + "]");
}
JSONObject jsonPayload = new JSONObject(mqttMessage.toString());
String actualMessage;
try {
String tenantDomain = (String) jsonPayload.get(JSON_TENANT_KEY);
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceManagementProviderService deviceManagementProviderService =
(DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class,
null);
ctx.setTenantDomain(tenantDomain, true);
if (deviceManagementProviderService != null) {
DeviceIdentifier identifier = new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE);
Device device = deviceManagementProviderService.getDevice(identifier);
if (device != null) {
String owner = device.getEnrolmentInfo().getOwner();
ctx.setUsername(owner);
} else {
return;
}
}
Long serialNo = (Long)jsonPayload.get(JSON_SERIAL_KEY);
// the hash-code of the deviceId is used as the alias for device certificates during SCEP enrollment.
// hence, the same is used here to fetch the device-specific-certificate from the key store.
PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();
PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey("" + serialNo);
// the MQTT-messages from VirtualFireAlarm devices are in the form {"Msg":<MESSAGE>, "Sig":<SIGNATURE>}
actualMessage = VirtualFireAlarmServiceUtils.extractMessageFromPayload(mqttMessage.toString(),
serverPrivateKey,
clientPublicKey);
if (log.isDebugEnabled()) {
log.debug("MQTT: Received Message [" + actualMessage + "] topic: [" + topic + "]");
@ -174,30 +194,8 @@ public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler {
if (actualMessage.contains("PUBLISHER")) {
float temperature = Float.parseFloat(actualMessage.split(":")[2]);
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceManagementProviderService deviceManagementProviderService =
(DeviceManagementProviderService) ctx
.getOSGiService(DeviceManagementProviderService.class, null);
if (deviceManagementProviderService != null) {
DeviceIdentifier identifier = new DeviceIdentifier(deviceId,
VirtualFireAlarmConstants.DEVICE_TYPE);
Device device = deviceManagementProviderService.getDevice(identifier);
if (device != null) {
String owner = device.getEnrolmentInfo().getOwner();
ctx.setTenantDomain(MultitenantUtils.getTenantDomain(owner), true);
ctx.setUsername(owner);
if (!VirtualFireAlarmServiceUtils.publishToDAS(deviceId, temperature)) {
log.error("MQTT Subscriber: Publishing data to DAS failed.");
}
}
}
} catch (DeviceManagementException e) {
log.error("Failed to retreive the device managment service for device type " +
VirtualFireAlarmConstants.DEVICE_TYPE, e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
if (!VirtualFireAlarmServiceUtils.publishToDAS(deviceId, temperature)) {
log.error("MQTT Subscriber: Publishing data to DAS failed.");
}
if (log.isDebugEnabled()) {
log.debug("MQTT Subscriber: Published data to DAS successfully.");
@ -210,6 +208,11 @@ public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler {
String errorMsg =
"CertificateManagementService failure oo Signature-Verification/Decryption was unsuccessful.";
log.error(errorMsg, e);
} catch (DeviceManagementException e) {
log.error("Failed to retreive the device managment service for device type " +
VirtualFireAlarmConstants.DEVICE_TYPE, e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
} else {
String errorMsg =
@ -225,39 +228,30 @@ public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler {
*/
@Override
public void publishDeviceData(String... publishData) throws TransportHandlerException {
if (publishData.length != 4) {
if (publishData.length != 3) {
String errorMsg = "Incorrect number of arguments received to SEND-MQTT Message. " +
"Need to be [owner, deviceId, resource{BULB/TEMP}, state{ON/OFF or null}]";
log.error(errorMsg);
throw new TransportHandlerException(errorMsg);
}
String deviceOwner = publishData[0];
String deviceId = publishData[1];
String resource = publishData[2];
String state = publishData[3];
String deviceId = publishData[0];
String resource = publishData[1];
String state = publishData[2];
MqttMessage pushMessage = new MqttMessage();
String publishTopic = "wso2/" + VirtualFireAlarmConstants.DEVICE_TYPE + "/" + deviceId;
try {
PublicKey devicePublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();
String actualMessage = resource + ":" + state;
String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage,
devicePublicKey,
serverPrivateKey);
String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage, serverPrivateKey);
pushMessage.setPayload(encryptedMsg.getBytes(StandardCharsets.UTF_8));
pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE);
pushMessage.setRetained(false);
publishToQueue(publishTopic, pushMessage);
} catch (VirtualFireAlarmException e) {
String errorMsg = "Preparing Secure payload failed for device - [" + deviceId + "] of owner - " +
"[" + deviceOwner + "].";
String errorMsg = "Preparing Secure payload failed for device - [" + deviceId + "]";
log.error(errorMsg);
throw new TransportHandlerException(errorMsg, e);
}

@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.transport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.packet.Message;
import org.json.JSONObject;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppAccount;
import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig;
@ -29,15 +30,14 @@ import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException;
import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException;
import org.wso2.carbon.device.mgt.iot.transport.xmpp.XMPPTransportHandler;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.SecurityManager;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util.VirtualFireAlarmServiceUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Calendar;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@ -52,6 +52,7 @@ public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler {
private static String xmppVFireAlarmAdminAccountJID;
private static final String V_FIREALARM_XMPP_PASSWORD = "vfirealarm@123";
private static final String DEVICEMGT_CONFIG_FILE = "devicemgt-config.xml";
private static final String JSON_SERIAL_KEY = "SerialNumber";
private ScheduledFuture<?> connectorServiceHandler;
private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
@ -155,9 +156,15 @@ public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler {
}
try {
PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();
String actualMessage = VirtualFireAlarmServiceUtils.extractMessageFromPayload(message, serverPrivateKey,
PrivilegedCarbonContext.startTenantFlow();
String tenantDomain = MultitenantUtils.getTenantDomain(owner);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(owner);
JSONObject jsonPayload = new JSONObject(message);
Long serialNo = (Long)jsonPayload.get(JSON_SERIAL_KEY);
PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey("" + serialNo);
String actualMessage = VirtualFireAlarmServiceUtils.extractMessageFromPayload(message,
clientPublicKey);
if (log.isDebugEnabled()) {
log.debug("XMPP: Received Message [" + actualMessage + "] from: [" + from + "]");
@ -166,10 +173,6 @@ public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler {
switch (subject) {
case "PUBLISHER":
float temperature = Float.parseFloat(actualMessage.split(":")[1]);
PrivilegedCarbonContext.startTenantFlow();
String tenantDomain = MultitenantUtils.getTenantDomain(owner);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(owner);
if (!VirtualFireAlarmServiceUtils.publishToDAS(deviceId, temperature)) {
log.error("XMPP Connector: Publishing VirtualFirealarm data to DAS failed.");
}
@ -194,6 +197,8 @@ public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler {
String errorMsg =
"CertificateManagementService failure oo Signature-Verification/Decryption was unsuccessful.";
log.error(errorMsg, e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
} else {
log.warn("Received XMPP message from client with unexpected JID [" + from + "].");
@ -215,14 +220,9 @@ public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler {
String state = publishData[3];
try {
PublicKey devicePublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId);
PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey();
String actualMessage = resource + ":" + state;
String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage,
devicePublicKey,
serverPrivateKey);
String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage, serverPrivateKey);
String clientToConnect = deviceId + "@" + xmppServerIP + File.separator + deviceOwner;
sendXMPPMessage(clientToConnect, encryptedMsg, "CONTROL-REQUEST");

@ -13,9 +13,13 @@ import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.dto.SensorRecord;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.service.RealmService;
import java.util.ArrayList;
import java.util.HashMap;
@ -63,7 +67,8 @@ public class APIUtil {
return analyticsDataAPI;
}
public static List<SensorRecord> getAllEventsForDevice(String tableName, String query, List<SortByField> sortByFields) throws AnalyticsException {
public static List<SensorRecord> getAllEventsForDevice(String tableName, String query,
List<SortByField> sortByFields) throws AnalyticsException {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
AnalyticsDataAPI analyticsDataAPI = getAnalyticsDataAPI();
int eventCount = analyticsDataAPI.searchCount(tenantId, tableName, query);
@ -159,4 +164,52 @@ public class APIUtil {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
return threadLocalCarbonContext.getTenantDomain();
}
public static UserStoreManager getUserStoreManager() {
RealmService realmService;
UserStoreManager userStoreManager;
try {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
realmService = (RealmService) ctx.getOSGiService(RealmService.class, null);
if (realmService == null) {
String msg = "Realm service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
int tenantId = ctx.getTenantId();
userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager();
} catch (UserStoreException e) {
String msg = "Error occurred while retrieving current user store manager";
log.error(msg, e);
throw new IllegalStateException(msg);
}
return userStoreManager;
}
public static void registerApiAccessRoles(String user) {
UserStoreManager userStoreManager = null;
try {
userStoreManager = getUserStoreManager();
if (userStoreManager != null) {
String[] userList = new String[]{user};
if (!userStoreManager.isExistingRole(Constants.DEFAULT_ROLE_NAME)) {
userStoreManager.addRole(Constants.DEFAULT_ROLE_NAME, userList, Constants.DEFAULT_PERMISSION);
}
}
} catch (UserStoreException e) {
log.error("Error while creating a role and adding a user for virtual_firealarm.", e);
}
}
public static DeviceAccessAuthorizationService getDeviceAccessAuthorizationService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceAccessAuthorizationService deviceAccessAuthorizationService =
(DeviceAccessAuthorizationService) ctx.getOSGiService(DeviceAccessAuthorizationService.class, null);
if (deviceAccessAuthorizationService == null) {
String msg = "Device Authorization service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceAccessAuthorizationService;
}
}

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util;
import org.wso2.carbon.user.core.Permission;
/**
* This hold the constants related to the device type.
*/
public class Constants {
public static final String DEFAULT_PERMISSION_RESOURCE = "/permission/admin/device-mgt/virtual_firealarm/user";
public static final String DEFAULT_ROLE_NAME = "virtual_firealarm_user";
public static final Permission DEFAULT_PERMISSION[] = new Permission[]{new Permission(Constants.DEFAULT_PERMISSION_RESOURCE,
"ui.execute")};
}

@ -18,6 +18,7 @@
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.service.impl.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
@ -253,8 +254,6 @@ public class VirtualFireAlarmServiceUtils {
payloadData);
} catch (DataPublisherConfigurationException e) {
return false;
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
return true;
}
@ -264,43 +263,39 @@ public class VirtualFireAlarmServiceUtils {
/**
*
* @param message
* @param encryptionKey
* @param signatureKey
* @return
* @throws VirtualFireAlarmException
*/
public static String prepareSecurePayLoad(String message, Key encryptionKey, PrivateKey signatureKey)
throws VirtualFireAlarmException {
String encryptedMsg = SecurityManager.encryptMessage(message, encryptionKey);
String signedPayload = SecurityManager.signMessage(encryptedMsg, signatureKey);
public static String prepareSecurePayLoad(String message, PrivateKey signatureKey) throws VirtualFireAlarmException {
message = Base64.encodeBase64String(message.getBytes());
String signedPayload = SecurityManager.signMessage(message, signatureKey);
JSONObject jsonPayload = new JSONObject();
jsonPayload.put(JSON_MESSAGE_KEY, encryptedMsg);
jsonPayload.put(JSON_MESSAGE_KEY, message);
jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload);
return jsonPayload.toString();
}
/**
*
* @param message
* @param decryptionKey
* @param verifySignatureKey
* @return
* @throws VirtualFireAlarmException
*/
public static String extractMessageFromPayload(String message, Key decryptionKey, PublicKey verifySignatureKey)
public static String extractMessageFromPayload(String message, PublicKey verifySignatureKey)
throws VirtualFireAlarmException {
String actualMessage;
JSONObject jsonPayload = new JSONObject(message);
Object encryptedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
Object encodedMessage = jsonPayload.get(JSON_MESSAGE_KEY);
Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY);
if (encryptedMessage != null && signedPayload != null) {
if (encodedMessage != null && signedPayload != null) {
if (SecurityManager.verifySignature(
encryptedMessage.toString(), signedPayload.toString(), verifySignatureKey)) {
actualMessage = SecurityManager.decryptMessage(encryptedMessage.toString(), decryptionKey);
encodedMessage.toString(), signedPayload.toString(), verifySignatureKey)) {
actualMessage = new String(Base64.decodeBase64(encodedMessage.toString()));
//SecurityManager.decryptMessage(encryptedMessage.toString(), decryptionKey);
} else {
String errorMsg = "The message was not signed by a valid client. Could not verify signature on payload";
throw new VirtualFireAlarmException(errorMsg);
@ -316,17 +311,13 @@ public class VirtualFireAlarmServiceUtils {
/**
*
* @param deviceId
* @param alias
* @return
* @throws VirtualFireAlarmException
*/
public static PublicKey getDevicePublicKey(String deviceId) throws VirtualFireAlarmException {
public static PublicKey getDevicePublicKey(String alias) throws VirtualFireAlarmException {
PublicKey clientPublicKey;
String alias = "";
try {
alias += deviceId.hashCode();
CertificateManagementService certificateManagementService =
VirtualFireAlarmServiceUtils.getCertificateManagementService();
X509Certificate clientCertificate = (X509Certificate) certificateManagementService.getCertificateByAlias(
@ -348,7 +339,7 @@ public class VirtualFireAlarmServiceUtils {
}
throw new VirtualFireAlarmException(errorMsg, e);
} else {
errorMsg = "An error occurred whilst trying to retrieve certificate for deviceId [" + deviceId +
errorMsg = "An error occurred whilst trying to retrieve certificate for alias [" + alias +
"] with alias: [" + alias + "]";
if(log.isDebugEnabled()){
log.debug(errorMsg);

@ -30,91 +30,64 @@
<!-- Device related APIs -->
<Permission>
<name>Get device</name>
<path>/device-mgt/user/devices/list</path>
<url>/devices/*</url>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/enrollment/devices/*</url>
<method>GET</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Remove device</name>
<path>/device-mgt/user/devices/remove</path>
<url>/devices/*</url>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/enrollment/devices/*</url>
<method>DELETE</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Download device</name>
<path>/device-mgt/user/devices/add</path>
<url>/devices/download</url>
<path>/login</path>
<url>/enrollment/devices/download</url>
<method>GET</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Update device</name>
<path>/device-mgt/user/devices/update</path>
<url>/devices/*</url>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/enrollment/devices/*</url>
<method>POST</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Get Devices</name>
<path>/device-mgt/user/devices</path>
<url>/devices</url>
<method>GET</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Generate Link</name>
<path>/device-mgt/user/devices/generate_link</path>
<url>/devices/generate_link</url>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/enrollment/devices</url>
<method>GET</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Register Device</name>
<path>/device-mgt/user/device/register</path>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/device/register/*/*/*</url>
<method>POST</method>
<scope>virtual_firealarm_device</scope>
</Permission>
<Permission>
<name>Control Buzz</name>
<path>/device-mgt/user/device/buzz</path>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/device/*/buzz</url>
<method>POST</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Get Temperature</name>
<path>/device-mgt/user/device/temperature</path>
<url>/device/*/temperature</url>
<method>GET</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Push Temperature</name>
<path>/device-mgt/user/device/temperature</path>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/device/temperature</url>
<method>POST</method>
<scope>virtual_firealarm_device</scope>
</Permission>
<Permission>
<name>Get SCEP</name>
<path>/device-mgt/user/device/scep</path>
<url>/device/scep</url>
<method>GET</method>
<scope>virtual_firealarm_user</scope>
</Permission>
<Permission>
<name>Push SCEP</name>
<path>/device-mgt/user/device/scep</path>
<url>/device/scep</url>
<method>POST</method>
<scope>virtual_firealarm_device</scope>
</Permission>
<Permission>
<name>Get Stats</name>
<path>/device-mgt/user/device/stats</path>
<path>/device-mgt/virtual_firealarm/user</path>
<url>/device/stats/*/sensors/*</url>
<method>GET</method>
<scope>virtual_firealarm_device</scope>

@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>virtual-fire-alarm-plugin</artifactId>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<version>2.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.api</artifactId>
<packaging>war</packaging>
<name>WSO2 Carbon - IoT Server SCEP Server API</name>
<description>WSO2 Carbon - Virtual FireAlarm SCEP Server API Implementation</description>
<url>http://wso2.org</url>
<dependencies>
<!-- CDM -->
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.certificate.mgt.core</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>commons-codec.wso2</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<scope>provided</scope>
</dependency>
<!--JAX-RS -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-httpclient.wso2</groupId>
<artifactId>commons-httpclient</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bouncycastle.wso2</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.user.api</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.queuing</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.base</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2</artifactId>
</exclusion>
<exclusion>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smack</artifactId>
</exclusion>
<exclusion>
<groupId>org.igniterealtime.smack.wso2</groupId>
<artifactId>smackx</artifactId>
</exclusion>
<exclusion>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
</exclusion>
<exclusion>
<groupId>commons-fileupload.wso2</groupId>
<artifactId>commons-fileupload</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant.wso2</groupId>
<artifactId>ant</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant.wso2</groupId>
<artifactId>ant</artifactId>
</exclusion>
<exclusion>
<groupId>commons-httpclient.wso2</groupId>
<artifactId>commons-httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.equinox</groupId>
<artifactId>javax.servlet</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.registry.api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-codec.wso2</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>${wso2.maven.compiler.source}</source>
<target>${wso2.maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>virtual_firealarm_scep</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.InputStream;
public interface VirtualFireAlarmScepServer {
/**
* This is an API called/used by the SCEP Client of the VirtualFirealarm device in its SCEP enrollment process.
* This acts as the endpoint exposed as part of the SCEP-Server for use by a SCEP Client. This is one of the two
* method-signatures that takes different parameters according to the SCEP-Operation executed by the SCEP-Client
* of the enrolling device. The API supports 2 SCEP Operations [GetCACert] and [GetCACaps].
* <p/>
* Operation [GetCACert] returns the CA cert of the SCEP-Server for the device to verify its authenticity.
* Operation [GetCACaps] returns the CA Capabilities of the SCEP-Server.
*
* @param operation the SCEP operation requested by the client. [GetCACert] or [GetCACaps]
* @param message any messages pertaining to the requested SCEP Operation.
* @return an HTTP Response object with either the CA-Cert or the CA-Capabilities according to the operation.
*/
@GET
@Path("scep")
Response scepRequest(@QueryParam("operation") String operation, @QueryParam("message") String message);
/**
* This is an API called/used by the SCEP Client of the VirtualFirealarm device in its SCEP enrollment process.
* This acts as the endpoint exposed as part of the SCEP-Server for use by a SCEP Client. This is one of the two
* method-signatures that takes different parameters according to the SCEP-Operation executed by the SCEP-Client
* of the enrolling device. This API supports the SCEP Operation [PKIOperation].
* <p/>
* Operation [PKIOperation] returns a certificate generated by the SCEP-Server for the enrolling device.
*
* @param operation the final SCEP operation executed in the enrollment process - which is [PKIOperation]
* @param inputStream an input stream consisting of the Certificate-Signing-Request (CSR) from the device.
* @return an HTTP Response object with the signed certificate for the device by the CA of the SCEP Server.
*/
@POST
@Path("scep")
Response scepRequestPost(@QueryParam("operation") String operation, InputStream inputStream);
}

@ -0,0 +1,136 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.device.mgt.iot.virtualfirealarm.scep.service.impl.exception.VirtualFireAlarmException;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.util.scep.ContentType;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.util.scep.SCEPOperation;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.util.VirtualFireAlarmServiceUtils;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
@SuppressWarnings("Non-Annoted WebService")
public class VirtualFireAlarmScepServerImpl implements VirtualFireAlarmScepServer {
private static Log log = LogFactory.getLog(VirtualFireAlarmScepServerImpl.class);
@GET
@Path("scep")
public Response scepRequest(@QueryParam("operation") String operation, @QueryParam("message") String message) {
if (log.isDebugEnabled()) {
log.debug("Invoking SCEP operation " + operation);
}
if (SCEPOperation.GET_CA_CERT.getValue().equals(operation)) {
if (log.isDebugEnabled()) {
log.debug("Invoking GetCACert");
}
try {
CertificateManagementService certificateManagementService =
VirtualFireAlarmServiceUtils.getCertificateManagementService();
SCEPResponse scepResponse = certificateManagementService.getCACertSCEP();
Response.ResponseBuilder responseBuilder;
switch (scepResponse.getResultCriteria()) {
case CA_CERT_FAILED:
log.error("CA cert failed");
responseBuilder = Response.serverError();
break;
case CA_CERT_RECEIVED:
if (log.isDebugEnabled()) {
log.debug("CA certificate received in GetCACert");
}
responseBuilder = Response.ok(scepResponse.getEncodedResponse(),
ContentType.X_X509_CA_CERT);
break;
case CA_RA_CERT_RECEIVED:
if (log.isDebugEnabled()) {
log.debug("CA and RA certificates received in GetCACert");
}
responseBuilder = Response.ok(scepResponse.getEncodedResponse(),
ContentType.X_X509_CA_RA_CERT);
break;
default:
log.error("Invalid SCEP request");
responseBuilder = Response.serverError();
break;
}
return responseBuilder.build();
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the VirtualFireAlarm device", e);
} catch (KeystoreException e) {
log.error("Keystore error occurred while enrolling the VirtualFireAlarm device", e);
}
} else if (SCEPOperation.GET_CA_CAPS.getValue().equals(operation)) {
if (log.isDebugEnabled()) {
log.debug("Invoking GetCACaps");
}
try {
CertificateManagementService certificateManagementService = VirtualFireAlarmServiceUtils.
getCertificateManagementService();
byte caCaps[] = certificateManagementService.getCACapsSCEP();
return Response.ok(caCaps, MediaType.TEXT_PLAIN).build();
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the device", e);
}
} else {
log.error("Invalid SCEP operation " + operation);
}
return Response.serverError().build();
}
@POST
@Path("scep")
public Response scepRequestPost(@QueryParam("operation") String operation, InputStream inputStream) {
if (log.isDebugEnabled()) {
log.debug("Invoking SCEP operation " + operation);
}
if (SCEPOperation.PKI_OPERATION.getValue().equals(operation)) {
if (log.isDebugEnabled()) {
log.debug("Invoking PKIOperation");
}
try {
CertificateManagementService certificateManagementService = VirtualFireAlarmServiceUtils.
getCertificateManagementService();
byte pkiMessage[] = certificateManagementService.getPKIMessageSCEP(inputStream);
return Response.ok(pkiMessage, ContentType.X_PKI_MESSAGE).build();
} catch (VirtualFireAlarmException e) {
log.error("Error occurred while enrolling the device", e);
} catch (KeystoreException e) {
log.error("Keystore error occurred while enrolling the device", e);
}
}
return Response.serverError().build();
}
}

@ -0,0 +1,31 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.exception;
public class VirtualFireAlarmException extends Exception {
private static final long serialVersionUID = 118512086957330189L;
public VirtualFireAlarmException(String errorMessage) {
super(errorMessage);
}
public VirtualFireAlarmException(String errorMessage, Throwable throwable) {
super(errorMessage, throwable);
}
}

@ -0,0 +1,103 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.util;
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.service.CertificateManagementService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.exception.VirtualFireAlarmException;
import java.lang.*;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
/**
*
*/
public class VirtualFireAlarmServiceUtils {
private static final Log log = LogFactory.getLog(VirtualFireAlarmServiceUtils.class);
/**
*
* @return
* @throws VirtualFireAlarmException
*/
public static CertificateManagementService getCertificateManagementService() throws VirtualFireAlarmException {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
CertificateManagementService certificateManagementService = (CertificateManagementService)
ctx.getOSGiService(CertificateManagementService.class, null);
if (certificateManagementService == null) {
String msg = "EnrollmentService is not initialized";
log.error(msg);
throw new VirtualFireAlarmException(msg);
}
return certificateManagementService;
}
/**
*
* @param deviceId
* @return
* @throws VirtualFireAlarmException
*/
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.";
if(log.isDebugEnabled()){
log.debug(errorMsg);
}
throw new VirtualFireAlarmException(errorMsg, e);
} catch (KeystoreException e) {
String errorMsg;
if (e.getMessage().contains("NULL_CERT")) {
errorMsg = "The Device-View page might have been accessed prior to the device being started.";
if(log.isDebugEnabled()){
log.debug(errorMsg);
}
throw new VirtualFireAlarmException(errorMsg, e);
} else {
errorMsg = "An error occurred whilst trying to retrieve certificate for deviceId [" + deviceId +
"] with alias: [" + alias + "]";
if(log.isDebugEnabled()){
log.debug(errorMsg);
}
throw new VirtualFireAlarmException(errorMsg, e);
}
}
return clientPublicKey;
}
}

@ -0,0 +1,26 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.util.scep;
public class ContentType {
public static final String X_PKI_MESSAGE = "application/x-pki-message";
public static final String X_X509_CA_CERT = "application/x-x509-ca-cert";
public static final String X_X509_CA_RA_CERT = "application/x-x509-ca-ra-cert";
}

@ -0,0 +1,39 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.util.scep;
public enum SCEPOperation {
GET_CA_CERT("GetCACert"),
GET_CA_CAPS("GetCACaps"),
PKI_OPERATION("PKIOperation");
private String value;
private SCEPOperation(String value) {
this.setValue(value);
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
~ Copyright 2005-2013 WSO2, Inc. (http://wso2.com)
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!--
This file defines class loading policy of the whole container. But this behaviour can be overridden by individual webapps by putting this file into the META-INF/ directory.
-->
<Classloading xmlns="http://wso2.org/projects/as/classloading">
<!-- Parent-first or child-first. Default behaviour is child-first.-->
<ParentFirst>false</ParentFirst>
<!--
Default environments that contains provides to all the webapps. This can be overridden by individual webapps by specifing required environments
Tomcat environment is the default and every webapps gets it even if they didn't specify it.
e.g. If a webapps requires CXF, they will get both Tomcat and CXF.
-->
<Environments>CXF,Carbon</Environments>
</Classloading>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except
~ in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<jaxrs:server id="VirtualFireAlarmScepServer" address="/">
<jaxrs:serviceBeans>
<bean id="VirtualFireAlarmScepServerService"
class="org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.service.impl.VirtualFireAlarmScepServerImpl">
</bean>
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
</beans>

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
metadata-complete="true">
<display-name>WSO2 IoT Server</display-name>
<description>WSO2 IoT Server</description>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>isAdminService</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>doAuthentication</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>isSharedWithAllTenants</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>providerTenantDomain</param-name>
<param-value>carbon.super</param-value>
</context-param>
<!--publish to apim-->
<context-param>
<param-name>managed-api-enabled</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>managed-api-owner</param-name>
<param-value>admin</param-value>
</context-param>
</web-app>

@ -15,7 +15,7 @@
Operations
</div>
<div class="add-margin-top-4x">
{{unit "iot.unit.device.operation-bar" device=device}}
{{unit "iot.unit.device.operation-bar" device=device backendApiUri=backendApiUri}}
</div>
{{/zone}}

@ -24,9 +24,8 @@ function onRequest(context) {
if (deviceType != null && deviceType != undefined && deviceId != null && deviceId != undefined) {
var deviceModule = require("/app/modules/device.js").deviceModule;
var device = deviceModule.viewDevice(deviceType, deviceId);
if (device && device.status != "error") {
return {"device": device};
return {"device": device, "backendApiUri" : devicemgtProps["httpsURL"] + "/virtual_firealarm/"};
} else {
response.sendError(404, "Device Id " + deviceId + " of type " + deviceType + " cannot be found!");
exit();

@ -140,10 +140,6 @@ function downloadAgent() {
$('#downloadForm').submit();
hideAgentDownloadPopup();
$(modalPopupContent).html($('#device-agent-downloading-content').html());
showAgentDownloadPopup();
setTimeout(function () {
hideAgentDownloadPopup();
}, 1000);
} else {
$("#invalid-username-error-msg span").text("Invalid device name");
$("#invalid-username-error-msg").removeClass("hidden");

@ -38,6 +38,7 @@
<module>org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl</module>
<module>org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl</module>
<module>org.wso2.carbon.device.mgt.iot.virtualfirealarm.api</module>
<module>org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.api</module>
</modules>
<build>

@ -9,9 +9,6 @@ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../featur
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.androidsense_${feature.version}/datasources/,target:${installFolder}/../../conf/datasources/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/jaggeryapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.androidsense_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/android_sense/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.androidsense_${feature.version}/agent/,target:${installFolder}/../../resources/sketches/android_sense/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.androidsense_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\

@ -36,10 +36,10 @@
<Enabled>false</Enabled>
<ControlClass>org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient</ControlClass>
<Protocol>XMPP</Protocol>
<ServerURL>http://204.232.188.215</ServerURL>
<ServerURL>http://localhost</ServerURL>
<Port>9090</Port>
<Username>admin</Username>
<Password>wso2iot123</Password>
<Password>admin</Password>
</ControlQueue>
</ControlQueues>
</DeviceManagementConfigurations>

@ -46,6 +46,11 @@
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.api</artifactId>
<type>war</type>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.api</artifactId>
<type>war</type>
</dependency>
<dependency>
<groupId>com.h2database.wso2</groupId>
<artifactId>h2-database-engine</artifactId>
@ -124,6 +129,15 @@
<outputDirectory>${project.build.directory}/maven-shared-archive-resources/webapps/</outputDirectory>
<destFileName>virtual_firealarm.war</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.api
</artifactId>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/maven-shared-archive-resources/webapps/</outputDirectory>
<destFileName>virtual_firealarm_scep.war</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>

@ -20,7 +20,8 @@ server-name=${SERVER_NAME}
owner=${DEVICE_OWNER}
deviceId=${DEVICE_ID}
device-name=${DEVICE_NAME}
controller-context=/virtual_firealarm/controller
controller-context=/virtual_firealarm/device
scep-context=/virtual_firealarm_scep
https-ep=${HTTPS_EP}
http-ep=${HTTP_EP}
apim-ep=${APIM_EP}

@ -20,7 +20,8 @@ server-name=${SERVER_NAME}
owner=${DEVICE_OWNER}
deviceId=${DEVICE_ID}
device-name=${DEVICE_NAME}
controller-context=/virtual_firealarm/controller
controller-context=/virtual_firealarm/device
scep-context=/virtual_firealarm_scep
https-ep=${HTTPS_EP}
http-ep=${HTTP_EP}
apim-ep=${APIM_EP}

@ -2,7 +2,7 @@
"deviceType": {
"label": "Virtual Firealarm",
"category": "virtual",
"downloadAgentLinkGenUri": "manager/device/virtual_firealarm/generate_link"
"downloadAgentUri": "virtual_firealarm/enrollment/devices/download"
},
"analyticStreams": [
{

@ -19,6 +19,8 @@ instructions.unconfigure = \
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../conf/device-types/virtual_firealarm.json);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm.war);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm_scep.war);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/virtual_firealarm_scep);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../dbscripts/cdm/plugins/virtual_firealarm);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../resources/sketches/virtual_firealarm);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../resources/sketches/virtual_firealarm_advanced);\

@ -423,6 +423,12 @@
<version>${carbon.devicemgt.plugins.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>org.wso2.carbon.device.mgt.iot.virtualfirealarm.scep.api</artifactId>
<version>${carbon.devicemgt.plugins.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId>

Loading…
Cancel
Save