Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
opcua-asyncio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nikola Balog
opcua-asyncio
Commits
35288e53
Commit
35288e53
authored
Jul 07, 2015
by
Olivier R-D
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add minimal user support, default address space to read-only
parent
549ec004
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
110 additions
and
29 deletions
+110
-29
example-server.py
example-server.py
+8
-3
opcua/address_space.py
opcua/address_space.py
+23
-5
opcua/client.py
opcua/client.py
+11
-3
opcua/internal_server.py
opcua/internal_server.py
+16
-10
opcua/node.py
opcua/node.py
+16
-4
tests.py
tests.py
+36
-4
No files found.
example-server.py
View file @
35288e53
...
...
@@ -48,10 +48,15 @@ if __name__ == "__main__":
# optional setup logging
logging
.
basicConfig
(
level
=
logging
.
WARN
)
#logger = logging.getLogger("opcua.address_space")
#logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.internal_server")
# logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.subscription_server")
# logger.setLevel(logging.DEBUG)
#logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.binary_server_asyncio")
#logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.uaprocessor")
#logger.setLevel(logging.DEBUG)
#logger = logging.getLogger("opcua.subscription_service")
#logger.setLevel(logging.DEBUG)
# now setup our server
server
=
Server
()
...
...
opcua/address_space.py
View file @
35288e53
...
...
@@ -4,6 +4,7 @@ import pickle
from
datetime
import
datetime
from
opcua
import
ua
from
opcua.users
import
User
class
AttributeValue
(
object
):
...
...
@@ -44,10 +45,18 @@ class AttributeService(object):
res
.
append
(
self
.
_aspace
.
get_attribute_value
(
readvalue
.
NodeId
,
readvalue
.
AttributeId
))
return
res
def
write
(
self
,
params
):
self
.
logger
.
debug
(
"write %s
"
,
params
)
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
:
# FIXME: check WriteMask and UserWriteMask!!!
al
=
self
.
_aspace
.
get_attribute_value
(
writevalue
.
NodeId
,
ua
.
AttributeIds
.
WriteMask
)
ual
=
self
.
_aspace
.
get_attribute_value
(
writevalue
.
NodeId
,
ua
.
AttributeIds
.
UserWriteMask
)
# FIXME: very strange to use OpenFileMode for access rights?!?!?
if
not
al
.
Value
.
Value
&
ua
.
OpenFileMode
.
Write
and
not
ual
.
Value
.
Value
&
ua
.
OpenFileMode
.
Write
:
res
.
append
(
ua
.
StatusCode
(
ua
.
StatusCodes
.
BadUserAccessDenied
))
continue
res
.
append
(
self
.
_aspace
.
set_attribute_value
(
writevalue
.
NodeId
,
writevalue
.
AttributeId
,
writevalue
.
Value
))
return
res
...
...
@@ -158,13 +167,13 @@ class NodeManagementService(object):
self
.
logger
=
logging
.
getLogger
(
__name__
)
self
.
_aspace
=
aspace
def
add_nodes
(
self
,
addnodeitems
):
def
add_nodes
(
self
,
addnodeitems
,
user
=
User
.
Admin
):
results
=
[]
for
item
in
addnodeitems
:
results
.
append
(
self
.
_add_node
(
item
))
results
.
append
(
self
.
_add_node
(
item
,
user
))
return
results
def
_add_node
(
self
,
item
):
def
_add_node
(
self
,
item
,
user
):
result
=
ua
.
AddNodesResult
()
if
item
.
RequestedNewNodeId
in
self
.
_aspace
:
...
...
@@ -188,6 +197,15 @@ class NodeManagementService(object):
result
.
StatusCode
=
ua
.
StatusCode
(
ua
.
StatusCodes
.
BadParentNodeIdInvalid
)
return
result
else
:
if
user
!=
User
.
Admin
:
# FIXME: is checking against WriteMask correct??
al
=
self
.
_aspace
.
get_attribute_value
(
item
.
ParentNodeId
,
ua
.
AttributeIds
.
WriteMask
)
ual
=
self
.
_aspace
.
get_attribute_value
(
item
.
ParentNodeId
,
ua
.
AttributeIds
.
UserWriteMask
)
# FIXME: very strange to use OpenFileMode for access rights?!?!?
if
not
al
.
Value
.
Value
&
ua
.
OpenFileMode
.
Write
and
not
ual
.
Value
.
Value
&
ua
.
OpenFileMode
.
Write
:
result
.
StatusCode
=
ua
.
StatusCode
(
ua
.
StatusCodes
.
BadUserAccessDenied
)
return
result
desc
=
ua
.
ReferenceDescription
()
desc
.
ReferenceTypeId
=
item
.
ReferenceTypeId
desc
.
NodeId
=
item
.
RequestedNewNodeId
...
...
opcua/client.py
View file @
35288e53
...
...
@@ -169,7 +169,7 @@ class Client(object):
params
.
EndpointUrl
=
self
.
server_url
.
geturl
()
params
.
SessionName
=
self
.
description
+
" Session"
+
str
(
self
.
_session_counter
)
params
.
RequestedSessionTimeout
=
3600000
params
.
MaxResponseMessageSize
=
0
# means no
t
max size
params
.
MaxResponseMessageSize
=
0
# means no max size
response
=
self
.
bclient
.
create_session
(
params
)
self
.
session_timeout
=
response
.
RevisedSessionTimeout
self
.
keepalive
=
KeepAlive
(
self
,
min
(
self
.
session_timeout
,
self
.
secure_channel_timeout
)
*
0.7
)
# 0.7 is from spec
...
...
@@ -179,8 +179,16 @@ class Client(object):
def
activate_session
(
self
):
params
=
ua
.
ActivateSessionParameters
()
params
.
LocaleIds
.
append
(
"en"
)
params
.
UserIdentityToken
=
ua
.
AnonymousIdentityToken
()
params
.
UserIdentityToken
.
PolicyId
=
b"anonymous"
if
not
self
.
server_url
.
username
:
params
.
UserIdentityToken
=
ua
.
AnonymousIdentityToken
()
params
.
UserIdentityToken
.
PolicyId
=
b"anonymous"
else
:
params
.
UserIdentityToken
=
ua
.
UserNameIdentityToken
()
params
.
UserIdentityToken
.
UserName
=
self
.
server_url
.
username
if
self
.
server_url
.
password
:
params
.
UserIdentityToken
.
Password
=
bytes
(
self
.
server_url
.
password
)
params
.
UserIdentityToken
.
PolicyId
=
b"user_name"
#params.EncryptionAlgorithm = ''
return
self
.
bclient
.
activate_session
(
params
)
def
close_session
(
self
):
...
...
opcua/internal_server.py
View file @
35288e53
...
...
@@ -23,6 +23,7 @@ from opcua.address_space import NodeManagementService
from
opcua.address_space
import
MethodService
from
opcua.subscription_service
import
SubscriptionService
from
opcua
import
standard_address_space
from
opcua.users
import
User
class
SessionState
(
Enum
):
Created
=
0
...
...
@@ -46,11 +47,10 @@ class InternalServer(object):
#standard_address_space.fill_address_space_from_disk(self.aspace)
self
.
loop
=
utils
.
ThreadLoop
()
self
.
sub
cs
ription_service
=
SubscriptionService
(
self
.
loop
,
self
.
aspace
)
self
.
sub
sc
ription_service
=
SubscriptionService
(
self
.
loop
,
self
.
aspace
)
# create a session to use on server side
self
.
isession
=
InternalSession
(
self
,
self
.
aspace
,
self
.
subcsription_service
,
"Internal"
)
self
.
_timer
=
None
self
.
isession
=
InternalSession
(
self
,
self
.
aspace
,
self
.
subscription_service
,
"Internal"
,
user
=
User
.
Admin
)
self
.
current_time_node
=
Node
(
self
.
isession
,
ua
.
NodeId
(
ua
.
ObjectIds
.
Server_ServerStatus_CurrentTime
))
uries
=
[
"http://opcfoundation.org/UA/"
]
ns_node
=
Node
(
self
.
isession
,
ua
.
NodeId
(
ua
.
ObjectIds
.
Server_NamespaceArray
))
...
...
@@ -106,20 +106,21 @@ class InternalServer(object):
return
servers
def
create_session
(
self
,
name
):
return
InternalSession
(
self
,
self
.
aspace
,
self
.
sub
csription_service
,
name
)
def
create_session
(
self
,
name
,
user
=
User
.
Anonymous
):
return
InternalSession
(
self
,
self
.
aspace
,
self
.
sub
scription_service
,
name
,
user
=
user
)
class
InternalSession
(
object
):
_counter
=
10
_auth_counter
=
1000
def
__init__
(
self
,
internal_server
,
aspace
,
submgr
,
name
):
def
__init__
(
self
,
internal_server
,
aspace
,
submgr
,
name
,
user
=
User
.
Anonymous
):
self
.
logger
=
logging
.
getLogger
(
__name__
)
self
.
iserver
=
internal_server
self
.
aspace
=
aspace
self
.
subscription_service
=
submgr
self
.
name
=
name
self
.
user
=
user
self
.
state
=
SessionState
.
Created
self
.
session_id
=
ua
.
NodeId
(
self
.
_counter
)
InternalSession
.
_counter
+=
1
...
...
@@ -127,11 +128,12 @@ class InternalSession(object):
InternalSession
.
_auth_counter
+=
1
self
.
nonce
=
utils
.
create_nonce
()
self
.
subscriptions
=
[]
self
.
logger
.
warning
(
"Created internal session %s"
,
self
.
name
)
#self.logger.debug("Created internal session %s for user %s", self.name, self.user)
print
(
"Created internal session {} for user {}"
.
format
(
self
.
name
,
self
.
user
))
self
.
_lock
=
Lock
()
def
__str__
(
self
):
return
"InternalSession(name:{},
id:{}, auth_token:{})"
.
format
(
self
.
name
,
self
.
session_id
,
self
.
authentication_token
)
return
"InternalSession(name:{},
user:{}, id:{}, auth_token:{})"
.
format
(
self
.
name
,
self
.
user
,
self
.
session_id
,
self
.
authentication_token
)
def
get_endpoints
(
self
,
params
=
None
,
sockname
=
None
):
return
self
.
iserver
.
get_endpoints
(
params
,
sockname
)
...
...
@@ -164,13 +166,17 @@ class InternalSession(object):
for
_
in
params
.
ClientSoftwareCertificates
:
result
.
Results
.
append
(
ua
.
StatusCode
())
self
.
state
=
SessionState
.
Activated
id_token
=
ua
.
downcast_extobject
(
params
.
UserIdentityToken
)
if
id_token
.
TypeId
==
ua
.
FourByteNodeId
(
ua
.
ObjectIds
.
UserNameIdentityToken_Encoding_DefaultBinary
):
if
id_token
.
UserName
in
(
"admin"
,
"Admin"
):
self
.
user
=
User
.
Admin
return
result
def
read
(
self
,
params
):
return
self
.
iserver
.
attribute_service
.
read
(
params
)
def
write
(
self
,
params
):
return
self
.
iserver
.
attribute_service
.
write
(
params
)
return
self
.
iserver
.
attribute_service
.
write
(
params
,
self
.
user
)
def
browse
(
self
,
params
):
return
self
.
iserver
.
view_service
.
browse
(
params
)
...
...
@@ -179,7 +185,7 @@ class InternalSession(object):
return
self
.
iserver
.
view_service
.
translate_browsepaths_to_nodeids
(
params
)
def
add_nodes
(
self
,
params
):
return
self
.
iserver
.
node_mgt_service
.
add_nodes
(
params
)
return
self
.
iserver
.
node_mgt_service
.
add_nodes
(
params
,
self
.
user
)
def
add_method_callback
(
self
,
methodid
,
callback
):
return
self
.
aspace
.
add_method_callback
(
methodid
,
callback
)
...
...
opcua/node.py
View file @
35288e53
...
...
@@ -195,6 +195,14 @@ class Node(object):
set_data_value
=
set_value
def
set_writable
(
self
,
writable
=
True
):
if
writable
:
self
.
set_attribute
(
ua
.
AttributeIds
.
WriteMask
,
ua
.
DataValue
(
ua
.
OpenFileMode
.
Write
))
self
.
set_attribute
(
ua
.
AttributeIds
.
UserWriteMask
,
ua
.
DataValue
(
ua
.
OpenFileMode
.
Write
))
else
:
self
.
set_attribute
(
ua
.
AttributeIds
.
WriteMask
,
ua
.
DataValue
(
ua
.
OpenFileMode
.
Read
))
self
.
set_attribute
(
ua
.
AttributeIds
.
UserWriteMask
,
ua
.
DataValue
(
ua
.
OpenFileMode
.
Read
))
def
set_attribute
(
self
,
attributeid
,
datavalue
):
"""
Set an attribute of a node
...
...
@@ -331,6 +339,8 @@ def _create_folder(server, parentnodeid, nodeid, qname):
attrs
=
ua
.
ObjectAttributes
()
attrs
.
Description
=
ua
.
LocalizedText
(
qname
.
Name
)
attrs
.
DisplayName
=
ua
.
LocalizedText
(
qname
.
Name
)
attrs
.
WriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
UserWriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
EventNotifier
=
0
node
.
NodeAttributes
=
attrs
results
=
server
.
add_nodes
([
node
])
...
...
@@ -350,6 +360,8 @@ def _create_object(server, parentnodeid, nodeid, qname):
attrs
.
Description
=
ua
.
LocalizedText
(
qname
.
Name
)
attrs
.
DisplayName
=
ua
.
LocalizedText
(
qname
.
Name
)
attrs
.
EventNotifier
=
0
attrs
.
WriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
UserWriteMask
=
ua
.
OpenFileMode
.
Read
node
.
NodeAttributes
=
attrs
results
=
server
.
add_nodes
([
node
])
results
[
0
].
StatusCode
.
check
()
...
...
@@ -381,8 +393,8 @@ def _create_variable(server, parentnodeid, nodeid, qname, val, isproperty=False)
attrs
.
DataType
=
_guess_uatype
(
val
)
attrs
.
Value
=
val
attrs
.
ValueRank
=
0
attrs
.
WriteMask
=
0
attrs
.
UserWriteMask
=
0
attrs
.
WriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
UserWriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
Historizing
=
0
node
.
NodeAttributes
=
attrs
results
=
server
.
add_nodes
([
node
])
...
...
@@ -401,8 +413,8 @@ def _create_method(parent, nodeid, qname, callback, inputs, outputs):
attrs
=
ua
.
MethodAttributes
()
attrs
.
Description
=
ua
.
LocalizedText
(
qname
.
Name
)
attrs
.
DisplayName
=
ua
.
LocalizedText
(
qname
.
Name
)
attrs
.
WriteMask
=
0
attrs
.
UserWriteMask
=
0
attrs
.
WriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
UserWriteMask
=
ua
.
OpenFileMode
.
Read
attrs
.
Executable
=
True
attrs
.
UserExecutable
=
True
node
.
NodeAttributes
=
attrs
...
...
tests.py
View file @
35288e53
...
...
@@ -629,7 +629,7 @@ def add_server_methods(srv):
o
=
srv
.
get_objects_node
()
v
=
o
.
add_method
(
ua
.
NodeId
(
"ServerMethodArray2"
,
2
),
ua
.
QualifiedName
(
'ServerMethodArray2'
,
2
),
func3
,
[
ua
.
VariantType
.
Int64
],
[
ua
.
VariantType
.
Int64
])
class
TestClient
(
unittest
.
TestCase
,
CommonTests
):
class
Admin
TestClient
(
unittest
.
TestCase
,
CommonTests
):
'''
Run common tests on client side
...
...
@@ -645,15 +645,23 @@ class TestClient(unittest.TestCase, CommonTests):
add_server_methods
(
self
.
srv
)
self
.
srv
.
start
()
# start client
self
.
clt
=
Client
(
'opc.tcp://localhost:%d'
%
port_num1
)
# start
admin
client
self
.
clt
=
Client
(
'opc.tcp://
admin@
localhost:%d'
%
port_num1
)
self
.
clt
.
connect
()
self
.
opc
=
self
.
clt
# start anonymous client
self
.
ro_clt
=
Client
(
'opc.tcp://localhost:%d'
%
port_num1
)
self
.
ro_clt
.
connect
()
@
classmethod
def
tearDownClass
(
self
):
#stop our clients
self
.
ro_clt
.
disconnect
()
self
.
clt
.
disconnect
()
# stop the server
in its own process
# stop the server
self
.
srv
.
stop
()
def
test_service_fault
(
self
):
...
...
@@ -662,6 +670,30 @@ class TestClient(unittest.TestCase, CommonTests):
with
self
.
assertRaises
(
Exception
):
self
.
clt
.
bclient
.
_send_request
(
request
)
def
test_ro_objects
(
self
):
objects
=
self
.
ro_clt
.
get_objects_node
()
with
self
.
assertRaises
(
Exception
):
objects
.
set_attribute
(
ua
.
AttributeIds
.
WriteMask
,
ua
.
DataValue
(
999
))
with
self
.
assertRaises
(
Exception
):
f
=
objects
.
add_folder
(
3
,
'MyFolder'
)
def
test_ro_variable
(
self
):
objects
=
self
.
clt
.
get_objects_node
()
v
=
objects
.
add_variable
(
3
,
'MyROVariable'
,
6
)
v
.
set_value
(
4
)
#this should work
v_ro
=
self
.
ro_clt
.
get_node
(
v
.
nodeid
)
with
self
.
assertRaises
(
Exception
):
v_ro
.
set_value
(
2
)
self
.
assertEqual
(
v_ro
.
get_value
(),
4
)
v
.
set_writable
(
True
)
v_ro
.
set_value
(
2
)
#now it should work
self
.
assertEqual
(
v_ro
.
get_value
(),
2
)
v
.
set_writable
(
False
)
with
self
.
assertRaises
(
Exception
):
v_ro
.
set_value
(
9
)
self
.
assertEqual
(
v_ro
.
get_value
(),
2
)
class
TestServer
(
unittest
.
TestCase
,
CommonTests
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment