Skip to main content

opcua_server/
builder.rs

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