Add configuration retrieve endpoint

revert-70aa11f8
Pahansith 5 years ago
parent 9f7addebef
commit a3f44b43b4

@ -0,0 +1,277 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
~
~ Entgra (Pvt) Ltd. 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/maven-v4_0_0.xsd">
<parent>
<artifactId>device-mgt</artifactId>
<groupId>org.wso2.carbon.devicemgt</groupId>
<version>3.2.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>io.entgra.carbon.device.mgt.config.api</artifactId>
<packaging>war</packaging>
<name>Entgra Carbon - Mobile Device Management Configuration API</name>
<description>Entgra Carbon - Mobile Device Management Configuration API</description>
<url>https://entgra.io</url>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingExcludes>WEB-INF/lib/*cxf*.jar</packagingExcludes>
<warName>api#device-mgt-config#v1.0</warName>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<destFile>${basedir}/target/coverage-reports/jacoco-unit.exec</destFile>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${basedir}/target/coverage-reports/jacoco-unit.exec</dataFile>
<outputDirectory>${basedir}/target/coverage-reports/site</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<log4j.configuration>file:src/test/resources/log4j.properties</log4j.configuration>
</systemPropertyVariables>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>deploy</id>
<build>
<defaultGoal>compile</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy todir="${basedir}/../../../repository/deployment/server/webapps" overwrite="true">
<fileset dir="${basedir}/target">
<include name="api#device-mgt-config#v1.0.war" />
</fileset>
</copy>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>client</id>
<build>
<defaultGoal>test</defaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<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>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</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>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
<exclusion>
<groupId>javassist</groupId>
<artifactId>javassist</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>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.user.mgt</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.orbit.com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.orbit.com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.apimgt.annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.identity.jwt.client.extension</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.wso2.tomcat</groupId>
<artifactId>tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.wso2.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

@ -0,0 +1,50 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ApiOriginFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
}
public void destroy() {
//do nothing
}
public void init(FilterConfig filterConfig) throws ServletException {
//do nothing
}
}

@ -0,0 +1,77 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs.beans;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotNull;
@ApiModel(description = "")
public class ErrorListItem {
@NotNull
private String code = null;
@NotNull
private String message = null;
@ApiModelProperty(required = true, value = "")
@JsonProperty("code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public ErrorListItem() {}
public ErrorListItem(String code, String msg) {
this.code = code;
this.message = msg;
}
/**
* Description about individual errors occurred
**/
@ApiModelProperty(required = true, value = "Description about individual errors occurred")
@JsonProperty("message")
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("errorItem {\n");
sb.append(" code: ").append(code).append("\n");
sb.append(" message: ").append(message).append("\n");
sb.append("}\n");
return sb.toString();
}
}

@ -0,0 +1,150 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs.beans;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.ArrayList;
import java.util.List;
@ApiModel(description = "")
public class ErrorResponse {
private Long code = null;
private String message = null;
private String description = null;
private String moreInfo = null;
private List<ErrorListItem> errorItems = new ArrayList<>();
public ErrorResponse() {}
@JsonProperty(value = "code")
@ApiModelProperty(required = true, value = "")
public Long getCode() {
return code;
}
public void setCode(Long code) {
this.code = code;
}
@JsonProperty(value = "message")
@ApiModelProperty(required = true, value = "ErrorResponse message.")
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@JsonProperty(value = "description")
@ApiModelProperty(value = "A detail description about the error message.")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@JsonProperty(value = "moreInfo")
@ApiModelProperty(value = "Preferably an url with more details about the error.")
public String getMoreInfo() {
return moreInfo;
}
public void setMoreInfo(String moreInfo) {
this.moreInfo = moreInfo;
}
public void addErrorListItem(ErrorListItem item) {
this.errorItems.add(item);
}
/**
* If there are more than one error list them out. For example, list out validation errors by each field.
*/
@JsonProperty(value = "errorItems")
@ApiModelProperty(value = "If there are more than one error list them out. \n" +
"For example, list out validation errors by each field.")
public List<ErrorListItem> getErrorItems() {
return errorItems;
}
public void setErrorItems(List<ErrorListItem> error) {
this.errorItems = error;
}
public static class ErrorResponseBuilder {
private Long code = null;
private String message = null;
private String description = null;
private String moreInfo = null;
private List<ErrorListItem> error;
public ErrorResponseBuilder() {
this.error = new ArrayList<>();
}
public ErrorResponseBuilder setCode(long code) {
this.code = code;
return this;
}
public ErrorResponseBuilder setMessage(String message) {
this.message = message;
return this;
}
public ErrorResponseBuilder setDescription(String description) {
this.description = description;
return this;
}
public ErrorResponseBuilder setMoreInfo(String moreInfo) {
this.moreInfo = moreInfo;
return this;
}
public ErrorResponseBuilder addErrorItem(String code, String msg) {
ErrorListItem item = new ErrorListItem();
item.setCode(code);
item.setMessage(msg);
this.error.add(item);
return this;
}
public ErrorResponse build() {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setCode(code);
errorResponse.setMessage(message);
errorResponse.setErrorItems(error);
errorResponse.setDescription(description);
errorResponse.setMoreInfo(moreInfo);
return errorResponse;
}
}
}

@ -0,0 +1,97 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs.common;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@Provider
@Produces(APPLICATION_JSON)
@Consumes(APPLICATION_JSON)
public class GsonMessageBodyHandler implements MessageBodyWriter<Object>, MessageBodyReader<Object> {
public static final String DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss Z";
private Gson gson;
private static final String UTF_8 = "UTF-8";
public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return true;
}
private Gson getGson() {
if (gson == null) {
final GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.setDateFormat(DATE_FORMAT).create();
}
return gson;
}
public Object readFrom(Class<Object> objectClass, Type type, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, String> stringStringMultivaluedMap,
InputStream entityStream)
throws IOException, WebApplicationException {
InputStreamReader reader = new InputStreamReader(entityStream, "UTF-8");
try {
return getGson().fromJson(reader, type);
} finally {
reader.close();
}
}
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return true;
}
public long getSize(Object o, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return -1;
}
public void writeTo(Object object, Class<?> aClass, Type type, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> stringObjectMultivaluedMap,
OutputStream entityStream)
throws IOException, WebApplicationException {
OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8);
try {
getGson().toJson(object, type, writer);
} finally {
writer.close();
}
}
}

@ -0,0 +1,134 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs.service;
import io.entgra.carbon.device.mgt.config.jaxrs.beans.ErrorResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Extension;
import io.swagger.annotations.ExtensionProperty;
import io.swagger.annotations.Info;
import io.swagger.annotations.ResponseHeader;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.Tag;
import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.common.search.PropertyMap;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@SwaggerDefinition(
info = @Info(
version = "1.0.0",
title = "",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = "name", value = "DeviceManagementConfiguration"),
@ExtensionProperty(name = "context",
value = "/api/device-mgt-config/v1.0/configurations"),
})
}
),
tags = {
@Tag(name = "device_management", description = "")
}
)
@Path("/configurations")
@Api(value = "Device Management Configuration")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Scopes(scopes = {
@Scope(
name = "View configurations",
description = "",
key = "perm:view-configuration",
permissions = {"/device-mgt/platform-configurations/view"}
)
}
)
public interface DeviceManagementConfigService {
@GET
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Getting General device Configurations",
notes = "This API is responsible for send device configuration data to an IOT device when the " +
"device starts provisioning",
tags = "Device Management Configuration"
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the device configurations.",
response = DeviceConfiguration.class,
responseContainer = "List",
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource has been modified " +
"the last time.Used by caches, or in " +
"conditional requests."),
}
),
@ApiResponse(
code = 400,
message = "Bad request.\n The request contains invalid parameters"),
@ApiResponse(
code = 401,
message = "Unauthorized.\n The requested is not authorized"),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while " +
"fetching device configurations.",
response = ErrorResponse.class)
})
Response getConfiguration(@ApiParam(
name = "token",
value = "value for identify an already enrolled and authorized device",
required = true)
@HeaderParam("token")
String token,
@ApiParam(
name = "properties",
value = "The properties list using for query a device",
required = true)
@QueryParam("properties")
String properties);
}

@ -0,0 +1,151 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs.service.impl;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.entgra.carbon.device.mgt.config.jaxrs.beans.ErrorResponse;
import io.entgra.carbon.device.mgt.config.jaxrs.service.DeviceManagementConfigService;
import io.entgra.carbon.device.mgt.config.jaxrs.util.DeviceMgtAPIUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.AppRegistrationCredentials;
import org.wso2.carbon.device.mgt.common.ApplicationRegistrationException;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.AmbiguousConfigurationException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.core.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.Map;
@Path("/configurations")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class DeviceManagementConfigServiceImpl implements DeviceManagementConfigService {
private static final Log log = LogFactory.getLog(DeviceManagementConfigServiceImpl.class);
@Override
@GET
public Response getConfiguration(@HeaderParam("token") String token,
@QueryParam("properties") String properties) {
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
try {
if (token == null || token.isEmpty()) {
String msg = "No valid token property found";
log.error(msg);
return Response.status(Response.Status.UNAUTHORIZED).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()
).build();
}
if (properties == null || properties.isEmpty()) {
String msg = "Devices configuration retrieval criteria cannot be null or empty.";
log.error(msg);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()
).build();
}
ObjectMapper mapper = new ObjectMapper();
properties = parseUriParamsToJSON(properties);
Map<String, String> deviceProps = mapper.readValue(properties,
new TypeReference<Map<String, String>>() {
});
deviceProps.put("token", token);
DeviceConfiguration devicesConfiguration =
dms.getDeviceConfiguration(deviceProps);
setAccessTokenToDeviceConfigurations(devicesConfiguration);
return Response.status(Response.Status.OK).entity(devicesConfiguration).build();
} catch (DeviceManagementException e) {
String msg = "Error occurred while retrieving configurations";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (DeviceNotFoundException e) {
log.error(e.getMessage(), e);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
} catch (AmbiguousConfigurationException e) {
String msg = "Configurations are ambiguous";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (JsonParseException | JsonMappingException e) {
String msg = "Malformed device property structure";
log.error(msg.concat(" ").concat(properties), e);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (IOException e) {
String msg = "Error occurred while parsing query param JSON data";
log.error(msg.concat(" ").concat(properties), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
private String parseUriParamsToJSON(String uriParams) {
uriParams = uriParams.replaceAll("=", "\":\"");
uriParams = uriParams.replaceAll("&", "\",\"");
return "{\"" + uriParams + "\"}";
}
private void setAccessTokenToDeviceConfigurations(DeviceConfiguration devicesConfiguration)
throws DeviceManagementException {
try {
AppRegistrationCredentials credentials =
DeviceManagerUtil.getApplicationRegistrationCredentials(
System.getProperty(DeviceManagementConstants
.ConfigurationManagement.IOT_GATEWAY_HOST),
System.getProperty(DeviceManagementConstants
.ConfigurationManagement.IOT_GATEWAY_HTTPS_PORT),
DeviceManagementConstants.ConfigurationManagement.ADMIN_CREDENTIALS);
AccessTokenInfo accessTokenForAdmin = DeviceManagerUtil.getAccessTokenForDeviceOwner(
DeviceManagementConstants.ConfigurationManagement.SCOPES_FOR_TOKEN,
credentials.getClient_id(), credentials.getClient_secret(),
devicesConfiguration.getDeviceOwner());
devicesConfiguration.setAccessToken(accessTokenForAdmin.getAccessToken());
devicesConfiguration.setRefreshToken(accessTokenForAdmin.getRefreshToken());
} catch (ApplicationRegistrationException e) {
String msg = "Failure on retrieving application registration";
log.error(msg, e);
throw new DeviceManagementException(msg, e);
} catch (JWTClientException e) {
String msg = "Error occurred while creating JWT client : " + e.getMessage();
log.error(msg, e);
throw new DeviceManagementException(msg, e);
}
}
}

@ -0,0 +1,43 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.carbon.device.mgt.config.jaxrs.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
/**
* MDMAPIUtils class provides utility function used by CDM REST-API classes.
*/
public class DeviceMgtAPIUtils {
private static Log log = LogFactory.getLog(DeviceMgtAPIUtils.class);
public static DeviceManagementProviderService getDeviceManagementService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceManagementProviderService deviceManagementProviderService =
(DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null);
if (deviceManagementProviderService == null) {
String msg = "DeviceImpl Management provider service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceManagementProviderService;
}
}

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
~
~ Entgra (Pvt) Ltd. 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.
-->
<!-- This file contains the list of permissions that are associated with URL end points
of the web app. Each permission should contain the name, permission path ,API path
(URL) , HTTP method and OAUTH2 authorization scope (not-required).
When defining dynamic paths for APIs, path variables are denoted by '*' notation.
For ex:
Actual API endpoint: devicemgt_admin/1.0.0/devices/{device-id}
URL to be represented here: /devices/*
NOTE: All the endpoints of the web app should be available in this file. Otherwise
it will result 403 error at the runtime.
-->
<PermissionConfiguration>
<APIVersion></APIVersion>
<!--Permission Tree Name-->
<Permission>
<name>Device Management Configuration</name>
<path>/device-mgt-config</path>
<url>/</url>
<method>GET</method>
</Permission>
</PermissionConfiguration>

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
~ Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
~
~ Entgra (Pvt) Ltd. 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.
-->
<!--
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) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
~
~ Entgra (Pvt) Ltd. 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="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<jaxrs:server id="services-10" address="/">
<jaxrs:serviceBeans>
<ref bean="configManagementService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
<bean id="configManagementService"
class="io.entgra.carbon.device.mgt.config.jaxrs.service.impl.DeviceManagementConfigServiceImpl"/>
<bean id="jsonProvider" class="io.entgra.carbon.device.mgt.config.jaxrs.common.GsonMessageBodyHandler"/>
</beans>

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
~
~ Entgra (Pvt) Ltd. 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.
-->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>Device-Config-Webapp</display-name>
<servlet>
<description>JAX-WS/JAX-RS Device Configuration Endpoint</description>
<display-name>JAX-WS/JAX-RS Servlet</display-name>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<!-- configure a security filter -->
<init-param>
<param-name>swagger.security.filter</param-name>
<param-value>ApiAuthorizationFilterImpl</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<context-param>
<param-name>doAuthentication</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>nonSecuredEndPoints</param-name>
<param-value>
/api/device-mgt-config/v1.0/configurations
</param-value>
</context-param>
<!--publish to apim-->
<context-param>
<param-name>managed-api-enabled</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>managed-api-owner</param-name>
<param-value>admin</param-value>
</context-param>
<context-param>
<param-name>isSharedWithAllTenants</param-name>
<param-value>true</param-value>
</context-param>
<!-- Below configuration is used to redirect http requests to https -->
<security-constraint>
<web-resource-collection>
<web-resource-name>DeviceMgt-Admin</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<filter>
<filter-name>ApiOriginFilter</filter-name>
<filter-class>io.entgra.carbon.device.mgt.config.jaxrs.ApiOriginFilter</filter-class>
</filter>
<filter>
<filter-name>HttpHeaderSecurityFilter</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<init-param>
<param-name>hstsEnabled</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter>
<filter-name>ContentTypeBasedCachePreventionFilter</filter-name>
<filter-class>org.wso2.carbon.ui.filters.cache.ContentTypeBasedCachePreventionFilter</filter-class>
<init-param>
<param-name>patterns</param-name>
<param-value>text/html" ,application/json" ,text/plain</param-value>
</init-param>
<init-param>
<param-name>filterAction</param-name>
<param-value>enforce</param-value>
</init-param>
<init-param>
<param-name>httpHeaders</param-name>
<param-value>Cache-Control: no-store, no-cache, must-revalidate, private</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HttpHeaderSecurityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>ContentTypeBasedCachePreventionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>ApiOriginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

@ -0,0 +1,23 @@
<!--
~ Copyright (c) 2019, Entgra (Pvt) Ltd. (http://entgra.io) All Rights Reserved.
~
~ Entgra (Pvt) Ltd. 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.
-->
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="DeviceManagementExtensions">
<parameter name="useDefaultListeners" value="false"/>
</suite>

@ -0,0 +1,43 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common;
/**
* Wrap application registration response payload
*/
public class AppRegistrationCredentials {
private String client_id;
private String client_secret;
public String getClient_id() {
return client_id;
}
public void setClient_id(String client_id) {
this.client_id = client_id;
}
public String getClient_secret() {
return client_secret;
}
public void setClient_secret(String client_secret) {
this.client_secret = client_secret;
}
}

@ -0,0 +1,65 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common;
import java.util.List;
/**
* This class is use to wrap and send
* Application registration data to the API publisher
* Use only for application registration doing inside the IoTs
*/
public class ApplicationRegistration {
private String applicationName;
private List<String> tags;
private boolean isAllowedToAllDomains;
private long validityPeriod;
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public boolean isAllowedToAllDomains() {
return isAllowedToAllDomains;
}
public void setAllowedToAllDomains(boolean allowedToAllDomains) {
isAllowedToAllDomains = allowedToAllDomains;
}
public long getValidityPeriod() {
return validityPeriod;
}
public void setValidityPeriod(long validityPeriod) {
this.validityPeriod = validityPeriod;
}
}

@ -0,0 +1,46 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common;
/**
* Throw this if any errors throw when the application registration API calling
*/
public class ApplicationRegistrationException extends Exception {
private static final long serialVersionUID = 4718132518977041928L;
public ApplicationRegistrationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
}
public ApplicationRegistrationException(String message, Throwable cause) {
super(message, cause);
}
public ApplicationRegistrationException(String msg) {
super(msg);
}
public ApplicationRegistrationException() {
super();
}
public ApplicationRegistrationException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,46 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common;
/**
* Throws if any arguments send to an API is wrong or invalid
*/
public class InvalidArgumentException extends Exception {
private static final long serialVersionUID = -2365244687985953509L;
public InvalidArgumentException(String msg, Exception nestedEx) {
super(msg, nestedEx);
}
public InvalidArgumentException(String message, Throwable cause) {
super(message, cause);
}
public InvalidArgumentException(String msg) {
super(msg);
}
public InvalidArgumentException() {
super();
}
public InvalidArgumentException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,25 @@
package org.wso2.carbon.device.mgt.common.configuration.mgt;
public class AmbiguousConfigurationException extends Exception{
private static final long serialVersionUID = 7039039961721642766L;
public AmbiguousConfigurationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
}
public AmbiguousConfigurationException(String message, Throwable cause) {
super(message, cause);
}
public AmbiguousConfigurationException(String msg) {
super(msg);
}
public AmbiguousConfigurationException() {
super();
}
public AmbiguousConfigurationException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,111 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common.configuration.mgt;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
/**
* This class is use to wrap and send device configuration data
* to the device
*/
@ApiModel(value = "DeviceConfiguration", description = "This class carries all information related to " +
"Device configurations required to communicate with " +
"the server")
public class DeviceConfiguration {
@ApiModelProperty(name = "deviceId", value = "ID of the device", required = true)
private int deviceId;
@ApiModelProperty(name = "deviceType", value = "Type of the device", required = true)
private String deviceType;
@ApiModelProperty(name = "tenantDomain", value = "Tenant which the device owned")
private String tenantDomain;
@ApiModelProperty(name = "configurationEntries", value = "Platform Configurations", required = true)
private List<ConfigurationEntry> configurationEntries;
@ApiModelProperty(name = "accessToken", value = "Token that can be use to communicate with the server")
private String accessToken;
@ApiModelProperty(name = "refreshToken", value = "Token that can be use to communicate with the server")
private String refreshToken;
@ApiModelProperty(name = "deviceOwner", value = "Owner of the selected device", required = true)
private String deviceOwner;
public int getDeviceId() {
return deviceId;
}
public void setDeviceId(int deviceId) {
this.deviceId = deviceId;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getTenantDomain() {
return tenantDomain;
}
public void setTenantDomain(String tenantDomain) {
this.tenantDomain = tenantDomain;
}
public List<ConfigurationEntry> getConfigurationEntries() {
return configurationEntries;
}
public void setConfigurationEntries(
List<ConfigurationEntry> configurationEntries) {
this.configurationEntries = configurationEntries;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getDeviceOwner() {
return deviceOwner;
}
public void setDeviceOwner(String deviceOwner) {
this.deviceOwner = deviceOwner;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
}

@ -0,0 +1,63 @@
/*
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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.common.configuration.mgt;
/**
* This bean is use for retrieve and wrap device property info get from DB
*/
public class DevicePropertyInfo {
private String deviceIdentifier = "default";
private String deviceTypeName = "default";
private String tenantId = "default";
public String getDeviceIdentifier() {
return deviceIdentifier;
}
public void setDeviceIdentifier(String deviceIdentifier) {
this.deviceIdentifier = deviceIdentifier;
}
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
public String getDeviceTypeName() {
return deviceTypeName;
}
public void setDeviceTypeName(String deviceTypeName) {
this.deviceTypeName = deviceTypeName;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DevicePropertyInfo) {
DevicePropertyInfo devicePropertyInfo = (DevicePropertyInfo)obj;
return devicePropertyInfo.getDeviceIdentifier().equals(this.deviceIdentifier)
&& devicePropertyInfo.getDeviceTypeName().equals(this.deviceTypeName)
&& devicePropertyInfo.getTenantId().equals(this.tenantId);
}
return false;
}
}

@ -27,6 +27,21 @@ public final class DeviceManagementConstants {
public static final String DEVICE_CACHE = "DEVICE_CACHE"; public static final String DEVICE_CACHE = "DEVICE_CACHE";
public static final String ENROLLMENT_NOTIFICATION_API_ENDPOINT = "/api/device-mgt/enrollment-notification"; public static final String ENROLLMENT_NOTIFICATION_API_ENDPOINT = "/api/device-mgt/enrollment-notification";
public static final class ConfigurationManagement {
private ConfigurationManagement(){
throw new AssertionError();
}
public static final String ADMIN_CREDENTIALS = "admin:admin";
public static final String SCOPES_FOR_TOKEN = "perm:device:operations perm:device:publish-event";
public static final String IOT_GATEWAY_HOST = "iot.gateway.host";
public static final String IOT_GATEWAY_HTTPS_PORT = "iot.gateway.https.port";
public static final String MQTT_ENDPOINTS = "mqttEndpoints";
public static final String APPLICATION_REGISTRATION_API_ENDPOINT =
"/api-application-registration/register";
public static final String AUTHORIZATION_HEADER = "authorization";
public static final String BASIC_AUTH = "Basic";
}
public static final class Common { public static final class Common {
private Common() { private Common() {
throw new AssertionError(); throw new AssertionError();

@ -40,6 +40,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status; import org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status;
import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.geo.GeoCluster; import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
@ -190,6 +191,15 @@ public interface DeviceDAO {
*/ */
List<Device> getDeviceBasedOnDeviceProperties(Map<String, String> deviceProps, int tenantId) throws DeviceManagementDAOException; List<Device> getDeviceBasedOnDeviceProperties(Map<String, String> deviceProps, int tenantId) throws DeviceManagementDAOException;
/**
* Retrieves a list of devices based on a given criteria of properties
* This will ignores the tenant and it will return devices registered under every tenants
* @param deviceProps properties by which devices need to be filtered
* @return list of devices with properties
* @throws DeviceManagementDAOException if the SQL query has failed to be executed
*/
List<DevicePropertyInfo> getDeviceBasedOnDeviceProperties(Map<String, String> deviceProps)
throws DeviceManagementDAOException;
/** /**
* Retrieves properties of given device identifier * Retrieves properties of given device identifier

@ -0,0 +1,28 @@
package org.wso2.carbon.device.mgt.core.dao;
/**
* Throws if the querying device is not found in the DB
*/
public class DeviceNotFoundDAOException extends Exception {
private static final long serialVersionUID = 2126172787830234694L;
public DeviceNotFoundDAOException(String msg, Exception nestedEx) {
super(msg, nestedEx);
}
public DeviceNotFoundDAOException(String message, Throwable cause) {
super(message, cause);
}
public DeviceNotFoundDAOException(String msg) {
super(msg);
}
public DeviceNotFoundDAOException() {
super();
}
public DeviceNotFoundDAOException(Throwable cause) {
super(cause);
}
}

@ -42,6 +42,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status; import org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status;
import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
import org.wso2.carbon.device.mgt.core.dao.DeviceDAO; import org.wso2.carbon.device.mgt.core.dao.DeviceDAO;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
@ -62,6 +63,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.StringJoiner; import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractDeviceDAOImpl implements DeviceDAO { public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
@ -71,6 +73,7 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
private static final String PROPERTY_VALUE_COLUMN_NAME = "PROPERTY_VALUE"; private static final String PROPERTY_VALUE_COLUMN_NAME = "PROPERTY_VALUE";
private static final String PROPERTY_DEVICE_TYPE_NAME = "DEVICE_TYPE_NAME"; private static final String PROPERTY_DEVICE_TYPE_NAME = "DEVICE_TYPE_NAME";
private static final String PROPERTY_DEVICE_IDENTIFICATION = "DEVICE_IDENTIFICATION"; private static final String PROPERTY_DEVICE_IDENTIFICATION = "DEVICE_IDENTIFICATION";
private static final String PROPERTY_TENANT_ID = "TENANT_ID";
@Override @Override
public int addDevice(int typeId, Device device, int tenantId) throws DeviceManagementDAOException { public int addDevice(int typeId, Device device, int tenantId) throws DeviceManagementDAOException {
@ -330,6 +333,65 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
return devices; return devices;
} }
@Override
public List<DevicePropertyInfo> getDeviceBasedOnDeviceProperties(Map<String, String> deviceProps)
throws DeviceManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
ResultSet resultSet = null;
List<DevicePropertyInfo> deviceProperties = new ArrayList<>();
try {
conn = this.getConnection();
List<List<DevicePropertyInfo>> outputLists = new ArrayList<>();
String sql = "SELECT " +
"p.DEVICE_IDENTIFICATION, " +
"p.DEVICE_TYPE_NAME, " +
"p.TENANT_ID FROM " +
"DM_DEVICE_PROPERTIES p ";
String groupByClause = "GROUP BY " +
"p.DEVICE_IDENTIFICATION, " +
"p.DEVICE_TYPE_NAME, " +
"p.TENANT_ID";
AtomicInteger iterationCount = new AtomicInteger(0);
StringBuilder propertyQuery = new StringBuilder(" ");
for (Map.Entry<String, String> stringStringEntry : deviceProps.entrySet()) {
String tempTableId = "t".concat(Integer.toString(iterationCount.getAndIncrement()));
propertyQuery.append("JOIN DM_DEVICE_PROPERTIES ")
.append(tempTableId).append(" ").append("ON p.DEVICE_IDENTIFICATION = ")
.append(tempTableId).append(".DEVICE_IDENTIFICATION ")
.append("AND ")
.append(tempTableId).append(".PROPERTY_NAME = ? ")
.append("AND ")
.append(tempTableId).append(".PROPERTY_VALUE = ? ");
}
sql = sql.concat(propertyQuery.toString()).concat(groupByClause);
stmt = conn.prepareStatement(sql);
int index = 1;
for (Map.Entry<String, String> entry : deviceProps.entrySet()) {
stmt.setString(index++, entry.getKey());
stmt.setString(index++, entry.getValue());
}
resultSet = stmt.executeQuery();
while (resultSet.next()) {
DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo();
devicePropertyInfo
.setDeviceIdentifier(resultSet.getString(PROPERTY_DEVICE_IDENTIFICATION));
devicePropertyInfo.setTenantId(resultSet.getString(PROPERTY_TENANT_ID));
devicePropertyInfo.setDeviceTypeName(resultSet.getString(PROPERTY_DEVICE_TYPE_NAME));
deviceProperties.add(devicePropertyInfo);
}
return deviceProperties;
} catch (SQLException e) {
String msg = "Error occurred while fetching devices against criteria : '" + deviceProps;
log.error(msg, e);
throw new DeviceManagementDAOException(msg, e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, resultSet);
}
}
@Override @Override
public Device getDeviceProps(String deviceId, int tenantId) throws DeviceManagementDAOException { public Device getDeviceProps(String deviceId, int tenantId) throws DeviceManagementDAOException {
Connection conn = null; Connection conn = null;
@ -385,7 +447,6 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
return intersectedResult; return intersectedResult;
} }
@Override @Override
public Device getDevice(String deviceIdentifier, Date since, int tenantId) public Device getDevice(String deviceIdentifier, Date since, int tenantId)
throws DeviceManagementDAOException { throws DeviceManagementDAOException {

@ -38,17 +38,22 @@ package org.wso2.carbon.device.mgt.core.service;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.InvalidArgumentException;
import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.MonitoringOperation; import org.wso2.carbon.device.mgt.common.MonitoringOperation;
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig; import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult; import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.StartupOperationConfig; import org.wso2.carbon.device.mgt.common.StartupOperationConfig;
import org.wso2.carbon.device.mgt.common.UnauthorizedDeviceAccessException;
import org.wso2.carbon.device.mgt.common.UserNotFoundException; import org.wso2.carbon.device.mgt.common.UserNotFoundException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.AmbiguousConfigurationException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.license.mgt.License; import org.wso2.carbon.device.mgt.common.license.mgt.License;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
@ -729,4 +734,19 @@ public interface DeviceManagementProviderService {
boolean updateEnrollment(String owner, List<String> deviceIdentifiers) boolean updateEnrollment(String owner, List<String> deviceIdentifiers)
throws DeviceManagementException, UserNotFoundException, InvalidDeviceException; throws DeviceManagementException, UserNotFoundException, InvalidDeviceException;
/**
* Retrieves a list of configurations of a specific device
* using the device's properties
* @param propertyMap properties by which devices need to be drawn
* @return list of device configuration
* @throws DeviceManagementException if any service level or DAO level error occurs
* @throws DeviceNotFoundException if there is no any device can found for specified properties
* @throws UnauthorizedDeviceAccessException if the required token property is not found on
* @throws AmbiguousConfigurationException if configuration is ambiguous
* the property payload
*/
DeviceConfiguration getDeviceConfiguration(Map<String, String> propertyMap)
throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException,
AmbiguousConfigurationException;
} }

@ -60,6 +60,7 @@ import org.wso2.carbon.device.mgt.common.DeviceTypeNotFoundException;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.FeatureManager; import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.InitialOperationConfig; import org.wso2.carbon.device.mgt.common.InitialOperationConfig;
import org.wso2.carbon.device.mgt.common.InvalidArgumentException;
import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.InvalidDeviceException;
import org.wso2.carbon.device.mgt.common.MonitoringOperation; import org.wso2.carbon.device.mgt.common.MonitoringOperation;
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig; import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
@ -67,9 +68,14 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult; import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.StartupOperationConfig; import org.wso2.carbon.device.mgt.common.StartupOperationConfig;
import org.wso2.carbon.device.mgt.common.TransactionManagementException; import org.wso2.carbon.device.mgt.common.TransactionManagementException;
import org.wso2.carbon.device.mgt.common.UnauthorizedDeviceAccessException;
import org.wso2.carbon.device.mgt.common.UserNotFoundException; import org.wso2.carbon.device.mgt.common.UserNotFoundException;
import org.wso2.carbon.device.mgt.common.app.mgt.Application; import org.wso2.carbon.device.mgt.common.app.mgt.Application;
import org.wso2.carbon.device.mgt.common.configuration.mgt.AmbiguousConfigurationException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo;
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation;
@ -3273,4 +3279,86 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
+ "constructing is failed", e); + "constructing is failed", e);
} }
} }
@Override
public DeviceConfiguration getDeviceConfiguration(Map<String, String> deviceProps)
throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException,
AmbiguousConfigurationException {
if (log.isDebugEnabled()) {
log.debug("Attempting to get device configurations based on properties.");
}
DevicePropertyInfo deviceProperties;
List<DevicePropertyInfo> devicePropertyList;
try {
DeviceManagementDAOFactory.openConnection();
devicePropertyList = deviceDAO.getDeviceBasedOnDeviceProperties(deviceProps);
if (devicePropertyList == null || devicePropertyList.isEmpty()) {
String msg = "Cannot find device for specified properties";
log.info(msg);
throw new DeviceNotFoundException(msg);
}
//In this service, there should be only one device for the specified property values
//If multiple values retrieved, It'll be marked as ambiguous.
if (devicePropertyList.size() > 1) {
String msg = "Device property list contains more than one element";
log.error(msg);
throw new AmbiguousConfigurationException(msg);
}
//Get the only existing value of the list
deviceProperties = devicePropertyList.get(0);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new DeviceManagementException(msg, e);
} catch (DeviceManagementDAOException e) {
String msg = "Devices configuration retrieval criteria cannot be null or empty.";
log.error(msg);
throw new DeviceManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
try {
Device device = this.getDevice(new DeviceIdentifier(deviceProperties.getDeviceIdentifier(),
deviceProperties.getDeviceTypeName()), false);
String owner = device.getEnrolmentInfo().getOwner();
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
ctx.setTenantId(Integer.parseInt(deviceProperties.getTenantId()), true);
PlatformConfiguration configuration = this.getConfiguration(device.getType());
List<ConfigurationEntry> configurationEntries = new ArrayList<>();
if (configuration != null) {
configurationEntries = configuration.getConfiguration();
}
return wrapConfigurations(device, ctx.getTenantDomain(), configurationEntries, owner);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
/**
* Wrap the device configuration data into DeviceConfiguration bean
* @param device Device queried using the properties
* @param tenantDomain tenant domain
* @param configurationEntries platformConfiguration list
* @param deviceOwner name of the device owner
* @return Wrapped {@link DeviceConfiguration} object with data
*/
private DeviceConfiguration wrapConfigurations(Device device,
String tenantDomain,
List<ConfigurationEntry> configurationEntries,
String deviceOwner) {
DeviceConfiguration deviceConfiguration = new DeviceConfiguration();
deviceConfiguration.setDeviceId(device.getId());
deviceConfiguration.setDeviceType(device.getType());
deviceConfiguration.setTenantDomain(tenantDomain);
deviceConfiguration.setConfigurationEntries(configurationEntries);
deviceConfiguration.setDeviceOwner(deviceOwner);
return deviceConfiguration;
}
} }

@ -17,13 +17,25 @@
*/ */
package org.wso2.carbon.device.mgt.core.util; package org.wso2.carbon.device.mgt.core.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.caching.impl.CacheImpl; import org.wso2.carbon.caching.impl.CacheImpl;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService; import org.wso2.carbon.device.mgt.analytics.data.publisher.service.EventsPublisherService;
import org.wso2.carbon.device.mgt.common.AppRegistrationCredentials;
import org.wso2.carbon.device.mgt.common.ApplicationRegistration;
import org.wso2.carbon.device.mgt.common.ApplicationRegistrationException;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.DeviceManagementException;
@ -49,6 +61,10 @@ import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder;
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMgtConstants; import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMgtConstants;
import org.wso2.carbon.device.mgt.core.operation.mgt.util.DeviceIDHolder; import org.wso2.carbon.device.mgt.core.operation.mgt.util.DeviceIDHolder;
import org.wso2.carbon.identity.jwt.client.extension.JWTClient;
import org.wso2.carbon.identity.jwt.client.extension.dto.AccessTokenInfo;
import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
import org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService;
import org.wso2.carbon.user.api.TenantManager; import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.CarbonUtils;
@ -63,9 +79,13 @@ import javax.sql.DataSource;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
@ -588,4 +608,102 @@ public final class DeviceManagerUtil {
} }
return deviceCache; return deviceCache;
} }
/**
* Create an app and get app registration token from the application registration endpoint
*
* @return AppRegistrationToken object which contains access and refresh tokens
* @throws ApplicationRegistrationException when application fails to connect with the app registration
* endpoint
*/
@SuppressWarnings("PackageAccessibility")
public static AppRegistrationCredentials getApplicationRegistrationCredentials(String host, String port,
String credentials)
throws ApplicationRegistrationException {
if (host == null || port == null) {
String msg = "Required gatewayHost or gatewayPort system property is null";
log.error(msg);
throw new ApplicationRegistrationException(msg);
}
String internalServerAddr = "https://".concat(host).concat(":").concat(port);
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpPost apiEndpoint = new HttpPost(
internalServerAddr + DeviceManagementConstants.ConfigurationManagement
.APPLICATION_REGISTRATION_API_ENDPOINT);
apiEndpoint.setHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
apiEndpoint.setHeader(DeviceManagementConstants.ConfigurationManagement.AUTHORIZATION_HEADER,
DeviceManagementConstants.ConfigurationManagement.BASIC_AUTH.concat(" ")
.concat(getBase64EncodedCredentials(credentials)));
apiEndpoint.setEntity(constructApplicationRegistrationPayload());
HttpResponse response = client.execute(apiEndpoint);
if (response != null) {
log.info("Obtained client credentials: " + response.getStatusLine().getStatusCode());
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuilder result = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
result.append(line);
}
return new ObjectMapper().readValue(result.toString(), AppRegistrationCredentials.class);
} else {
String msg = "Response is 'NUll' for the Application Registration API call.";
log.error(msg);
throw new ApplicationRegistrationException(msg);
}
} catch (IOException e) {
throw new ApplicationRegistrationException(
"Error occurred when invoking API. API endpoint: "
+ internalServerAddr + DeviceManagementConstants.ConfigurationManagement
.APPLICATION_REGISTRATION_API_ENDPOINT, e);
}
}
/**
* Use default admin credentials and encode them in Base64
*
* @return Base64 encoded client credentials
*/
private static String getBase64EncodedCredentials(String credentials) {
return Base64.getEncoder().encodeToString(credentials.getBytes());
}
/**
* Create a JSON payload for application registration
*
* @return Generated JSON payload
*/
@SuppressWarnings("PackageAccessibility")
private static StringEntity constructApplicationRegistrationPayload() {
ApplicationRegistration applicationRegistration = new ApplicationRegistration();
applicationRegistration.setApplicationName("MyApp");
applicationRegistration.setAllowedToAllDomains(false);
List<String> tags = new ArrayList<>();
tags.add("device_management");
applicationRegistration.setTags(tags);
applicationRegistration.setValidityPeriod(3600);
Gson gson = new Gson();
String payload = gson.toJson(applicationRegistration);
return new StringEntity(payload, ContentType.APPLICATION_JSON);
}
/**
* Retrieves access token for a given device
* @param scopes scopes for token
* @param clientId clientId
* @param clientSecret clientSecret
* @param deviceOwner owner of the device that is going to generate token
* @return @{@link AccessTokenInfo} wrapped object of retrieved access token and refresh token
* @throws JWTClientException if an error occurs when the jwt client creation or token retrieval
*/
public static AccessTokenInfo getAccessTokenForDeviceOwner(String scopes, String clientId,
String clientSecret, String deviceOwner)
throws JWTClientException {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
JWTClientManagerService jwtClientManagerService = (JWTClientManagerService) ctx
.getOSGiService(JWTClientManagerService.class, null);
JWTClient jwtClient = jwtClientManagerService.getJWTClient();
return jwtClient.getAccessToken(clientId, clientSecret, deviceOwner, scopes);
}
} }

@ -42,6 +42,7 @@
<module>org.wso2.carbon.device.mgt.analytics.data.publisher</module> <module>org.wso2.carbon.device.mgt.analytics.data.publisher</module>
<module>org.wso2.carbon.device.mgt.url.printer</module> <module>org.wso2.carbon.device.mgt.url.printer</module>
<module>org.wso2.carbon.device.mgt.analytics.wsproxy</module> <module>org.wso2.carbon.device.mgt.analytics.wsproxy</module>
<module>io.entgra.carbon.device.mgt.config.api</module>
</modules> </modules>
</project> </project>

@ -232,7 +232,11 @@
<artifactId>powermock-module-testng</artifactId> <artifactId>powermock-module-testng</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.identity.jwt.client.extension</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -85,6 +85,29 @@
</artifactItems> </artifactItems>
</configuration> </configuration>
</execution> </execution>
<execution>
<id>copy config api</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>io.entgra.carbon.device.mgt.config.api
</artifactId>
<version>${project.version}</version>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>
${project.build.directory}/maven-shared-archive-resources/webapps
</outputDirectory>
<destFileName>api#device-mgt-config#v1.0.war</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>

@ -1,4 +1,5 @@
instructions.configure = \ instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\ org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api#device-mgt#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt#v1.0.war,overwrite:true);\ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api#device-mgt#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt#v1.0.war,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api#device-mgt#v0.9.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt#v0.9.war,overwrite:true);\ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api#device-mgt#v0.9.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt#v0.9.war,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.api_${feature.version}/webapps/api#device-mgt-config#v1.0.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt-config#v1.0.war,overwrite:true);\
Loading…
Cancel
Save