From 60b4a2493cc0141e81bdd74a0d0e071eeee5ffe4 Mon Sep 17 00:00:00 2001 From: inoshperera Date: Sun, 29 Mar 2020 12:59:28 +0530 Subject: [PATCH 01/11] merge conflics resoved --- .../device/details/DeviceDetailsWrapper.java | 20 +++++ .../impl/DeviceInformationManagerImpl.java | 85 +++++++++++++++---- .../GroupManagementProviderService.java | 10 +++ .../GroupManagementProviderServiceImpl.java | 36 ++++++++ .../mgt/core/util/DeviceManagerUtil.java | 33 ++++++- .../configuration.hbs | 15 ++++ .../public/js/platform-configuration.js | 13 ++- 7 files changed, 194 insertions(+), 18 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceDetailsWrapper.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceDetailsWrapper.java index 80f637c880..975d27b50f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceDetailsWrapper.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceDetailsWrapper.java @@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.common.device.details; import com.google.gson.Gson; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.app.mgt.Application; +import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; import java.util.List; @@ -31,6 +32,25 @@ public class DeviceDetailsWrapper { DeviceLocation location; int tenantId; + List groups; + String [] role; + + public List getGroups() { + return groups; + } + + public void setGroups(List groups) { + this.groups = groups; + } + + public String [] getRole() { + return role; + } + + public void setRole(String [] role) { + this.role = role; + } + public int getTenantId() { return tenantId; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java index 5261b56246..d4ad97c043 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java @@ -31,6 +31,8 @@ import org.wso2.carbon.device.mgt.common.exceptions.EventPublishingException; import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException; 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.group.mgt.DeviceGroup; +import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; import org.wso2.carbon.device.mgt.core.dao.DeviceDAO; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; @@ -41,8 +43,11 @@ import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsMgtDAOException; import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; import org.wso2.carbon.device.mgt.core.report.mgt.Constants; +import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil; import org.wso2.carbon.device.mgt.core.util.HttpReportingUtil; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; import java.sql.SQLException; import java.util.ArrayList; @@ -58,6 +63,7 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { private static final Log log = LogFactory.getLog(DeviceInformationManagerImpl.class); private static final String LOCATION_EVENT_STREAM_DEFINITION = "org.wso2.iot.LocationStream"; private static final String DEVICE_INFO_EVENT_STREAM_DEFINITION = "org.wso2.iot.DeviceInfoStream"; + private static final String IS_EVENT_PUBLISHING_ENABED = "isEventPublishingEnabled"; public DeviceInformationManagerImpl() { this.deviceDAO = DeviceManagementDAOFactory.getDeviceDAO(); @@ -79,6 +85,9 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { @Override public void addDeviceInfo(Device device, DeviceInfo deviceInfo) throws DeviceDetailsMgtException { try { + + publishEvents(device, deviceInfo); + DeviceManagementDAOFactory.beginTransaction(); DeviceInfo newDeviceInfo; DeviceInfo previousDeviceInfo = deviceDetailsDAO.getDeviceInformation(device.getId(), @@ -117,18 +126,6 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { deviceDAO.updateDevice(device, CarbonContext.getThreadLocalCarbonContext().getTenantId()); DeviceManagementDAOFactory.commitTransaction(); - String reportingHost = System.getProperty(DeviceManagementConstants.Report - .REPORTING_EVENT_HOST); - if (reportingHost != null && !reportingHost.isEmpty()) { - DeviceDetailsWrapper deviceDetailsWrapper = new DeviceDetailsWrapper(); - deviceDetailsWrapper.setDevice(device); - deviceDetailsWrapper.setDeviceInfo(deviceInfo); - deviceDetailsWrapper.getJSONString(); - - HttpReportingUtil.invokeApi(deviceDetailsWrapper.getJSONString(), - reportingHost + DeviceManagementConstants.Report.DEVICE_INFO_ENDPOINT); - } - //TODO :: This has to be fixed by adding the enrollment ID. if (DeviceManagerUtil.isPublishDeviceInfoResponseEnabled()) { Object[] metaData = {device.getDeviceIdentifier(), device.getType()}; @@ -174,14 +171,54 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { } catch (DataPublisherConfigurationException e) { DeviceManagementDAOFactory.rollbackTransaction(); throw new DeviceDetailsMgtException("Error occurred while publishing the device location information.", e); - } catch (EventPublishingException e) { - DeviceManagementDAOFactory.rollbackTransaction(); - throw new DeviceDetailsMgtException("Error occurred while sending events", e); - } finally { + }finally { DeviceManagementDAOFactory.closeConnection(); } } + private void publishEvents(Device device, DeviceInfo deviceInfo) { + String reportingHost = System.getProperty(DeviceManagementConstants.Report + .REPORTING_EVENT_HOST); + if (reportingHost != null && !reportingHost.isEmpty() && isPublishingEnabledForTenant()) { + try { + DeviceDetailsWrapper deviceDetailsWrapper = new DeviceDetailsWrapper(); + deviceDetailsWrapper.setDevice(device); + deviceDetailsWrapper.setDeviceInfo(deviceInfo); + deviceDetailsWrapper.getJSONString(); + GroupManagementProviderService groupManagementService = DeviceManagementDataHolder + .getInstance().getGroupManagementProviderService(); + + List groups = groupManagementService.getGroups(device, false); + if (groups != null && groups.size() > 0) { + deviceDetailsWrapper.setGroups(groups); + } + + String[] rolesOfUser = getRolesOfUser(CarbonContext.getThreadLocalCarbonContext() + .getUsername()); + if (rolesOfUser != null && rolesOfUser.length > 0) { + deviceDetailsWrapper.setRole(rolesOfUser); + } + + HttpReportingUtil.invokeApi(deviceDetailsWrapper.getJSONString(), + reportingHost + DeviceManagementConstants.Report.DEVICE_INFO_ENDPOINT); + } catch (EventPublishingException e) { + log.error("Error occurred while sending events", e); + } catch (GroupManagementException e) { + log.error("Error occurred while getting group list", e); + } catch (UserStoreException e) { + log.error("Error occurred while getting role list", e); + } + } + } + + private boolean isPublishingEnabledForTenant() { + Object configuration = DeviceManagerUtil.getConfiguration(IS_EVENT_PUBLISHING_ENABED); + if (configuration != null) { + return Boolean.valueOf(configuration.toString()); + } + return false; + } + @Override public DeviceInfo getDeviceInfo(DeviceIdentifier deviceId) throws DeviceDetailsMgtException { Device device = getDevice(deviceId); @@ -426,6 +463,7 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { return newDeviceInfo; } + /** * Generate and add a value depending on the device's OS version included in device info * @@ -460,5 +498,20 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { } } } + + private String[] getRolesOfUser(String userName) throws UserStoreException { + UserRealm userRealm = CarbonContext.getThreadLocalCarbonContext().getUserRealm(); + String[] roleList; + if (userRealm != null) { + userRealm.getUserStoreManager().getRoleNames(); + roleList = userRealm.getUserStoreManager().getRoleListOfUser(userName); + } else { + String msg = "User realm is not initiated. Logged in user: " + userName; + log.error(msg); + throw new UserStoreException(msg); + } + return roleList; + } + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderService.java index 4300ce232b..cca1768bd1 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderService.java @@ -243,6 +243,16 @@ public interface GroupManagementProviderService { */ List getGroups(DeviceIdentifier deviceIdentifier, boolean requireGroupProps) throws GroupManagementException; + /** + * Get groups which contains particular device. + * + * @param device interested devoce. + * @return groups contain the device. + * @throws GroupManagementException + */ + public List getGroups(Device device, boolean requireGroupProps) + throws GroupManagementException; + /** * Checks for the default group existence and create group based on device ownership. * @param groupName of the group diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderServiceImpl.java index efe71421db..0fc3e978c9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/GroupManagementProviderServiceImpl.java @@ -938,6 +938,42 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid } } + @Override + public List getGroups(Device device, boolean requireGroupProps) + throws GroupManagementException { + if (device.getDeviceIdentifier() == null) { + String msg = "Received empty device identifier for getGroups"; + log.error(msg); + throw new GroupManagementException(msg); + } + if (log.isDebugEnabled()) { + log.debug("Get groups of device " + device.getDeviceIdentifier()); + } + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + try { + GroupManagementDAOFactory.openConnection(); + List deviceGroups = groupDAO.getGroups(device.getId(), tenantId); + if (requireGroupProps) { + if (deviceGroups != null && !deviceGroups.isEmpty()) { + for (DeviceGroup group : deviceGroups) { + populateGroupProperties(group, tenantId); + } + } + } + return deviceGroups; + } catch (GroupManagementDAOException | SQLException e) { + String msg = "Error occurred while retrieving device groups."; + log.error(msg, e); + throw new GroupManagementException(msg, e); + } catch (Exception e) { + String msg = "Error occurred in getGroups"; + log.error(msg, e); + throw new GroupManagementException(msg, e); + } finally { + GroupManagementDAOFactory.closeConnection(); + } + } + /** * {@inheritDoc} */ 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 0c0308d6b1..14d0aeba68 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 @@ -38,6 +38,10 @@ 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.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; +import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.GroupPaginationRequest; @@ -53,6 +57,8 @@ import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig; import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig; import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition; +import org.wso2.carbon.device.mgt.core.config.policy.PolicyConfiguration; +import org.wso2.carbon.device.mgt.core.config.tenant.PlatformConfigurationManagementServiceImpl; 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.DeviceTypeDAO; @@ -97,9 +103,10 @@ import java.util.regex.Pattern; import java.util.stream.IntStream; -public final class DeviceManagerUtil { + public final class DeviceManagerUtil { private static final Log log = LogFactory.getLog(DeviceManagerUtil.class); + public static final String GENERAL_CONFIG_RESOURCE_PATH = "general"; private static boolean isDeviceCacheInitialized = false; @@ -804,4 +811,28 @@ public final class DeviceManagerUtil { } return joiner.toString(); } + + public static Object getConfiguration(String key) { + + PlatformConfigurationManagementService configMgtService = + new PlatformConfigurationManagementServiceImpl(); + + try { + PlatformConfiguration tenantConfiguration = configMgtService.getConfiguration + (GENERAL_CONFIG_RESOURCE_PATH); + List configuration = tenantConfiguration.getConfiguration(); + + if (configuration != null && !configuration.isEmpty()) { + for (ConfigurationEntry cEntry : configuration) { + if (key.equalsIgnoreCase(cEntry.getName())) { + return cEntry.getValue(); + } + } + } + } catch (ConfigurationManagementException e) { + log.error("Error while getting the configurations from registry.", e); + return null; + } + return null; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs index 753a3c8851..d938d1050d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/configuration.hbs @@ -95,6 +95,21 @@ class="form-control" placeholder="[ Required Field ]"> +
+ + +
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js index 9e4176066b..a9bf2bb255 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.platform.configuration/public/js/platform-configuration.js @@ -22,7 +22,8 @@ $(document).ready(function () { var configParams = { "NOTIFIER_TYPE": "notifierType", - "NOTIFIER_FREQUENCY": "notifierFrequency" + "NOTIFIER_FREQUENCY": "notifierFrequency", + "IS_EVENT_PUBLISHING_ENABLED": "isEventPublishingEnabled" }; var responseCodes = { @@ -51,6 +52,8 @@ $(document).ready(function () { var config = data.configuration[i]; if (config.name == configParams["NOTIFIER_FREQUENCY"]) { $("input#monitoring-config-frequency").val(config.value / 1000); + } else if (config.name == configParams["IS_EVENT_PUBLISHING_ENABLED"]) { + $("select#publish-for-analytics").val(config.value); } } } @@ -65,6 +68,7 @@ $(document).ready(function () { */ $("button#save-general-btn").click(function () { var notifierFrequency = $("input#monitoring-config-frequency").val(); + var publishEvents = $("select#publish-for-analytics").val(); var errorMsgWrapper = "#email-config-error-msg"; var errorMsg = "#email-config-error-msg span"; @@ -84,6 +88,13 @@ $(document).ready(function () { "contentType": "text" }; + var publishEventsDetails = { + "name": configParams["IS_EVENT_PUBLISHING_ENABLED"], + "value": publishEvents, + "contentType": "text" + }; + + configList.push(publishEventsDetails); configList.push(monitorFrequency); addConfigFormData.configuration = configList; From 30da5afdab3d56b6bb7e1d517415f8880b237313 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Wed, 4 Mar 2020 13:10:45 +0530 Subject: [PATCH 02/11] Add hourly and daily usage to application bean --- .../mgt/common/app/mgt/Application.java | 20 +++++++++++++++++++ .../mgt/core/DeviceManagementConstants.java | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/app/mgt/Application.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/app/mgt/Application.java index ecbafd974c..38d7cf5d7b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/app/mgt/Application.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/app/mgt/Application.java @@ -53,6 +53,10 @@ public class Application implements Serializable { private int memoryUsage; @ApiModelProperty(name = "isActive", value = "Is the application actively running", required = true) private boolean isActive; + @ApiModelProperty(name = "hourlyUsage", value = "App hourly usage") + private long hourlyUsage; + @ApiModelProperty(name = "dailyUsage", value = "App daily usage") + private long dailyUsage; public String getType() { @@ -179,4 +183,20 @@ public class Application implements Serializable { public void setActive(boolean active) { isActive = active; } + + public long getHourlyUsage() { + return hourlyUsage; + } + + public void setHourlyUsage(long hourlyUsage) { + this.hourlyUsage = hourlyUsage; + } + + public long getDailyUsage() { + return dailyUsage; + } + + public void setDailyUsage(long dailyUsage) { + this.dailyUsage = dailyUsage; + } } 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 def109fd04..0a61682060 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 @@ -144,8 +144,9 @@ public final class DeviceManagementConstants { private Report() { throw new AssertionError(); } + public static final String REPORTING_EVENT_HOST = "iot.reporting.event.host"; public static final String REPORTING_CONTEXT = "/event"; public static final String DEVICE_INFO_ENDPOINT = REPORTING_CONTEXT + "/device-info"; - public static final String REPORTING_EVENT_HOST = "iot.reporting.event.host"; + public static final String APP_USAGE_ENDPOINT = REPORTING_CONTEXT + "/app-usage"; } } From 3a7ea53c3ace25608d2fc05f71a393667933adf6 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Wed, 4 Mar 2020 13:11:25 +0530 Subject: [PATCH 03/11] Add a method to retrieve the reporting host --- .../wso2/carbon/device/mgt/core/util/HttpReportingUtil.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/HttpReportingUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/HttpReportingUtil.java index 385f5866b4..2d034d74f9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/HttpReportingUtil.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/util/HttpReportingUtil.java @@ -25,11 +25,16 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.protocol.HTTP; import org.wso2.carbon.device.mgt.common.exceptions.EventPublishingException; +import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; import java.io.IOException; public class HttpReportingUtil { + public static String getReportingHost() { + return System.getProperty(DeviceManagementConstants.Report.REPORTING_EVENT_HOST); + } + public static int invokeApi(String payload, String endpoint) throws EventPublishingException { try (CloseableHttpClient client = HttpClients.createDefault()) { HttpPost apiEndpoint = new HttpPost(endpoint); From 9da0bc8de0575a0b0e2646d1c15b466f23b1926d Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Wed, 4 Mar 2020 13:12:54 +0530 Subject: [PATCH 04/11] Call reporting app usage endpoint --- .../mgt/ApplicationManagerProviderServiceImpl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/app/mgt/ApplicationManagerProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/app/mgt/ApplicationManagerProviderServiceImpl.java index e9cc0583ff..c22a8ff44d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/app/mgt/ApplicationManagerProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/app/mgt/ApplicationManagerProviderServiceImpl.java @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.device.details.DeviceDetailsWrapper; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException; @@ -39,6 +40,7 @@ import org.wso2.carbon.device.mgt.core.dao.ApplicationDAO; 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.internal.DeviceManagementDataHolder; +import org.wso2.carbon.device.mgt.core.util.HttpReportingUtil; import java.sql.SQLException; import java.util.ArrayList; @@ -277,6 +279,17 @@ public class ApplicationManagerProviderServiceImpl implements ApplicationManagem device.getEnrolmentInfo().getId(), tenantId); } DeviceManagementDAOFactory.commitTransaction(); + + String reportingHost = HttpReportingUtil.getReportingHost(); + if (!StringUtils.isBlank(reportingHost)) { + DeviceDetailsWrapper deviceDetailsWrapper = new DeviceDetailsWrapper(); + deviceDetailsWrapper.setTenantId(tenantId); + deviceDetailsWrapper.setDevice(device); + deviceDetailsWrapper.setApplications(newApplications); + HttpReportingUtil.invokeApi(deviceDetailsWrapper.getJSONString(), + reportingHost + DeviceManagementConstants.Report.APP_USAGE_ENDPOINT); + } + } catch (DeviceManagementDAOException e) { DeviceManagementDAOFactory.rollbackTransaction(); String msg = "Error occurred saving application list of the device " + device.getDeviceIdentifier(); From a45d2d7cb0486ce07b22937d2d8bc80442944f29 Mon Sep 17 00:00:00 2001 From: Saad Sahibjan Date: Wed, 4 Mar 2020 14:10:06 +0530 Subject: [PATCH 05/11] Use the method to retrieve the reporting host --- .../details/mgt/impl/DeviceInformationManagerImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java index d4ad97c043..5ccb9f6bd2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java @@ -177,9 +177,8 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { } private void publishEvents(Device device, DeviceInfo deviceInfo) { - String reportingHost = System.getProperty(DeviceManagementConstants.Report - .REPORTING_EVENT_HOST); - if (reportingHost != null && !reportingHost.isEmpty() && isPublishingEnabledForTenant()) { + String reportingHost = HttpReportingUtil.getReportingHost(); + if (!StringUtils.isBlank(reportingHost) && isPublishingEnabledForTenant()) { try { DeviceDetailsWrapper deviceDetailsWrapper = new DeviceDetailsWrapper(); deviceDetailsWrapper.setDevice(device); From af12d3fe9a2c0f54abc24b00b0ba18368b76be83 Mon Sep 17 00:00:00 2001 From: inoshperera Date: Thu, 5 Mar 2020 20:56:19 +0530 Subject: [PATCH 06/11] Proxied API calls for sub tenant using super tenant details --- .../framework/AuthenticationInfo.java | 9 ++++ .../authenticator/framework/Constants.java | 1 + .../framework/WebappAuthenticationValve.java | 45 ++++++++++++++++++- .../authenticator/OAuthAuthenticator.java | 6 +++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationInfo.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationInfo.java index d7a0ec1c61..674728491f 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationInfo.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationInfo.java @@ -30,6 +30,7 @@ public class AuthenticationInfo { private String username; private String tenantDomain; private int tenantId = -1; + private boolean isSuperTenantAdmin; public WebappAuthenticator.Status getStatus() { return status; @@ -71,4 +72,12 @@ public class AuthenticationInfo { public void setTenantId(int tenantId) { this.tenantId = tenantId; } + + public boolean isSuperTenantAdmin() { + return isSuperTenantAdmin; + } + + public void setSuperTenantAdmin(boolean superTenantAdmin) { + isSuperTenantAdmin = superTenantAdmin; + } } diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java index 26166e864a..af69a320ea 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java @@ -22,6 +22,7 @@ public final class Constants { public static final String AUTHORIZATION_HEADER_PREFIX_BEARER = "Bearer"; public static final String NO_MATCHING_AUTH_SCHEME = "noMatchedAuthScheme"; + public static final String PROXY_TENANT_ID = "ProxyTenantId"; public static final class HTTPHeaders { private HTTPHeaders() { diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java index 4b596c4ed3..16bf4d695e 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java @@ -27,6 +27,9 @@ import org.owasp.encoder.Encode; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve; import org.wso2.carbon.tomcat.ext.valves.CompositeValve; +import org.wso2.carbon.user.api.Tenant; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator; import org.wso2.carbon.webapp.authenticator.framework.authorizer.WebappTenantAuthorizer; @@ -60,6 +63,8 @@ public class WebappAuthenticationValve extends CarbonTomcatValve { WebappAuthenticator.Status status = WebappTenantAuthorizer.authorize(request, authenticationInfo); authenticationInfo.setStatus(status); } + + Tenant tenant = null; if (authenticationInfo.getTenantId() != -1) { try { PrivilegedCarbonContext.startTenantFlow(); @@ -67,10 +72,48 @@ public class WebappAuthenticationValve extends CarbonTomcatValve { privilegedCarbonContext.setTenantId(authenticationInfo.getTenantId()); privilegedCarbonContext.setTenantDomain(authenticationInfo.getTenantDomain()); privilegedCarbonContext.setUsername(authenticationInfo.getUsername()); - this.processRequest(request, response, compositeValve, authenticationInfo); + if (authenticationInfo.isSuperTenantAdmin()) { + // If this is a call from super admin to an API and the ProxyTenantId is also + // present, this is a call that is made with super admin credentials to call + // an API on behalf of another tenant. Hence the actual tenants, details are + // resolved instead of calling processRequest. + int tenantId = Integer.valueOf(request.getHeader(Constants.PROXY_TENANT_ID)); + RealmService realmService = (RealmService) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(RealmService.class, null); + if (realmService == null) { + String msg = "RealmService is not initialized"; + log.error(msg); + AuthenticationFrameworkUtil.handleResponse(request, response, + HttpServletResponse.SC_BAD_REQUEST, msg); + return; + } + tenant = realmService.getTenantManager().getTenant(tenantId); + } else { + this.processRequest(request, response, compositeValve, authenticationInfo); + } + } catch (UserStoreException e) { + String msg = "Could not locate the tenant"; + log.error(msg); + AuthenticationFrameworkUtil.handleResponse(request, response, + HttpServletResponse.SC_BAD_REQUEST, msg); } finally { PrivilegedCarbonContext.endTenantFlow(); } + + // A call from super admin to a child tenant. Start a new tenant flow of the target + // tenant and pass to the API. + if (tenant != null) { + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext privilegedCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + privilegedCarbonContext.setTenantId(tenant.getId()); + privilegedCarbonContext.setTenantDomain(tenant.getDomain()); + privilegedCarbonContext.setUsername(tenant.getAdminName()); + this.processRequest(request, response, compositeValve, authenticationInfo); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } } else { this.processRequest(request, response, compositeValve, authenticationInfo); } diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OAuthAuthenticator.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OAuthAuthenticator.java index 1f793bb799..9735f054e9 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OAuthAuthenticator.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OAuthAuthenticator.java @@ -25,6 +25,7 @@ import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.wso2.carbon.webapp.authenticator.framework.AuthenticationException; import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo; +import org.wso2.carbon.webapp.authenticator.framework.Constants; import org.wso2.carbon.webapp.authenticator.framework.Utils.Utils; import org.wso2.carbon.webapp.authenticator.framework.authenticator.oauth.OAuth2TokenValidator; import org.wso2.carbon.webapp.authenticator.framework.authenticator.oauth.OAuthTokenValidationException; @@ -77,6 +78,11 @@ public class OAuthAuthenticator implements WebappAuthenticator { String resource = requestUri + ":" + requestMethod; OAuthValidationResponse oAuthValidationResponse = this.tokenValidator.validateToken(bearerToken, resource); authenticationInfo = Utils.setAuthenticationInfo(oAuthValidationResponse, authenticationInfo); + if (authenticationInfo.getTenantId() == -1234 && properties.getProperty("Username") + .equals(authenticationInfo.getUsername()) + && request.getHeader(Constants.PROXY_TENANT_ID) != null) { + authenticationInfo.setSuperTenantAdmin(true); + } } catch (AuthenticationException e) { log.error("Failed to authenticate the incoming request", e); } catch (OAuthTokenValidationException e) { From 1193910f526c7243dad0a3152a5fdf5d99153a1d Mon Sep 17 00:00:00 2001 From: inoshperera Date: Thu, 5 Mar 2020 20:59:00 +0530 Subject: [PATCH 07/11] minor refactoring for getTenantId --- .../details/mgt/impl/DeviceInformationManagerImpl.java | 7 ++++++- .../carbon/device/mgt/core/util/DeviceManagerUtil.java | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java index 5ccb9f6bd2..628321619f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java @@ -183,7 +183,7 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { DeviceDetailsWrapper deviceDetailsWrapper = new DeviceDetailsWrapper(); deviceDetailsWrapper.setDevice(device); deviceDetailsWrapper.setDeviceInfo(deviceInfo); - deviceDetailsWrapper.getJSONString(); + deviceDetailsWrapper.setTenantId(DeviceManagerUtil.getTenantId()); GroupManagementProviderService groupManagementService = DeviceManagementDataHolder .getInstance().getGroupManagementProviderService(); @@ -207,6 +207,11 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { } catch (UserStoreException e) { log.error("Error occurred while getting role list", e); } + } else { + if(log.isTraceEnabled()) { + log.trace("Event publishing is not enabled for tenant " + + DeviceManagerUtil.getTenantId()); + } } } 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 14d0aeba68..5ed3470c5c 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 @@ -355,6 +355,11 @@ import java.util.stream.IntStream; } } + public static int getTenantId() { + return PrivilegedCarbonContext + .getThreadLocalCarbonContext().getTenantId(); + } + public static int validateActivityListPageSize(int limit) throws OperationManagementException { if (limit == 0) { DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance(). From 1bb18f30c9a4cc19117c2f19d7b512f662be05b0 Mon Sep 17 00:00:00 2001 From: inoshperera Date: Tue, 10 Mar 2020 22:06:08 +0530 Subject: [PATCH 08/11] Add get tenant API --- .../admin/DeviceManagementAdminService.java | 57 ++++++++++++ .../DeviceManagementAdminServiceImpl.java | 54 ++++++++++++ .../mgt/common/general/TenantDetail.java | 88 +++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/general/TenantDetail.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java index 29d8a2cb43..d5695b519a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java @@ -49,6 +49,7 @@ import org.apache.axis2.transport.http.HTTPConstants; import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scopes; import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.general.TenantDetail; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; @@ -100,6 +101,12 @@ import java.util.List; description = "Permanently Delete the device specified by device id", key = "perm:devices:permanent-delete", permissions = {"/device-mgt/admin/devices/permanent-delete"} + ), + @Scope( + name = "Getting Details of Device tenants", + description = "Getting Details of Device tenants", + key = "perm:admin:tenant:view", + permissions = {"/device-mgt/devices/tenants/view"} ) } ) @@ -353,4 +360,54 @@ public interface DeviceManagementAdminService { value = "List of device identifiers.", required = true) List deviceIdentifiers); + + @GET + @Path("/tenants") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Details of tenants", + notes = "Get the details of tenants.", + response = TenantDetail.class, + responseContainer = "List", + tags = "Device Management Administrative Service", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = + "perm:admin:tenant:view") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully fetched the list of tenants.", + response = TenantDetail.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 was last modified.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 304, + message = "Not Modified. Empty body because the client already has the latest version of the " + + "requested resource.\n"), + @ApiResponse( + code = 401, + message = "Unauthorized.\n The unauthorized access to the requested resource.", + response = ErrorResponse.class), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the" + + " tenant list.", + response = ErrorResponse.class) + }) + Response getTenants(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java index 9533c43a42..dccd5f69d2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java @@ -45,13 +45,19 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.exceptions.UserNotFoundException; +import org.wso2.carbon.device.mgt.common.general.TenantDetail; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.DeviceManagementAdminService; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; +import org.wso2.carbon.user.api.Tenant; +import org.wso2.carbon.user.api.TenantManager; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.Size; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -62,6 +68,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.util.ArrayList; import java.util.List; @Path("/admin/devices") @@ -189,4 +196,51 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); } } + + @Override + @Path("/tenants") + @GET + public Response getTenants() { + List tenantDetails; + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + if (tenantId == MultitenantConstants.SUPER_TENANT_ID) { + RealmService realmService = (RealmService) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(RealmService.class, null); + if (realmService == null) { + String msg = "RealmService is not initialized"; + log.error(msg); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } + + try { + Tenant[] tenants = realmService.getTenantManager().getAllTenants(); + tenantDetails = new ArrayList<>(); + if (tenants != null && tenants.length > 0) { + for (Tenant tenant : tenants) { + TenantDetail tenantDetail = new TenantDetail(); + tenantDetail.setId(tenant.getId()); + tenantDetail.setAdminFirstName(tenant.getAdminFirstName()); + tenantDetail.setAdminFullName(tenant.getAdminFullName()); + tenantDetail.setAdminLastName(tenant.getAdminLastName()); + tenantDetail.setAdminName(tenant.getAdminName()); + tenantDetail.setDomain(tenant.getDomain()); + tenantDetail.setEmail(tenant.getEmail()); + tenantDetails.add(tenantDetail); + } + return Response.status(Response.Status.OK).entity(tenantDetails).build(); + } else { + return Response.status(Response.Status.NOT_FOUND).entity("No tenants found") + .build(); + } + } catch (UserStoreException e) { + String msg = "Error occurred while fetching tenant list"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + } else { + return Response.status(Response.Status.BAD_REQUEST).entity("This API is available " + + "for super tenant admin only.").build(); + } + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/general/TenantDetail.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/general/TenantDetail.java new file mode 100644 index 0000000000..870207fb5d --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/general/TenantDetail.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (https://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.general; + +public class TenantDetail { + + private int id; + private String domain; + + private String adminName; + private String adminFullName; + private String adminFirstName; + private String adminLastName; + private String email; + + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getAdminName() { + return adminName; + } + + public void setAdminName(String adminName) { + this.adminName = adminName; + } + + public String getAdminFullName() { + return adminFullName; + } + + public void setAdminFullName(String adminFullName) { + this.adminFullName = adminFullName; + } + + public String getAdminFirstName() { + return adminFirstName; + } + + public void setAdminFirstName(String adminFirstName) { + this.adminFirstName = adminFirstName; + } + + public String getAdminLastName() { + return adminLastName; + } + + public void setAdminLastName(String adminLastName) { + this.adminLastName = adminLastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +} From 2ab0efbcddd793526b393ef45ba535a540403c7b Mon Sep 17 00:00:00 2001 From: inoshperera Date: Thu, 26 Mar 2020 16:12:39 +0530 Subject: [PATCH 09/11] validate oauth token and permission --- .../pom.xml | 5 ++ .../AuthenticationFrameworkUtil.java | 47 +++++++++++++++++++ .../framework/WebappAuthenticationValve.java | 37 +++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml index 2d2ba8214b..5cb2b2a9b0 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml @@ -86,6 +86,7 @@ org.wso2.carbon.utils, org.wso2.carbon.utils.multitenancy, org.xml.sax, + com.google.gson.*, javax.servlet, javax.servlet.http, javax.xml, @@ -215,6 +216,10 @@ org.wso2.carbon.devicemgt org.wso2.carbon.device.mgt.common + + com.google.code.gson + gson + org.wso2.orbit.org.apache.httpcomponents httpclient diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java index f3e0a4fe88..7c506737e7 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java @@ -22,6 +22,13 @@ import org.apache.catalina.connector.Response; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; +import org.wso2.carbon.webapp.authenticator.framework.internal.AuthenticatorFrameworkDataHolder; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; @@ -32,6 +39,7 @@ import java.io.IOException; public class AuthenticationFrameworkUtil { private static final Log log = LogFactory.getLog(AuthenticationFrameworkUtil.class); + private static final String UI_EXECUTE = "ui.execute"; static void handleResponse(Request request, Response response, int statusCode, String payload) { response.setStatus(statusCode); @@ -65,4 +73,43 @@ public class AuthenticationFrameworkUtil { } } + static boolean isUserAuthorized(int tenantId, String tenantDomain, String username, String + permission) throws + AuthenticationException { + boolean tenantFlowStarted = false; + + try{ + //If this is a tenant user + if(tenantId != MultitenantConstants.SUPER_TENANT_ID){ + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username); + tenantFlowStarted = true; + } + + RealmService realmService = AuthenticatorFrameworkDataHolder.getInstance().getRealmService(); + if (realmService == null) { + String msg = "RealmService is not initialized"; + log.error(msg); + throw new AuthenticationException(msg); + } + UserRealm userRealm = realmService.getTenantUserRealm(tenantId); + + return userRealm.getAuthorizationManager() + .isUserAuthorized(MultitenantUtils + .getTenantAwareUsername(username), permission, UI_EXECUTE); + + } catch (UserStoreException e) { + String msg = "Error while getting username"; + log.error(msg, e); + throw new AuthenticationException(msg, e); + } + finally { + if (tenantFlowStarted) { + PrivilegedCarbonContext.endTenantFlow(); + } + } + } + } diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java index 16bf4d695e..e09b7e9c86 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java @@ -18,9 +18,11 @@ */ package org.wso2.carbon.webapp.authenticator.framework; +import com.google.gson.Gson; import org.apache.catalina.Context; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.owasp.encoder.Encode; @@ -42,6 +44,8 @@ public class WebappAuthenticationValve extends CarbonTomcatValve { private static final Log log = LogFactory.getLog(WebappAuthenticationValve.class); private static TreeMap nonSecuredEndpoints = new TreeMap<>(); + private static final String PERMISSION_PREFIX = "/permission/admin"; + public static final String AUTHORIZE_PERMISSION = "Authorize-Permission"; @Override public void invoke(Request request, Response response, CompositeValve compositeValve) { @@ -64,6 +68,39 @@ public class WebappAuthenticationValve extends CarbonTomcatValve { authenticationInfo.setStatus(status); } + // This section will allow to validate a given access token is authenticated to access given + // resource(permission) + if (request.getCoyoteRequest() != null + && StringUtils.isNotEmpty(request.getHeader(AUTHORIZE_PERMISSION)) + && (authenticationInfo.getStatus() == WebappAuthenticator.Status.CONTINUE || + authenticationInfo.getStatus() == WebappAuthenticator.Status.SUCCESS)) { + boolean isAllowed; + try { + isAllowed = AuthenticationFrameworkUtil.isUserAuthorized( + authenticationInfo.getTenantId(), authenticationInfo.getTenantDomain(), + authenticationInfo.getUsername(), + PERMISSION_PREFIX + request.getHeader (AUTHORIZE_PERMISSION)); + } catch (AuthenticationException e) { + String msg = "Could not authorize permission"; + log.error(msg); + AuthenticationFrameworkUtil.handleResponse(request, response, + HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg); + return; + } + + if (isAllowed) { + Gson gson = new Gson(); + AuthenticationFrameworkUtil.handleResponse(request, response, HttpServletResponse.SC_OK, + gson.toJson(authenticationInfo)); + return; + } else { + log.error("Unauthorized message from user " + authenticationInfo.getUsername()); + AuthenticationFrameworkUtil.handleResponse(request, response, + HttpServletResponse.SC_FORBIDDEN, "Unauthorized to access the API"); + return; + } + } + Tenant tenant = null; if (authenticationInfo.getTenantId() != -1) { try { From 9fab25d8d4c491b88bc05a53f3093e18ee99553f Mon Sep 17 00:00:00 2001 From: inoshperera Date: Sun, 29 Mar 2020 12:08:48 +0530 Subject: [PATCH 10/11] Test case fix for proxy tenant id --- .../carbon/webapp/authenticator/framework/Constants.java | 2 +- .../framework/WebappAuthenticationValve.java | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java index af69a320ea..2694ea069a 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java @@ -22,7 +22,7 @@ public final class Constants { public static final String AUTHORIZATION_HEADER_PREFIX_BEARER = "Bearer"; public static final String NO_MATCHING_AUTH_SCHEME = "noMatchedAuthScheme"; - public static final String PROXY_TENANT_ID = "ProxyTenantId"; + public static final String PROXY_TENANT_ID = "Proxy-Tenant-Id"; public static final class HTTPHeaders { private HTTPHeaders() { diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java index e09b7e9c86..1370482cd2 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java @@ -50,8 +50,9 @@ public class WebappAuthenticationValve extends CarbonTomcatValve { @Override public void invoke(Request request, Response response, CompositeValve compositeValve) { - if (this.isContextSkipped(request) || this.skipAuthentication(request)) { - this.getNext().invoke(request, response, compositeValve); + if ((this.isContextSkipped(request) || this.skipAuthentication(request)) + && (StringUtils.isEmpty(request.getHeader(AUTHORIZE_PERMISSION)))) { + this.getNext().invoke(request, response, compositeValve); return; } @@ -109,7 +110,8 @@ public class WebappAuthenticationValve extends CarbonTomcatValve { privilegedCarbonContext.setTenantId(authenticationInfo.getTenantId()); privilegedCarbonContext.setTenantDomain(authenticationInfo.getTenantDomain()); privilegedCarbonContext.setUsername(authenticationInfo.getUsername()); - if (authenticationInfo.isSuperTenantAdmin()) { + if (authenticationInfo.isSuperTenantAdmin() && request.getHeader(Constants + .PROXY_TENANT_ID) != null) { // If this is a call from super admin to an API and the ProxyTenantId is also // present, this is a call that is made with super admin credentials to call // an API on behalf of another tenant. Hence the actual tenants, details are From b843d8eefe05f45e7f0924addb527207db324468 Mon Sep 17 00:00:00 2001 From: inoshperera Date: Sun, 29 Mar 2020 12:19:09 +0530 Subject: [PATCH 11/11] test fixes --- .../WebappAuthenticationValveTest.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java index 69cbac221a..91dfad24ca 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java @@ -55,8 +55,9 @@ public class WebappAuthenticationValveTest { @Test(description = "This method tests the invoke method of the WebAppAuthenticationValve with the context path " + "starting with carbon") - public void testInvokeWithContextSkippedScenario1() { + public void testInvokeWithContextSkippedScenario1() throws NoSuchFieldException, IllegalAccessException { Request request = new Request(); + getCoyoteRequest(request); Context context = new StandardContext(); context.setPath("carbon"); CompositeValve compositeValve = Mockito.mock(CompositeValve.class); @@ -64,6 +65,7 @@ public class WebappAuthenticationValveTest { request.setContext(context); webappAuthenticationValve.invoke(request, null, compositeValve); request = new TestRequest("", "test"); + getCoyoteRequest(request); context = new StandardContext(); compositeValve = Mockito.mock(CompositeValve.class); Mockito.doNothing().when(compositeValve).continueInvocation(Mockito.any(), Mockito.any()); @@ -73,8 +75,9 @@ public class WebappAuthenticationValveTest { @Test(description = "This method tests the behaviour of the invoke method of WebAuthenticationValve when " + "un-secured endpoints are invoked.") - public void testInvokeUnSecuredEndpoints() { + public void testInvokeUnSecuredEndpoints() throws IllegalAccessException, NoSuchFieldException { Request request = new TestRequest("", "test"); + getCoyoteRequest(request); Context context = new StandardContext(); context.setPath("carbon1"); context.addParameter("doAuthentication", String.valueOf(true)); @@ -85,6 +88,22 @@ public class WebappAuthenticationValveTest { webappAuthenticationValve.invoke(request, null, compositeValve); } + private void getCoyoteRequest(Request request) throws + IllegalAccessException, + NoSuchFieldException { + + Field headersField = org.apache.coyote.Request.class.getDeclaredField("headers"); + headersField.setAccessible(true); + org.apache.coyote.Request coyoteRequest = new org.apache.coyote.Request(); + + MimeHeaders mimeHeaders = new MimeHeaders(); + MessageBytes bytes = mimeHeaders.addValue("content-type"); + bytes.setString("test"); + + headersField.set(coyoteRequest, mimeHeaders); + request.setCoyoteRequest(coyoteRequest); + } + @Test(description = "This method tests the behaviour of the invoke method of WebAuthenticationValve when " + "secured endpoints are invoked.") public void testInvokeSecuredEndpoints() throws NoSuchFieldException, IllegalAccessException {