Skip to content

Commit 53048e3

Browse files
brubbeloroulet
authored andcommitted
Pull user authentication out of InternalServer class
Also: private_key from InternalServer -> Server
1 parent 9357c99 commit 53048e3

File tree

5 files changed

+115
-98
lines changed

5 files changed

+115
-98
lines changed

opcua/server/address_space.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pickle
1010

1111
from opcua import ua
12-
from opcua.server.users import User
12+
from opcua.server.user_manager import UserManager
1313

1414

1515
class AttributeValue(object):
@@ -50,11 +50,11 @@ def read(self, params):
5050
res.append(self._aspace.get_attribute_value(readvalue.NodeId, readvalue.AttributeId))
5151
return res
5252

53-
def write(self, params, user=User.Admin):
53+
def write(self, params, user=UserManager.User.Admin):
5454
self.logger.debug("write %s as user %s", params, user)
5555
res = []
5656
for writevalue in params.NodesToWrite:
57-
if user != User.Admin:
57+
if user != UserManager.User.Admin:
5858
if writevalue.AttributeId != ua.AttributeIds.Value:
5959
res.append(ua.StatusCode(ua.StatusCodes.BadUserAccessDenied))
6060
continue
@@ -182,13 +182,13 @@ def __init__(self, aspace):
182182
self.logger = logging.getLogger(__name__)
183183
self._aspace = aspace
184184

185-
def add_nodes(self, addnodeitems, user=User.Admin):
185+
def add_nodes(self, addnodeitems, user=UserManager.User.Admin):
186186
results = []
187187
for item in addnodeitems:
188188
results.append(self._add_node(item, user))
189189
return results
190190

191-
def try_add_nodes(self, addnodeitems, user=User.Admin, check=True):
191+
def try_add_nodes(self, addnodeitems, user=UserManager.User.Admin, check=True):
192192
for item in addnodeitems:
193193
ret = self._add_node(item, user, check=check)
194194
if not ret.StatusCode.is_good():
@@ -198,7 +198,7 @@ def _add_node(self, item, user, check=True):
198198
self.logger.debug("Adding node %s %s", item.RequestedNewNodeId, item.BrowseName)
199199
result = ua.AddNodesResult()
200200

201-
if not user == User.Admin:
201+
if not user == UserManager.User.Admin:
202202
result.StatusCode = ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)
203203
return result
204204

@@ -302,14 +302,14 @@ def _add_type_definition(self, nodedata, item):
302302
addref.TargetNodeClass = ua.NodeClass.DataType
303303
self._add_reference_no_check(nodedata, addref)
304304

305-
def delete_nodes(self, deletenodeitems, user=User.Admin):
305+
def delete_nodes(self, deletenodeitems, user=UserManager.User.Admin):
306306
results = []
307307
for item in deletenodeitems.NodesToDelete:
308308
results.append(self._delete_node(item, user))
309309
return results
310310

311311
def _delete_node(self, item, user):
312-
if user != User.Admin:
312+
if user != UserManager.User.Admin:
313313
return ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)
314314

315315
if item.NodeId not in self._aspace:
@@ -337,13 +337,13 @@ def _delete_node_callbacks(self, nodedata):
337337
except Exception as ex:
338338
self.logger.exception("Error calling delete node callback callback %s, %s, %s", nodedata, ua.AttributeIds.Value, ex)
339339

340-
def add_references(self, refs, user=User.Admin):
340+
def add_references(self, refs, user=UserManager.User.Admin):
341341
result = []
342342
for ref in refs:
343343
result.append(self._add_reference(ref, user))
344344
return result
345345

346-
def try_add_references(self, refs, user=User.Admin):
346+
def try_add_references(self, refs, user=UserManager.User.Admin):
347347
for ref in refs:
348348
if not self._add_reference(ref, user).is_good():
349349
yield ref
@@ -354,7 +354,7 @@ def _add_reference(self, addref, user):
354354
return ua.StatusCode(ua.StatusCodes.BadSourceNodeIdInvalid)
355355
if addref.TargetNodeId not in self._aspace:
356356
return ua.StatusCode(ua.StatusCodes.BadTargetNodeIdInvalid)
357-
if user != User.Admin:
357+
if user != UserManager.User.Admin:
358358
return ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)
359359
return self._add_reference_no_check(sourcedata, addref)
360360

@@ -375,7 +375,7 @@ def _add_reference_no_check(self, sourcedata, addref):
375375
rdesc.DisplayName = dname
376376
return self._add_unique_reference(sourcedata, rdesc)
377377

378-
def delete_references(self, refs, user=User.Admin):
378+
def delete_references(self, refs, user=UserManager.User.Admin):
379379
result = []
380380
for ref in refs:
381381
result.append(self._delete_reference(ref, user))
@@ -400,7 +400,7 @@ def _delete_reference(self, item, user):
400400
return ua.StatusCode(ua.StatusCodes.BadTargetNodeIdInvalid)
401401
if item.ReferenceTypeId not in self._aspace:
402402
return ua.StatusCode(ua.StatusCodes.BadReferenceTypeIdInvalid)
403-
if user != User.Admin:
403+
if user != UserManager.User.Admin:
404404
return ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)
405405

406406
if item.DeleteBidirectional:

opcua/server/internal_server.py

Lines changed: 16 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"""
55
from datetime import datetime, timedelta
66
from copy import copy
7-
from struct import unpack_from, unpack
87
import os
98
import logging
109
from threading import Lock
@@ -28,16 +27,9 @@
2827
from opcua.server.address_space import MethodService
2928
from opcua.server.subscription_service import SubscriptionService
3029
from opcua.server.standard_address_space import standard_address_space
31-
from opcua.server.users import User
30+
from opcua.server.user_manager import UserManager
3231
#from opcua.common import xmlimporter
3332

34-
use_crypto = True
35-
try:
36-
from opcua.crypto import uacrypto
37-
except ImportError:
38-
logging.getLogger(__name__).warning("cryptography is not installed, use of crypto disabled")
39-
use_crypto = False
40-
4133

4234
class SessionState(Enum):
4335
Created = 0
@@ -53,19 +45,17 @@ def __init__(self, serv, cap=None):
5345

5446
class InternalServer(object):
5547

56-
def __init__(self, shelffile=None):
48+
def __init__(self, shelffile=None, parent=None):
5749
self.logger = logging.getLogger(__name__)
5850

51+
self._parent = parent
5952
self.server_callback_dispatcher = CallbackDispatcher()
6053

6154
self.endpoints = []
6255
self._channel_id_counter = 5
63-
self.allow_remote_admin = True
6456
self.disabled_clock = False # for debugging we may want to disable clock that writes too much in log
6557
self._known_servers = {} # used if we are a discovery server
6658

67-
self.private_key = None
68-
6959
self.aspace = AddressSpace()
7060
self.attribute_service = AttributeService(self.aspace)
7161
self.view_service = ViewService(self.aspace)
@@ -80,15 +70,18 @@ def __init__(self, shelffile=None):
8070

8171
self.history_manager = HistoryManager(self)
8272

83-
self.user_manager = default_user_manager # defined at the end of this file
84-
8573
# create a session to use on server side
86-
self.isession = InternalSession(self, self.aspace, self.subscription_service, "Internal", user=User.Admin)
74+
self.isession = InternalSession(self, self.aspace, \
75+
self.subscription_service, "Internal", user=UserManager.User.Admin)
8776

8877
self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
8978
self._address_space_fixes()
9079
self.setup_nodes()
9180

81+
@property
82+
def userManager(self):
83+
return self._parent.userManager
84+
9285
def setup_nodes(self):
9386
"""
9487
Set up some nodes as defined by spec
@@ -219,7 +212,7 @@ def register_server(self, server, conf=None):
219212
def register_server2(self, params):
220213
return self.register_server(params.Server, params.DiscoveryConfiguration)
221214

222-
def create_session(self, name, user=User.Anonymous, external=False):
215+
def create_session(self, name, user=UserManager.User.Anonymous, external=False):
223216
return InternalSession(self, self.aspace, self.subscription_service, name, user=user, external=external)
224217

225218
def enable_history_data_change(self, node, period=timedelta(days=7), count=0):
@@ -280,48 +273,12 @@ def set_attribute_value(self, nodeid, datavalue, attr=ua.AttributeIds.Value):
280273
"""
281274
self.aspace.set_attribute_value(nodeid, ua.AttributeIds.Value, datavalue)
282275

283-
def set_user_manager(self, user_manager):
284-
"""
285-
set up a function which that will check for authorize users. Input function takes username
286-
and password as paramters and returns True of user is allowed access, False otherwise.
287-
"""
288-
self.user_manager = user_manager
289-
290-
def check_user_token(self, isession, token):
291-
"""
292-
unpack the username and password for the benefit of the user defined user manager
293-
"""
294-
userName = token.UserName
295-
passwd = token.Password
296-
297-
# decrypt password is we can
298-
if str(token.EncryptionAlgorithm) != "None":
299-
if use_crypto == False:
300-
return False;
301-
try:
302-
if token.EncryptionAlgorithm == "http://www.w3.org/2001/04/xmlenc#rsa-1_5":
303-
raw_pw = uacrypto.decrypt_rsa15(self.private_key, passwd)
304-
elif token.EncryptionAlgorithm == "http://www.w3.org/2001/04/xmlenc#rsa-oaep":
305-
raw_pw = uacrypto.decrypt_rsa_oaep(self.private_key, passwd)
306-
else:
307-
self.logger.warning("Unknown password encoding '{0}'".format(token.EncryptionAlgorithm))
308-
return False
309-
length = unpack_from('<I', raw_pw)[0] - len(isession.nonce)
310-
passwd = raw_pw[4:4 + length]
311-
passwd = passwd.decode('utf-8')
312-
except Exception as exp:
313-
self.logger.warning("Unable to decrypt password")
314-
return False
315-
316-
# call user_manager
317-
return self.user_manager(self, isession, userName, passwd)
318-
319276

320277
class InternalSession(object):
321278
_counter = 10
322279
_auth_counter = 1000
323280

324-
def __init__(self, internal_server, aspace, submgr, name, user=User.Anonymous, external=False):
281+
def __init__(self, internal_server, aspace, submgr, name, user=UserManager.User.Anonymous, external=False):
325282
self.logger = logging.getLogger(__name__)
326283
self.iserver = internal_server
327284
self.external = external # define if session is external, we need to copy some objects if it is internal
@@ -339,6 +296,10 @@ def __init__(self, internal_server, aspace, submgr, name, user=User.Anonymous, e
339296
self.logger.info("Created internal session %s", self.name)
340297
self._lock = Lock()
341298

299+
@property
300+
def userManager(self):
301+
return self.iserver.userManager
302+
342303
def __str__(self):
343304
return "InternalSession(name:{0}, user:{1}, id:{2}, auth_token:{3})".format(
344305
self.name, self.user, self.session_id, self.authentication_token)
@@ -377,7 +338,7 @@ def activate_session(self, params):
377338
self.state = SessionState.Activated
378339
id_token = params.UserIdentityToken
379340
if isinstance(id_token, ua.UserNameIdentityToken):
380-
if self.iserver.check_user_token(self, id_token) == False:
341+
if self.userManager.check_user_token(self, id_token) == False:
381342
raise utils.ServiceError(ua.StatusCodes.BadUserAccessDenied)
382343
self.logger.info("Activated internal session %s for user %s", self.name, self.user)
383344
return result
@@ -457,12 +418,3 @@ def publish(self, acks=None):
457418
if acks is None:
458419
acks = []
459420
return self.subscription_service.publish(acks)
460-
461-
462-
def default_user_manager(iserver, isession, userName, password):
463-
"""
464-
Default user_manager, does nothing much but check for admin
465-
"""
466-
if iserver.allow_remote_admin and userName in ("admin", "Admin"):
467-
isession.user = User.Admin
468-
return True

opcua/server/server.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from opcua.server.binary_server_asyncio import BinaryServer
1616
from opcua.server.internal_server import InternalServer
1717
from opcua.server.event_generator import EventGenerator
18+
from opcua.server.user_manager import UserManager
1819
from opcua.common.node import Node
1920
from opcua.common.subscription import Subscription
2021
from opcua.common.manage_nodes import delete_nodes
@@ -86,7 +87,7 @@ def __init__(self, shelffile=None, iserver=None):
8687
if iserver is not None:
8788
self.iserver = iserver
8889
else:
89-
self.iserver = InternalServer(shelffile)
90+
self.iserver = InternalServer(shelffile = shelffile, parent = self)
9091
self.bserver = None
9192
self._discovery_clients = {}
9293
self._discovery_period = 60
@@ -113,6 +114,8 @@ def __init__(self, shelffile=None, iserver=None):
113114

114115
# enable all endpoints by default
115116
self.certificate = None
117+
self.private_key = None
118+
self.userManager = UserManager(parent = self)
116119
self._security_policy = [
117120
ua.SecurityPolicyType.NoSecurity,
118121
ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
@@ -134,7 +137,7 @@ def load_certificate(self, path):
134137
self.certificate = uacrypto.load_certificate(path)
135138

136139
def load_private_key(self, path):
137-
self.iserver.private_key = uacrypto.load_private_key(path)
140+
self.private_key = uacrypto.load_private_key(path)
138141

139142
def disable_clock(self, val=True):
140143
"""
@@ -204,7 +207,7 @@ def allow_remote_admin(self, allow):
204207
"""
205208
Enable or disable the builtin Admin user from network clients
206209
"""
207-
self.iserver.allow_remote_admin = allow
210+
self.userManager.allow_remote_admin = allow
208211

209212
def set_endpoint(self, url):
210213
self.endpoint = urlparse(url)
@@ -256,7 +259,7 @@ def _setup_server_nodes(self):
256259
self._policies = [ua.SecurityPolicyFactory()]
257260

258261
if self._security_policy != [ua.SecurityPolicyType.NoSecurity]:
259-
if not (self.certificate and self.iserver.private_key):
262+
if not (self.certificate and self.private_key):
260263
self.logger.warning("Endpoints other than open requested but private key and certificate are not set.")
261264
return
262265

@@ -269,15 +272,15 @@ def _setup_server_nodes(self):
269272
self._policies.append(ua.SecurityPolicyFactory(security_policies.SecurityPolicyBasic256Sha256,
270273
ua.MessageSecurityMode.SignAndEncrypt,
271274
self.certificate,
272-
self.iserver.private_key)
275+
self.private_key)
273276
)
274277
if ua.SecurityPolicyType.Basic256Sha256_Sign in self._security_policy:
275278
self._set_endpoints(security_policies.SecurityPolicyBasic256Sha256,
276279
ua.MessageSecurityMode.Sign)
277280
self._policies.append(ua.SecurityPolicyFactory(security_policies.SecurityPolicyBasic256Sha256,
278281
ua.MessageSecurityMode.Sign,
279282
self.certificate,
280-
self.iserver.private_key)
283+
self.private_key)
281284
)
282285

283286
def _set_endpoints(self, policy=ua.SecurityPolicy, mode=ua.MessageSecurityMode.None_):

0 commit comments

Comments
 (0)