Commit 6a68a039 authored by ORD's avatar ORD

Merge pull request #153 from FreeOpcUa/history

History fixes and event support WORK IN PROGRESS
parents eb491cfa cb660789
......@@ -74,11 +74,12 @@ Server: what works:
* encryption
* certificate handling
* removing nodes
* history support
Tested clients: freeopcua C++, freeopcua Python, uaexpert, prosys, quickopc
Server: what is not implemented
* history support
* history support for events
* views
* localized text feature
* better securty model with users and password
......
......@@ -318,7 +318,11 @@ class Client(object):
params.RequestedSessionTimeout = 3600000
params.MaxResponseMessageSize = 0 # means no max size
response = self.uaclient.create_session(params)
self.security_policy.asymmetric_cryptography.verify(self.security_policy.client_certificate + nonce, response.ServerSignature.Signature)
if self.security_policy.client_certificate is None:
data = nonce
else:
data = self.security_policy.client_certificate + nonce
self.security_policy.asymmetric_cryptography.verify(data, response.ServerSignature.Signature)
self._server_nonce = response.ServerNonce
if not self.security_policy.server_certificate:
self.security_policy.server_certificate = response.ServerCertificate
......@@ -361,7 +365,8 @@ class Client(object):
Activate session using either username and password or private_key
"""
params = ua.ActivateSessionParameters()
challenge = self.security_policy.server_certificate + self._server_nonce
cert = self.security_policy.server_certificate if self.security_policy.server_certificate is not None else b""
challenge = cert + self._server_nonce
params.ClientSignature.Algorithm = b"http://www.w3.org/2000/09/xmldsig#rsa-sha1"
params.ClientSignature.Signature = self.security_policy.asymmetric_cryptography.signature(challenge)
params.LocaleIds.append("en")
......
......@@ -3,6 +3,7 @@ from datetime import datetime
from opcua import Subscription
from opcua import ua
from opcua.common import utils
class HistoryStorageInterface(object):
......@@ -207,7 +208,7 @@ class HistoryManager(object):
# implementation. This is contradictory, so we assume details is
# send correctly with continuation point
#starttime = bytes_to_datetime(rv.ContinuationPoint)
starttime = ua.unpack_datetime(rv.ContinuationPoint)
starttime = ua.unpack_datetime(utils.Buffer(rv.ContinuationPoint))
dv, cont = self.storage.read_node_history(rv.NodeId,
starttime,
......
......@@ -122,7 +122,11 @@ class UaProcessor(object):
response = ua.CreateSessionResponse()
response.Parameters = sessiondata
response.Parameters.ServerCertificate = self._connection._security_policy.client_certificate
response.Parameters.ServerSignature.Signature = self._connection._security_policy.asymmetric_cryptography.signature(self._connection._security_policy.server_certificate + params.ClientNonce)
if self._connection._security_policy.server_certificate is None:
data = params.ClientNonce
else:
data = self._connection._security_policy.server_certificate + params.ClientNonce
response.Parameters.ServerSignature.Signature = self._connection._security_policy.asymmetric_cryptography.signature(data)
response.Parameters.ServerSignature.Algorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
self.logger.info("sending create sesssion response")
......@@ -146,7 +150,11 @@ class UaProcessor(object):
self.logger.info("request to activate non-existing session")
raise utils.ServiceError(ua.StatusCodes.BadSessionIdInvalid)
self._connection._security_policy.asymmetric_cryptography.verify(self._connection._security_policy.client_certificate + self.session.nonce, params.ClientSignature.Signature)
if self._connection._security_policy.client_certificate is None:
data = self.session.nonce
else:
data = self._connection._security_policy.client_certificate + self.session.nonce
self._connection._security_policy.asymmetric_cryptography.verify(data, params.ClientSignature.Signature)
result = self.session.activate_session(params)
......
......@@ -84,7 +84,11 @@ def parse_args(parser, requirenodeid=False):
def get_node(client, args):
node = client.get_node(args.nodeid)
if args.path:
node = node.get_child(args.path.split(","))
path = args.path.split(",")
if node.nodeid == ua.NodeId(84, 0) and path[0] == "0:Root":
# let user specify root if not node given
path = path[1:]
node = node.get_child(path)
return node
......
......@@ -163,8 +163,8 @@ class AsymmetricAlgorithmHeader(uatypes.FrozenClass):
def __init__(self):
self.SecurityPolicyURI = "http://opcfoundation.org/UA/SecurityPolicy#None"
self.SenderCertificate = b""
self.ReceiverCertificateThumbPrint = b""
self.SenderCertificate = None
self.ReceiverCertificateThumbPrint = None
self._freeze = True
def to_binary(self):
......@@ -308,8 +308,8 @@ class SecurityPolicy(object):
self.asymmetric_cryptography = CryptographyNone()
self.symmetric_cryptography = CryptographyNone()
self.Mode = auto.MessageSecurityMode.None_
self.server_certificate = b""
self.client_certificate = b""
self.server_certificate = None
self.client_certificate = None
def make_symmetric_key(self, a, b):
pass
......
......@@ -218,8 +218,6 @@ def pack_string(string):
if isinstance(string, unicode):
string = string.encode('utf-8')
length = len(string)
if length == 0:
return b'\xff\xff\xff\xff'
return uatype_Int32.pack(length) + string
pack_bytes = pack_string
......@@ -228,13 +226,14 @@ pack_bytes = pack_string
def unpack_bytes(data):
length = uatype_Int32.unpack(data.read(4))[0]
if length == -1:
# FIXME: return None, check it does not break things
return b''
return None
return data.read(length)
def py3_unpack_string(data):
b = unpack_bytes(data)
if b is None:
return b
return b.decode("utf-8")
......
......@@ -16,7 +16,7 @@ except ImportError:
from tests_cmd_lines import TestCmdLines
from tests_server import TestServer
from tests_client import TestClient
from tests_unit import Unit
from tests_unit import TestUnit
if CRYPTOGRAPHY_AVAILABLE:
from tests_crypto_connect import TestCryptoConnect
......
......@@ -12,7 +12,7 @@ from opcua.ua.uatypes import flatten, get_shape, reshape
class Unit(unittest.TestCase):
class TestUnit(unittest.TestCase):
'''
Simple unit test that do not need to setup a server or a client
......@@ -140,13 +140,22 @@ class Unit(unittest.TestCase):
with self.assertRaises(ua.UaError):
ua.QualifiedName.from_string("i:::yu")
def test_expandednodeid(self):
nid = ua.ExpandedNodeId()
self.assertEqual(nid.NodeIdType, ua.NodeIdType.TwoByte)
nid2 = ua.ExpandedNodeId.from_binary(ua.utils.Buffer(nid.to_binary()))
self.assertEqual(nid, nid2)
def test_null_string(self):
v = ua.Variant(None, ua.VariantType.String)
b = v.to_binary()
v2 = ua.Variant.from_binary(ua.utils.Buffer(b))
self.assertEqual(v.Value, v2.Value)
v = ua.Variant("", ua.VariantType.String)
b = v.to_binary()
v2 = ua.Variant.from_binary(ua.utils.Buffer(b))
self.assertEqual(v.Value, v2.Value)
def test_extension_object(self):
obj = ua.UserNameIdentityToken()
obj.UserName = "admin"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment