예제 #1
0
    async def _read_history(self, details, rv):
        """
        determine if the history read is for a data changes or events;
        then read the history for that node
        """
        result = ua.HistoryReadResult()
        if isinstance(details, ua.ReadRawModifiedDetails):
            if details.IsReadModified:
                result.HistoryData = ua.HistoryModifiedData()
                # we do not support modified history by design so we return what we have
            else:
                result.HistoryData = ua.HistoryData()
            dv, cont = await self._read_datavalue_history(rv, details)
            result.HistoryData.DataValues = dv
            result.ContinuationPoint = cont

        elif isinstance(details, ua.ReadEventDetails):
            result.HistoryData = ua.HistoryEvent()
            # FIXME: filter is a cumbersome type, maybe transform it something easier
            # to handle for storage
            ev, cont = await self._read_event_history(rv, details)
            result.HistoryData.Events = ev
            result.ContinuationPoint = cont

        else:
            # we do not currently support the other types, clients can process data themselves
            result.StatusCode = ua.StatusCode(ua.StatusCodes.BadNotImplemented)
        return result
예제 #2
0
 async def read_node_history(self, node_id, start, end, nb_values):
     table = self._get_table_name(node_id)
     start_time, end_time, order, limit = self._get_bounds(
         start, end, nb_values)
     cont = None
     results = []
     # select values from the database; recreate UA Variant from binary
     try:
         async with self._db.execute(
                 f'SELECT * FROM "{table}" WHERE "SourceTimestamp" BETWEEN ? AND ? '
                 f'ORDER BY "_Id" {order} LIMIT ?',
             (
                 start_time,
                 end_time,
                 limit,
             ),
         ) as cursor:
             async for row in cursor:
                 # rebuild the data value object
                 dv = ua.DataValue(
                     variant_from_binary(Buffer(row[6])),
                     ServerTimestamp=row[1],
                     SourceTimestamp=row[2],
                     StatusCode_=ua.StatusCode(row[3]),
                 )
                 results.append(dv)
     except aiosqlite.Error as e:
         self.logger.error("Historizing SQL Read Error for %s: %s", node_id,
                           e)
     if len(results) > self.max_history_data_response_size:
         cont = results[self.max_history_data_response_size].SourceTimestamp
     results = results[:self.max_history_data_response_size]
     return results, cont
예제 #3
0
    def activate_session(self, params, peer_certificate):
        self.logger.info('activate session')
        result = ua.ActivateSessionResult()
        if self.state != SessionState.Created:
            raise ServiceError(ua.StatusCodes.BadSessionIdInvalid)
        if InternalSession._current_connections >= InternalSession.max_connections:
            raise ServiceError(ua.StatusCodes.BadMaxConnectionsReached)
        self.nonce = create_nonce(32)
        result.ServerNonce = self.nonce
        for _ in params.ClientSoftwareCertificates:
            result.Results.append(ua.StatusCode())
        self.state = SessionState.Activated
        InternalSession._current_connections += 1
        id_token = params.UserIdentityToken
        if self.iserver.user_manager is not None:
            if isinstance(id_token, ua.UserNameIdentityToken):
                username = id_token.UserName
                password = id_token.Password
            else:
                username, password = None, None

            user = self.iserver.user_manager.get_user(
                self.iserver,
                username=username,
                password=password,
                certificate=peer_certificate)
            if user is None:
                raise ServiceError(ua.StatusCodes.BadUserAccessDenied)
            else:
                self.user = user
        self.logger.info("Activated internal session %s for user %s",
                         self.name, self.user)
        return result
예제 #4
0
def string_to_val(string, vtype):
    """
    Convert back a string to a python or python-asyncua object
    Note: no error checking is done here, supplying null strings could raise exceptions (datetime and guid)
    """
    string = string.strip()
    if string.startswith("["):
        string = string[1:-1]
        var = []
        for s in string.split(","):
            s = s.strip()
            val = string_to_val(s, vtype)
            var.append(val)
        return var

    if vtype == ua.VariantType.Null:
        val = None
    elif vtype == ua.VariantType.Boolean:
        if string in ("True", "true", "on", "On", "1"):
            val = True
        else:
            val = False
    elif vtype in (ua.VariantType.SByte, ua.VariantType.Int16, ua.VariantType.Int32, ua.VariantType.Int64):
        if not string:
            val = 0
        else:
            val = int(string)
    elif vtype in (ua.VariantType.Byte, ua.VariantType.UInt16, ua.VariantType.UInt32, ua.VariantType.UInt64):
        if not string:
            val = 0
        else:
            val = int(string)
    elif vtype in (ua.VariantType.Float, ua.VariantType.Double):
        if not string:
            val = 0.0
        else:
            val = float(string)
    elif vtype == ua.VariantType.XmlElement:
        val = ua.XmlElement(string)
    elif vtype == ua.VariantType.String:
        val = string
    elif vtype == ua.VariantType.ByteString:
        val = string.encode()
    elif vtype in (ua.VariantType.NodeId, ua.VariantType.ExpandedNodeId):
        val = ua.NodeId.from_string(string)
    elif vtype == ua.VariantType.QualifiedName:
        val = ua.QualifiedName.from_string(string)
    elif vtype == ua.VariantType.DateTime:
        val = parser.parse(string)
    elif vtype == ua.VariantType.LocalizedText:
        val = ua.LocalizedText.from_string(string)
    elif vtype == ua.VariantType.StatusCode:
        val = ua.StatusCode(string)
    elif vtype == ua.VariantType.Guid:
        val = uuid.UUID(string)
    else:
        # FIXME: Some types are probably missing!
        raise NotImplementedError
    return val
예제 #5
0
 async def write(self, params, user=User.Admin):
     #self.logger.debug("write %s as user %s", params, user)
     res = []
     for writevalue in params.NodesToWrite:
         if user != User.Admin:
             if writevalue.AttributeId != ua.AttributeIds.Value:
                 res.append(ua.StatusCode(ua.StatusCodes.BadUserAccessDenied))
                 continue
             al = self._aspace.read_attribute_value(writevalue.NodeId, ua.AttributeIds.AccessLevel)
             ual = self._aspace.read_attribute_value(writevalue.NodeId, ua.AttributeIds.UserAccessLevel)
             if not al.StatusCode.is_good() or not ua.ua_binary.test_bit(
                     al.Value.Value, ua.AccessLevel.CurrentWrite) or not ua.ua_binary.test_bit(
                 ual.Value.Value, ua.AccessLevel.CurrentWrite):
                 res.append(ua.StatusCode(ua.StatusCodes.BadUserAccessDenied))
                 continue
         res.append(await self._aspace.write_attribute_value(writevalue.NodeId, writevalue.AttributeId, writevalue.Value))
     return res
예제 #6
0
def func(parent, variant: Variant):
    print("func method call with parameters: ", variant.Value)
    ret = False
    if not isinstance(variant.Value, int):
        return ua.StatusCode(StatusCodes.BadInvalidArgument)
    if variant.Value % 2 == 0:
        ret = True
    return [ua.Variant(ret, ua.VariantType.Boolean)]
예제 #7
0
 def _delete_node_callbacks(self, nodedata):
     if ua.AttributeIds.Value in nodedata.attributes:
         for handle, callback in list(nodedata.attributes[ua.AttributeIds.Value].datachange_callbacks.items()):
             try:
                 callback(handle, None, ua.StatusCode(ua.StatusCodes.BadNodeIdUnknown))
                 self._aspace.delete_datachange_callback(handle)
             except Exception as ex:
                 self.logger.exception("Error calling delete node callback callback %s, %s, %s", nodedata,
                     ua.AttributeIds.Value, ex)
 async def delete_subscriptions(self, ids):
     self.logger.info("delete subscriptions: %s", ids)
     res = []
     existing_subs = []
     for i in ids:
         sub = self.subscriptions.pop(i, None)
         if sub is None:
             res.append(ua.StatusCode(ua.StatusCodes.BadSubscriptionIdInvalid))
         else:
             existing_subs.append(sub)
             res.append(ua.StatusCode())
     stop_results = await asyncio.gather(
         *[sub.stop() for sub in existing_subs], return_exceptions=True
     )
     for stop_result in stop_results:
         if isinstance(res, Exception):
             self.logger.warning("Exception while stopping subscription", exc_info=stop_result)
     return res
 def delete_monitored_items(self, params):
     self.logger.info("delete monitored items")
     if params.SubscriptionId not in self.subscriptions:
         res = []
         for _ in params.MonitoredItemIds:
             res.append(ua.StatusCode(ua.StatusCodes.BadSubscriptionIdInvalid))
         return res
     return self.subscriptions[params.SubscriptionId].monitored_item_srv.delete_monitored_items(
         params.MonitoredItemIds)
예제 #10
0
 def _translate_browsepath_to_nodeid(self, path):
     #self.logger.debug("looking at path: %s", path)
     res = ua.BrowsePathResult()
     if path.StartingNode not in self._aspace:
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdInvalid)
         return res
     current = path.StartingNode
     for el in path.RelativePath.Elements:
         nodeid = self._find_element_in_node(el, current)
         if not nodeid:
             res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNoMatch)
             return res
         current = nodeid
     target = ua.BrowsePathTarget()
     target.TargetId = current
     target.RemainingPathIndex = 4294967295
     res.Targets = [target]
     return res
예제 #11
0
    def _delete_node(self, item, user):
        if user != User.Admin:
            return ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)

        if item.NodeId not in self._aspace:
            self.logger.warning("DeleteNodesItem: NodeId %s does not exists", item.NodeId)
            return ua.StatusCode(ua.StatusCodes.BadNodeIdUnknown)

        if item.DeleteTargetReferences:
            for elem in self._aspace.keys():
                for rdesc in self._aspace[elem].references:
                    if rdesc.NodeId == item.NodeId:
                        self._aspace[elem].references.remove(rdesc)

        self._delete_node_callbacks(self._aspace[item.NodeId])

        del (self._aspace[item.NodeId])

        return ua.StatusCode()
 def modify_monitored_items(self, params):
     self.logger.info("modify monitored items")
     if params.SubscriptionId not in self.subscriptions:
         res = []
         for _ in params.ItemsToModify:
             result = ua.MonitoredItemModifyResult()
             result.StatusCode = ua.StatusCode(ua.StatusCodes.BadSubscriptionIdInvalid)
             res.append(result)
         return res
     return self.subscriptions[params.SubscriptionId].monitored_item_srv.modify_monitored_items(params)
 async def create_monitored_items(self, params: ua.CreateMonitoredItemsParameters):
     self.logger.info("create monitored items")
     if params.SubscriptionId not in self.subscriptions:
         res = []
         for _ in params.ItemsToCreate:
             response = ua.MonitoredItemCreateResult()
             response.StatusCode = ua.StatusCode(ua.StatusCodes.BadSubscriptionIdInvalid)
             res.append(response)
         return res
     return await self.subscriptions[params.SubscriptionId].monitored_item_srv.create_monitored_items(params)
예제 #14
0
 def _browse(self, desc):
     res = ua.BrowseResult()
     if desc.NodeId not in self._aspace:
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdInvalid)
         return res
     node = self._aspace[desc.NodeId]
     for ref in node.references:
         if not self._is_suitable_ref(desc, ref):
             continue
         res.References.append(ref)
     return res
예제 #15
0
    async def write_attribute_value(self, nodeid, attr, value):
        # self.logger.debug("set attr val: %s %s %s", nodeid, attr, value)
        node = self._nodes.get(nodeid, None)
        if node is None:
            return ua.StatusCode(ua.StatusCodes.BadNodeIdUnknown)
        attval = node.attributes.get(attr, None)
        if attval is None:
            return ua.StatusCode(ua.StatusCodes.BadAttributeIdInvalid)

        old = attval.value
        attval.value = value
        cbs = []
        if old.Value != value.Value:  # only send call callback when a value change has happend
            cbs = list(attval.datachange_callbacks.items())

        for k, v in cbs:
            try:
                await v(k, value)
            except Exception as ex:
                self.logger.exception("Error calling datachange callback %s, %s, %s", k, v, ex)

        return ua.StatusCode()
예제 #16
0
 def update_history(self, params):
     """
     Update history for a node
     This is the part AttributeService, but implemented as its own service
     since it requires more logic than other attribute service methods
     """
     results = []
     for _ in params.HistoryUpdateDetails:
         result = ua.HistoryUpdateResult()
         # we do not accept to rewrite history
         result.StatusCode = ua.StatusCode(ua.StatusCodes.BadNotWritable)
         results.append(results)
     return results
예제 #17
0
 async def process_message(self, seqhdr, body):
     """
     Process incoming messages.
     """
     typeid = nodeid_from_binary(body)
     requesthdr = struct_from_binary(ua.RequestHeader, body)
     _logger.debug('process_message %r %r', typeid, requesthdr)
     try:
         return await self._process_message(typeid, requesthdr, seqhdr, body)
     except ServiceError as e:
         status = ua.StatusCode(e.code)
         response = ua.ServiceFault()
         response.ResponseHeader.ServiceResult = status
         _logger.error("sending service fault response: %s (%s)", status.doc, status.name)
         self.send_response(requesthdr.RequestHandle, seqhdr, response)
         return True
     except Exception:
         _logger.exception('Error while processing message')
         response = ua.ServiceFault()
         response.ResponseHeader.ServiceResult = ua.StatusCode(ua.StatusCodes.BadInternalError)
         self.send_response(requesthdr.RequestHandle, seqhdr, response)
         return True
예제 #18
0
 def _translate_browsepath_to_nodeid(self, path):
     # self.logger.debug("looking at path: %s", path)
     res = ua.BrowsePathResult()
     if not path.RelativePath.Elements[-1].TargetName:
         # OPC UA Part 4: Services, 5.8.4 TranslateBrowsePathsToNodeIds
         # it's unclear if this the check should also handle empty strings
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadBrowseNameInvalid)
         return res
     if path.StartingNode not in self._aspace:
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdInvalid)
         return res
     target_nodeids = self._navigate(path.StartingNode,
                                     path.RelativePath.Elements)
     if not target_nodeids:
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNoMatch)
         return res
     for nodeid in target_nodeids:
         target = ua.BrowsePathTarget()
         target.TargetId = nodeid
         target.RemainingPathIndex = 4294967295
         res.Targets.append(target)
     # FIXME: might need to order these one way or another
     return res
예제 #19
0
 def _translate_browsepath_to_nodeid(self, path):
     #self.logger.debug("looking at path: %s", path)
     res = ua.BrowsePathResult()
     if not path.RelativePath.Elements[-1].TargetName:
         # OPC UA Part 4: Services, 5.8.4 TranslateBrowsePathsToNodeIds
         # it's unclear if this the check should also handle empty strings
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadBrowseNameInvalid)
         return res
     if path.StartingNode not in self._aspace:
         res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdInvalid)
         return res
     current = path.StartingNode
     for el in path.RelativePath.Elements:
         nodeid = self._find_element_in_node(el, current)
         if not nodeid:
             res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNoMatch)
             return res
         current = nodeid
     target = ua.BrowsePathTarget()
     target.TargetId = current
     target.RemainingPathIndex = 4294967295
     res.Targets = [target]
     return res
예제 #20
0
 async def process_message(self, seqhdr, body):
     """
     Process incoming messages.
     """
     typeid = nodeid_from_binary(body)
     requesthdr = struct_from_binary(ua.RequestHeader, body)
     _logger.debug('process_message %r %r', typeid, requesthdr)
     try:
         return await self._process_message(typeid, requesthdr, seqhdr,
                                            body)
     except ServiceError as e:
         status = ua.StatusCode(e.code)
         response = ua.ServiceFault()
         response.ResponseHeader.ServiceResult = status
         _logger.error("sending service fault response: %s (%s)",
                       status.doc, status.name)
         self.send_response(requesthdr.RequestHandle, seqhdr, response)
         return True
     except ua.uaerrors.BadUserAccessDenied as e:
         if self.session:
             user = self.session.user
         else:
             user = '******'
         _logger.warning(
             "%s attempted to do something they are not permitted to do",
             user)
         response = ua.ServiceFault()
         response.ResponseHeader.ServiceResult = ua.StatusCode(
             ua.StatusCodes.BadUserAccessDenied)
         self.send_response(requesthdr.RequestHandle, seqhdr, response)
     except Exception:
         _logger.exception('Error while processing message')
         response = ua.ServiceFault()
         response.ResponseHeader.ServiceResult = ua.StatusCode(
             ua.StatusCodes.BadInternalError)
         self.send_response(requesthdr.RequestHandle, seqhdr, response)
         return True
예제 #21
0
 def activate_session(self, params):
     self.logger.info('activate session')
     result = ua.ActivateSessionResult()
     if self.state != SessionState.Created:
         raise ServiceError(ua.StatusCodes.BadSessionIdInvalid)
     self.nonce = create_nonce(32)
     result.ServerNonce = self.nonce
     for _ in params.ClientSoftwareCertificates:
         result.Results.append(ua.StatusCode())
     self.state = SessionState.Activated
     id_token = params.UserIdentityToken
     if isinstance(id_token, ua.UserNameIdentityToken):
         if self.iserver.check_user_token(self, id_token) is False:
             raise ServiceError(ua.StatusCodes.BadUserAccessDenied)
     self.logger.info("Activated internal session %s for user %s", self.name, self.user)
     return result
 def publish_results(self):
     """
     Publish all enqueued data changes, events and status changes though the callback.
     """
     if self._publish_cycles_count > self.data.RevisedLifetimeCount:
         self.logger.warning("Subscription %s has expired, publish cycle count(%s) > lifetime count (%s)", self,
             self._publish_cycles_count, self.data.RevisedLifetimeCount)
         # FIXME this will never be send since we do not have publish request anyway
         self.monitored_item_srv.trigger_statuschange(ua.StatusCode(ua.StatusCodes.BadTimeout))
     result = None
     if self.has_published_results():
         self._publish_cycles_count += 1
         result = self._pop_publish_result()
     if result is not None:
         self.logger.info('publish_results for %s', self.data.SubscriptionId)
         self.pub_result_callback(result)
예제 #23
0
    async def setup_nodes(self):
        """
        Set up some nodes as defined by spec
        """
        uries = ['http://opcfoundation.org/UA/']
        ns_node = Node(self.isession,
                       ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
        await ns_node.write_value(uries)

        params = ua.WriteParameters()
        for nodeid in (
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerRead,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryReadData,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryReadEvents,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerWrite,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryUpdateData,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryUpdateEvents,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerMethodCall,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerBrowse,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerRegisterNodes,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerTranslateBrowsePathsToNodeIds,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxNodesPerNodeManagement,
                ua.ObjectIds.
                Server_ServerCapabilities_OperationLimits_MaxMonitoredItemsPerCall,
        ):
            attr = ua.WriteValue()
            attr.NodeId = ua.NodeId(nodeid)
            attr.AttributeId = ua.AttributeIds.Value
            attr.Value = ua.DataValue(
                ua.Variant(10000, ua.VariantType.UInt32),
                StatusCode_=ua.StatusCode(ua.StatusCodes.Good),
                ServerTimestamp=datetime.utcnow(),
            )
            params.NodesToWrite.append(attr)
        result = await self.isession.write(params)
        result[0].check()
    def _create_events_monitored_item(self, params: ua.MonitoredItemCreateRequest):
        self.logger.info("request to subscribe to events for node %s and attribute %s", params.ItemToMonitor.NodeId,
                         params.ItemToMonitor.AttributeId)

        result, mdata = self._make_monitored_item_common(params)
        ev_notify_byte = self.aspace.read_attribute_value(params.ItemToMonitor.NodeId,
                                                         ua.AttributeIds.EventNotifier).Value.Value

        if ev_notify_byte is None or not ua.ua_binary.test_bit(ev_notify_byte, ua.EventNotifier.SubscribeToEvents):
            result.StatusCode = ua.StatusCode(ua.StatusCodes.BadServiceUnsupported)
            return result
        # result.FilterResult = ua.EventFilterResult()  # spec says we can ignore if not error
        mdata.where_clause_evaluator = WhereClauseEvaluator(self.logger, self.aspace, mdata.filter.WhereClause)
        self._commit_monitored_item(result, mdata)
        if params.ItemToMonitor.NodeId not in self._monitored_events:
            self._monitored_events[params.ItemToMonitor.NodeId] = []
        self._monitored_events[params.ItemToMonitor.NodeId].append(result.MonitoredItemId)
        return result
예제 #25
0
 def publish_results(self):
     if self._publish_cycles_count > self.data.RevisedLifetimeCount:
         self.logger.warning(
             "Subscription %s has expired, publish cycle count(%s) > lifetime count (%s)",
             self, self._publish_cycles_count,
             self.data.RevisedLifetimeCount)
         # FIXME this will never be send since we do not have publish request anyway
         self.monitored_item_srv.trigger_statuschange(
             ua.StatusCode(ua.StatusCodes.BadTimeout))
     result = None
     if self.has_published_results():
         # FIXME: should we pop a publish request here? or we do not care?
         self._publish_cycles_count += 1
         result = self._pop_publish_result()
     if result is not None:
         if inspect.iscoroutinefunction(self.callback):
             self.subservice.loop.create_task(self.callback(result))
         else:
             self.callback(result)
예제 #26
0
 async def publish_results(self):
     """
     Publish all enqueued data changes, events and status changes though the callback.
     """
     if self._publish_cycles_count > self.data.RevisedLifetimeCount:
         self.logger.warning(
             "Subscription %s has expired, publish cycle count(%s) > lifetime count (%s)",
             self, self._publish_cycles_count,
             self.data.RevisedLifetimeCount)
         # FIXME this will never be send since we do not have publish request anyway
         await self.monitored_item_srv.trigger_statuschange(
             ua.StatusCode(ua.StatusCodes.BadTimeout))
     result = None
     if self.has_published_results():
         if not self.no_acks:
             self._publish_cycles_count += 1
         result = self._pop_publish_result()
     if result is not None:
         # self.logger.info('publish_results for %s', self.data.SubscriptionId)
         # The callback can be:
         #    Subscription.publish_callback -> server internal subscription
         #    UaProcessor.forward_publish_response -> client subscription
         await self.pub_result_callback(result)
예제 #27
0
    async def _process_message(self, typeid, requesthdr, seqhdr, body):
        if typeid in [
                ua.NodeId(
                    ua.ObjectIds.CreateSessionRequest_Encoding_DefaultBinary),
                ua.NodeId(
                    ua.ObjectIds.ActivateSessionRequest_Encoding_DefaultBinary)
        ]:
            # The connection is first created without a user being attached, and then during activation the
            user = None
        elif self.session is None:
            raise ua.uaerrors.BadUserAccessDenied
        else:
            user = self.session.user
            if self._connection.security_policy.permissions is not None:
                if self._connection.security_policy.permissions.check_validity(
                        user, typeid, body) is False:
                    raise ua.uaerrors.BadUserAccessDenied

        if typeid == ua.NodeId(
                ua.ObjectIds.CreateSessionRequest_Encoding_DefaultBinary):
            _logger.info("Create session request (%s)", user)
            params = struct_from_binary(ua.CreateSessionParameters, body)
            # create the session on server
            self.session = self.iserver.create_session(self.name,
                                                       external=True)
            # get a session creation result to send back
            sessiondata = await self.session.create_session(
                params, sockname=self.sockname)
            response = ua.CreateSessionResponse()
            response.Parameters = sessiondata
            response.Parameters.ServerCertificate = self._connection.security_policy.host_certificate
            if self._connection.security_policy.peer_certificate is None:
                data = params.ClientNonce
            else:
                data = self._connection.security_policy.peer_certificate + params.ClientNonce
            response.Parameters.ServerSignature.Signature = \
                self._connection.security_policy.asymmetric_cryptography.signature(data)
            response.Parameters.ServerSignature.Algorithm = self._connection.security_policy.AsymmetricSignatureURI
            #_logger.info("sending create session response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.CloseSessionRequest_Encoding_DefaultBinary):
            _logger.info("Close session request (%s)", user)
            if self.session:
                deletesubs = ua.ua_binary.Primitives.Boolean.unpack(body)
                await self.session.close_session(deletesubs)
            else:
                _logger.info("Request to close non-existing session (%s)",
                             user)

            response = ua.CloseSessionResponse()
            _logger.info("sending close session response (%s)", user)
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.ActivateSessionRequest_Encoding_DefaultBinary):
            _logger.info("Activate session request (%s)", user)
            params = struct_from_binary(ua.ActivateSessionParameters, body)
            if not self.session:
                _logger.info("request to activate non-existing session (%s)",
                             user)
                raise ServiceError(ua.StatusCodes.BadSessionIdInvalid)
            if self._connection.security_policy.host_certificate is None:
                data = self.session.nonce
            else:
                data = self._connection.security_policy.host_certificate + self.session.nonce
            self._connection.security_policy.asymmetric_cryptography.verify(
                data, params.ClientSignature.Signature)
            result = self.session.activate_session(
                params, self._connection.security_policy.peer_certificate)
            response = ua.ActivateSessionResponse()
            response.Parameters = result
            #_logger.info("sending read response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.ReadRequest_Encoding_DefaultBinary):
            _logger.info("Read request (%s)", user)
            params = struct_from_binary(ua.ReadParameters, body)
            results = await self.session.read(params)
            response = ua.ReadResponse()
            response.Results = results
            #_logger.info("sending read response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.WriteRequest_Encoding_DefaultBinary):
            _logger.info("Write request (%s)", user)
            params = struct_from_binary(ua.WriteParameters, body)
            results = await self.session.write(params)
            response = ua.WriteResponse()
            response.Results = results
            #_logger.info("sending write response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.BrowseRequest_Encoding_DefaultBinary):
            _logger.info("Browse request (%s)", user)
            params = struct_from_binary(ua.BrowseParameters, body)
            results = await self.session.browse(params)
            response = ua.BrowseResponse()
            response.Results = results
            #_logger.info("sending browse response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.GetEndpointsRequest_Encoding_DefaultBinary):
            _logger.info("get endpoints request (%s)", user)
            params = struct_from_binary(ua.GetEndpointsParameters, body)
            endpoints = await self.iserver.get_endpoints(
                params, sockname=self.sockname)
            response = ua.GetEndpointsResponse()
            response.Endpoints = endpoints
            #_logger.info("sending get endpoints response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.FindServersRequest_Encoding_DefaultBinary):
            _logger.info("find servers request (%s)", user)
            params = struct_from_binary(ua.FindServersParameters, body)
            servers = self.iserver.find_servers(params)
            response = ua.FindServersResponse()
            response.Servers = servers
            #_logger.info("sending find servers response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.RegisterServerRequest_Encoding_DefaultBinary):
            _logger.info("register server request %s", user)
            serv = struct_from_binary(ua.RegisteredServer, body)
            self.iserver.register_server(serv)
            response = ua.RegisterServerResponse()
            #_logger.info("sending register server response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.RegisterServer2Request_Encoding_DefaultBinary):
            _logger.info("register server 2 request %s", user)
            params = struct_from_binary(ua.RegisterServer2Parameters, body)
            results = self.iserver.register_server2(params)
            response = ua.RegisterServer2Response()
            response.ConfigurationResults = results
            #_logger.info("sending register server 2 response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.
                TranslateBrowsePathsToNodeIdsRequest_Encoding_DefaultBinary):
            _logger.info("translate browsepaths to nodeids request (%s)", user)
            params = struct_from_binary(
                ua.TranslateBrowsePathsToNodeIdsParameters, body)
            paths = await self.session.translate_browsepaths_to_nodeids(
                params.BrowsePaths)
            response = ua.TranslateBrowsePathsToNodeIdsResponse()
            response.Results = paths
            #_logger.info("sending translate browsepaths to nodeids response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.AddNodesRequest_Encoding_DefaultBinary):
            _logger.info("add nodes request (%s)", user)
            params = struct_from_binary(ua.AddNodesParameters, body)
            results = await self.session.add_nodes(params.NodesToAdd)
            response = ua.AddNodesResponse()
            response.Results = results
            #_logger.info("sending add node response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.DeleteNodesRequest_Encoding_DefaultBinary):
            _logger.info("delete nodes request (%s)", user)
            params = struct_from_binary(ua.DeleteNodesParameters, body)
            results = await self.session.delete_nodes(params)
            response = ua.DeleteNodesResponse()
            response.Results = results
            #_logger.info("sending delete node response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.AddReferencesRequest_Encoding_DefaultBinary):
            _logger.info("add references request (%s)", user)
            params = struct_from_binary(ua.AddReferencesParameters, body)
            results = await self.session.add_references(params.ReferencesToAdd)
            response = ua.AddReferencesResponse()
            response.Results = results
            #_logger.info("sending add references response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.DeleteReferencesRequest_Encoding_DefaultBinary):
            _logger.info("delete references request (%s)", user)
            params = struct_from_binary(ua.DeleteReferencesParameters, body)
            results = await self.session.delete_references(
                params.ReferencesToDelete)
            response = ua.DeleteReferencesResponse()
            response.Parameters.Results = results
            #_logger.info("sending delete references response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.CreateSubscriptionRequest_Encoding_DefaultBinary):
            _logger.info("create subscription request (%s)", user)
            params = struct_from_binary(ua.CreateSubscriptionParameters, body)
            result = await self.session.create_subscription(
                params, callback=self.forward_publish_response)
            response = ua.CreateSubscriptionResponse()
            response.Parameters = result
            #_logger.info("sending create subscription response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.DeleteSubscriptionsRequest_Encoding_DefaultBinary
        ):
            _logger.info("delete subscriptions request (%s)", user)
            params = struct_from_binary(ua.DeleteSubscriptionsParameters, body)
            results = await self.session.delete_subscriptions(
                params.SubscriptionIds)
            response = ua.DeleteSubscriptionsResponse()
            response.Results = results
            #_logger.info("sending delete subscription response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.CreateMonitoredItemsRequest_Encoding_DefaultBinary
        ):
            _logger.info("create monitored items request (%s)", user)
            params = struct_from_binary(ua.CreateMonitoredItemsParameters,
                                        body)
            results = await self.session.create_monitored_items(params)
            response = ua.CreateMonitoredItemsResponse()
            response.Results = results
            #_logger.info("sending create monitored items response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.ModifyMonitoredItemsRequest_Encoding_DefaultBinary
        ):
            _logger.info("modify monitored items request (%s)", user)
            params = struct_from_binary(ua.ModifyMonitoredItemsParameters,
                                        body)
            results = await self.session.modify_monitored_items(params)
            response = ua.ModifyMonitoredItemsResponse()
            response.Results = results
            #_logger.info("sending modify monitored items response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.DeleteMonitoredItemsRequest_Encoding_DefaultBinary
        ):
            _logger.info("delete monitored items request (%s)", user)
            params = struct_from_binary(ua.DeleteMonitoredItemsParameters,
                                        body)
            results = await self.session.delete_monitored_items(params)
            response = ua.DeleteMonitoredItemsResponse()
            response.Results = results
            #_logger.info("sending delete monitored items response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.HistoryReadRequest_Encoding_DefaultBinary):
            _logger.info("history read request (%s)", user)
            params = struct_from_binary(ua.HistoryReadParameters, body)
            results = await self.session.history_read(params)
            response = ua.HistoryReadResponse()
            response.Results = results
            #_logger.info("sending history read response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.RegisterNodesRequest_Encoding_DefaultBinary):
            _logger.info("register nodes request (%s)", user)
            params = struct_from_binary(ua.RegisterNodesParameters, body)
            _logger.info("Node registration not implemented")
            response = ua.RegisterNodesResponse()
            response.Parameters.RegisteredNodeIds = params.NodesToRegister
            #_logger.info("sending register nodes response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.UnregisterNodesRequest_Encoding_DefaultBinary):
            _logger.info("unregister nodes request (%s)", user)
            params = struct_from_binary(ua.UnregisterNodesParameters, body)
            response = ua.UnregisterNodesResponse()
            #_logger.info("sending unregister nodes response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.PublishRequest_Encoding_DefaultBinary):
            _logger.debug("publish request (%s)", user)
            if not self.session:
                return False
            params = struct_from_binary(ua.PublishParameters, body)
            data = PublishRequestData(requesthdr=requesthdr, seqhdr=seqhdr)
            # Store the Publish Request (will be used to send publish answers from server)
            self._publish_requests.append(data)
            # If there is an enqueued result forward it immediately
            while self._publish_results:
                result = self._publish_results.popleft()
                if result.SubscriptionId not in self.session.subscription_service.active_subscription_ids:
                    # Discard the result if the subscription is no longer active
                    continue
                await self.forward_publish_response(result)
                break
            self.session.publish(params.SubscriptionAcknowledgements)
            #_logger.debug("publish forward to server")

        elif typeid == ua.NodeId(
                ua.ObjectIds.RepublishRequest_Encoding_DefaultBinary):
            _logger.info("re-publish request (%s)", user)
            params = struct_from_binary(ua.RepublishParameters, body)
            msg = self.session.republish(params)
            response = ua.RepublishResponse()
            response.NotificationMessage = msg
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.CloseSecureChannelRequest_Encoding_DefaultBinary):
            _logger.info("close secure channel request (%s)", user)
            self._connection.close()
            response = ua.CloseSecureChannelResponse()
            self.send_response(requesthdr.RequestHandle, seqhdr, response)
            return False

        elif typeid == ua.NodeId(
                ua.ObjectIds.CallRequest_Encoding_DefaultBinary):
            _logger.info("call request (%s)", user)
            params = struct_from_binary(ua.CallParameters, body)
            results = await self.session.call(params.MethodsToCall)
            response = ua.CallResponse()
            response.Results = results
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.SetMonitoringModeRequest_Encoding_DefaultBinary):
            _logger.info("set monitoring mode request (%s)", user)
            params = struct_from_binary(ua.SetMonitoringModeParameters, body)
            # FIXME: Implement SetMonitoringMode
            # For now send dummy results to keep clients happy
            response = ua.SetMonitoringModeResponse()
            results = ua.SetMonitoringModeResult()
            ids = params.MonitoredItemIds
            statuses = [ua.StatusCode(ua.StatusCodes.Good) for node_id in ids]
            results.Results = statuses
            response.Parameters = results
            _logger.info("sending set monitoring mode response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        elif typeid == ua.NodeId(
                ua.ObjectIds.SetPublishingModeRequest_Encoding_DefaultBinary):
            _logger.info("set publishing mode request (%s)", user)
            params = struct_from_binary(ua.SetPublishingModeParameters, body)
            # FIXME: Implement SetPublishingMode
            # For now send dummy results to keep clients happy
            response = ua.SetPublishingModeResponse()
            results = ua.SetPublishingModeResult()
            ids = params.SubscriptionIds
            statuses = [ua.StatusCode(ua.StatusCodes.Good) for node_id in ids]
            results.Results = statuses
            response.Parameters = results
            _logger.info("sending set publishing mode response")
            self.send_response(requesthdr.RequestHandle, seqhdr, response)

        else:
            _logger.warning("Unknown message received %s (%s)", typeid, user)
            raise ServiceError(ua.StatusCodes.BadServiceUnsupported)

        return True
예제 #28
0
    def _add_node(self, item, user, check=True):
        #self.logger.debug("Adding node %s %s", item.RequestedNewNodeId, item.BrowseName)
        result = ua.AddNodesResult()

        if not user == User.Admin:
            result.StatusCode = ua.StatusCode(
                ua.StatusCodes.BadUserAccessDenied)
            return result

        if item.RequestedNewNodeId.has_null_identifier():
            # If Identifier of requested NodeId is null we generate a new NodeId using
            # the namespace of the nodeid, this is an extention of the spec to allow
            # to requests the server to generate a new nodeid in a specified namespace
            #self.logger.debug("RequestedNewNodeId has null identifier, generating Identifier")
            item.RequestedNewNodeId = self._aspace.generate_nodeid(
                item.RequestedNewNodeId.NamespaceIndex)
        else:
            if item.RequestedNewNodeId in self._aspace:
                self.logger.warning(
                    "AddNodesItem: Requested NodeId %s already exists",
                    item.RequestedNewNodeId)
                result.StatusCode = ua.StatusCode(
                    ua.StatusCodes.BadNodeIdExists)
                return result

        if item.ParentNodeId.is_null():
            # self.logger.info("add_node: while adding node %s, requested parent node is null %s %s",
            # item.RequestedNewNodeId, item.ParentNodeId, item.ParentNodeId.is_null())
            if check:
                result.StatusCode = ua.StatusCode(
                    ua.StatusCodes.BadParentNodeIdInvalid)
                return result

        parentdata = self._aspace.get(item.ParentNodeId)
        if parentdata is None and not item.ParentNodeId.is_null():
            self.logger.info(
                "add_node: while adding node %s, requested parent node %s does not exists",
                item.RequestedNewNodeId, item.ParentNodeId)
            result.StatusCode = ua.StatusCode(
                ua.StatusCodes.BadParentNodeIdInvalid)
            return result

        nodedata = NodeData(item.RequestedNewNodeId)

        self._add_node_attributes(nodedata, item, add_timestamps=check)

        # now add our node to db
        self._aspace[nodedata.nodeid] = nodedata

        if parentdata is not None:
            self._add_ref_from_parent(nodedata, item, parentdata)
            self._add_ref_to_parent(nodedata, item, parentdata)

        # add type definition
        if item.TypeDefinition != ua.NodeId():
            self._add_type_definition(nodedata, item)

        result.StatusCode = ua.StatusCode()
        result.AddedNodeId = nodedata.nodeid

        return result
예제 #29
0
async def test_xml_statuscode(opc, tmpdir):
    o = await opc.opc.nodes.objects.add_variable(
        2, "xmllstatuscode",
        ua.StatusCode(value=ua.StatusCodes.BadNodeIdInvalid))
    await _test_xml_var_type(opc, tmpdir, o, "statuscode")
    await opc.opc.delete_nodes([o])
예제 #30
0
    def _parse_value(self, val_el, obj):
        """
        Parse the node val_el as a constant.
        """
        if val_el is not None and val_el.text is not None:
            ntag = self._retag.match(val_el.tag).groups()[1]
        else:
            ntag = "Null"

        obj.valuetype = ntag
        if ntag == "Null":
            obj.value = None
        elif hasattr(ua.ua_binary.Primitives1, ntag):
            # Elementary types have their parsing directly relying on ua_type_to_python.
            obj.value = ua_type_to_python(val_el.text, ntag)
        elif ntag == "DateTime":
            obj.value = ua_type_to_python(val_el.text, ntag)
            # According to specs, DateTime should be either UTC or with a timezone.
            if obj.value.tzinfo is None or obj.value.tzinfo.utcoffset(obj.value) is None:
                utc.localize(obj.value)  # FIXME Forcing to UTC if unaware, maybe should raise?
        elif ntag == "ByteString":
            if val_el.text is None:
                mytext = b""
            else:
                mytext = val_el.text.encode()
                mytext = base64.b64decode(mytext)
            obj.value = mytext
        elif ntag == "String" or ntag == "XmlElement":
            # String and XMLElement are identical only type is different
            mytext = val_el.text
            if mytext is None:
                # Support importing null strings.
                mytext = ""
            if ntag == "XmlElement":
                obj.value = ua.XmlElement(mytext)
            else:
                obj.value = mytext
        elif ntag == "Guid":
            self._parse_contained_value(val_el, obj)
            # Override parsed string type to guid.
            obj.valuetype = ntag
        elif ntag == "NodeId":
            id_el = val_el.find("uax:Identifier", self.ns)
            if id_el is not None:
                obj.value = id_el.text
        elif ntag == "ExpandedNodeId":
            id_el = val_el.find("uax:Identifier", self.ns)
            if id_el is not None:
                obj.value = ua.NodeId.from_string(id_el.text)
                if not isinstance(obj.value, ua.ExpandedNodeId):
                    obj.value = ua.ExpandedNodeId(obj.value.Identifier, obj.value.NamespaceIndex)
        elif ntag == "ExtensionObject":
            obj.value = self._parse_ext_obj(val_el)
        elif ntag == "LocalizedText":
            obj.value = self._parse_body(val_el)
        elif ntag == "ListOfLocalizedText":
            obj.value = self._parse_list_of_localized_text(val_el)
        elif ntag == "ListOfExtensionObject":
            obj.value = self._parse_list_of_extension_object(val_el)
        elif ntag == "StatusCode":
            code_el = val_el.find("uax:Code", self.ns)
            val = code_el.text if code_el is not None else "0"
            obj.value = ua.StatusCode(string_to_val(val, ua.VariantType.UInt32))
        elif ntag == "QualifiedName":
            obj.value = self._parse_qualifed_name(val_el)
        elif ntag.startswith("ListOf"):
            # Default case for "ListOf" types.
            # Should stay after particular cases (e.g.: "ListOfLocalizedText").
            obj.value = []
            for val_el in val_el:
                tmp = NodeData()
                self._parse_value(val_el, tmp)
                obj.value.append(tmp.value)
        else:
            # Missing according to ua.VariantType (also missing in string_to_val):
            # DataValue, Variant, DiagnosticInfo.
            self.logger.warning("Parsing value of type '%s' not implemented", ntag)