5 # Copyright 2012 Intel Corporation.
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
19 # Luc Yriarte <luc.yriarte@intel.com>
20 # Christophe Guiraud <christophe.guiraud@intel.com>
21 # Frederic Paut <frederic.paut@intel.com>
25 import argparse, dbus, json, sys
27 from twisted.internet import glib2reactor
28 # Configure the twisted mainloop to be run inside the glib mainloop.
29 # This must be done before importing the other twisted modules
30 glib2reactor.install()
31 from twisted.internet import reactor
33 from autobahn.websocket import listenWS
34 from autobahn.wamp import WampServerFactory, WampCraServerProtocol
36 from dbus.mainloop.glib import DBusGMainLoop
39 gobject.threads_init()
45 from twisted.python import log
47 ###############################################################################
49 from engine import VERSION, SERVICELIST, CloudeebusService, cache
57 ###############################################################################
59 ## Convert an ip or an IP mask (such as ip/24 or ip/255.255.255.0) in hex value (32bits)
62 if mask.rfind(".") == -1:
64 maskHex = (2**(int(mask))-1)
65 maskHex = maskHex << (32-int(mask))
67 raise Exception("Illegal mask (larger than 32 bits) " + mask)
69 maskField = mask.split(".")
70 # Check if mask has four fields (byte)
71 if len(maskField) != 4:
72 raise Exception("Illegal ip address / mask (should be 4 bytes) " + mask)
73 for maskQuartet in maskField:
74 byte = int(maskQuartet)
75 # Check if each field is really a byte
77 raise Exception("Illegal ip address / mask (digit larger than a byte) " + mask)
79 maskHex = maskHex << 8
80 maskHex = maskHex >> 8
83 ###############################################################################
84 class CloudeebusServerProtocol(WampCraServerProtocol):
86 connexion and session authentication management
89 def onSessionOpen(self):
90 # CRA authentication options
91 self.clientAuthTimeout = 0
92 self.clientAuthAllowAnonymous = OPENDOOR
93 # CRA authentication init
94 WampCraServerProtocol.onSessionOpen(self)
97 def getAuthPermissions(self, key, extra):
98 return {'permissions': extra.get("permissions", None),
99 'authextra': extra.get("authextra", None),
100 'services': extra.get("services", None)}
102 def getAuthSecret(self, key):
103 secret = CREDENTIALS.get(key, None)
106 # secret must be of str type to be hashed
110 def onAuthenticated(self, key, permissions):
115 for netfilter in NETMASK:
116 ipHex=ipV4ToHex(self.peer.host)
117 ipAllowed = (ipHex & netfilter['mask']) == netfilter['ipAllowed'] & netfilter['mask']
121 raise Exception("host " + self.peer.host + " is not allowed!")
122 # check authentication key
124 raise Exception("Authentication failed")
125 # check permissions, array.index throws exception
126 if (permissions['permissions'] != None):
127 for req in permissions['permissions']:
128 WHITELIST.index(req);
129 # check allowed service creation, array.index throws exception
130 if (permissions['services'] != None):
131 for req in permissions['services']:
132 SERVICELIST.index(req);
133 # create cloudeebus service instance
134 self.cloudeebusService = CloudeebusService(permissions)
135 # register it for RPC
136 self.registerForRpc(self.cloudeebusService)
137 # register for Publish / Subscribe
138 self.registerForPubSub("", True)
141 def connectionLost(self, reason):
142 WampCraServerProtocol.connectionLost(self, reason)
143 if factory.getConnectionCount() == 0:
148 ###############################################################################
150 if __name__ == '__main__':
151 parser = argparse.ArgumentParser(description='Javascript DBus bridge.')
152 parser.add_argument('-v', '--version', action='store_true',
153 help='print version and exit')
154 parser.add_argument('-d', '--debug', action='store_true',
155 help='log debug info on standard output')
156 parser.add_argument('-o', '--opendoor', action='store_true',
157 help='allow anonymous access to all services')
158 parser.add_argument('-p', '--port', default='9000',
160 parser.add_argument('-c', '--credentials',
161 help='path to credentials file')
162 parser.add_argument('-w', '--whitelist',
163 help='path to whitelist file (DBus services to use)')
164 parser.add_argument('-s', '--servicelist',
165 help='path to servicelist file (DBus services to export)')
166 parser.add_argument('-n', '--netmask',
167 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')
169 args = parser.parse_args(sys.argv[1:])
172 print("Cloudeebus version " + VERSION)
176 log.startLogging(sys.stdout)
178 OPENDOOR = args.opendoor
181 jfile = open(args.credentials)
182 CREDENTIALS = json.load(jfile)
186 jfile = open(args.whitelist)
187 WHITELIST.extend(json.load(jfile))
191 jfile = open(args.servicelist)
192 SERVICELIST.extend(json.load(jfile))
196 iplist = args.netmask.split(",")
198 if ip.rfind("/") != -1:
204 mask = "255.255.255.255"
205 NETMASK.append( {'ipAllowed': ipV4ToHex(ipAllowed), 'mask' : ipV4ToHex(mask)} )
207 uri = "ws://localhost:" + args.port
209 factory = WampServerFactory(uri, debugWamp = args.debug)
210 factory.protocol = CloudeebusServerProtocol
211 factory.setProtocolOptions(allowHixie76 = True)
213 # Configure engine for WAMP.
214 engine.factory = factory
215 engine.OPENDOOR = OPENDOOR
219 DBusGMainLoop(set_as_default=True)