X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cloudeebus%2Fcloudeebus.py;h=66e646d47e660d08690327268e91147211130503;hb=5489d61ff5688acb67752f2affa4a16d5b5a3b74;hp=82cb354d06bab4cc854f489cf6e1a32f34835ae6;hpb=d3a68905f61eda2979dc1a234bdfd7f9cd277c97;p=contrib%2Fcloudeebus.git diff --git a/cloudeebus/cloudeebus.py b/cloudeebus/cloudeebus.py index 82cb354..66e646d 100755 --- a/cloudeebus/cloudeebus.py +++ b/cloudeebus/cloudeebus.py @@ -18,6 +18,7 @@ # # Luc Yriarte # Christophe Guiraud +# Frederic Paut # @@ -48,13 +49,40 @@ from twisted.python import log # XML parser module from xml.etree.ElementTree import XMLParser - ############################################################################### -VERSION = "0.3.0" +VERSION = "0.5.99" OPENDOOR = False CREDENTIALS = {} WHITELIST = [] +SERVICELIST = [] +NETMASK = [] + +############################################################################### +def ipV4ToHex(mask): + ## Convert an ip or an IP mask (such as ip/24 or ip/255.255.255.0) in hex value (32bits) + maskHex = 0 + byte = 0 + if mask.rfind(".") == -1: + if (int(mask) < 32): + maskHex = (2**(int(mask))-1) + maskHex = maskHex << (32-int(mask)) + else: + raise Exception("Illegal mask (larger than 32 bits) " + mask) + else: + maskField = mask.split(".") + # Check if mask has four fields (byte) + if len(maskField) != 4: + raise Exception("Illegal ip address / mask (should be 4 bytes) " + mask) + for maskQuartet in maskField: + byte = int(maskQuartet) + # Check if each field is really a byte + if byte > 255: + raise Exception("Illegal ip address / mask (digit larger than a byte) " + mask) + maskHex += byte + maskHex = maskHex << 8 + maskHex = maskHex >> 8 + return maskHex ############################################################################### class DbusCache: @@ -251,6 +279,10 @@ class XmlCbParser: # The target object of the parser +############################################################################### +def createClassName(objectPath): + return re.sub('/', '_', objectPath[1:]) + ################################################################################ class DynDBusClass(): def __init__(self, className, globalCtx, localCtx): @@ -266,9 +298,9 @@ class DynDBusClass(): ## Overload of __init__ method self.def_method("__init__") - self.add_method("bus, callback=None, objName='/sample', busName='org.cloudeebus'") + self.add_method("bus, callback=None, objPath='/sample', busName='org.cloudeebus'") self.add_stmt("self.bus = bus") - self.add_stmt("self.objName = objName") + self.add_stmt("self.objPath = objPath") self.add_stmt("self.callback = callback") self.add_stmt("dbus.service.Object.__init__(self, conn=bus, bus_name=busName)") self.end_method() @@ -276,13 +308,13 @@ class DynDBusClass(): ## Create 'add_to_connection' method self.def_method("add_to_connection") self.add_method("connection=None, path=None") - self.add_stmt("dbus.service.Object.add_to_connection(self, connection=self.bus, path=self.objName)") + self.add_stmt("dbus.service.Object.add_to_connection(self, connection=self.bus, path=self.objPath)") self.end_method() ## Create 'remove_from_connection' method self.def_method("remove_from_connection") self.add_method("connection=None, path=None") - self.add_stmt("dbus.service.Object.remove_from_connection(self, connection=None, path=self.objName)") + self.add_stmt("dbus.service.Object.remove_from_connection(self, connection=None, path=self.objPath)") self.end_method() def createDBusServiceFromXML(self, xml): @@ -379,9 +411,9 @@ class DynDBusClass(): def add_body_method(self): if (self.methodToAdd != None): if (self.args_str != str()): - self.class_code.append_stmt("self.callback('" + self.methodToAdd + "', '" + self.ifName + "', " + "dbus_async_cb, dbus_async_err_cb, %s)" % self.args_str) + self.class_code.append_stmt("self.callback('" + self.methodToAdd + "', self.objPath, '" + self.ifName + "', " + "dbus_async_cb, dbus_async_err_cb, %s)" % self.args_str) else: - self.class_code.append_stmt("self.callback('" + self.methodToAdd + "', '" + self.ifName + "', " + "dbus_async_cb, dbus_async_err_cb)") + self.class_code.append_stmt("self.callback('" + self.methodToAdd + "', self.objPath, '" + self.ifName + "', " + "dbus_async_cb, dbus_async_err_cb)") def add_body_signal(self): self.class_code.append_stmt("return") ## TODO: Remove and fix with code ad hoc @@ -401,7 +433,10 @@ class CloudeebusService: support for sending DBus messages and registering for DBus signals ''' def __init__(self, permissions): - self.permissions = permissions; + self.permissions = {}; + self.permissions['permissions'] = permissions['permissions'] + self.permissions['authextra'] = permissions['authextra'] + self.permissions['services'] = permissions['services'] self.proxyObjects = {} self.proxyMethods = {} self.pendingCalls = [] @@ -421,7 +456,7 @@ class CloudeebusService: if not self.proxyObjects.has_key(id): if not OPENDOOR: # check permissions, array.index throws exception - self.permissions.index(serviceName) + self.permissions['permissions'].index(serviceName) bus = cache.dbusConnexion(busName) self.proxyObjects[id] = bus.get_object(serviceName, objectName) return self.proxyObjects[id] @@ -448,7 +483,7 @@ class CloudeebusService: if not OPENDOOR: # check permissions, array.index throws exception - self.permissions.index(list[1]) + self.permissions['permissions'].index(list[1]) # check if a handler exists sigId = "#".join(list) @@ -536,13 +571,19 @@ class CloudeebusService: else: raise Exception("No methodID " + methodId) - def srvCB(self, name, ifName, async_succes_cb, async_error_cb, *args): - methodId = self.srvName + "#" + self.agentObjectPath + "#" + ifName + "#" + name + def srvCB(self, name, objPath, ifName, async_succes_cb, async_error_cb, *args): + methodId = self.srvName + "#" + objPath + "#" + ifName + "#" + name cb = { 'successCB': async_succes_cb, 'errorCB': async_error_cb} if methodId not in self.servicePendingCalls: self.servicePendingCalls[methodId] = {'count': 0, 'calls': []} - pendingCallStr = json.dumps({'callIndex': len(self.servicePendingCalls[methodId]['calls']), 'args': args}) + + try: + pendingCallStr = json.dumps({'callIndex': len(self.servicePendingCalls[methodId]['calls']), 'args': args}) + except Exception, e: + args = eval( str(args).replace("dbus.Byte", "dbus.Int16") ) + pendingCallStr = json.dumps({'callIndex': len(self.servicePendingCalls[methodId]['calls']), 'args': args}) + self.servicePendingCalls[methodId]['calls'].append(cb) self.servicePendingCalls[methodId]['count'] = self.servicePendingCalls[methodId]['count'] + 1 factory.dispatch(methodId, pendingCallStr) @@ -553,9 +594,12 @@ class CloudeebusService: arguments: busName, srvName ''' busName = list[0] - self.bus = cache.dbusConnexion( busName['name'] ) + self.bus = cache.dbusConnexion( busName ) self.srvName = list[1] - if (self.services.has_key(self.srvName) == False): + if not OPENDOOR and (SERVICELIST == [] or SERVICELIST != [] and self.permissions['services'] == None): + SERVICELIST.index(self.srvName) + + if (self.services.has_key(self.srvName) == False): self.services[self.srvName] = dbus.service.BusName(name = self.srvName, bus = self.bus) return self.srvName @@ -569,7 +613,7 @@ class CloudeebusService: self.services.pop(self.srvName) return self.srvName else: - raise Exception(self.srvName + " do not exist") + raise Exception(self.srvName + " does not exist") @exportRpc def serviceAddAgent(self, list): @@ -578,7 +622,7 @@ class CloudeebusService: ''' self.agentObjectPath = list[0] xmlTemplate = list[1] - self.className = re.sub('/', '_', self.agentObjectPath[1:]) + self.className = createClassName(self.agentObjectPath) if (self.dynDBusClasses.has_key(self.className) == False): self.dynDBusClasses[self.className] = DynDBusClass(self.className, self.globalCtx, self.localCtx) self.dynDBusClasses[self.className].createDBusServiceFromXML(xmlTemplate) @@ -586,7 +630,7 @@ class CloudeebusService: ## Class already exist, instanciate it if not already instanciated if (self.serviceAgents.has_key(self.className) == False): - self.serviceAgents[self.className] = eval(self.className + "(self.bus, callback=self.srvCB, objName=self.agentObjectPath, busName=self.srvName)", self.globalCtx, self.localCtx) + self.serviceAgents[self.className] = eval(self.className + "(self.bus, callback=self.srvCB, objPath=self.agentObjectPath, busName=self.srvName)", self.globalCtx, self.localCtx) self.serviceAgents[self.className].add_to_connection() return (self.agentObjectPath) @@ -597,7 +641,7 @@ class CloudeebusService: arguments: objectPath, xmlTemplate ''' agentObjectPath = list[0] - className = re.sub('/', '_', agentObjectPath[1:]) + className = createClassName(agentObjectPath) if (self.serviceAgents.has_key(className)): self.serviceAgents[self.className].remove_from_connection() @@ -631,25 +675,41 @@ class CloudeebusServerProtocol(WampCraServerProtocol): def getAuthPermissions(self, key, extra): - return json.loads(extra.get("permissions", "[]")) - + return {'permissions': extra.get("permissions", None), + 'authextra': extra.get("authextra", None), + 'services': extra.get("services", None)} def getAuthSecret(self, key): secret = CREDENTIALS.get(key, None) if secret is None: return None # secret must be of str type to be hashed - return secret.encode('utf-8') + return str(secret) def onAuthenticated(self, key, permissions): if not OPENDOOR: + # check net filter + if NETMASK != []: + ipAllowed = False + for netfilter in NETMASK: + ipHex=ipV4ToHex(self.peer.host) + ipAllowed = (ipHex & netfilter['mask']) == netfilter['ipAllowed'] & netfilter['mask'] + if ipAllowed: + break + if not ipAllowed: + raise Exception("host " + self.peer.host + " is not allowed!") # check authentication key if key is None: raise Exception("Authentication failed") # check permissions, array.index throws exception - for req in permissions: - WHITELIST.index(req) + if (permissions['permissions'] != None): + for req in permissions['permissions']: + WHITELIST.index(req); + # check allowed service creation, array.index throws exception + if (permissions['services'] != None): + for req in permissions['services']: + SERVICELIST.index(req); # create cloudeebus service instance self.cloudeebusService = CloudeebusService(permissions) # register it for RPC @@ -683,7 +743,11 @@ if __name__ == '__main__': parser.add_argument('-c', '--credentials', help='path to credentials file') parser.add_argument('-w', '--whitelist', - help='path to whitelist file') + help='path to whitelist file (which the list of allowed DBus service to use)') + parser.add_argument('-s', '--servicelist', + help='path to servicelist file (which the list of allowed DBus service to create (=agent))') + parser.add_argument('-n', '--netmask', + help='netmask,IP filter (comma separated.) eg. : -n 127.0.0.1,192.168.2.0/24,10.12.16.0/255.255.255.0') args = parser.parse_args(sys.argv[1:]) @@ -705,7 +769,32 @@ if __name__ == '__main__': jfile = open(args.whitelist) WHITELIST = json.load(jfile) jfile.close() + + if args.servicelist: + jfile = open(args.servicelist) + SERVICELIST = json.load(jfile) + jfile.close() + + if args.netmask: + iplist = args.netmask.split(",") + for ip in iplist: + if ip.rfind("/") != -1: + ip=ip.split("/") + ipAllowed = ip[0] + mask = ip[1] + else: + ipAllowed = ip + mask = "255.255.255.255" + NETMASK.append( {'ipAllowed': ipV4ToHex(ipAllowed), 'mask' : ipV4ToHex(mask)} ) + if args.debug: + print "OPENDOOR='" + str(OPENDOOR) + "'" + print "CREDENTIALS='" + str(args.credentials) + "'" + print "WHITELIST='" + str(args.whitelist) + "'" + print "SERVICELIST='" + str(args.servicelist) + "'" + print "NETMASK='" + str(args.netmask) + "'" + print + uri = "ws://localhost:" + args.port factory = WampServerFactory(uri, debugWamp = args.debug)