Java tutorial
/* * * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.emm.agent.services; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; import org.json.JSONException; import org.json.JSONObject; import org.wso2.emm.agent.AndroidAgentException; import org.wso2.emm.agent.R; import org.wso2.emm.agent.api.ApplicationManager; import org.wso2.emm.agent.api.WiFiConfig; import org.wso2.emm.agent.beans.AppRestriction; import org.wso2.emm.agent.beans.ComplianceFeature; import org.wso2.emm.agent.beans.DeviceAppInfo; import org.wso2.emm.agent.utils.CommonUtils; import org.wso2.emm.agent.utils.Constants; import org.wso2.emm.agent.utils.Preference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * This class is used to check device policy compliance by checking each policy * with current device status. */ public class PolicyComplianceChecker { private static final String TAG = PolicyOperationsMapper.class.getSimpleName(); private Context context; private DevicePolicyManager devicePolicyManager; private Resources resources; private ComponentName deviceAdmin; private ComplianceFeature policy; private ApplicationManager applicationManager; public PolicyComplianceChecker(Context context) { this.context = context; this.resources = context.getResources(); this.devicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); this.deviceAdmin = new ComponentName(context, AgentDeviceAdminReceiver.class); this.applicationManager = new ApplicationManager(context.getApplicationContext()); } /** * Checks EMM policy on the device. * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ public ComplianceFeature checkPolicyState(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException { policy = new ComplianceFeature(); policy.setFeatureCode(operation.getCode()); switch (operation.getCode()) { case Constants.Operation.CAMERA: return checkCameraPolicy(operation); case Constants.Operation.INSTALL_APPLICATION: return checkInstallAppPolicy(operation); case Constants.Operation.UNINSTALL_APPLICATION: return checkUninstallAppPolicy(operation); case Constants.Operation.ENCRYPT_STORAGE: return checkEncryptPolicy(operation); case Constants.Operation.PASSCODE_POLICY: return checkPasswordPolicy(); case Constants.Operation.WIFI: return checkWifiPolicy(operation); case Constants.Operation.WORK_PROFILE: return checkWorkProfilePolicy(operation); case Constants.Operation.DISALLOW_ADJUST_VOLUME: case Constants.Operation.DISALLOW_CONFIG_BLUETOOTH: case Constants.Operation.DISALLOW_CONFIG_CELL_BROADCASTS: case Constants.Operation.DISALLOW_CONFIG_CREDENTIALS: case Constants.Operation.DISALLOW_CONFIG_MOBILE_NETWORKS: case Constants.Operation.DISALLOW_CONFIG_TETHERING: case Constants.Operation.DISALLOW_CONFIG_VPN: case Constants.Operation.DISALLOW_CONFIG_WIFI: case Constants.Operation.DISALLOW_APPS_CONTROL: case Constants.Operation.DISALLOW_CREATE_WINDOWS: case Constants.Operation.DISALLOW_CROSS_PROFILE_COPY_PASTE: case Constants.Operation.DISALLOW_DEBUGGING_FEATURES: ; case Constants.Operation.DISALLOW_FACTORY_RESET: case Constants.Operation.DISALLOW_ADD_USER: case Constants.Operation.DISALLOW_INSTALL_APPS: case Constants.Operation.DISALLOW_INSTALL_UNKNOWN_SOURCES: case Constants.Operation.DISALLOW_MODIFY_ACCOUNTS: case Constants.Operation.DISALLOW_MOUNT_PHYSICAL_MEDIA: case Constants.Operation.DISALLOW_NETWORK_RESET: case Constants.Operation.DISALLOW_OUTGOING_BEAM: case Constants.Operation.DISALLOW_OUTGOING_CALLS: case Constants.Operation.DISALLOW_REMOVE_USER: case Constants.Operation.DISALLOW_SAFE_BOOT: case Constants.Operation.DISALLOW_SHARE_LOCATION: case Constants.Operation.DISALLOW_SMS: case Constants.Operation.DISALLOW_UNINSTALL_APPS: case Constants.Operation.DISALLOW_UNMUTE_MICROPHONE: case Constants.Operation.DISALLOW_USB_FILE_TRANSFER: case Constants.Operation.ALLOW_PARENT_PROFILE_APP_LINKING: case Constants.Operation.ENSURE_VERIFY_APPS: case Constants.Operation.AUTO_TIME: case Constants.Operation.ENABLE_ADMIN: case Constants.Operation.SET_SCREEN_CAPTURE_DISABLED: case Constants.Operation.SET_STATUS_BAR_DISABLED: case Constants.Operation.SYSTEM_UPDATE_POLICY: if (applicationManager.isPackageInstalled(Constants.SYSTEM_SERVICE_PACKAGE)) { CommonUtils.callSystemApp(context, operation.getCode(), Boolean.toString(operation.isEnabled()), null); } // Since without rooting the device a policy set by the device owner cannot // be violated or overridden, no compliance check is necessary. //TODO: implement a mechanism in the system app to call the agent back and report //policy status to agent. policy.setCompliance(true); return policy; case Constants.Operation.APP_RESTRICTION: return checkAppRestrictionPolicy(operation); default: throw new AndroidAgentException("Invalid operation code received"); } } /** * Checks camera policy on the device (camera enabled/disabled). * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ private ComplianceFeature checkCameraPolicy(org.wso2.emm.agent.beans.Operation operation) { boolean cameraStatus = devicePolicyManager.getCameraDisabled(deviceAdmin); if ((operation.isEnabled() && !cameraStatus) || (!operation.isEnabled() && cameraStatus)) { policy.setCompliance(true); } else { policy.setCompliance(false); } return policy; } /** * Checks install app policy on the device (Particular app in the policy should be installed). * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ private ComplianceFeature checkInstallAppPolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException { String appIdentifier = null; String name = null; try { JSONObject appData = new JSONObject(operation.getPayLoad().toString()); if (!appData.isNull(resources.getString(R.string.app_identifier))) { appIdentifier = appData.getString(resources.getString(R.string.app_identifier)); } if (!appData.isNull(resources.getString(R.string.app_identifier))) { name = appData.getString(resources.getString(R.string.intent_extra_name)); } if (isAppInstalled(appIdentifier)) { policy.setCompliance(true); } else { policy.setCompliance(false); policy.setMessage(resources.getString(R.string.error_app_install_policy) + name); } } catch (JSONException e) { policy.setCompliance(false); throw new AndroidAgentException("Invalid JSON format.", e); } return policy; } /** * Checks uninstall app policy on the device (Particular app in the policy should be removed). * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ private ComplianceFeature checkUninstallAppPolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException { String appIdentifier = null; String name = null; try { JSONObject appData = new JSONObject(operation.getPayLoad().toString()); if (!appData.isNull(resources.getString(R.string.app_identifier))) { appIdentifier = appData.getString(resources.getString(R.string.app_identifier)); } if (!appData.isNull(resources.getString(R.string.app_identifier))) { name = appData.getString(resources.getString(R.string.intent_extra_name)); } if (!isAppInstalled(appIdentifier)) { policy.setCompliance(true); } else { policy.setCompliance(false); policy.setMessage(resources.getString(R.string.error_app_uninstall_policy) + name); } } catch (JSONException e) { policy.setCompliance(false); throw new AndroidAgentException("Invalid JSON format.", e); } return policy; } /** * Checks if the app is already installed on the device. * * @param appIdentifier - App package name. * @return appInstalled - App installed status. */ private boolean isAppInstalled(String appIdentifier) { boolean appInstalled = false; ArrayList<DeviceAppInfo> apps = new ArrayList<>(applicationManager.getInstalledApps().values()); for (DeviceAppInfo appInfo : apps) { if (appIdentifier.trim().equals(appInfo.getPackagename())) { appInstalled = true; } } return appInstalled; } /** * Checks device encrypt policy on the device (Device external storage encryption). * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ private ComplianceFeature checkEncryptPolicy(org.wso2.emm.agent.beans.Operation operation) { boolean encryptStatus = (devicePolicyManager .getStorageEncryptionStatus() != devicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED && devicePolicyManager .getStorageEncryptionStatus() != devicePolicyManager.ENCRYPTION_STATUS_INACTIVE); if ((operation.isEnabled() && encryptStatus) || (!operation.isEnabled() && !encryptStatus)) { policy.setCompliance(true); } else { policy.setCompliance(false); policy.setMessage(resources.getString(R.string.error_encrypt_policy)); } return policy; } /** * Checks screen lock password policy on the device. * * @return policy - ComplianceFeature object. */ private ComplianceFeature checkPasswordPolicy() { if (devicePolicyManager.isActivePasswordSufficient()) { policy.setCompliance(true); } else { policy.setCompliance(false); } return policy; } /** * Checks Wifi policy on the device (Particular wifi configuration in the policy should be enforced). * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ private ComplianceFeature checkWifiPolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException { String ssid = null; try { JSONObject wifiData = new JSONObject(operation.getPayLoad().toString()); if (!wifiData.isNull(resources.getString(R.string.intent_extra_ssid))) { ssid = (String) wifiData.get(resources.getString(R.string.intent_extra_ssid)); } WiFiConfig config = new WiFiConfig(context.getApplicationContext()); if (config.findWifiConfigurationBySsid(ssid)) { policy.setCompliance(true); } else { policy.setCompliance(false); policy.setMessage(resources.getString(R.string.error_wifi_policy)); } } catch (JSONException e) { throw new AndroidAgentException("Invalid JSON format.", e); } return policy; } /** * Check the app restriction policy (black list or white list) for compliance * * @param operation - Operation object * @return - Compliance feature object * @throws AndroidAgentException */ private ComplianceFeature checkAppRestrictionPolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException { AppRestriction appRestriction = CommonUtils.getAppRestrictionTypeAndList(operation, null, null); List<String> installedAppPackages = CommonUtils.getInstalledAppPackages(context); String ownershipType = Preference.getString(context, Constants.DEVICE_TYPE); if (Constants.OWNERSHIP_COPE.equals(ownershipType)) { if (Constants.AppRestriction.BLACK_LIST.equals(appRestriction.getRestrictionType())) { List<String> commonApps = new ArrayList<>(installedAppPackages); if (commonApps.retainAll(appRestriction.getRestrictedList())) { if (commonApps.size() > 0) { policy.setCompliance(false); policy.setMessage(commonApps.toString()); return policy; } } } else if (Constants.AppRestriction.WHITE_LIST.equals(appRestriction.getRestrictionType())) { List<String> installedAppPackagesByUser = CommonUtils.getInstalledAppPackagesByUser(context); List<String> remainApps = new ArrayList<>(installedAppPackagesByUser); remainApps.remove(Constants.AGENT_PACKAGE); remainApps.remove(Constants.SYSTEM_SERVICE_PACKAGE); remainApps.removeAll(appRestriction.getRestrictedList()); if (remainApps.size() > 0) { policy.setCompliance(false); policy.setMessage(remainApps.toString()); return policy; } } policy.setCompliance(true); return policy; } else if (Constants.OWNERSHIP_BYOD.equals(ownershipType)) { if (Constants.AppRestriction.BLACK_LIST.equals(appRestriction.getRestrictionType())) { List<String> commonApps = new ArrayList<>(installedAppPackages); if (commonApps.retainAll(appRestriction.getRestrictedList())) { if (commonApps.size() > 0) { policy.setCompliance(false); return policy; } } } else if (Constants.AppRestriction.WHITE_LIST.equals(appRestriction.getRestrictionType())) { List<String> remainApps = new ArrayList<>(installedAppPackages); remainApps.removeAll(appRestriction.getRestrictedList()); if (remainApps.size() > 0) { policy.setCompliance(false); return policy; } } policy.setCompliance(true); return policy; } policy.setCompliance(true); return policy; } /** * Checks Work-Profile policy on the device (Particular work-profile configuration in the policy should be enforced). * * @param operation - Operation object. * @return policy - ComplianceFeature object. */ private ComplianceFeature checkWorkProfilePolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException { String profileName; String systemAppsData; String googlePlayAppsData; try { JSONObject profileData = new JSONObject(operation.getPayLoad().toString()); if (!profileData.isNull(resources.getString(R.string.intent_extra_profile_name))) { profileName = (String) profileData.get(resources.getString(R.string.intent_extra_profile_name)); //yet there is no method is given to get the current profile name. //add a method to test whether profile name is set correctly once introduced. } if (!profileData.isNull(resources.getString(R.string.intent_extra_enable_system_apps))) { // generate the System app list which are configured by user and received to agent as a single String // with packages separated by Commas. systemAppsData = (String) profileData .get(resources.getString(R.string.intent_extra_enable_system_apps)); List<String> systemAppList = Arrays .asList(systemAppsData.split(resources.getString(R.string.split_delimiter))); for (String packageName : systemAppList) { if (!applicationManager.isPackageInstalled(packageName)) { policy.setCompliance(false); policy.setMessage(resources.getString(R.string.error_work_profile_policy)); return policy; } } } if (!profileData.isNull(resources.getString(R.string.intent_extra_enable_google_play_apps))) { googlePlayAppsData = (String) profileData .get(resources.getString(R.string.intent_extra_enable_google_play_apps)); List<String> playStoreAppList = Arrays .asList(googlePlayAppsData.split(resources.getString(R.string.split_delimiter))); for (String packageName : playStoreAppList) { if (!applicationManager.isPackageInstalled(packageName)) { policy.setCompliance(false); policy.setMessage(resources.getString(R.string.error_work_profile_policy)); return policy; } } } } catch (JSONException e) { throw new AndroidAgentException("Invalid JSON format.", e); } policy.setCompliance(true); return policy; } }