Beispiel #1
0
    def xmlrpc_forward(self, request, query, annotations=None):
        """
        """

        Log.info("Incoming XMLRPC request, query = %r, annotations = %r" %
                 (self.display_query(query), annotations))
        if Options().disable_auth:
            Log.info("Authentication disabled by configuration")
        else:
            if not annotations or not 'authentication' in annotations:
                msg = "You need to specify an authentication token in annotations"
                return dict(ResultValue.get_error(ResultValue.FORBIDDEN, msg))

            # We expect to find an authentication token in the annotations
            if annotations:
                auth = annotations.get('authentication', None)
            else:
                auth = {}

            auth['request'] = request

            # Check login password
            try:
                user = Auth(auth, self.interface).check()
            except Exception, e:
                Log.warning(
                    "XMLRPCAPI::xmlrpc_forward: Authentication failed...: %s" %
                    str(e))
                msg = "Authentication failed: %s" % e
                return dict(ResultValue.get_error(ResultValue.FORBIDDEN, msg))
Beispiel #2
0
    def process_qp_results(self,
                           namespace,
                           query,
                           records,
                           annotations,
                           query_plan,
                           policy=True):
        # namespace and table are back together in process_qp_results
        # in order to send the results in the right Cache entry
        if namespace is not None:
            query.object = namespace + ':' + query.object

        # Handling internal queries
        is_local = (namespace == self.LOCAL_NAMESPACE)
        is_metadata = (namespace and query.object == "object")
        if policy and not is_local and not is_metadata:
            # XXX What to do in case of errors, and records is []
            for record in records:
                # We process records one by one...
                (decision, data) = self.policy.filter(query,
                                                      record,
                                                      annotations,
                                                      is_query=False)
                if decision == Policy.ACCEPT:
                    pass
                elif decision == Policy.REWRITE:
                    print "WEIRD CASE: maybe it should be changed since here we are not replacing a query but a record"
                    _query, _annotations = data
                    if _query:
                        query = _query
                    if _annotations:
                        annotations = _annotations

                elif decision in [Policy.DENIED, Policy.ERROR]:
                    print "WEIRD CASE also for records"
                    if decision == Policy.DENIED:
                        data = ResultValue.get_error(ResultValue.FORBIDDEN)
                    return self.send_result_value(query, data, annotations,
                                                  is_deferred)

                else:
                    raise Exception, "Unknown RECORD decision from policy engine: %s" % Policy.map_decision[
                        decision]

        description = query_plan.get_result_value_array()

        return ResultValue.get_result_value(records, description)
Beispiel #3
0
    def forward(self,
                query,
                annotations=None,
                is_deferred=False,
                execute=True):
        """
        Forwards an incoming Query to the appropriate Gateways managed by this Router.
        Args:
            query: The user's Query.
            is_deferred: (bool)
            execute: Set to true if the QueryPlan must be executed.
            user: The user issuing the Query.
        Returns:
            A ResultValue in case of success.
            None in case of failure.
        """
        Log.info("Router::forward: %s" % query)

        # TMP CACHE DEBUG
        #import pdb
        #pdb.set_trace()

        # INVALIDATE CACHE - should be per object?
        if query.get_action() != 'get':
            self.delete_cache(annotations)

        user = annotations[
            'user'] if annotations and 'user' in annotations else None
        if annotations is None:
            annotations = {}

        ret = super(Router, self).forward(query, annotations, is_deferred,
                                          execute)
        if ret:
            # Note: we do not run hooks at the moment for local queries
            return ret

        # Previously, cache etc had nothing to do. We now enforce policy, and
        # eventually this will give us a new query plan
        query_plan = None

        # Enforcing policy
        # XXX This issues after a check (in interface) that we are not
        # considering local or object tables... and we need to do the proper
        # check when records are received, otherwise the query is absent from
        # the cache. This is sources of errors, and should be fixed.
        #
        # Possible results and related actions:
        # - ACCEPT : the query passes and will trigger a new query plan
        # - CACHED : ill named, the cache is taking care of everything, no new query plan to do
        #    This will handle multiple scenarios such as buffered (a mixed of
        #    cached and real time records), and multicast (real time records).
        # - DENIED
        # - ERROR

        (decision, data) = self.policy.filter(query, None, annotations)

        # TMP CACHE DEBUG
        #pdb.set_trace()

        if decision == Policy.ACCEPT:
            pass
        elif decision == Policy.REWRITE:
            _query, _annotations = data
            if _query:
                query = _query
            if _annotations:
                annotations = _annotations

        elif decision == Policy.CACHE_HIT:
            query_plan = data
            #return self.send(query, data, annotations, is_deferred)

        elif decision in [Policy.DENIED, Policy.ERROR]:
            if decision == Policy.DENIED:
                data = ResultValue.get_error(ResultValue.FORBIDDEN)
            return self.send_result_value(query, data, annotations,
                                          is_deferred)

        else:
            raise Exception, "Unknown QUERY decision from policy engine: %s" % Policy.map_decision[
                decision]

        # TMP CACHE DEBUG
        #pdb.set_trace()

        # We suppose we have no namespace from here
        if not execute:
            if not query_plan:
                query_plan = QueryPlan()
                query_plan.build(query, self.g_3nf, allowed_platforms,
                                 self.allowed_capabilities, user)

            Log.info(query_plan.dump())

            # Note: no hook either for queries that are not executed
            return ResultValue.get_success(None)

        # The query plan will be the same whatever the action: it represents
        # the easier way to reach the destination = routing
        # We do not need the full query for the query plan, in fact just the
        # destination, which is a subpart of the query = (fact, filters, fields)
        # action = what to do on this QP
        # ts = how it behaves

        # XXX disabled
        #if query.get_action() == "update":
        #    # At the moment we can only update if the primary key is present
        #    keys = self.metadata_get_keys(query.get_from())
        #    if not keys:
        #        raise Exception, "Missing metadata for table %s" % query.get_from()
        #    key_fields = keys.one().get_minimal_names()
        #
        #    # XXX THIS SHOULD BE ABLE TO ACCEPT TUPLES
        #    #if not query.filters.has_eq(key):
        #    #    raise Exception, "The key field(s) '%r' must be present in update request" % key

        # Execute query plan
        # the deferred object is sent to execute function of the query_plan
        # This might be a deferred, we cannot put any hook here...

        try:
            # Namespace and table are splited if prefix is used in the query
            # namespace is passed as a parameter
            # Then namespace and table are back together in process_qp_results
            # in order to send the results in the right Cache entry
            if ":" in query.get_from():
                namespace, table_name = query.get_from().rsplit(":", 2)
                query.object = table_name
            else:
                namespace = None

            if query_plan:
                return self.execute_query_plan(namespace,
                                               query,
                                               annotations,
                                               query_plan,
                                               is_deferred,
                                               policy=False)
            else:
                return self.execute_query(namespace, query, annotations,
                                          is_deferred)
        except Exception, e:
            return ResultValue.get_error(e, traceback.format_exc())