diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/pom.xml b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/pom.xml new file mode 100644 index 0000000000..3ba0ed3cf5 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/pom.xml @@ -0,0 +1,109 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + mb-extensions + 2.2.6-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization + bundle + WSO2 Carbon - Component - MQTT - Authorization Manager + MQTT authorization manager based on Carbon device manager + http://wso2.org + + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.wso2.carbon + org.wso2.carbon.core + + + org.wso2.andes.wso2 + andes + + + org.wso2.carbon + org.wso2.carbon.user.api + + + org.wso2.carbon + org.wso2.carbon.user.core + + + commons-lang + commons-lang + + + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.artifactId} + ${project.artifactId} + + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.internal + + + !org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.internal, + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.* + + + org.apache.log4j, + org.dna.mqtt.moquette.server, + org.wso2.andes.configuration.enums, + org.wso2.andes.mqtt, + org.wso2.carbon.context, + org.jaxen, + org.apache.axiom.*, + org.wso2.securevault, + org.apache.commons.*, + org.osgi.service.component, + org.wso2.carbon.user.core.service, + org.wso2.carbon.user.core.tenant, + org.wso2.carbon.user.api, + *;resolution:=optional + + * + + + + + + + + diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/DeviceAccessBasedMQTTAuthorizer.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/DeviceAccessBasedMQTTAuthorizer.java new file mode 100644 index 0000000000..effd878ab0 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/DeviceAccessBasedMQTTAuthorizer.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.dna.mqtt.moquette.server.IAuthorizer; +import org.wso2.andes.configuration.enums.MQTTAuthoriztionPermissionLevel; +import org.wso2.andes.mqtt.MQTTAuthorizationSubject; +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.config.AuthorizationConfigurationManager; +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.internal.AuthorizationDataHolder; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; + +import java.util.List; + +/** + * Authorize the connecting users against Carbon Permission Model. Intended usage is + * via providing fully qualified class name in broker.xml + *

+ * This is just a simple authorization model. For dynamic topics use an implementation based on IAuthorizer + */ +public class DeviceAccessBasedMQTTAuthorizer implements IAuthorizer { + + private static final String SCOPE_IDENTIFIER = "scope"; + private static final String UI_EXECUTE = "ui.execute"; + private static Log logger = LogFactory.getLog(DeviceAccessBasedMQTTAuthorizer.class); + AuthorizationConfigurationManager MQTTAuthorizationConfiguration; + + public DeviceAccessBasedMQTTAuthorizer() { + this.MQTTAuthorizationConfiguration = AuthorizationConfigurationManager.getInstance(); + } + + /** + * {@inheritDoc} Authorize the user against carbon device mgt model. + */ + @Override + public boolean isAuthorizedForTopic(MQTTAuthorizationSubject authorizationSubject, String topic, + MQTTAuthoriztionPermissionLevel permissionLevel) { + if (isUserAuthorized(authorizationSubject, MQTTAuthorizationConfiguration.getAdminPermission(), UI_EXECUTE)) { + return true; + } + String topics[] = topic.split("/"); + if (topics.length < 3) { + return false; + } + String tenantIdFromTopic = topics[0]; + if (!tenantIdFromTopic.equals(authorizationSubject.getTenantDomain())) { + return false; + } + String deviceType = topics[1]; + String deviceId = topics[2]; + Object scopeObject = authorizationSubject.getProperties().get(SCOPE_IDENTIFIER); + + if (!deviceId.isEmpty() && !deviceType.isEmpty() && scopeObject != null) { + List scopes = (List) scopeObject; + String permissionScope = MQTTAuthorizationConfiguration.getMQTTPublisherScopeIdentifier(); + if (permissionLevel == MQTTAuthoriztionPermissionLevel.SUBSCRIBE) { + permissionScope = MQTTAuthorizationConfiguration.getMQTTSubscriberScopeIdentifier(); + } + String requiredScope = MQTTAuthorizationConfiguration.getDevicemgtScopeIdentifier() + ":" + deviceType + ":" + + deviceId + ":" + permissionScope; + for (String scope : scopes) { + if (requiredScope.equals(scope)) { + return true; + } + } + } + return false; + } + + /** + * {@inheritDoc} Authorized the user against carbon device mgt model. + */ + @Override + public boolean isAuthorizedToConnect(MQTTAuthorizationSubject authorizationSubject) { + return isUserAuthorized(authorizationSubject, MQTTAuthorizationConfiguration.getConnectionPermission() + , UI_EXECUTE); + } + + /** + * Check whether the client is authorized with the given permission and action. + * + * @param authorizationSubject this contains the client information + * @param permission Carbon permission that requires for the use + * @param action Carbon permission action that requires for the given permission. + * @return boolean - true if user is authorized else return false. + */ + private boolean isUserAuthorized(MQTTAuthorizationSubject authorizationSubject, String permission, String action) { + String username = authorizationSubject.getUsername(); + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain( + authorizationSubject.getTenantDomain(), true); + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + UserRealm userRealm = AuthorizationDataHolder.getInstance().getRealmService() + .getTenantUserRealm(tenantId); + return userRealm != null && userRealm.getAuthorizationManager() != null && + userRealm.getAuthorizationManager().isUserAuthorized(username, permission, action); + } catch (UserStoreException e) { + String errorMsg = String.format("Unable to authorize the user : %s", username); + logger.error(errorMsg, e); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } +} \ No newline at end of file diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/AuthorizationConfiguration.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/AuthorizationConfiguration.java new file mode 100644 index 0000000000..1a417a9245 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/AuthorizationConfiguration.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.config; + +import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.impl.builder.StAXOMBuilder; +import org.apache.axiom.om.xpath.AXIOMXPath; +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jaxen.JaxenException; +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.exception.AuthorizationException; +import org.wso2.carbon.utils.ServerConstants; +import org.wso2.securevault.SecretResolver; +import org.wso2.securevault.SecretResolverFactory; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.lang.reflect.InvocationTargetException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This class acts as a access point to retrieve config parameters used within the authorization. + * this configuration is read from broker.xml + */ +public class AuthorizationConfiguration { + /** + * Reserved Prefixes that activate different processing logic. + */ + private static final String LIST_TYPE = "LIST_"; + private static final QName SECURE_VAULT_QNAME = new QName("http://org.wso2.securevault/configuration" + , "secretAlias"); + /** + * Common Error states + */ + private static final String GENERIC_CONFIGURATION_PARSE_ERROR = "Error occurred when trying to parse " + + "configuration value {0}."; + private static final String NO_CHILD_FOR_KEY_IN_PROPERTY = "There was no child at the given key {0} for the " + + "parent property {1}."; + private static final String PROPERTY_NOT_A_LIST = "The input property {0} does not contain a list of child " + + "properties."; + /** + * location to broker.xml + */ + private static final String ROOT_CONFIG_FILE_PATH = System.getProperty(ServerConstants.CARBON_HOME) + + "/repository/conf/"; + /** + * File name of the main configuration file. + */ + private static final String ROOT_CONFIG_FILE_NAME = "broker.xml"; + private static Log log = LogFactory.getLog(AuthorizationConfigurationManager.class); + private static CompositeConfiguration compositeConfiguration; + /** + * This hashmap is used to maintain any properties that were read from broker.xml + */ + private static ConcurrentHashMap propertyList; + + public static void initialize() throws AuthorizationException { + String brokerConfigFilePath = ROOT_CONFIG_FILE_PATH + ROOT_CONFIG_FILE_NAME; + if (log.isDebugEnabled()) { + log.debug("Configuration located at : " + brokerConfigFilePath); + } + try { + compositeConfiguration = new CompositeConfiguration(); + compositeConfiguration.setDelimiterParsingDisabled(true); + XMLConfiguration rootConfiguration = new XMLConfiguration(); + rootConfiguration.setDelimiterParsingDisabled(true); + rootConfiguration.setFileName(brokerConfigFilePath); + rootConfiguration.setExpressionEngine(new XPathExpressionEngine()); + rootConfiguration.load(); + readConfigurationFromFile(brokerConfigFilePath); + compositeConfiguration.addConfiguration(rootConfiguration); + } catch (FileNotFoundException e) { + String error = "Error occurred when trying to read the configuration file : " + brokerConfigFilePath; + log.error(error, e); + throw new AuthorizationException(error, e); + } catch (JaxenException e) { + String error = "Error occurred when trying to process file : " + brokerConfigFilePath; + log.error(error, e); + throw new AuthorizationException(error, e); + } catch (XMLStreamException e) { + String error = "Error occurred when trying to process file : " + brokerConfigFilePath; + log.error(error, e); + throw new AuthorizationException(error, e); + } catch (ConfigurationException e) { + String error = "Error occurred when trying to process file :" + brokerConfigFilePath; + log.error(error, e); + throw new AuthorizationException(error, e); + } + } + + + private static void readConfigurationFromFile(String filePath) throws FileNotFoundException, JaxenException + , XMLStreamException { + propertyList = new ConcurrentHashMap(); + StAXOMBuilder stAXOMBuilder = new StAXOMBuilder(new FileInputStream(new File(filePath))); + OMElement dom = stAXOMBuilder.getDocumentElement(); + SecretResolver secretResolver = SecretResolverFactory.create(dom, false); + AXIOMXPath xpathExpression = new AXIOMXPath("//*[@*[local-name() = \'secretAlias\']]"); + List nodeList = xpathExpression.selectNodes(dom); + String propertyKey; + String propertyValue; + for (Iterator i$ = nodeList.iterator(); i$.hasNext(); propertyList.put(propertyKey, propertyValue)) { + Object o = i$.next(); + propertyKey = ((OMElement) o).getAttributeValue(SECURE_VAULT_QNAME); + propertyValue = ""; + if (secretResolver != null && secretResolver.isInitialized()) { + if (secretResolver.isTokenProtected(propertyKey)) { + propertyValue = secretResolver.resolve(propertyKey); + } + } else { + log.warn("Error while reading properties form file"); + } + } + + } + + /** + * Using this method, you can access a singular property of a child. + * example, + * + * /permission/admin/device-mgt/user + * /permission/admin/device-mgt/admin + * mqtt-subscriber + * mqtt-subscriber + * device-mgt + * scenario. + * + * @param configurationProperty relevant enum value (e.g.- above scenario -> org.wso2.carbon.andes.extensions + * .device.mgt.mqtt.authorization.config.TRANSPORT_MQTT_AUTHORIZATION_PROPERTIES) + * @param key key of the child of whom you seek the value (e.g. above scenario -> "property list") + */ + static T readValueOfChildByKey(MQTTConfiguration configurationProperty, String key) { + + String constructedKey = configurationProperty.get().getKeyInFile().replace("{key}", + key); + try { + return (T) deriveValidConfigurationValue(constructedKey, + configurationProperty.get().getDataType(), + configurationProperty.get().getDefaultValue()); + } catch (ConfigurationException e) { + log.error(MessageFormat.format(NO_CHILD_FOR_KEY_IN_PROPERTY, key, configurationProperty), e); + return null; + } + } + + + /** + * Use this method when you need to acquire a list of properties of same group. + * + * @param configurationProperty relevant enum value (e.g.- org.wso2.carbon.andes.extensions + * .device.mgt.mqtt.authorization.config.LIST_TRANSPORT_MQTT_AUTHORIZATION_PROPERTIES) + * @return String list of required property values + */ + static List readValueList(MQTTConfiguration configurationProperty) { + + if (configurationProperty.toString().startsWith(LIST_TYPE)) { + return Arrays.asList(compositeConfiguration.getStringArray(configurationProperty.get().getKeyInFile())); + } else { + log.error(MessageFormat.format(PROPERTY_NOT_A_LIST, configurationProperty)); + return new ArrayList<>(); + } + } + + + /** + * Given the data type and the value read from a config, this returns the parsed value + * of the property. + * + * @param key The Key to the property being read (n xpath format as contained in file.) + * @param dataType Expected data type of the property + * @param defaultValue This parameter should NEVER be null since we assign a default value to + * every config property. + * @param Expected data type of the property + * @return Value of config in the expected data type. + * @throws ConfigurationException if there are any configuration issues + */ + private static T deriveValidConfigurationValue(String key, Class dataType, + String defaultValue) throws ConfigurationException { + if (log.isDebugEnabled()) { + log.debug("Reading configuration value " + key); + } + String readValue = compositeConfiguration.getString(key); + String validValue = defaultValue; + if (StringUtils.isBlank(readValue)) { + log.warn("Error when trying to read property : " + key + ". Switching to " + "default value : " + + defaultValue); + } else { + validValue = overrideWithDecryptedValue(key, readValue); + } + if (log.isDebugEnabled()) { + log.debug("Valid value read for andes configuration property " + key + " is : " + validValue); + } + try { + return dataType.getConstructor(String.class).newInstance(validValue); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) { + throw new ConfigurationException(MessageFormat.format(GENERIC_CONFIGURATION_PARSE_ERROR, key), e); + } + } + + /** + * If the property is contained in the propertyList, replace the raw value with that value. + * + * @param keyInFile xpath expression used to extract the value from file. + * @param rawValue The value read from the file without any processing. + * @return the value with corresponding to actual value. + */ + private static String overrideWithDecryptedValue(String keyInFile, String rawValue) { + if (!StringUtils.isBlank(keyInFile)) { + String key = keyInFile.replaceAll("/", "."); + if (propertyList.containsKey(key)) { + return propertyList.get(key); + } + } + return rawValue; + } +} diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/AuthorizationConfigurationManager.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/AuthorizationConfigurationManager.java new file mode 100644 index 0000000000..c477af77a6 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/AuthorizationConfigurationManager.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.config; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.List; + +public class AuthorizationConfigurationManager { + + private static final String CONNECTION_PERMISSION = "connectionPermission"; + private static final String ADMIN_PERMISSION = "adminPermission"; + private static final String MQTT_PUBLISHER_SCOPE_IDENTIFIER = "MQTTPublisherScopeIdentifier"; + private static final String MQTT_SUBSCRIBER_SCOPE_IDENTIFIER = "MQTTSubscriberScopeIdentifier"; + private static final String DEVICE_MGT_SCOPE_IDENTIFIER = "devicemgtScopeIdentifier"; + private static final AuthorizationConfigurationManager oAuthConfigurationManager + = new AuthorizationConfigurationManager(); + private static Log logger = LogFactory.getLog(AuthorizationConfigurationManager.class); + private String connectionPermission; + private String adminPermission; + private String MQTTPublisherScopeIdentifier; + private String MQTTSubscriberScopeIdentifier; + private String devicemgtScopeIdentifier; + + private AuthorizationConfigurationManager() { + + } + + public static AuthorizationConfigurationManager getInstance() { + return oAuthConfigurationManager; + } + + public String getConnectionPermission() { + return connectionPermission; + } + + public void setConnectionPermission(String connectionPermission) { + if (connectionPermission != null) { + this.connectionPermission = connectionPermission; + } else { + logger.error("Connection permission can't be null "); + } + } + + public String getAdminPermission() { + return adminPermission; + } + + public void setAdminPermission(String adminPermission) { + if (adminPermission != null) { + this.adminPermission = adminPermission; + } else { + logger.error("admin permission can't be null "); + } + } + + public String getMQTTPublisherScopeIdentifier() { + return MQTTPublisherScopeIdentifier; + } + + public void setMQTTPublisherScopeIdentifier(String MQTTPublisherScopeIdentifier) { + if (MQTTPublisherScopeIdentifier != null) { + this.MQTTPublisherScopeIdentifier = MQTTPublisherScopeIdentifier; + } else { + logger.error("MQTT publisher scope identifier can't be null "); + } + } + + public String getMQTTSubscriberScopeIdentifier() { + return MQTTSubscriberScopeIdentifier; + } + + public void setMQTTSubscriberScopeIdentifier(String MQTTSubscriberScopeIdentifier) { + if (MQTTSubscriberScopeIdentifier != null) { + this.MQTTSubscriberScopeIdentifier = MQTTSubscriberScopeIdentifier; + } else { + logger.error("MQTT subscriber scope identifier can't be null "); + } + } + + public String getDevicemgtScopeIdentifier() { + return devicemgtScopeIdentifier; + } + + public void setDevicemgtScopeIdentifier(String devicemgtScopeIdentifier) { + if (devicemgtScopeIdentifier != null) { + this.devicemgtScopeIdentifier = devicemgtScopeIdentifier; + } else { + logger.error("Device management scope identifier can't be null "); + } + } + + /** + * Initialize the configuration properties that required for MQTT Authorization + */ + public synchronized void initConfig() { + List mqttTransportAuthorizationProperties = AuthorizationConfiguration.readValueList(MQTTConfiguration + .LIST_TRANSPORT_MQTT_AUTHORIZATION_PROPERTIES); + for (String property : mqttTransportAuthorizationProperties) { + String propertyValue = AuthorizationConfiguration.readValueOfChildByKey( + MQTTConfiguration.TRANSPORT_MQTT_AUTHORIZATION_PROPERTIES, property); + switch (property) { + case CONNECTION_PERMISSION: + setConnectionPermission(propertyValue); + break; + case ADMIN_PERMISSION: + setAdminPermission(propertyValue); + break; + case MQTT_PUBLISHER_SCOPE_IDENTIFIER: + setMQTTPublisherScopeIdentifier(propertyValue); + break; + case MQTT_SUBSCRIBER_SCOPE_IDENTIFIER: + setMQTTSubscriberScopeIdentifier(propertyValue); + break; + case DEVICE_MGT_SCOPE_IDENTIFIER: + setDevicemgtScopeIdentifier(propertyValue); + break; + default: + break; + } + } + } +} diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/MQTTConfiguration.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/MQTTConfiguration.java new file mode 100644 index 0000000000..9e56118da6 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/config/MQTTConfiguration.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.config; + +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.util.ImmutableMetaProperties; +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.util.MetaProperties; + +import java.util.List; + +public enum MQTTConfiguration { + + /** + * List of properties that can define how the server will authenticate the user with the authentication service. + */ + LIST_TRANSPORT_MQTT_AUTHORIZATION_PROPERTIES("transports/mqtt/security/authorizer/property/@name", "", List.class), + + /** + * This can be used to access a property by giving its key. e.g. hosturl + */ + TRANSPORT_MQTT_AUTHORIZATION_PROPERTIES("transports/mqtt/security/authorizer/property[@name = '{key}']", "" + , String.class); + + /** + * Meta data about configuration. + */ + private final MetaProperties metaProperties; + + /** + * Constructor to define a configuration in broker. + * + * @param keyInFile Xpath (or any key value) which can be used to identify the configuration in the file. + * @param defaultValue the default value + * @param dataType data type of the config ( e.g. boolean, string ) + */ + MQTTConfiguration(String keyInFile, String defaultValue, Class dataType) { + // We need to pass the enum name as the identifier : therefore this.name() + this.metaProperties = new ImmutableMetaProperties(this.name(), keyInFile, defaultValue, dataType); + } + + public MetaProperties get() { + return metaProperties; + } + + +} + diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/exception/AuthorizationException.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/exception/AuthorizationException.java new file mode 100644 index 0000000000..4343886350 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/exception/AuthorizationException.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.exception; + +public class AuthorizationException extends Exception { + /** + * Default Serialization UID + */ + private static final long serialVersionUID = 1L; + + /** + * error code for our custom exception type to identify specific scenarios and handle them properly. + */ + private String errorCode = ""; + + public AuthorizationException() { + } + + public AuthorizationException(String message) { + super(message); + } + + /*** + * Constructor + * @param message descriptive message + * @param errorCode one of the above defined constants that classifies the error. + */ + public AuthorizationException(String message, String errorCode) { + super(message); + this.errorCode = errorCode; + } + + /*** + * Constructor + * @param message descriptive message + * @param cause reference to the exception for reference. + */ + public AuthorizationException(String message, Throwable cause) { + super(message, cause); + } + + /*** + * Constructor + * @param message descriptive message + * @param errorCode one of the above defined constants that classifies the error. + * @param cause reference to the exception for reference. + */ + public AuthorizationException(String message, String errorCode, Throwable cause) { + super(message, cause); + this.errorCode = errorCode; + } + + /*** + * Constructor + * @param cause reference to the exception for reference. + */ + public AuthorizationException(Throwable cause) { + super(cause); + } + + /*** + * One of the above defined constants that classifies the error. e.g.- MESSAGE_CONTENT_OBSOLETE + * @return + */ + public String getErrorCode() { + return errorCode; + } +} diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/internal/AuthorizationDataHolder.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/internal/AuthorizationDataHolder.java new file mode 100644 index 0000000000..f36ac6d458 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/internal/AuthorizationDataHolder.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.internal; + +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.user.core.tenant.TenantManager; + +public class AuthorizationDataHolder { + + private static AuthorizationDataHolder thisInstance = new AuthorizationDataHolder(); + private RealmService realmService; + private TenantManager tenantManager; + + private AuthorizationDataHolder() { + } + + public static AuthorizationDataHolder getInstance() { + return thisInstance; + } + + public RealmService getRealmService() { + return realmService; + } + + public void setRealmService(RealmService realmService) { + this.realmService = realmService; + this.setTenantManager(realmService); + } + + public TenantManager getTenantManager() { + return tenantManager; + } + + private void setTenantManager(RealmService realmService) { + if (realmService == null) { + throw new IllegalStateException("Realm service is not initialized properly"); + } + this.tenantManager = realmService.getTenantManager(); + } + +} diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/internal/AuthorizationServiceComponent.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/internal/AuthorizationServiceComponent.java new file mode 100644 index 0000000000..7a72d5969a --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/internal/AuthorizationServiceComponent.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.config.AuthorizationConfiguration; +import org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.config.AuthorizationConfigurationManager; +import org.wso2.carbon.user.core.service.RealmService; + +/** + * @scr.component name="org.wso2.carbon.devicemgt.policy.manager" immediate="true" + * @scr.reference name="user.realmservice.default" + * interface="org.wso2.carbon.user.core.service.RealmService" + * cardinality="1..1" + * policy="dynamic" + * bind="setRealmService" + * unbind="unsetRealmService" + */ +@SuppressWarnings("unused") +public class AuthorizationServiceComponent { + + private static Log log = LogFactory.getLog(AuthorizationServiceComponent.class); + + protected void activate(ComponentContext componentContext) { + try { + AuthorizationConfiguration.initialize(); + AuthorizationConfigurationManager.getInstance().initConfig(); + } catch (Throwable e) { + log.error("Failed to activate org.wso2.carbon.andes.authorization.internal." + + "AuthorizationServiceComponent : " + e); + } + } + + @SuppressWarnings("unused") + protected void deactivate(ComponentContext componentContext) { + + } + + /** + * Sets Realm Service + * + * @param realmService An instance of RealmService + */ + protected void setRealmService(RealmService realmService) { + if (log.isDebugEnabled()) { + log.debug("Setting Realm Service"); + } + AuthorizationDataHolder.getInstance().setRealmService(realmService); + } + + /** + * Unsets Realm Service + * + * @param realmService An instance of RealmService + */ + protected void unsetRealmService(RealmService realmService) { + if (log.isDebugEnabled()) { + log.debug("Unsetting Realm Service"); + } + AuthorizationDataHolder.getInstance().setRealmService(null); + } + +} diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/util/ImmutableMetaProperties.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/util/ImmutableMetaProperties.java new file mode 100644 index 0000000000..5ff2b92dab --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/util/ImmutableMetaProperties.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.util; + +/** + * This class contains the immutable meta attributes of a config property. These are + * immutable so that enums can contain them. + */ +public final class ImmutableMetaProperties implements MetaProperties { + + private final String keyInFile; + private final String defaultValue; + private final Class dataType; + private final String name; + + /** + * constructor + * + * @param keyInFile xpath expression to the property in the config file + * @param defaultValue default value of property in case its not specified or found in config files. + * @param dataType expected data type of the property + */ + public ImmutableMetaProperties(String name, String keyInFile, String defaultValue, Class dataType) { + this.name = name; + this.keyInFile = keyInFile; + this.defaultValue = defaultValue; + this.dataType = dataType; + } + + /** + * {@inheritDoc} + */ + @Override + public String getKeyInFile() { + return keyInFile; + } + + /** + * {@inheritDoc} + */ + @Override + public String getDefaultValue() { + return defaultValue; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getDataType() { + return dataType; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "Property : " + keyInFile + " data-type : " + dataType.getName() + " default value" + + " : " + defaultValue; + } +} diff --git a/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/util/MetaProperties.java b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/util/MetaProperties.java new file mode 100644 index 0000000000..003dcd12f2 --- /dev/null +++ b/components/extensions/mb-extensions/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization/src/main/java/org/wso2/carbon/andes/extensions/device/mgt/mqtt/authorization/util/MetaProperties.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.util; + +/** + * Contains methods that should be implemented to access meta properties of a config + * property. + */ +public interface MetaProperties { + + /** + * @return actual key with which the property is set in relevant config file. + */ + String getKeyInFile(); + + /** + * @return Default value specified for the config property, + * in case it is not set in file. + */ + String getDefaultValue(); + + /** + * @return Datatype of the property. (There could be numeric,date or boolean values.) + */ + Class getDataType(); + + /** + * @return Name of the property (e.g. TRANSPORTS_AMQP_DEFAULT_CONNECTION_PORT) + */ + String getName(); + +} diff --git a/components/extensions/mb-extensions/pom.xml b/components/extensions/mb-extensions/pom.xml new file mode 100644 index 0000000000..eb13c05718 --- /dev/null +++ b/components/extensions/mb-extensions/pom.xml @@ -0,0 +1,58 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + extensions + 2.2.6-SNAPSHOT + ../pom.xml + + + 4.0.0 + mb-extensions + pom + WSO2 Carbon - MB Extension + http://wso2.org + + + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/extensions/pom.xml b/components/extensions/pom.xml index b8d2076d76..1e3c2c3d4b 100644 --- a/components/extensions/pom.xml +++ b/components/extensions/pom.xml @@ -35,6 +35,7 @@ appm-connector cdmf-transport-adapters + mb-extensions diff --git a/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/pom.xml b/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/pom.xml new file mode 100644 index 0000000000..d3118d5f2f --- /dev/null +++ b/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/pom.xml @@ -0,0 +1,79 @@ + + + + + + + + org.wso2.carbon.devicemgt-plugins + extensions-feature + 2.2.6-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature + pom + WSO2 Carbon - MQTT Authorization Feature + http://wso2.org + This feature contains the bundles required for mqtt authorization + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization + + + + + + org.wso2.maven + carbon-p2-plugin + ${carbon.p2.plugin.version} + + + 4-p2-feature-generation + package + + p2-feature-gen + + + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization + ../../etc/feature.properties + + + org.wso2.carbon.p2.category.type:server + org.eclipse.equinox.p2.type.group:true + + + + + org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization:${carbon.devicemgt.plugins.version} + + + + org.wso2.carbon.core.server:4.4.9 + + + + + + + + diff --git a/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/src/main/resources/build.properties b/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/src/main/resources/build.properties new file mode 100644 index 0000000000..ddedd58dc4 --- /dev/null +++ b/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/src/main/resources/build.properties @@ -0,0 +1,19 @@ +# +# Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +# +# WSO2 Inc. licenses this file to you under the Apache License, +# Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +custom = true diff --git a/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/src/main/resources/p2.inf b/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/src/main/resources/p2.inf new file mode 100644 index 0000000000..7ab37b9d7d --- /dev/null +++ b/features/extensions-feature/org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature/src/main/resources/p2.inf @@ -0,0 +1 @@ +instructions.configure = \ \ No newline at end of file diff --git a/features/extensions-feature/pom.xml b/features/extensions-feature/pom.xml index dd2de92bbd..8b3e4aed41 100644 --- a/features/extensions-feature/pom.xml +++ b/features/extensions-feature/pom.xml @@ -36,6 +36,7 @@ org.wso2.carbon.appmgt.mdm.osgiconnector.feature org.wso2.carbon.device.mgt.adapter.feature + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization.feature diff --git a/pom.xml b/pom.xml index 248afa466b..27724bdbbf 100644 --- a/pom.xml +++ b/pom.xml @@ -1139,6 +1139,22 @@ org.wso2.carbon.apimgt.keymgt.client ${carbon.api.mgt.version} + + + org.wso2.andes.wso2 + andes + ${carbon.messaging.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.andes.extensions.device.mgt.mqtt.authorization + ${carbon.devicemgt.plugins.version} + + + commons-lang + commons-lang + ${commons.lang.version} + @@ -1245,6 +1261,7 @@ 1.0.8 1.8 0.9.1 + 2.2 3.1.0.wso2v2 @@ -1297,6 +1314,9 @@ 5.0.2.Final [0.0.0,1.0.0) + + + 3.1.11