Esempio n. 1
0
    def _modifyConfig(self, txn, configDelta):
        ## determine actual set of modified stuff
        ##
        modified = {}
        for c in configDelta:
            txn.execute("SELECT value FROM config WHERE key = ?", [
                c,
            ])
            res = txn.fetchone()
            if res:
                cval = json_loads(res[0])
                if cval != configDelta[c]:
                    modified[c] = configDelta[c]
                    txn.execute("UPDATE config SET value = ? WHERE key = ?",
                                [json_dumps(configDelta[c]), c])

        ## only something to do when there was an actual change
        ##
        if len(modified) > 0:
            ## recache config
            ##
            services = self.proto.factory.services
            if services.has_key("config"):
                services["config"].recache(txn)

            ## check if WebSocket option changed .. if so, notify WS factory
            ##
            wsOptionChanged = False
            for k in modified:
                if k[:2] == 'ws':
                    wsOptionChanged = True
                    break
            if wsOptionChanged:
                if self.proto.factory.services.has_key("appws"):
                    self.proto.factory.services["appws"].setOptionsFromConfig()
                if self.proto.factory.services.has_key("echows"):
                    self.proto.factory.services["echows"].setOptionsFromConfig(
                    )

            ## check for restart required
            ##
            for k in modified:
                if k in Database.SERVICES:
                    self.proto.factory.issueRestartRequired()

            ## notify subscribers
            ##
            self.proto.dispatch(URI_EVENT + "on-config-modified", modified,
                                [self.proto])

            ## return modified set to caller
            ##
            return modified
        else:
            ## nothing changed
            ##
            return {}
Esempio n. 2
0
 def __repr__(self):
    r = {'id': self.id,
         #'connectionTimeout': self.connectionTimeout,
         'host': self.host,
         'port': self.port,
         'database': self.database,
         'user': self.user,
         'password': self.password}
    return json_dumps(r)
 def render_GET(self, request):
    port = self.config.get(self.port + "-port", None)
    tls = self.config.get(self.port + "-tls", None)
    if self.port == "hub-websocket":
       path = self.config.get("ws-websocket-path", "")
       res = (port, tls, path)
    else:
       res = (port, tls)
    return json_dumps(res)
Esempio n. 4
0
 def __repr__(self):
    r = {'id': self.id,
         'driver': self.driver,
         'host': self.host,
         'port': self.port,
         'database': self.database,
         'user': self.user,
         'password': self.password}
    return json_dumps(r)
Esempio n. 5
0
 def render_GET(self, request):
     port = self.config.get(self.port + "-port", None)
     tls = self.config.get(self.port + "-tls", None)
     if self.port == "hub-websocket":
         path = self.config.get("ws-websocket-path", "")
         res = (port, tls, path)
     else:
         res = (port, tls)
     return json_dumps(res)
Esempio n. 6
0
    def _storeObject(self, txn, uri, obj):
        ## check arguments
        ##
        if type(uri) not in [str, unicode]:
            raise Exception(
                URI_ERROR + "illegal-argument",
                "Expected type str/unicode for argument uri, but got %s" %
                str(type(uri)))

        ## resolve URI
        ##
        uri = self.proto.resolveOrPass(uri)
        modified = True

        txn.execute("SELECT obj FROM objstore WHERE uri = ?", [uri])
        res = txn.fetchone()
        if res is not None:
            oldobj = json_loads(res[0])
            if obj is not None:
                objser = json_dumps(obj)
                if objser != res[0]:
                    txn.execute("UPDATE objstore SET obj = ? WHERE uri = ?",
                                [objser, uri])
                else:
                    modified = False
            else:
                txn.execute("DELETE FROM objstore WHERE uri = ?", [uri])
        else:
            oldobj = None
            if obj is not None:
                objser = json_dumps(obj)
                txn.execute("INSERT INTO objstore (uri, obj) VALUES (?, ?)",
                            [uri, objser])
            else:
                modified = False

        if modified:
            event = {'uri': uri, 'old': oldobj, 'new': obj}
            self.proto.dispatch(URI_EVENT + "on-store-modified", event,
                                [self.proto])
            event["uri"] = self.proto.shrink(uri)
            return event
        else:
            return None
   def _createActivationRequest(self, txn, origin, licenseType, extra):

      LICENSE_TYPES = ['BETA']

      if licenseType not in LICENSE_TYPES:
         raise Exception(URI_ERROR + "illegal-argument", "Unknown license type '%s'" % str(licenseType), LICENSE_TYPES)

      ## construct license activation request
      ##
      hostid = self.factory.services['platform'].getHostId()
      instanceid = self.serviceConfig._getSingleConfig(txn, "instance-id")
      msg = {'type': licenseType,
             'host-id': hostid,
             'instance-id': instanceid}

      dbcreated = self.serviceConfig._getSingleConfig(txn, "database-created")
      platform = self.factory.services['platform'].getPlatformInfo()
      network = self.factory.services['platform'].getNetworkConfig()

      msg['info'] = {'request-time': utcnow(),
                     'database-created': dbcreated,
                     'platform': platform,
                     'network': network}

      if extra is not None:
         msg['extra'] = extra

      log.msg("created license activation request: %s" % msg)

      rmsg = json_dumps(msg)

      ## load instance key pair
      ##
      pubkey = str(self.serviceConfig._getSingleConfig(txn, "instance-pub-key"))
      privkey = str(self.serviceConfig._getSingleConfig(txn, "instance-priv-key"))

      ## encrypt activation request for Tavendo public key
      ## and sign encrypted message using instance private key
      ##
      (emsg, skey, dig, sig) = encrypt_and_sign(rmsg,
                                                privkey,
                                                Database.WEBMQ_LICENSE_CA_PUBKEY)

      payload = "%s,%s,%s,%s,%s,%s" % (emsg,
                                       skey,
                                       dig,
                                       sig,
                                       urllib.quote_plus(pubkey),
                                       urllib.quote_plus(origin + "/doactivate"))

      #print payload

      return {'request': msg,
              'url': self.factory.services['master'].licenseserver,
              'payload': payload}
   def _changePassword(self, txn, oldpassword, newpassword1, newpassword2):
      attrs = {"oldpassword": (True,
                               [str, unicode],
                               AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
                               AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
                               AdminWebSocketProtocol.USER_PASSWORD_PATTERN),
               "newpassword1": (True,
                                [str, unicode],
                                AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
                                AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
                                AdminWebSocketProtocol.USER_PASSWORD_PATTERN),
               "newpassword2": (True,
                                [str, unicode],
                                AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
                                AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
                                AdminWebSocketProtocol.USER_PASSWORD_PATTERN)}

      errcnt, errs = self.checkDictArg("user password",
                                       {"oldpassword": oldpassword,
                                        "newpassword1": newpassword1,
                                        "newpassword2": newpassword2},
                                       attrs)

      if newpassword1 != newpassword2:
         errcnt += 1
         if not errs.has_key('newpassword1') or errs.has_key('newpassword2'):
            p = 'newpassword1'
         else:
            p = 'newpassword2'
         if not errs.has_key(p):
            errs[p] = []
         errs[p].append((self.shrink(URI_ERROR + "invalid-attribute-value"), "New password values do not match"))

      if errcnt:
         raise Exception(URI_ERROR + "illegal-argument", "one or more illegal arguments (%d errors)" % errcnt, errs)

      txn.execute("SELECT value FROM config WHERE key = ?", ['admin-password'])
      res = txn.fetchone()
      if res:
         pw = str(json_loads(res[0]))
         if pw == oldpassword:
            if newpassword1 != oldpassword:
               txn.execute("UPDATE config SET value = ? WHERE key = ?", [json_dumps(newpassword1), "admin-password"])
            else:
               raise Exception(URI_ERROR + "illegal-argument",
                               "one or more illegal arguments (%d errors)" % 2,
                               {'newpassword1': [(self.shrink(URI_ERROR + "attribute-value-unchanged"), "Password unchanged")],
                                'newpassword2': [(self.shrink(URI_ERROR + "attribute-value-unchanged"), "Password unchanged")]})
         else:
            raise Exception(URI_ERROR + "illegal-argument",
                            "one or more illegal arguments (%d errors)" % 1,
                            {'oldpassword': [(self.shrink(URI_ERROR + "invalid-attribute-value"), "Old password is invalid")]})
      else:
         raise Exception(URI_ERROR + "internal-error", "Could not retrieve admin password from database.")
Esempio n. 9
0
 def __repr__(self):
     r = {
         'id': self.id,
         'driver': self.driver,
         'host': self.host,
         'port': self.port,
         'database': self.database,
         'user': self.user,
         'password': self.password
     }
     return json_dumps(r)
Esempio n. 10
0
 def __repr__(self):
     r = {
         'id': self.id,
         #'connectionTimeout': self.connectionTimeout,
         'host': self.host,
         'port': self.port,
         'database': self.database,
         'user': self.user,
         'password': self.password
     }
     return json_dumps(r)
Esempio n. 11
0
 def __repr__(self):
    r = {'id': self.id,
         #'connectionTimeout': self.connectionTimeout,
         'host': self.host,
         'port': self.port,
         'sid': self.sid,
         'user': self.user,
         'password': self.password,
         'demo-user': self.demoUser,
         'demo-password': self.demoPassword,
         }
    return json_dumps(r)
Esempio n. 12
0
   def _modifyConfig(self, txn, configDelta):
      ## determine actual set of modified stuff
      ##
      modified = {}
      for c in configDelta:
         txn.execute("SELECT value FROM config WHERE key = ?", [c,])
         res = txn.fetchone()
         if res:
            cval = json_loads(res[0])
            if cval != configDelta[c]:
               modified[c] = configDelta[c]
               txn.execute("UPDATE config SET value = ? WHERE key = ?", [json_dumps(configDelta[c]), c])

      ## only something to do when there was an actual change
      ##
      if len(modified) > 0:
         ## recache config
         ##
         services = self.proto.factory.services
         if services.has_key("config"):
           services["config"].recache(txn)

         ## check if WebSocket option changed .. if so, notify WS factory
         ##
         wsOptionChanged = False
         for k in modified:
            if k[:2] == 'ws':
               wsOptionChanged = True
               break
         if wsOptionChanged:
            if self.proto.factory.services.has_key("appws"):
               self.proto.factory.services["appws"].setOptionsFromConfig()
            if self.proto.factory.services.has_key("echows"):
               self.proto.factory.services["echows"].setOptionsFromConfig()

         ## check for restart required
         ##
         for k in modified:
            if k in Database.SERVICES:
               self.proto.factory.issueRestartRequired()

         ## notify subscribers
         ##
         self.proto.dispatch(URI_EVENT + "on-config-modified", modified, [self.proto])

         ## return modified set to caller
         ##
         return modified
      else:
         ## nothing changed
         ##
         return {}
Esempio n. 13
0
 def __repr__(self):
     r = {
         'id': self.id,
         #'connectionTimeout': self.connectionTimeout,
         'host': self.host,
         'port': self.port,
         'sid': self.sid,
         'user': self.user,
         'password': self.password,
         'demo-user': self.demoUser,
         'demo-password': self.demoPassword,
     }
     return json_dumps(r)
Esempio n. 14
0
   def _storeObject(self, txn, uri, obj):
      ## check arguments
      ##
      if type(uri) not in [str, unicode]:
         raise Exception(URI_ERROR + "illegal-argument", "Expected type str/unicode for argument uri, but got %s" % str(type(uri)))

      ## resolve URI
      ##
      uri = self.proto.resolveOrPass(uri)
      modified = True

      txn.execute("SELECT obj FROM objstore WHERE uri = ?", [uri])
      res = txn.fetchone()
      if res is not None:
         oldobj = json_loads(res[0])
         if obj is not None:
            objser = json_dumps(obj)
            if objser != res[0]:
               txn.execute("UPDATE objstore SET obj = ? WHERE uri = ?", [objser, uri])
            else:
               modified = False
         else:
            txn.execute("DELETE FROM objstore WHERE uri = ?", [uri])
      else:
         oldobj = None
         if obj is not None:
            objser = json_dumps(obj)
            txn.execute("INSERT INTO objstore (uri, obj) VALUES (?, ?)", [uri, objser])
         else:
            modified = False

      if modified:
         event = {'uri': uri, 'old': oldobj, 'new': obj}
         self.proto.dispatch(URI_EVENT + "on-store-modified", event, [self.proto])
         event["uri"] = self.proto.shrink(uri)
         return event
      else:
         return None
Esempio n. 15
0
    def _setPassword(self, txn, password1, password2):
        txn.execute("SELECT value FROM config WHERE key = ?",
                    ['admin-password'])
        res = txn.fetchone()
        if res:
            pw = json_loads(res[0])
            if pw is not None:
                raise Exception((URI_ERROR + "invalid-invocation",
                                 "Initial password already set."))
        else:
            raise Exception(
                URI_ERROR + "internal-error",
                "Could not retrieve admin password from database.")

        attrs = {
            "password1":
            (True, [str,
                    unicode], AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_PATTERN),
            "password2":
            (True, [str,
                    unicode], AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_PATTERN)
        }

        errcnt, errs = self.checkDictArg("user password", {
            "password1": password1,
            "password2": password2
        }, attrs)

        if password1 != password2:
            errcnt += 1
            if not errs.has_key('password1') or errs.has_key('password2'):
                p = 'password1'
            else:
                p = 'password2'
            if not errs.has_key(p):
                errs[p] = []
            errs[p].append((self.shrink(URI_ERROR + "invalid-attribute-value"),
                            "Passwords do not match"))

        if errcnt:
            raise Exception(
                URI_ERROR + "illegal-argument",
                "one or more illegal arguments (%d errors)" % errcnt, errs)

        txn.execute("UPDATE config SET value = ? WHERE key = ?",
                    [json_dumps(password1), "admin-password"])
Esempio n. 16
0
 def _acceptEula(self, txn):
    txn.execute("SELECT value FROM config WHERE key = ?", ["eula-accepted"])
    res = txn.fetchone()
    if res:
       eula_accepted = json_loads(res[0])
       if eula_accepted:
          raise Exception(URI_ERROR + "illegal-invocation", "EULA already accepted.")
       else:
          now = utcnow()
          txn.execute("UPDATE config SET value = ? WHERE key = ?", [json_dumps(now), "eula-accepted"])
          self.factory.services["config"].recache(txn)
          return now
    else:
       raise Exception(URI_ERROR + "internal-error", "EULA key not found.")
Esempio n. 17
0
 def getDiagnostics(self, as_json=False):
     r = {}
     r["python-site-packages"] = self.getSitePackages()
     r["package-info"] = self.getPkgInfo()
     r["interface-config"] = self.getIfconfig()
     r["dmesg"] = self.getDmesg()
     r["twisted-version"] = self.getTwistedVersion()
     r["python-version"] = self.getPythonVersion()
     r["os-version"] = self.getOsVersion()
     r["host-id"] = self.getHostId()
     r["network-config"] = self.getNetworkConfig()
     r["sysctl"] = self.getSysctl()
     if as_json:
         return json_dumps(r, indent=3)
     else:
         return r
Esempio n. 18
0
 def getDiagnostics(self, as_json = False):
    r = {}
    r['python-site-packages'] = self.getSitePackages()
    r['package-info'] = self.getPkgInfo()
    r['interface-config'] = self.getIfconfig()
    r['dmesg'] = self.getDmesg()
    r['twisted-version'] = self.getTwistedVersion()
    r['python-version'] = self.getPythonVersion()
    r['os-version'] = self.getOsVersion()
    r['host-id'] = self.getHostId()
    r['network-config'] = self.getNetworkConfig()
    r['sysctl'] = self.getSysctl()
    if as_json:
       return json_dumps(r, indent = 3)
    else:
       return r
Esempio n. 19
0
 def getDiagnostics(self, as_json=False):
     r = {}
     r['python-site-packages'] = self.getSitePackages()
     r['package-info'] = self.getPkgInfo()
     r['interface-config'] = self.getIfconfig()
     r['dmesg'] = self.getDmesg()
     r['twisted-version'] = self.getTwistedVersion()
     r['python-version'] = self.getPythonVersion()
     r['os-version'] = self.getOsVersion()
     r['host-id'] = self.getHostId()
     r['network-config'] = self.getNetworkConfig()
     r['sysctl'] = self.getSysctl()
     if as_json:
         return json_dumps(r, indent=3)
     else:
         return r
Esempio n. 20
0
 def __repr__(self):
     r = {
         'id': self.id,
         'appkey': self.appkey,
         'host': self.host,
         'port': self.port,
         'database': self.database,
         'user': self.user,
         'password': self.password,
         'schemaList': self.schemaList,
         'rpcBaseUri': self.rpcBaseUri,
         'connectionPoolMinSize': self.connectionPoolMinSize,
         'connectionPoolMaxSize': self.connectionPoolMaxSize,
         'connectionTimeout': self.connectionTimeout,
         'requestTimeout': self.requestTimeout,
     }
     return json_dumps(r)
Esempio n. 21
0
 def __repr__(self):
     r = {
         "id": self.id,
         "appkey": self.appkey,
         "host": self.host,
         "port": self.port,
         "database": self.database,
         "user": self.user,
         "password": self.password,
         "schemaList": self.schemaList,
         "rpcBaseUri": self.rpcBaseUri,
         "connectionPoolMinSize": self.connectionPoolMinSize,
         "connectionPoolMaxSize": self.connectionPoolMaxSize,
         "connectionTimeout": self.connectionTimeout,
         "requestTimeout": self.requestTimeout,
     }
     return json_dumps(r)
Esempio n. 22
0
   def __repr__(self):
      r = {'id': self.id,
           'appkey': self.appkey,

           'host': self.host,
           'port': self.port,
           'sid': self.sid,
           'user': self.user,
           'password': self.password,

           'schemaList': self.schemaList,
           'rpcBaseUri': self.rpcBaseUri,
           'connectionPoolMinSize': self.connectionPoolMinSize,
           'connectionPoolMaxSize': self.connectionPoolMaxSize,
           'connectionTimeout': self.connectionTimeout,
           'requestTimeout': self.requestTimeout,
           }
      return json_dumps(r)
Esempio n. 23
0
 def _acceptEula(self, txn):
     txn.execute("SELECT value FROM config WHERE key = ?",
                 ["eula-accepted"])
     res = txn.fetchone()
     if res:
         eula_accepted = json_loads(res[0])
         if eula_accepted:
             raise Exception(URI_ERROR + "illegal-invocation",
                             "EULA already accepted.")
         else:
             now = utcnow()
             txn.execute("UPDATE config SET value = ? WHERE key = ?",
                         [json_dumps(now), "eula-accepted"])
             self.factory.services["config"].recache(txn)
             return now
     else:
         raise Exception(URI_ERROR + "internal-error",
                         "EULA key not found.")
Esempio n. 24
0
   def _setPassword(self, txn, password1, password2):
      txn.execute("SELECT value FROM config WHERE key = ?", ['admin-password'])
      res = txn.fetchone()
      if res:
         pw = json_loads(res[0])
         if pw is not None:
            raise Exception((URI_ERROR + "invalid-invocation", "Initial password already set."))
      else:
         raise Exception(URI_ERROR + "internal-error", "Could not retrieve admin password from database.")

      attrs = {"password1": (True,
                             [str, unicode],
                             AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
                             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
                             AdminWebSocketProtocol.USER_PASSWORD_PATTERN),
               "password2": (True,
                             [str, unicode],
                             AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
                             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
                             AdminWebSocketProtocol.USER_PASSWORD_PATTERN)}

      errcnt, errs = self.checkDictArg("user password", {"password1": password1, "password2": password2}, attrs)

      if password1 != password2:
         errcnt += 1
         if not errs.has_key('password1') or errs.has_key('password2'):
            p = 'password1'
         else:
            p = 'password2'
         if not errs.has_key(p):
            errs[p] = []
         errs[p].append((self.shrink(URI_ERROR + "invalid-attribute-value"), "Passwords do not match"))

      if errcnt:
         raise Exception(URI_ERROR + "illegal-argument", "one or more illegal arguments (%d errors)" % errcnt, errs)

      txn.execute("UPDATE config SET value = ? WHERE key = ?", [json_dumps(password1), "admin-password"])
Esempio n. 25
0
   def remoteCall(self, call):
      """
      RPC handler remoting to Ext.Direct servers. This method is usually
      registered via registerHandlerMethodForRpc on a WAMP protocol.
      """
      proto = call.proto
      uri = call.uri
      args = call.args

      ## extract extra information from RPC call handler argument
      (id, action, method, _) = call.extra

      ## get the Ext.Direct remote onto which we will forward the call
      remote = self.remotesById[id]

      ## construct the POST body
      d = {'action': action,
           'method': method,
           'data': args,
           'type': 'rpc',
           'tid': 1}
      body = json_dumps(d)

      if remote.forwardCookies and \
         proto.cookies and \
         proto.cookies.has_key(remote.routerDomain) and \
         proto.cookies[remote.routerDomain] != "":

         cookie = str(proto.cookies[remote.routerDomain])
      else:
         cookie = None

      if not remote.usePersistentConnections:
         ## Do HTTP/POST as individual request
         ##

         headers = {'Content-Type': 'application/json',
                    'User-Agent': ExtDirectRemoter.USER_AGENT}

         if cookie:
            headers['Cookie'] = cookie

         d = getPage(url = remote.routerUrl,
                     method = 'POST',
                     postdata = body,
                     headers = headers,
                     timeout = remote.requestTimeout,
                     connectionTimeout = remote.connectionTimeout,
                     followRedirect = remote.redirectLimit > 0)

      else:
         ## Do HTTP/POST via HTTP connection pool
         ##

         headers = {'Content-Type': ['application/json'],
                    'User-Agent': [ExtDirectRemoter.USER_AGENT]}

         if cookie:
            headers['Cookie'] = [cookie]

         agent = Agent(reactor,
                       pool = self.httppools[remote.id],
                       connectTimeout = remote.connectionTimeout)

         if remote.redirectLimit > 0:
            agent = RedirectAgent(agent, redirectLimit = remote.redirectLimit)

         ## FIXME: honor requestTimeout
         d = agent.request('POST',
                           remote.routerUrl,
                           Headers(headers),
                           StringProducer(body))

         def onResponse(response):
            if response.code == 200:
               finished = Deferred()
               response.deliverBody(StringReceiver(finished))
               return finished
            else:
               return defer.fail("%s [%s]" % (response.code, response.phrase))

         d.addCallback(onResponse)

      ## request information provided as error detail in case of call fails
      remotingRequest = {'provider': 'extdirect',
                         'router-url': remote.routerUrl,
                         'use-persistent-connections': remote.usePersistentConnections,
                         'request-timeout': remote.requestTimeout,
                         'connection-timeout': remote.connectionTimeout,
                         'action': action,
                         'method': method}

      d.addCallbacks(self._onRemoteCallResult,
                     self._onRemoteCallError,
                     callbackArgs = [remotingRequest],
                     errbackArgs = [remotingRequest])

      ## FIXME!
      d.addCallback(self.onAfterRemoteCallSuccess, id)
      d.addErrback(self.onAfterRemoteCallError, id)

      return d
Esempio n. 26
0
    def _setServicePorts(self, txn, ports, dryRun):

        ## check entry argument types
        ##
        if type(ports) != dict:
            raise Exception(
                URI_ERROR + "invalid-argument",
                "Invalid argument of type '%s' [expected dict]" %
                str(type(ports)))

        ## errors will be accumulated here (per port-key)
        ##
        errs = {}

        ## convenience handling in JS
        for u in Database.NETPORTS_TLS_PREFIXES:
            o = u + "-tlskey"
            if ports.has_key(o):
                if ports[o] == "null" or ports[o] == "":
                    ports[o] = None

        ## check each port in change for itself
        ##
        uports = {}
        c_tls_flags = {}
        c_tls_keys = {}
        for k in ports.keys():
            if k in Database.NETPORTS:
                try:
                    port = int(ports[k])
                except:
                    errs[k] = (
                        self.proto.shrink(URI_ERROR + "not-an-integer"),
                        "Invalid value '%s' for port '%s' (not an integer)" %
                        (ports[k], k))
                else:
                    if port < 1 or port > 65535:
                        errs[k] = (self.proto.shrink(
                            URI_ERROR + "out-of-range"
                        ), "Invalid value %d for port '%s' (out of valid range [1, 65535])"
                                   % (port, k))
                    else:
                        if k in Database.NETPORTS_READONLY:
                            errs[k] = (self.proto.shrink(URI_ERROR +
                                                         "read-only"),
                                       "Port '%s' is read-only." % k)
                        else:
                            uports[k] = port
            elif k in Database.NETPORTS_TLS_FLAGS:
                if type(ports[k]) != bool:
                    errs[k] = (self.proto.shrink(URI_ERROR +
                                                 "invalid-attribute-type"),
                               "Expected bool for attribute %s, got %s" %
                               (k, str(type(ports[k]))))
                else:
                    c_tls_flags[k] = ports[k]
            elif k in Database.NETPORTS_TLS_KEYS:
                if type(ports[k]) not in [str, unicode, types.NoneType]:
                    errs[k] = (
                        self.proto.shrink(URI_ERROR +
                                          "invalid-attribute-type"),
                        "Expected str/unicode for attribute %s, got %s" %
                        (k, str(type(ports[k]))))
                else:
                    c_tls_keys[k] = None
                    if ports[k] is not None:
                        ruri = str(ports[k]).strip()
                        if ruri != "":
                            uri = self.proto.resolveOrPass(ruri)
                            id = self.proto.uriToId(uri)
                            c_tls_keys[k] = id
            else:
                errs[str(k)] = (self.proto.shrink(URI_ERROR +
                                                  "unknown-attribute"),
                                "Illegal attribute '%s'" % k)

        ## determine all TLS flags/keys (changed+existing) and change set
        (all_tls_flags, changed_tls_flags) = self._getConfigChangeset(
            txn, Database.NETPORTS_TLS_FLAGS, c_tls_flags)
        (all_tls_keys, changed_tls_keys) = self._getConfigChangeset(
            txn, Database.NETPORTS_TLS_KEYS, c_tls_keys)

        for u in Database.NETPORTS_TLS_PREFIXES:

            o = u + "-tlskey"
            if changed_tls_keys.has_key(o):
                id = changed_tls_keys[o]
                if id is not None:
                    txn.execute("SELECT cert FROM servicekey WHERE ID = ?",
                                [id])
                    res = txn.fetchone()
                    if res:
                        if res[0] is None:
                            errs[o] = (
                                self.proto.shrink(
                                    URI_ERROR +
                                    "servicekey-without-certificate"),
                                "Service key with URI %s has no certificate" %
                                URI_SERVICEKEY + id)
                    else:
                        errs[o] = (
                            self.proto.shrink(URI_ERROR + "no-such-object"),
                            "No service key with URI %s" % URI_SERVICEKEY + id)
                else:
                    if all_tls_flags[u + "-tls"]:
                        errs[o] = (
                            self.proto.shrink(
                                URI_ERROR + "tls-enabled-without-servicekey"),
                            "TLS set to enabled, but no service key given.")

            o = u + "-tls"
            if changed_tls_flags.has_key(o):
                if changed_tls_flags[o] and all_tls_keys[u +
                                                         "-tlskey"] is None:
                    errs[o] = (self.proto.shrink(URI_ERROR +
                                                 "missing-servicekey"),
                               "TLS enabled, but service key missing.")

        ## For Admin Web/WebSocket pair, disallow running Web via TLS, but WebSocket non-TLS
        ## i.e. Firefox throws a "security-exception" when we try that ..
        ## For Hub Web/WebSocket we allow this, since both are "independent" services (that is Hub Web
        ## does not serve the HTML/JS that connects to Hub WebSocket)
        ##
        if all_tls_flags[
                "admin-web-tls"] and not all_tls_flags["admin-websocket-tls"]:
            errs["admin-websocket-tls"] = (self.proto.shrink(
                URI_ERROR + "non-tls-websocket-from-tls-web"
            ), "TLS on WebSocket port set to enabled, but corresponding Web serving port running non-TLS."
                                           )
            errs["admin-web-tls"] = (self.proto.shrink(
                URI_ERROR + "non-tls-websocket-from-tls-web"
            ), "TLS on WebSocket port set to enabled, but corresponding Web serving port running non-TLS."
                                     )

        ## determine all ports (changed+existing) and change set
        ##
        (aports, cports) = self._getConfigChangeset(txn, Database.NETPORTS,
                                                    uports)

        ## duplicate check
        ##
        if len(set(aports.values())) != len(aports):
            dups = {}
            for d in aports:
                if not dups.has_key(aports[d]):
                    dups[aports[d]] = []
                dups[aports[d]].append(d)
            for d in dups:
                if len(dups[d]) > 1:
                    for k in dups[d]:
                        errs[k] = (self.proto.shrink(URI_ERROR +
                                                     "duplicate-value"),
                                   "Duplicate port %d for %s" %
                                   (d, str(dups[d])))

        ## valid passive FTP port range
        ##
        if aports["ftp-passive-port-start"] > aports["ftp-passive-port-end"]:
            e = (self.proto.shrink(URI_ERROR + "invalid-range"),
                 "Start port must be <= end port")
            errs["ftp-passive-port-start"] = e
            errs["ftp-passive-port-end"] = e

        ## check collisions of service ports with passive FTP port range
        ##
        passive_port_range = xrange(aports["ftp-passive-port-start"],
                                    aports["ftp-passive-port-end"] + 1)
        for p in Database.NETPORTS:
            if aports[p] in passive_port_range and p not in [
                    "ftp-passive-port-start", "ftp-passive-port-end"
            ]:
                e = (self.proto.shrink(
                    URI_ERROR + "duplicate-value"
                ), "Duplicate port %d for %s collides with passive FTP port range %d-%d"
                     % (aports[p], p, aports["ftp-passive-port-start"],
                        aports["ftp-passive-port-end"]))
                errs[p] = e

        ## bail out on any errors accumulated
        ##
        if len(errs) > 0:
            raise Exception(
                URI_ERROR + "invalid-argument",
                "One or more invalid attributes (see errorDetails).", errs)

        ## now do the actual database update (if there is any change left)
        ##
        delta = {}
        delta.update(cports)
        delta.update(changed_tls_flags)
        delta.update(changed_tls_keys)

        if len(delta) > 0:
            if not dryRun:
                for p in delta:
                    txn.execute("UPDATE config SET value = ? WHERE key = ?",
                                [json_dumps(delta[p]), p])

                ## recache config
                services = self.proto.factory.services
                if services.has_key("config"):
                    services["config"].recache(txn)

            ## automatically restart services when required
            restartRequired = len(cports) > 0 or len(changed_tls_flags) > 0
            for t in Database.NETPORTS_TLS_PREFIXES:
                if delta.has_key(t + "-tlskey") and all_tls_flags[t + "-tls"]:
                    restartRequired = True
                    break

            for t in Database.NETPORTS_TLS_KEYS:
                if delta.has_key(t) and delta[t]:
                    delta[t] = URI_SERVICEKEY + delta[t]

            if not dryRun:
                self.proto.dispatch(URI_EVENT + "on-service-ports-set", delta,
                                    [self.proto])

            for t in Database.NETPORTS_TLS_KEYS:
                if delta.has_key(t) and delta[t]:
                    delta[t] = self.proto.shrink(delta[t])

            if restartRequired and not dryRun:
                from twisted.internet import reactor
                reactor.callLater(1, self.proto.serviceControl.restartHub)

        else:
            restartRequired = False

        ## return change set
        ##
        return [delta, restartRequired]
Esempio n. 27
0
    def _createActivationRequest(self, txn, origin, licenseType, extra):

        LICENSE_TYPES = ['BETA']

        if licenseType not in LICENSE_TYPES:
            raise Exception(URI_ERROR + "illegal-argument",
                            "Unknown license type '%s'" % str(licenseType),
                            LICENSE_TYPES)

        ## construct license activation request
        ##
        hostid = self.factory.services['platform'].getHostId()
        instanceid = self.serviceConfig._getSingleConfig(txn, "instance-id")
        msg = {
            'type': licenseType,
            'host-id': hostid,
            'instance-id': instanceid
        }

        dbcreated = self.serviceConfig._getSingleConfig(
            txn, "database-created")
        platform = self.factory.services['platform'].getPlatformInfo()
        network = self.factory.services['platform'].getNetworkConfig()

        msg['info'] = {
            'request-time': utcnow(),
            'database-created': dbcreated,
            'platform': platform,
            'network': network
        }

        if extra is not None:
            msg['extra'] = extra

        log.msg("created license activation request: %s" % msg)

        rmsg = json_dumps(msg)

        ## load instance key pair
        ##
        pubkey = str(
            self.serviceConfig._getSingleConfig(txn, "instance-pub-key"))
        privkey = str(
            self.serviceConfig._getSingleConfig(txn, "instance-priv-key"))

        ## encrypt activation request for Tavendo public key
        ## and sign encrypted message using instance private key
        ##
        (emsg, skey, dig,
         sig) = encrypt_and_sign(rmsg, privkey,
                                 Database.WEBMQ_LICENSE_CA_PUBKEY)

        payload = "%s,%s,%s,%s,%s,%s" % (
            emsg, skey, dig, sig, urllib.quote_plus(pubkey),
            urllib.quote_plus(origin + "/doactivate"))

        #print payload

        return {
            'request': msg,
            'url': self.factory.services['master'].licenseserver,
            'payload': payload
        }
Esempio n. 28
0
    def _changePassword(self, txn, oldpassword, newpassword1, newpassword2):
        attrs = {
            "oldpassword":
            (True, [str,
                    unicode], AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_PATTERN),
            "newpassword1":
            (True, [str,
                    unicode], AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_PATTERN),
            "newpassword2":
            (True, [str,
                    unicode], AdminWebSocketProtocol.USER_PASSWORD_MIN_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_MAX_LENGTH,
             AdminWebSocketProtocol.USER_PASSWORD_PATTERN)
        }

        errcnt, errs = self.checkDictArg(
            "user password", {
                "oldpassword": oldpassword,
                "newpassword1": newpassword1,
                "newpassword2": newpassword2
            }, attrs)

        if newpassword1 != newpassword2:
            errcnt += 1
            if not errs.has_key('newpassword1') or errs.has_key(
                    'newpassword2'):
                p = 'newpassword1'
            else:
                p = 'newpassword2'
            if not errs.has_key(p):
                errs[p] = []
            errs[p].append((self.shrink(URI_ERROR + "invalid-attribute-value"),
                            "New password values do not match"))

        if errcnt:
            raise Exception(
                URI_ERROR + "illegal-argument",
                "one or more illegal arguments (%d errors)" % errcnt, errs)

        txn.execute("SELECT value FROM config WHERE key = ?",
                    ['admin-password'])
        res = txn.fetchone()
        if res:
            pw = str(json_loads(res[0]))
            if pw == oldpassword:
                if newpassword1 != oldpassword:
                    txn.execute("UPDATE config SET value = ? WHERE key = ?",
                                [json_dumps(newpassword1), "admin-password"])
                else:
                    raise Exception(
                        URI_ERROR + "illegal-argument",
                        "one or more illegal arguments (%d errors)" % 2, {
                            'newpassword1':
                            [(self.shrink(URI_ERROR +
                                          "attribute-value-unchanged"),
                              "Password unchanged")],
                            'newpassword2': [
                                (self.shrink(URI_ERROR +
                                             "attribute-value-unchanged"),
                                 "Password unchanged")
                            ]
                        })
            else:
                raise Exception(
                    URI_ERROR + "illegal-argument",
                    "one or more illegal arguments (%d errors)" % 1, {
                        'oldpassword':
                        [(self.shrink(URI_ERROR + "invalid-attribute-value"),
                          "Old password is invalid")]
                    })
        else:
            raise Exception(
                URI_ERROR + "internal-error",
                "Could not retrieve admin password from database.")
Esempio n. 29
0
   def remoteCall(self, call):
      """
      RPC handler remoting to REST servers. This method is usually
      registered via registerHandlerMethodForRpc on a WAMP protocol.
      """
      proto = call.proto
      uri = call.uri
      args = call.args

      ## extract extra information from RPC call handler argument
      (id, method) = call.extra

      ## get the REST remote onto which we will forward the call
      remote = self.remotesById[id]

      body = None

      if method in ['GET', 'DELETE']:
         if len(args) != 1:
            raise Exception(URI_ERROR_REMOTING,
                            "Invalid number of arguments (expected 1, was %d)" % len(args))
      elif method in ['PUT', 'POST']:
         if len(args) != 2:
            raise Exception(URI_ERROR_REMOTING,
                            "Invalid number of arguments (expected 2, was %d)" % len(args))
         body = json_dumps(args[1])
      else:
         ## should not arrive here!
         raise Exception("logic error")

      if remote.forwardCookies and \
         proto.cookies and \
         proto.cookies.has_key(remote.restDomain) and \
         proto.cookies[remote.restDomain] != "":

         cookie = str(proto.cookies[remote.restDomain])
      else:
         cookie = None

      if type(args[0]) not in [str, unicode]:
         raise Exception(URI_ERROR_REMOTING,
                         "Invalid type for argument 1 (expected str, was %s)" % type(args[0]))

      url = urlparse.urljoin(str(remote.restBaseUrl), str(args[0]))

      if not remote.usePersistentConnections:
         ## Do HTTP/POST as individual request
         ##

         headers = {'Content-Type': 'application/json',
                    'User-Agent': RestRemoter.USER_AGENT}

         if cookie:
            headers['Cookie'] = cookie

         d = getPage(url = url,
                     method = method,
                     postdata = body,
                     headers = headers,
                     timeout = remote.requestTimeout,
                     connectionTimeout = remote.connectionTimeout,
                     followRedirect = remote.redirectLimit > 0)

      else:
         ## Do HTTP/POST via HTTP connection pool
         ##
         ## http://twistedmatrix.com/documents/12.1.0/web/howto/client.html
         ##

         ## avoid module level reactor import
         from twisted.web.client import Agent, RedirectAgent

         headers = {'Content-Type': ['application/json'],
                    'User-Agent': [RestRemoter.USER_AGENT]}

         if cookie:
            headers['Cookie'] = [cookie]

         agent = Agent(self.reactor,
                       pool = self.httppools[remote.id],
                       connectTimeout = remote.connectionTimeout)

         if remote.redirectLimit > 0:
            agent = RedirectAgent(agent, redirectLimit = remote.redirectLimit)

         ## FIXME: honor requestTimeout
         if body:
            d = agent.request(method,
                              url,
                              Headers(headers),
                              StringProducer(body))
         else:
            d = agent.request(method,
                              url,
                              Headers(headers))

         def onResponse(response):
            if response.code == 200:
               finished = Deferred()
               response.deliverBody(StringReceiver(finished))
               return finished
            else:
               return defer.fail("%s [%s]" % (response.code, response.phrase))

         d.addCallback(onResponse)

      ## request information provided as error detail in case of call fails
      remotingRequest = {'provider': 'rest',
                         'rest-base-url': remote.restBaseUrl,
                         'use-persistent-connections': remote.usePersistentConnections,
                         'request-timeout': remote.requestTimeout,
                         'connection-timeout': remote.connectionTimeout,
                         'method': method}

      d.addCallbacks(self._onRemoteCallResult,
                     self._onRemoteCallError,
                     callbackArgs = [remotingRequest],
                     errbackArgs = [remotingRequest])

      ## FIXME!
      d.addCallback(self.onAfterRemoteCallSuccess, id)
      d.addErrback(self.onAfterRemoteCallError, id)

      return d
Esempio n. 30
0
   def remoteCall(self, call):
      """
      RPC handler remoting to Ext.Direct servers. This method is usually
      registered via registerHandlerMethodForRpc on a WAMP protocol.
      """
      proto = call.proto
      uri = call.uri
      args = call.args

      ## extract extra information from RPC call handler argument
      (id, action, method, _) = call.extra

      ## get the Ext.Direct remote onto which we will forward the call
      remote = self.remotesById[id]

      ## construct the POST body
      d = {'action': action,
           'method': method,
           'data': args,
           'type': 'rpc',
           'tid': 1}
      body = json_dumps(d)

      if remote.forwardCookies and \
         proto.cookies and \
         proto.cookies.has_key(remote.routerDomain) and \
         proto.cookies[remote.routerDomain] != "":

         cookie = str(proto.cookies[remote.routerDomain])
      else:
         cookie = None

      if not remote.usePersistentConnections:
         ## Do HTTP/POST as individual request
         ##

         headers = {'Content-Type': 'application/json',
                    'User-Agent': ExtDirectRemoter.USER_AGENT}

         if cookie:
            headers['Cookie'] = cookie

         d = getPage(url = remote.routerUrl,
                     method = 'POST',
                     postdata = body,
                     headers = headers,
                     timeout = remote.requestTimeout,
                     connectionTimeout = remote.connectionTimeout,
                     followRedirect = remote.redirectLimit > 0)

      else:
         ## Do HTTP/POST via HTTP connection pool
         ##

         headers = {'Content-Type': ['application/json'],
                    'User-Agent': [ExtDirectRemoter.USER_AGENT]}

         if cookie:
            headers['Cookie'] = [cookie]

         agent = Agent(self.reactor,
                       pool = self.httppools[remote.id],
                       connectTimeout = remote.connectionTimeout)

         if remote.redirectLimit > 0:
            agent = RedirectAgent(agent, redirectLimit = remote.redirectLimit)

         ## FIXME: honor requestTimeout
         d = agent.request('POST',
                           remote.routerUrl,
                           Headers(headers),
                           StringProducer(body))

         def onResponse(response):
            if response.code == 200:
               finished = Deferred()
               response.deliverBody(StringReceiver(finished))
               return finished
            else:
               return defer.fail("%s [%s]" % (response.code, response.phrase))

         d.addCallback(onResponse)

      ## request information provided as error detail in case of call fails
      remotingRequest = {'provider': 'extdirect',
                         'router-url': remote.routerUrl,
                         'use-persistent-connections': remote.usePersistentConnections,
                         'request-timeout': remote.requestTimeout,
                         'connection-timeout': remote.connectionTimeout,
                         'action': action,
                         'method': method}

      d.addCallbacks(self._onRemoteCallResult,
                     self._onRemoteCallError,
                     callbackArgs = [remotingRequest],
                     errbackArgs = [remotingRequest])

      ## FIXME!
      d.addCallback(self.onAfterRemoteCallSuccess, id)
      d.addErrback(self.onAfterRemoteCallError, id)

      return d
Esempio n. 31
0
      cur.execute("""
                  CREATE TABLE config
                  (
                     key                 VARCHAR2(30)                     PRIMARY KEY,
                     value               VARCHAR2(4000)                   NOT NULL
                  )
                  """)
      log.msg("database table '%s' created" % "config")

      ## store database schema version
      ##
      config = [('schema-category', 'demo'),
                ('schema-version', SCHEMAVERSION),
                ('schema-created', utcnow())]
      for key, value in config:
         cur.execute("INSERT INTO config (key, value) VALUES (:1, :2)", [key, json_dumps(value)])
      conn.commit()

      log.msg("crossbar.io Demo schema created (version %d)!" % SCHEMAVERSION)

   else:

      log.msg("crossbar.io Demo schema dropped!")

   return dbschema.getSchemaVersion(conn, oraschema.LATESTVERSIONS)


def setupSchema(app, conn):
   r = dbschema.getSchemaVersion(conn, oraschema.LATESTVERSIONS)

   if r['schema-version'] is not None:
Esempio n. 32
0
   def _callSp(self, conn, call):
      """
      Call a remoted stored procedure.

      This is called using ConnectionPool.runWithConnection on the
      Twisted main thread from within DbRemoter.remoteCall.

      :param conn: A database connection from the pool.
      :type conn: obj
      :param session: Information on calling WAMP session.
      :type session: Instance of SessionInfo
      :param meta: SP metadata.
      :type meta: tuple
      :param args: SP calling arguments.
      :type args: list
      :return obj -- Result from calling the SP.
      """

      session = call.proto.sessionInfo
      meta = call.extra
      args = call.args

      import cx_Oracle

      ## http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm
      ## http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/datatypes.htm

      ## Supported:
      ##
      ##   cx_Oracle.NUMBER
      ##   cx_Oracle.NATIVE_FLOAT
      ##   cx_Oracle.STRING
      ##   cx_Oracle.UNICODE
      ##   cx_Oracle.FIXED_CHAR
      ##   cx_Oracle.FIXED_UNICODE
      ##   cx_Oracle.DATETIME
      ##   cx_Oracle.TIMESTAMP
      ##   cx_Oracle.INTERVAL
      ##   cx_Oracle.CURSOR
      ##
      ## Unsupported:
      ##
      ##   cx_Oracle.OBJECT
      ##   cx_Oracle.ROWID
      ##   cx_Oracle.BINARY
      ##   cx_Oracle.BFILE
      ##   cx_Oracle.LOB
      ##   cx_Oracle.BLOB
      ##   cx_Oracle.CLOB
      ##   cx_Oracle.NCLOB
      ##   cx_Oracle.LONG_BINARY
      ##   cx_Oracle.LONG_STRING
      ##   cx_Oracle.LONG_UNICODE

      ## Issues:
      ##
      ##  INTERVAL YEAR TO MONTH Support
      ##    Python datetime.timedelta only supports periods up to 1 day.
      ##    isodate has it's own Duration class to represent longer periods,
      ##    but such objects can't be consumed by cx_Oracle.
      ##


      ## map of endpoint.return_type / endpoint.arg_types to
      ##
      ##    (cx_Oracle bind var type, PL/SQL type, PL/SQL caster)
      ##
      ## for input parameters
      ##
      TYPEMAP = {'NUMBER': (cx_Oracle.NUMBER, None, None),
                 'VARCHAR2': (cx_Oracle.STRING, None, None),
                 'NVARCHAR2': (cx_Oracle.UNICODE, None, None),
                 'CHAR': (cx_Oracle.FIXED_CHAR, None, None),
                 'NCHAR': (cx_Oracle.FIXED_UNICODE, None, None),
                 'BINARY_FLOAT': (cx_Oracle.NATIVE_FLOAT, None, None),
                 'BINARY_DOUBLE': (cx_Oracle.NATIVE_FLOAT, None, None),
                 'DATE': (cx_Oracle.DATETIME, None, None),
                 'TIMESTAMP': (cx_Oracle.TIMESTAMP, None, None),
                 'TIMESTAMP WITH TIME ZONE': (cx_Oracle.TIMESTAMP, None, None),
                 'TIMESTAMP WITH LOCAL TIME ZONE': (cx_Oracle.TIMESTAMP, None, None),
                 'INTERVAL DAY TO SECOND': (cx_Oracle.INTERVAL, None, None),
                 #'INTERVAL YEAR TO MONTH': (cx_Oracle.INTERVAL, None, None),
                 'REF CURSOR': (cx_Oracle.CURSOR, None, None),
                 'JSON': (cx_Oracle.CLOB, 'json', 'json'),
                 'JSON_VALUE': (cx_Oracle.CLOB, 'json_value', 'json_parser.parse_any'),
                 'JSON_LIST': (cx_Oracle.CLOB, 'json_list', 'json_list'),
                 'CROSSBAR_SESSION': (None, 'crossbar_session', 'crossbar_session')}

      ## these object types are treated specially
      ##
      JSONTYPES = ['JSON',
                   'JSON_VALUE',
                   'JSON_LIST']

      DATETIMETYPES = ['DATE', 'TIMESTAMP']

      INTERVALTYPES = ['INTERVAL DAY TO SECOND',
                       #'INTERVAL YEAR TO MONTH',
                       ]

      ## create or get prepared cursor for calling SP
      ##
      cur, extra = conn.getPrepared(meta.uri)

      if not cur:
         ## construct SQL statement for calling SP
         ##

         ## input parameters
         ##
         arg_types = []
         if len(meta.arg_types) > 0:
            ## SP takes at least 1 input parameters
            ##
            iargs = []
            i = 0
            j = 0
            while i < len(meta.arg_types):
               if meta.arg_types[i] == 'CROSSBAR_SESSION':
                  if meta.arg_inouts[i] in ['IN', 'IN/OUT']:
                     iargs.append('l_sess')
                  else:
                     raise Exception("invalid direction %s for session object parameter" % meta.arg_sess_inout)
               else:
                  cast = TYPEMAP[meta.arg_types[i]][2]
                  if cast:
                     ## parameter value is casted
                     iargs.append('%s(:in%d)' % (cast, j))
                  else:
                     ## plain parameter
                     iargs.append(':in%d' % j)
                  arg_types.append(meta.arg_types[i])
                  j += 1
               i += 1
            s_args = "(" + ','.join(iargs) + ")"
         else:
            ## SP takes no input parameters
            ##
            s_args = ""

         ## return value
         ##
         if meta.return_type is not None:
            if meta.return_type not in JSONTYPES:
               s_out = ":out := "
            else:
               s_out = ""
         else:
            s_out = ""

         ## anonymous PL/SQL block
         ##
         ## For MODIFY_PACKAGE_STATE, see:
         ##   - http://stackoverflow.com/questions/12688317/clear-oracle-session-state
         ##   - http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/d_sessio.htm#CEGIICCC
         ##
         if meta.return_type in JSONTYPES:
            ## for JSON types the SQL is different since we need to cast from
            ## JSON object type to CLOB
            if meta.arg_sess_inout == "IN/OUT":
               sql = """
                     DECLARE
                        l_sess   crossbar_session := crossbar_session(:so1, :so2, JSON(:so3));
                        l_out    %s;
                     BEGIN
                        DBMS_SESSION.MODIFY_PACKAGE_STATE(DBMS_SESSION.REINITIALIZE);
                        l_out := %s%s;
                        l_out.to_clob(:out);
                        l_sess.data.to_clob(:sout);
                     END;
                     """ % (TYPEMAP[meta.return_type][1], meta.procedure, s_args)
            elif meta.arg_sess_inout == "IN":
               sql = """
                     DECLARE
                        l_sess   crossbar_session := crossbar_session(:so1, :so2, JSON(:so3));
                        l_out    %s;
                     BEGIN
                        DBMS_SESSION.MODIFY_PACKAGE_STATE(DBMS_SESSION.REINITIALIZE);
                        l_out := %s%s;
                        l_out.to_clob(:out);
                     END;
                     """ % (TYPEMAP[meta.return_type][1], meta.procedure, s_args)
            else:
               sql = """
                     DECLARE
                        l_out   %s;
                     BEGIN
                        DBMS_SESSION.MODIFY_PACKAGE_STATE(DBMS_SESSION.REINITIALIZE);
                        l_out := %s%s;
                        l_out.to_clob(:out);
                     END;
                     """ % (TYPEMAP[meta.return_type][1], meta.procedure, s_args)
         else:
            if meta.arg_sess_inout == "IN/OUT":
               sql = """
                     DECLARE
                        l_sess   crossbar_session := crossbar_session(:so1, :so2, JSON(:so3));
                     BEGIN
                        DBMS_SESSION.MODIFY_PACKAGE_STATE(DBMS_SESSION.REINITIALIZE);
                        %s%s%s;
                        l_sess.data.to_clob(:sout);
                     END;
                     """ % (s_out, meta.procedure, s_args)
            elif meta.arg_sess_inout == "IN":
               sql = """
                     DECLARE
                        l_sess   crossbar_session := crossbar_session(:so1, :so2, JSON(:so3));
                     BEGIN
                        DBMS_SESSION.MODIFY_PACKAGE_STATE(DBMS_SESSION.REINITIALIZE);
                        %s%s%s;
                     END;
                     """ % (s_out, meta.procedure, s_args)
            else:
               sql = """
                     BEGIN
                        DBMS_SESSION.MODIFY_PACKAGE_STATE(DBMS_SESSION.REINITIALIZE);
                        %s%s%s;
                     END;
                     """ % (s_out, meta.procedure, s_args)

         ## create fresh cursor and prepare SQL
         ##
         cur = conn.cursor()
         cur.prepare(sql)

         ## map var types to cx_Oracle types
         ##
         if meta.return_type in JSONTYPES:
            ## when calling a SP that returns a JSON type, the return bind var
            ## is the last, since we need to cast from JSON to CLOB/STRING
            ##
            ttypes = arg_types + [meta.return_type]
         elif meta.return_type is not None:
            ## otherwise if the SP returns something, the return bind var
            ## is the first
            ##
            ttypes = [meta.return_type] + arg_types
         else:
            ## otherwise when the SP does not return anything, bind vars
            ## are just input parameters
            ##
            ttypes = arg_types

         if meta.arg_sess_inout:
            ttypes = ['VARCHAR2', 'VARCHAR2', 'JSON'] + ttypes
            if meta.arg_sess_inout == "IN/OUT":
               ttypes.append('JSON')

         atypes = [TYPEMAP[x][0] for x in ttypes]

         ## setup cx_Oracle bind vars
         curvars = cur.setinputsizes(*atypes)

         ## save the prepared cursor and bindvars. we also save the SQL
         ## for debugging purposes
         ##
         conn.savePrepared(meta.uri, cur, (curvars, sql))

      else:
         ## cursor was saved previously - get the bind vars ..
         ##
         curvars, sql = extra


      ## set parameters and call SP
      ##

      ## indexes 'args'
      i = 0

      ## indexes 'curvars'
      if meta.return_type in JSONTYPES:
         ## json return value (needs to be unwrapped via local PL/SQL var)
         j = 0
      elif meta.return_type is not None:
         ## scalar/refcursor return
         j = 1
      else:
         ## no return value
         j = 0


      ## inject session information
      ##
      if meta.arg_sess_inout:
         curvars[0].setvalue(0, session.sessionId)
         curvars[1].setvalue(0, session.authenticatedAs)
         curvars[2].setvalue(0, json_dumps(session.data))
         j += 3

      ## indexes 'meta.arg_types'
      k = 0

      while k < len(meta.arg_types):
         if meta.arg_types[k] == 'CROSSBAR_SESSION':
            k += 1

         else:
            if meta.arg_types[k] in JSONTYPES:
               val = json_dumps(args[i])

            elif meta.arg_types[k] in DATETIMETYPES:
               ## Target argument is a DATE/TIMESTAMP. Need to convert
               ## to Python datetime.datetime from string. We use ISO 8601 format.
               ##
               if args[i] is not None:
                  try:
                     val = isodate.parse_datetime(args[i])
                  except Exception, e:
                     raise Exception("invalid value for datetime/timestamp - expected a string in ISO 8601 datetime format [%s]" % e)
               else:
                  val = None

            elif meta.arg_types[k] in INTERVALTYPES:
               ## Target argument is a INTERVAL. Need to convert
               ## to Python datetime.timedelta from string. We use ISO 8601 format.
               ##
               if args[i] is not None:
                  try:
                     val = isodate.parse_duration(args[i])
                     if not isinstance(val, datetime.timedelta):
                        ## val will be an instance of isodate.Duration, due to
                        ## limits of Python datetime.timedelta
                        raise Exception("invalid value for literal - ISO 8601 years/months currently unsupported")
                  except Exception, e:
                     raise Exception("invalid value for interval - expected a string in ISO 8601 period format [%s]" % e)
               else:
                  val = None
Esempio n. 33
0
    def remoteCall(self, call):
        """
      RPC handler remoting to REST servers. This method is usually
      registered via registerHandlerMethodForRpc on a WAMP protocol.
      """
        proto = call.proto
        uri = call.uri
        args = call.args

        ## extract extra information from RPC call handler argument
        (id, method) = call.extra

        ## get the REST remote onto which we will forward the call
        remote = self.remotesById[id]

        body = None

        if method in ['GET', 'DELETE']:
            if len(args) != 1:
                raise Exception(
                    URI_ERROR_REMOTING,
                    "Invalid number of arguments (expected 1, was %d)" %
                    len(args))
        elif method in ['PUT', 'POST']:
            if len(args) != 2:
                raise Exception(
                    URI_ERROR_REMOTING,
                    "Invalid number of arguments (expected 2, was %d)" %
                    len(args))
            body = json_dumps(args[1])
        else:
            ## should not arrive here!
            raise Exception("logic error")

        if remote.forwardCookies and \
           proto.cookies and \
           proto.cookies.has_key(remote.restDomain) and \
           proto.cookies[remote.restDomain] != "":

            cookie = str(proto.cookies[remote.restDomain])
        else:
            cookie = None

        if type(args[0]) not in [str, unicode]:
            raise Exception(
                URI_ERROR_REMOTING,
                "Invalid type for argument 1 (expected str, was %s)" %
                type(args[0]))

        url = urlparse.urljoin(str(remote.restBaseUrl), str(args[0]))

        if not remote.usePersistentConnections:
            ## Do HTTP/POST as individual request
            ##

            headers = {
                'Content-Type': 'application/json',
                'User-Agent': RestRemoter.USER_AGENT
            }

            if cookie:
                headers['Cookie'] = cookie

            d = getPage(url=url,
                        method=method,
                        postdata=body,
                        headers=headers,
                        timeout=remote.requestTimeout,
                        connectionTimeout=remote.connectionTimeout,
                        followRedirect=remote.redirectLimit > 0)

        else:
            ## Do HTTP/POST via HTTP connection pool
            ##
            ## http://twistedmatrix.com/documents/12.1.0/web/howto/client.html
            ##

            ## avoid module level reactor import
            from twisted.web.client import Agent, RedirectAgent

            headers = {
                'Content-Type': ['application/json'],
                'User-Agent': [RestRemoter.USER_AGENT]
            }

            if cookie:
                headers['Cookie'] = [cookie]

            agent = Agent(self.reactor,
                          pool=self.httppools[remote.id],
                          connectTimeout=remote.connectionTimeout)

            if remote.redirectLimit > 0:
                agent = RedirectAgent(agent,
                                      redirectLimit=remote.redirectLimit)

            ## FIXME: honor requestTimeout
            if body:
                d = agent.request(method, url, Headers(headers),
                                  StringProducer(body))
            else:
                d = agent.request(method, url, Headers(headers))

            def onResponse(response):
                if response.code == 200:
                    finished = Deferred()
                    response.deliverBody(StringReceiver(finished))
                    return finished
                else:
                    return defer.fail("%s [%s]" %
                                      (response.code, response.phrase))

            d.addCallback(onResponse)

        ## request information provided as error detail in case of call fails
        remotingRequest = {
            'provider': 'rest',
            'rest-base-url': remote.restBaseUrl,
            'use-persistent-connections': remote.usePersistentConnections,
            'request-timeout': remote.requestTimeout,
            'connection-timeout': remote.connectionTimeout,
            'method': method
        }

        d.addCallbacks(self._onRemoteCallResult,
                       self._onRemoteCallError,
                       callbackArgs=[remotingRequest],
                       errbackArgs=[remotingRequest])

        ## FIXME!
        d.addCallback(self.onAfterRemoteCallSuccess, id)
        d.addErrback(self.onAfterRemoteCallError, id)

        return d
Esempio n. 34
0
   def _setServicePorts(self, txn, ports, dryRun):

      ## check entry argument types
      ##
      if type(ports) != dict:
         raise Exception(URI_ERROR + "invalid-argument", "Invalid argument of type '%s' [expected dict]" % str(type(ports)))

      ## errors will be accumulated here (per port-key)
      ##
      errs = {}

      ## convenience handling in JS
      for u in Database.NETPORTS_TLS_PREFIXES:
         o = u + "-tlskey"
         if ports.has_key(o):
            if ports[o] == "null" or ports[o] == "":
               ports[o] = None

      ## check each port in change for itself
      ##
      uports = {}
      c_tls_flags = {}
      c_tls_keys = {}
      for k in ports.keys():
         if k in Database.NETPORTS:
            try:
               port = int(ports[k])
            except:
               errs[k] = (self.proto.shrink(URI_ERROR + "not-an-integer"), "Invalid value '%s' for port '%s' (not an integer)" % (ports[k], k))
            else:
               if port < 1 or port > 65535:
                  errs[k] = (self.proto.shrink(URI_ERROR + "out-of-range"), "Invalid value %d for port '%s' (out of valid range [1, 65535])" % (port, k))
               else:
                  if k in Database.NETPORTS_READONLY:
                     errs[k] = (self.proto.shrink(URI_ERROR + "read-only"), "Port '%s' is read-only." % k)
                  else:
                     uports[k] = port
         elif k in Database.NETPORTS_TLS_FLAGS:
            if type(ports[k]) != bool:
               errs[k] = (self.proto.shrink(URI_ERROR + "invalid-attribute-type"), "Expected bool for attribute %s, got %s" % (k, str(type(ports[k]))))
            else:
               c_tls_flags[k] = ports[k]
         elif k in Database.NETPORTS_TLS_KEYS:
            if type(ports[k]) not in [str, unicode, types.NoneType]:
               errs[k] = (self.proto.shrink(URI_ERROR + "invalid-attribute-type"), "Expected str/unicode for attribute %s, got %s" % (k, str(type(ports[k]))))
            else:
               c_tls_keys[k] = None
               if ports[k] is not None:
                  ruri = str(ports[k]).strip()
                  if ruri != "":
                     uri = self.proto.resolveOrPass(ruri)
                     id = self.proto.uriToId(uri)
                     c_tls_keys[k] = id
         else:
            errs[str(k)] = (self.proto.shrink(URI_ERROR + "unknown-attribute"), "Illegal attribute '%s'" % k)

      ## determine all TLS flags/keys (changed+existing) and change set
      (all_tls_flags, changed_tls_flags) = self._getConfigChangeset(txn, Database.NETPORTS_TLS_FLAGS, c_tls_flags)
      (all_tls_keys, changed_tls_keys) = self._getConfigChangeset(txn, Database.NETPORTS_TLS_KEYS, c_tls_keys)

      for u in Database.NETPORTS_TLS_PREFIXES:

         o = u + "-tlskey"
         if changed_tls_keys.has_key(o):
            id = changed_tls_keys[o]
            if id is not None:
               txn.execute("SELECT cert FROM servicekey WHERE ID = ?", [id])
               res = txn.fetchone()
               if res:
                  if res[0] is None:
                     errs[o] = (self.proto.shrink(URI_ERROR + "servicekey-without-certificate"), "Service key with URI %s has no certificate" % URI_SERVICEKEY + id)
               else:
                  errs[o] = (self.proto.shrink(URI_ERROR + "no-such-object"), "No service key with URI %s" % URI_SERVICEKEY + id)
            else:
               if all_tls_flags[u + "-tls"]:
                  errs[o] = (self.proto.shrink(URI_ERROR + "tls-enabled-without-servicekey"), "TLS set to enabled, but no service key given.")

         o = u + "-tls"
         if changed_tls_flags.has_key(o):
            if changed_tls_flags[o] and all_tls_keys[u + "-tlskey"] is None:
               errs[o] = (self.proto.shrink(URI_ERROR + "missing-servicekey"), "TLS enabled, but service key missing.")

      ## For Admin Web/WebSocket pair, disallow running Web via TLS, but WebSocket non-TLS
      ## i.e. Firefox throws a "security-exception" when we try that ..
      ## For Hub Web/WebSocket we allow this, since both are "independent" services (that is Hub Web
      ## does not serve the HTML/JS that connects to Hub WebSocket)
      ##
      if all_tls_flags["admin-web-tls"] and not all_tls_flags["admin-websocket-tls"]:
         errs["admin-websocket-tls"] = (self.proto.shrink(URI_ERROR + "non-tls-websocket-from-tls-web"), "TLS on WebSocket port set to enabled, but corresponding Web serving port running non-TLS.")
         errs["admin-web-tls"] = (self.proto.shrink(URI_ERROR + "non-tls-websocket-from-tls-web"), "TLS on WebSocket port set to enabled, but corresponding Web serving port running non-TLS.")

      ## determine all ports (changed+existing) and change set
      ##
      (aports, cports) = self._getConfigChangeset(txn, Database.NETPORTS, uports)

      ## duplicate check
      ##
      if len(set(aports.values())) != len(aports):
         dups = {}
         for d in aports:
            if not dups.has_key(aports[d]):
               dups[aports[d]] = []
            dups[aports[d]].append(d)
         for d in dups:
            if len(dups[d]) > 1:
               for k in dups[d]:
                  errs[k] = (self.proto.shrink(URI_ERROR + "duplicate-value"), "Duplicate port %d for %s" % (d, str(dups[d])))

      ## valid passive FTP port range
      ##
      if aports["ftp-passive-port-start"] > aports["ftp-passive-port-end"]:
         e = (self.proto.shrink(URI_ERROR + "invalid-range"), "Start port must be <= end port")
         errs["ftp-passive-port-start"] = e
         errs["ftp-passive-port-end"] = e

      ## check collisions of service ports with passive FTP port range
      ##
      passive_port_range = xrange(aports["ftp-passive-port-start"], aports["ftp-passive-port-end"] + 1)
      for p in Database.NETPORTS:
         if aports[p] in passive_port_range and p not in ["ftp-passive-port-start", "ftp-passive-port-end"]:
            e = (self.proto.shrink(URI_ERROR + "duplicate-value"),
                 "Duplicate port %d for %s collides with passive FTP port range %d-%d" % (aports[p],
                                                                                          p,
                                                                                          aports["ftp-passive-port-start"],
                                                                                          aports["ftp-passive-port-end"])
                 )
            errs[p] = e

      ## bail out on any errors accumulated
      ##
      if len(errs) > 0:
         raise Exception(URI_ERROR + "invalid-argument", "One or more invalid attributes (see errorDetails).", errs)

      ## now do the actual database update (if there is any change left)
      ##
      delta = {}
      delta.update(cports)
      delta.update(changed_tls_flags)
      delta.update(changed_tls_keys)

      if len(delta) > 0:
         if not dryRun:
            for p in delta:
               txn.execute("UPDATE config SET value = ? WHERE key = ?", [json_dumps(delta[p]), p])

            ## recache config
            services = self.proto.factory.services
            if services.has_key("config"):
              services["config"].recache(txn)

         ## automatically restart services when required
         restartRequired = len(cports) > 0 or len(changed_tls_flags) > 0
         for t in Database.NETPORTS_TLS_PREFIXES:
            if delta.has_key(t + "-tlskey") and all_tls_flags[t + "-tls"]:
               restartRequired = True
               break

         for t in Database.NETPORTS_TLS_KEYS:
            if delta.has_key(t) and delta[t]:
               delta[t] = URI_SERVICEKEY + delta[t]

         if not dryRun:
            self.proto.dispatch(URI_EVENT + "on-service-ports-set", delta, [self.proto])

         for t in Database.NETPORTS_TLS_KEYS:
            if delta.has_key(t) and delta[t]:
               delta[t] = self.proto.shrink(delta[t])

         if restartRequired and not dryRun:
            from twisted.internet import reactor
            reactor.callLater(1, self.proto.serviceControl.restartHub)

      else:
         restartRequired = False

      ## return change set
      ##
      return [delta, restartRequired]