From a3f44b43b4cdf54750bb82350d1ea4c92fbab28e Mon Sep 17 00:00:00 2001 From: Pahansith Date: Wed, 7 Aug 2019 10:26:02 +0530 Subject: [PATCH] Add configuration retrieve endpoint --- .../pom.xml | 277 ++++++++++++++++++ .../mgt/config/jaxrs/ApiOriginFilter.java | 50 ++++ .../mgt/config/jaxrs/beans/ErrorListItem.java | 77 +++++ .../mgt/config/jaxrs/beans/ErrorResponse.java | 150 ++++++++++ .../jaxrs/common/GsonMessageBodyHandler.java | 97 ++++++ .../DeviceManagementConfigService.java | 134 +++++++++ .../DeviceManagementConfigServiceImpl.java | 151 ++++++++++ .../config/jaxrs/util/DeviceMgtAPIUtils.java | 43 +++ .../src/main/webapp/META-INF/permissions.xml | 39 +++ .../webapp/META-INF/webapp-classloading.xml | 35 +++ .../src/main/webapp/WEB-INF/cxf-servlet.xml | 38 +++ .../src/main/webapp/WEB-INF/web.xml | 126 ++++++++ .../src/test/resources/testng.xml | 23 ++ .../common/AppRegistrationCredentials.java | 43 +++ .../mgt/common/ApplicationRegistration.java | 65 ++++ .../ApplicationRegistrationException.java | 46 +++ .../mgt/common/InvalidArgumentException.java | 46 +++ .../mgt/AmbiguousConfigurationException.java | 25 ++ .../mgt/DeviceConfiguration.java | 111 +++++++ .../configuration/mgt/DevicePropertyInfo.java | 63 ++++ .../mgt/core/DeviceManagementConstants.java | 15 + .../carbon/device/mgt/core/dao/DeviceDAO.java | 10 + .../core/dao/DeviceNotFoundDAOException.java | 28 ++ .../core/dao/impl/AbstractDeviceDAOImpl.java | 63 +++- .../DeviceManagementProviderService.java | 20 ++ .../DeviceManagementProviderServiceImpl.java | 88 ++++++ .../mgt/core/util/DeviceManagerUtil.java | 118 ++++++++ components/device-mgt/pom.xml | 1 + .../org.wso2.carbon.policy.mgt.core/pom.xml | 6 +- .../pom.xml | 23 ++ .../src/main/resources/p2.inf | 3 +- 31 files changed, 2011 insertions(+), 3 deletions(-) create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/pom.xml create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/ApiOriginFilter.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorListItem.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorResponse.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/common/GsonMessageBodyHandler.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/DeviceManagementConfigService.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/impl/DeviceManagementConfigServiceImpl.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/util/DeviceMgtAPIUtils.java create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/permissions.xml create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/test/resources/testng.xml create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/AppRegistrationCredentials.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistration.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistrationException.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/InvalidArgumentException.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/AmbiguousConfigurationException.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DeviceConfiguration.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DevicePropertyInfo.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceNotFoundDAOException.java diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/pom.xml b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/pom.xml new file mode 100644 index 00000000000..2cbb2505e5c --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/pom.xml @@ -0,0 +1,277 @@ + + + + + + + device-mgt + org.wso2.carbon.devicemgt + 3.2.9-SNAPSHOT + ../pom.xml + + + 4.0.0 + io.entgra.carbon.device.mgt.config.api + war + Entgra Carbon - Mobile Device Management Configuration API + Entgra Carbon - Mobile Device Management Configuration API + https://entgra.io + + + + + maven-compiler-plugin + + 1.8 + 1.8 + + + + maven-war-plugin + + WEB-INF/lib/*cxf*.jar + api#device-mgt-config#v1.0 + + + + org.jacoco + jacoco-maven-plugin + + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + test + + report + + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/site + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + file:src/test/resources/log4j.properties + + + src/test/resources/testng.xml + + + + + + + + + deploy + + compile + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + compile + + run + + + + + + + + + + + + + + + + + + client + + test + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + test + + java + + + + + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + javax.ws.rs + jsr311-api + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + org.mockito + mockito-core + + + javassist + javassist + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + + + org.wso2.carbon.identity.framework + org.wso2.carbon.user.mgt + + + + + io.swagger + swagger-annotations + + + io.swagger + swagger-core + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + + + org.slf4j + slf4j-api + + + org.wso2.orbit.com.fasterxml.jackson.core + jackson-core + + + + + io.swagger + swagger-jaxrs + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + + + org.slf4j + slf4j-api + + + org.wso2.orbit.com.fasterxml.jackson.core + jackson-core + + + + + javax.servlet + servlet-api + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + javax.ws.rs + javax.ws.rs-api + + + org.powermock + powermock-module-testng + test + + + org.powermock + powermock-api-mockito + test + + + org.wso2.carbon.devicemgt + org.wso2.carbon.identity.jwt.client.extension + provided + + + org.wso2.tomcat + tomcat + + + org.wso2.tomcat + tomcat-servlet-api + + + + + diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/ApiOriginFilter.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/ApiOriginFilter.java new file mode 100644 index 00000000000..ae3103866fa --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/ApiOriginFilter.java @@ -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 + } + +} diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorListItem.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorListItem.java new file mode 100644 index 00000000000..34939b3859b --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorListItem.java @@ -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(); + } + +} diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorResponse.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorResponse.java new file mode 100644 index 00000000000..8a6cf834ccc --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/beans/ErrorResponse.java @@ -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 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 getErrorItems() { + return errorItems; + } + + public void setErrorItems(List 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 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; + } + } +} + + diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/common/GsonMessageBodyHandler.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/common/GsonMessageBodyHandler.java new file mode 100644 index 00000000000..484c8df866c --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/common/GsonMessageBodyHandler.java @@ -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, MessageBodyReader { + + 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 objectClass, Type type, Annotation[] annotations, + MediaType mediaType, MultivaluedMap 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 stringObjectMultivaluedMap, + OutputStream entityStream) + throws IOException, WebApplicationException { + + OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8); + try { + getGson().toJson(object, type, writer); + } finally { + writer.close(); + } + } +} diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/DeviceManagementConfigService.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/DeviceManagementConfigService.java new file mode 100644 index 00000000000..5c53d8129ab --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/DeviceManagementConfigService.java @@ -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); +} diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/impl/DeviceManagementConfigServiceImpl.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/impl/DeviceManagementConfigServiceImpl.java new file mode 100644 index 00000000000..ab00cfcfff1 --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/service/impl/DeviceManagementConfigServiceImpl.java @@ -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 deviceProps = mapper.readValue(properties, + new TypeReference>() { + }); + 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); + } + } + +} diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/util/DeviceMgtAPIUtils.java b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/util/DeviceMgtAPIUtils.java new file mode 100644 index 00000000000..874a644bba0 --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/java/io/entgra/carbon/device/mgt/config/jaxrs/util/DeviceMgtAPIUtils.java @@ -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; + } +} diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/permissions.xml b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 00000000000..8b5c48b01ca --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,39 @@ + + + + + + + + + Device Management Configuration + /device-mgt-config + / + GET + + diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 00000000000..01aceabde5b --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 00000000000..e7426237cb2 --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/web.xml b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..0c2afe4a6f5 --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,126 @@ + + + + Device-Config-Webapp + + JAX-WS/JAX-RS Device Configuration Endpoint + JAX-WS/JAX-RS Servlet + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + + + swagger.security.filter + ApiAuthorizationFilterImpl + + 1 + + + CXFServlet + /* + + + 60 + + + + doAuthentication + true + + + + nonSecuredEndPoints + + /api/device-mgt-config/v1.0/configurations + + + + + + managed-api-enabled + true + + + managed-api-owner + admin + + + isSharedWithAllTenants + true + + + + + + DeviceMgt-Admin + /* + + + CONFIDENTIAL + + + + + ApiOriginFilter + io.entgra.carbon.device.mgt.config.jaxrs.ApiOriginFilter + + + + HttpHeaderSecurityFilter + org.apache.catalina.filters.HttpHeaderSecurityFilter + + hstsEnabled + false + + + + + ContentTypeBasedCachePreventionFilter + org.wso2.carbon.ui.filters.cache.ContentTypeBasedCachePreventionFilter + + patterns + text/html" ,application/json" ,text/plain + + + filterAction + enforce + + + httpHeaders + Cache-Control: no-store, no-cache, must-revalidate, private + + + + + HttpHeaderSecurityFilter + /* + + + + ContentTypeBasedCachePreventionFilter + /* + + + + ApiOriginFilter + /* + + + \ No newline at end of file diff --git a/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/test/resources/testng.xml b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/test/resources/testng.xml new file mode 100644 index 00000000000..5fe82227d37 --- /dev/null +++ b/components/device-mgt/io.entgra.carbon.device.mgt.config.api/src/test/resources/testng.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/AppRegistrationCredentials.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/AppRegistrationCredentials.java new file mode 100644 index 00000000000..191ee0d3d48 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/AppRegistrationCredentials.java @@ -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; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistration.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistration.java new file mode 100644 index 00000000000..13d6c9d53c8 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistration.java @@ -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 tags; + private boolean isAllowedToAllDomains; + private long validityPeriod; + + public String getApplicationName() { + return applicationName; + } + + public void setApplicationName(String applicationName) { + this.applicationName = applicationName; + } + + public List getTags() { + return tags; + } + + public void setTags(List 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; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistrationException.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistrationException.java new file mode 100644 index 00000000000..6ccfe677ef7 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/ApplicationRegistrationException.java @@ -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); + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/InvalidArgumentException.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/InvalidArgumentException.java new file mode 100644 index 00000000000..194f9713188 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/InvalidArgumentException.java @@ -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); + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/AmbiguousConfigurationException.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/AmbiguousConfigurationException.java new file mode 100644 index 00000000000..a18f437528a --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/AmbiguousConfigurationException.java @@ -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); + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DeviceConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DeviceConfiguration.java new file mode 100644 index 00000000000..da39516f414 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DeviceConfiguration.java @@ -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 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 getConfigurationEntries() { + return configurationEntries; + } + + public void setConfigurationEntries( + List 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; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DevicePropertyInfo.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DevicePropertyInfo.java new file mode 100644 index 00000000000..1af7982252e --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/configuration/mgt/DevicePropertyInfo.java @@ -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; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java index 57b00cb5a8c..7c7f265353a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java @@ -27,6 +27,21 @@ public final class DeviceManagementConstants { public static final String DEVICE_CACHE = "DEVICE_CACHE"; 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 { private Common() { throw new AssertionError(); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java index f62d915d1ba..f824a2255b9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java @@ -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.Status; 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.geo.GeoCluster; import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; @@ -190,6 +191,15 @@ public interface DeviceDAO { */ List getDeviceBasedOnDeviceProperties(Map 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 getDeviceBasedOnDeviceProperties(Map deviceProps) + throws DeviceManagementDAOException; /** * Retrieves properties of given device identifier diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceNotFoundDAOException.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceNotFoundDAOException.java new file mode 100644 index 00000000000..b4479ed20ae --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceNotFoundDAOException.java @@ -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); + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java index 413e9bc56c3..588f2ebd4a1 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java @@ -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.Status; 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.DeviceManagementDAOException; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; @@ -62,6 +63,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicInteger; 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_DEVICE_TYPE_NAME = "DEVICE_TYPE_NAME"; private static final String PROPERTY_DEVICE_IDENTIFICATION = "DEVICE_IDENTIFICATION"; + private static final String PROPERTY_TENANT_ID = "TENANT_ID"; @Override public int addDevice(int typeId, Device device, int tenantId) throws DeviceManagementDAOException { @@ -330,6 +333,65 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { return devices; } + @Override + public List getDeviceBasedOnDeviceProperties(Map deviceProps) + throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet resultSet = null; + List deviceProperties = new ArrayList<>(); + try { + conn = this.getConnection(); + List> 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 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 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 public Device getDeviceProps(String deviceId, int tenantId) throws DeviceManagementDAOException { Connection conn = null; @@ -385,7 +447,6 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { return intersectedResult; } - @Override public Device getDevice(String deviceIdentifier, Date since, int tenantId) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index b32ed7ed124..8aa8f71626c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -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.DeviceIdentifier; 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.EnrolmentInfo; 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.MonitoringOperation; import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; 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.configuration.mgt.AmbiguousConfigurationException; 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.license.mgt.License; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; @@ -729,4 +734,19 @@ public interface DeviceManagementProviderService { boolean updateEnrollment(String owner, List deviceIdentifiers) 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 propertyMap) + throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException, + AmbiguousConfigurationException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index dcf34c0e273..8aa8d5e2d89 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -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.FeatureManager; 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.MonitoringOperation; 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.StartupOperationConfig; 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.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.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.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; @@ -3273,4 +3279,86 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv + "constructing is failed", e); } } + + @Override + public DeviceConfiguration getDeviceConfiguration(Map deviceProps) + throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException, + AmbiguousConfigurationException { + + if (log.isDebugEnabled()) { + log.debug("Attempting to get device configurations based on properties."); + } + + DevicePropertyInfo deviceProperties; + List 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 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 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; + } + + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/DeviceManagerUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/DeviceManagerUtil.java index 44d8814fcd0..ccf6091d8c2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/DeviceManagerUtil.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/DeviceManagerUtil.java @@ -17,13 +17,25 @@ */ 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.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.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.caching.impl.CacheImpl; import org.wso2.carbon.context.PrivilegedCarbonContext; 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.DeviceIdentifier; 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.operation.mgt.OperationMgtConstants; 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.UserStoreException; import org.wso2.carbon.utils.CarbonUtils; @@ -63,9 +79,13 @@ import javax.sql.DataSource; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; import java.util.Hashtable; import java.util.List; @@ -588,4 +608,102 @@ public final class DeviceManagerUtil { } 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 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); + } } diff --git a/components/device-mgt/pom.xml b/components/device-mgt/pom.xml index 1b6c6930581..c0647a04f4d 100644 --- a/components/device-mgt/pom.xml +++ b/components/device-mgt/pom.xml @@ -42,6 +42,7 @@ org.wso2.carbon.device.mgt.analytics.data.publisher org.wso2.carbon.device.mgt.url.printer org.wso2.carbon.device.mgt.analytics.wsproxy + io.entgra.carbon.device.mgt.config.api diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/pom.xml b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/pom.xml index 8bf4cde0e60..d38319a04ce 100644 --- a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/pom.xml +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/pom.xml @@ -232,7 +232,11 @@ powermock-module-testng test - + + org.wso2.carbon.devicemgt + org.wso2.carbon.identity.jwt.client.extension + test + diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/pom.xml b/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/pom.xml index e1fc7e9d8ac..5b602cf81e9 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/pom.xml +++ b/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/pom.xml @@ -85,6 +85,29 @@ + + copy config api + package + + copy + + + + + org.wso2.carbon.devicemgt + io.entgra.carbon.device.mgt.config.api + + ${project.version} + war + true + + ${project.build.directory}/maven-shared-archive-resources/webapps + + api#device-mgt-config#v1.0.war + + + + diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/src/main/resources/p2.inf b/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/src/main/resources/p2.inf index fea8965f736..66e6d1f6de3 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/src/main/resources/p2.inf +++ b/features/device-mgt/org.wso2.carbon.device.mgt.api.feature/src/main/resources/p2.inf @@ -1,4 +1,5 @@ instructions.configure = \ 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#v0.9.war,target:${installFolder}/../../deployment/server/webapps/api#device-mgt#v0.9.war,overwrite:true);\ \ No newline at end of file +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);\ \ No newline at end of file