1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
use std::{path::PathBuf, sync::Arc};
use tokio_util::sync::CancellationToken;
use tracing::warn;
use crate::{constants, node_manager::TypeTreeForUser};
use opcua_core::config::Config;
use opcua_crypto::SecurityPolicy;
use opcua_types::{BuildInfo, MessageSecurityMode, TypeLoader, TypeLoaderCollection};
use super::{
authenticator::AuthManager, node_manager::NodeManagerBuilder, Limits, Server, ServerConfig,
ServerEndpoint, ServerHandle, ServerUserToken, ANONYMOUS_USER_TOKEN_ID,
};
/// Server builder, used to configure the server programatically,
/// and for setting core components like node managers, authenticator,
/// and type collections.
pub struct ServerBuilder {
pub(crate) config: ServerConfig,
pub(crate) node_managers: Vec<Box<dyn NodeManagerBuilder>>,
pub(crate) authenticator: Option<Arc<dyn AuthManager>>,
pub(crate) type_tree_getter: Option<Arc<dyn TypeTreeForUser>>,
pub(crate) type_loaders: TypeLoaderCollection,
pub(crate) token: CancellationToken,
pub(crate) build_info: BuildInfo,
}
impl Default for ServerBuilder {
fn default() -> Self {
let builder = Self {
config: Default::default(),
node_managers: Default::default(),
authenticator: None,
token: CancellationToken::new(),
type_tree_getter: None,
build_info: BuildInfo::default(),
type_loaders: TypeLoaderCollection::new(),
};
#[cfg(feature = "generated-address-space")]
{
builder
.with_node_manager(
super::node_manager::memory::InMemoryNodeManagerBuilder::new(
super::node_manager::memory::CoreNodeManagerBuilder,
),
)
.with_node_manager(super::diagnostics::DiagnosticsNodeManagerBuilder)
}
#[cfg(not(feature = "generated-address-space"))]
builder
}
}
impl ServerBuilder {
/// Create a new server builder.
///
/// If the generated address space is enabled, this will add the core and
/// diagnostic node managers.
pub fn new() -> Self {
Self::default()
}
/// Create a server builder from a config object.
pub fn from_config(config: ServerConfig) -> Self {
Self {
config,
..Default::default()
}
}
/// Creates a simple endpoint that accepts anonymous connections.
pub fn new_anonymous(application_name: impl Into<String>) -> Self {
Self::new()
.application_name(application_name)
.add_endpoint(
"none",
ServerEndpoint::new_none("/", &[ANONYMOUS_USER_TOKEN_ID.to_string()]),
)
.discovery_urls(vec!["/".to_owned()])
}
/// Creates and yields a builder which is configured with the sample server configuration.
/// Use this for testing and similar reasons. Do not rely upon this in production code because it could change.
pub fn new_sample() -> Self {
warn!("Sample configuration is for testing purposes only. Use a proper configuration in your production environment");
let user_token_ids = vec![
ANONYMOUS_USER_TOKEN_ID,
"sample_password_user",
"sample_x509_user",
];
let endpoint_path = "/";
Self::new()
.application_name("OPC UA Sample Server")
.application_uri("urn:OPC UA Sample Server")
.product_uri("urn:OPC UA Sample Server Testkit")
.create_sample_keypair(true)
.certificate_path("own/cert.der")
.private_key_path("private/private.pem")
.pki_dir("./pki")
.discovery_server_url(constants::DEFAULT_DISCOVERY_SERVER_URL)
.add_user_token(
"sample_password_user",
ServerUserToken {
user: "sample1".to_string(),
pass: Some("sample1pwd".to_string()),
..Default::default()
},
)
.add_user_token(
"sample_x509_user",
ServerUserToken {
user: "sample_x509".to_string(),
x509: Some("./users/sample-x509.der".to_string()),
..Default::default()
},
)
.add_endpoint(
"none",
(
endpoint_path,
SecurityPolicy::None,
MessageSecurityMode::None,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"basic128rsa15_sign",
(
endpoint_path,
SecurityPolicy::Basic128Rsa15,
MessageSecurityMode::Sign,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"basic128rsa15_sign_encrypt",
(
endpoint_path,
SecurityPolicy::Basic128Rsa15,
MessageSecurityMode::SignAndEncrypt,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"basic256_sign",
(
endpoint_path,
SecurityPolicy::Basic256,
MessageSecurityMode::Sign,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"basic256_sign_encrypt",
(
endpoint_path,
SecurityPolicy::Basic256,
MessageSecurityMode::SignAndEncrypt,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"basic256sha256_sign",
(
endpoint_path,
SecurityPolicy::Basic256Sha256,
MessageSecurityMode::Sign,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"basic256sha256_sign_encrypt",
(
endpoint_path,
SecurityPolicy::Basic256Sha256,
MessageSecurityMode::SignAndEncrypt,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"endpoint_aes128sha256rsaoaep_sign",
(
endpoint_path,
SecurityPolicy::Aes128Sha256RsaOaep,
MessageSecurityMode::Sign,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"endpoint_aes128sha256rsaoaep_sign_encrypt",
(
endpoint_path,
SecurityPolicy::Aes128Sha256RsaOaep,
MessageSecurityMode::SignAndEncrypt,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"endpoint_aes256sha256rsapss_sign",
(
endpoint_path,
SecurityPolicy::Aes256Sha256RsaPss,
MessageSecurityMode::Sign,
&user_token_ids as &[&str],
),
)
.add_endpoint(
"endpoint_aes256sha256rsapss_sign_encrypt",
(
endpoint_path,
SecurityPolicy::Aes256Sha256RsaPss,
MessageSecurityMode::SignAndEncrypt,
&user_token_ids as &[&str],
),
)
}
/// Get the currently configured config.
pub fn config(&self) -> &ServerConfig {
&self.config
}
/// Load config from a local file.
/// Will panic if this fails, if you prefer to propagate errors use
///
/// `with_config(ServerConfig::load(&"my_config.conf".into())?)`
pub fn with_config_from(mut self, path: impl Into<PathBuf>) -> Self {
self.config = ServerConfig::load(&path.into()).expect("Failed to load config");
self
}
/// Set the entire config object, which may be loaded from somewhere else.
pub fn with_config(mut self, config: ServerConfig) -> Self {
self.config = config;
self
}
/// Get a mutable reference to the currently configured config.
pub fn config_mut(&mut self) -> &mut ServerConfig {
&mut self.config
}
/// Get a mutable reference to the limits object.
pub fn limits_mut(&mut self) -> &mut Limits {
&mut self.config.limits
}
/// Add a node manager builder to the list of node managers.
/// Once the server is created you can retrieve it from
/// `handle.node_managers()`. This allows node managers to contain
/// core server types without late initialization.
pub fn with_node_manager(mut self, node_manager: impl NodeManagerBuilder + 'static) -> Self {
self.node_managers.push(Box::new(node_manager));
self
}
/// Clear all node managers.
///
/// Warning: your server will not be compliant without presenting the core namespace.
/// If you remove the core node manager you must implement the core namespace yourself.
pub fn without_node_managers(mut self) -> Self {
self.node_managers.clear();
self
}
/// Set a custom authenticator.
pub fn with_authenticator(mut self, authenticator: Arc<dyn AuthManager>) -> Self {
self.authenticator = Some(authenticator);
self
}
/// Set a custom type tree getter. Most servers do not need to touch this.
///
/// The type tree getter gets a type tree for a specific user, letting you have different type trees
/// for different users, which is relevant for some servers.
///
/// This is currently used for constructing event filters, and when building external references.
/// You only need to set this if you intend to have types that are not in the global `DefaultTypeTree`.
///
/// Note that built in node managers do not use the type tree getter, if you want to have
/// per-user types you need to implement a node manager that can correctly filter
/// during browse, etc. This only lets you use the custom type tree for each individual user.
pub fn with_type_tree_getter(mut self, type_tree_getter: Arc<dyn TypeTreeForUser>) -> Self {
self.type_tree_getter = Some(type_tree_getter);
self
}
/// Set information about the application exposed to the user in the
/// `ServerStatus/BuildInfo` variable on the server.
pub fn build_info(mut self, build_info: BuildInfo) -> Self {
self.build_info = build_info;
self
}
/// Server application name.
pub fn application_name(mut self, application_name: impl Into<String>) -> Self {
self.config.application_name = application_name.into();
self
}
/// Server application URI.
pub fn application_uri(mut self, application_uri: impl Into<String>) -> Self {
self.config.application_uri = application_uri.into();
self
}
/// Server product URI.
pub fn product_uri(mut self, product_uri: impl Into<String>) -> Self {
self.config.product_uri = product_uri.into();
self
}
/// Autocreates public / private keypair if they do not exist.
pub fn create_sample_keypair(mut self, create_sample_keypair: bool) -> Self {
self.config.create_sample_keypair = create_sample_keypair;
self
}
/// Path to a custom certificate, to be used instead of the default .der certificate
pub fn certificate_path(mut self, certificate_path: impl Into<PathBuf>) -> Self {
self.config.certificate_path = Some(certificate_path.into());
self
}
/// Path to a custom private key, used instead of the default private key.
pub fn private_key_path(mut self, private_key_path: impl Into<PathBuf>) -> Self {
self.config.private_key_path = Some(private_key_path.into());
self
}
/// Auto trust client certificates. Typically should only be used for testing
/// or samples, as it is potentially unsafe.
pub fn trust_client_certs(mut self, trust_client_certs: bool) -> Self {
self.config.certificate_validation.trust_client_certs = trust_client_certs;
self
}
/// Validate the valid from/to fields of a certificate.
pub fn check_cert_time(mut self, check_cert_time: bool) -> Self {
self.config.certificate_validation.check_time = check_cert_time;
self
}
/// PKI folder, either absolute or relative to executable.
pub fn pki_dir(mut self, pki_dir: impl Into<PathBuf>) -> Self {
self.config.pki_dir = pki_dir.into();
self
}
/// URL to a discovery server. Adding this makes the server attempt to register
/// itself with this discovery server.
pub fn discovery_server_url(mut self, url: impl Into<String>) -> Self {
self.config.discovery_server_url = Some(url.into());
self
}
/// Timeout for new connections to send a `HELLO` message, in seconds.
/// After this timeout expires without a valid hello message, the connection
/// is closed.
pub fn hello_timeout(mut self, timeout: u32) -> Self {
self.config.tcp_config.hello_timeout = timeout;
self
}
/// Hostname to listen to incoming TCP connections on.
pub fn host(mut self, host: impl Into<String>) -> Self {
self.config.tcp_config.host = host.into();
self
}
/// Port number used to listen for incoming TCP connections.
pub fn port(mut self, port: u16) -> Self {
self.config.tcp_config.port = port;
self
}
/// General server limits.
pub fn limits(mut self, limits: Limits) -> Self {
self.config.limits = limits;
self
}
/// Supported locale IDs.
pub fn locale_ids(mut self, locale_ids: Vec<String>) -> Self {
self.config.locale_ids = locale_ids;
self
}
/// Add a user to the list of known user tokens. Used by the default
/// authenticator, you can use a custom one instead.
pub fn add_user_token(mut self, key: impl Into<String>, token: ServerUserToken) -> Self {
self.config.user_tokens.insert(key.into(), token);
self
}
/// List of discovery endpoint URLs which may or may not be the same as the service
/// endpoints.
pub fn discovery_urls(mut self, discovery_urls: Vec<String>) -> Self {
self.config.discovery_urls = discovery_urls;
self
}
/// Default endpoint ID.
pub fn default_endpoint(mut self, endpoint_id: impl Into<String>) -> Self {
self.config.default_endpoint = Some(endpoint_id.into());
self
}
/// Add an endpoint to the list of endpoints supported by the server.
pub fn add_endpoint(
mut self,
id: impl Into<String>,
endpoint: impl Into<ServerEndpoint>,
) -> Self {
self.config.endpoints.insert(id.into(), endpoint.into());
self
}
/// Interval in milliseconds between each time the subscriptions are polled.
pub fn subscription_poll_interval_ms(mut self, interval: u64) -> Self {
self.config.subscription_poll_interval_ms = interval;
self
}
/// Default publish request timeout.
pub fn publish_timeout_default_ms(mut self, timeout: u64) -> Self {
self.config.publish_timeout_default_ms = timeout;
self
}
/// Max message timeout for non-publish requests.
/// Will not be applied for requests that are handled synchronously.
/// Set to 0 for no timeout, meaning that a timeout will only be applied if
/// the client requests one.
/// If this is greater than zero and the client requests a timeout of 0,
/// this will be used.
pub fn max_timeout_ms(mut self, timeout: u32) -> Self {
self.config.max_timeout_ms = timeout;
self
}
/// Maximum lifetime of secure channel tokens. The client will request a number,
/// this just sets an upper limit on that value.
/// Note that there is no lower limit, if a client sets an expiry of 0,
/// we will just instantly time out.
pub fn max_secure_channel_token_lifetime_ms(mut self, lifetime: u32) -> Self {
self.config.max_secure_channel_token_lifetime_ms = lifetime;
self
}
/// Try to construct a server from this builder, may fail if the configuration
/// is invalid.
pub fn build(self) -> Result<(Server, ServerHandle), String> {
Server::new_from_builder(self)
}
/// Maximum length of arrays when encoding or decoding messages.
pub fn max_array_length(mut self, max_array_length: usize) -> Self {
self.config.limits.max_array_length = max_array_length;
self
}
/// Maximum length of strings in bytes when encoding or decoding messages.
pub fn max_string_length(mut self, max_string_length: usize) -> Self {
self.config.limits.max_string_length = max_string_length;
self
}
/// Maximum byte string length in bytes when encoding or decoding messages.
pub fn max_byte_string_length(mut self, max_byte_string_length: usize) -> Self {
self.config.limits.max_byte_string_length = max_byte_string_length;
self
}
/// Maximum allowed message size in bytes.
pub fn max_message_size(mut self, max_message_size: usize) -> Self {
self.config.limits.max_message_size = max_message_size;
self
}
/// Maximum allowed chunk count per message.
pub fn max_chunk_count(mut self, max_chunk_count: usize) -> Self {
self.config.limits.max_chunk_count = max_chunk_count;
self
}
/// Maximum send buffer size, can be negotiated lower with clients.
pub fn send_buffer_size(mut self, send_buffer_size: usize) -> Self {
self.config.limits.send_buffer_size = send_buffer_size;
self
}
/// Maximum receive buffer size, can be negotiated lower with clients.
pub fn receive_buffer_size(mut self, receive_buffer_size: usize) -> Self {
self.config.limits.receive_buffer_size = receive_buffer_size;
self
}
/// Maximum number of browse continuation points per session.
pub fn max_browse_continuation_points(mut self, max_browse_continuation_points: usize) -> Self {
self.config.limits.max_browse_continuation_points = max_browse_continuation_points;
self
}
/// Maximum number of history continuation points per session.
pub fn max_history_continuation_points(
mut self,
max_history_continuation_points: usize,
) -> Self {
self.config.limits.max_history_continuation_points = max_history_continuation_points;
self
}
/// Maximum number of query continuation points per session.
pub fn max_query_continuation_points(mut self, max_query_continuation_points: usize) -> Self {
self.config.limits.max_query_continuation_points = max_query_continuation_points;
self
}
/// Maximum number of active sessions.
pub fn max_sessions(mut self, max_sessions: usize) -> Self {
self.config.limits.max_sessions = max_sessions;
self
}
/// Maximum time in milliseconds a session can be inactive before it is timed out and removed.
/// The client can request a lower value than this.
pub fn max_session_timeout_ms(mut self, max_session_timeout_ms: u64) -> Self {
self.config.max_session_timeout_ms = max_session_timeout_ms;
self
}
/// Set the cancellation token used by the server. You only need to
/// set the token if you need to use a token from somewhere else to cancel,
/// otherwise you can get the token after building the server with
/// `handle.token()`.
pub fn token(mut self, token: CancellationToken) -> Self {
self.token = token;
self
}
/// Register a type loader. Any deserialization will
/// use this type loader to handle types coming from the user.
///
/// If the user sends a type not in any registered type loader, decoding will fail.
pub fn with_type_loader(mut self, loader: Arc<dyn TypeLoader>) -> Self {
self.type_loaders.add(loader);
self
}
/// Set whether to enable diagnostics on the server or not.
/// Only users with the right permissions can read the diagnostics
pub fn diagnostics_enabled(mut self, enabled: bool) -> Self {
self.config.diagnostics = enabled;
self
}
}