opcua_server/
builder.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2022 Adam Lock
4
5use std::path::PathBuf;
6
7use opcua_core::config::Config;
8
9use crate::{
10    config::{ServerConfig, ServerEndpoint, ServerUserToken, ANONYMOUS_USER_TOKEN_ID},
11    constants,
12    server::Server,
13};
14
15const DEFAULT_ENDPOINT_PATH: &str = "/";
16
17/// The `ServerBuilder` is a builder for producing a [`Server`]. It is an alternative to constructing
18/// a [`ServerConfig`] from file or from scratch.
19///
20/// [`Server`]: ../client/struct.Server.html
21/// [`ServerConfig`]: ../config/struct.ServerConfig.html
22pub struct ServerBuilder {
23    config: ServerConfig,
24}
25
26impl ServerBuilder {
27    pub fn new() -> Self {
28        Self {
29            config: ServerConfig::default(),
30        }
31    }
32
33    /// Reads the config in as a starting point
34    pub fn from_config(config: ServerConfig) -> Self {
35        Self { config }
36    }
37
38    /// Creates a simple endpoint that accepts anonymous connections
39    pub fn new_anonymous<T>(application_name: T) -> Self
40    where
41        T: Into<String>,
42    {
43        let user_token_ids = vec![ANONYMOUS_USER_TOKEN_ID.to_string()];
44        Self::new()
45            .application_name(application_name)
46            .endpoint(
47                "none",
48                ServerEndpoint::new_none(DEFAULT_ENDPOINT_PATH, &user_token_ids),
49            )
50            .discovery_urls(vec![DEFAULT_ENDPOINT_PATH.into()])
51    }
52
53    /// Creates and yields a builder which is configured with the sample server configuration.
54    /// Use this for testing and similar reasons. Do not rely upon this in production code because it could change.
55    pub fn new_sample() -> Self {
56        warn!("Sample configuration is for testing purposes only. Use a proper configuration in your production environment");
57
58        let path = DEFAULT_ENDPOINT_PATH;
59
60        let user_token_ids = [
61            "sample_password_user",
62            "sample_x509_user",
63            ANONYMOUS_USER_TOKEN_ID,
64        ]
65        .iter()
66        .map(|u| u.to_string())
67        .collect::<Vec<String>>();
68
69        Self::new()
70            .application_name("OPC UA Sample Server")
71            .application_uri("urn:OPC UA Sample Server")
72            .product_uri("urn:OPC UA Sample Server Testkit")
73            .create_sample_keypair(true)
74            .certificate_path("own/cert.der")
75            .private_key_path("private/private.pem")
76            .pki_dir("./pki")
77            .discovery_server_url(Some(constants::DEFAULT_DISCOVERY_SERVER_URL.to_string()))
78            .user_token(
79                "sample_password_user",
80                ServerUserToken {
81                    user: "sample1".to_string(),
82                    pass: Some("sample1pwd".to_string()),
83                    x509: None,
84                    thumbprint: None,
85                },
86            )
87            .user_token(
88                "sample_x509_user",
89                ServerUserToken {
90                    user: "sample_x509".to_string(),
91                    pass: None,
92                    x509: Some("./users/sample-x509.der".to_string()),
93                    thumbprint: None,
94                },
95            )
96            .user_token(
97                "unused_user",
98                ServerUserToken {
99                    user: "unused".to_string(),
100                    pass: Some("unused1".to_string()),
101                    x509: None,
102                    thumbprint: None,
103                },
104            )
105            .endpoints(vec![
106                ("none", ServerEndpoint::new_none(path, &user_token_ids)),
107                (
108                    "basic128rsa15_sign",
109                    ServerEndpoint::new_basic128rsa15_sign(path, &user_token_ids),
110                ),
111                (
112                    "basic128rsa15_sign_encrypt",
113                    ServerEndpoint::new_basic128rsa15_sign_encrypt(path, &user_token_ids),
114                ),
115                (
116                    "aes128-sha256-rsaoaep_sign",
117                    ServerEndpoint::new_aes128_sha256_rsaoaep_sign(path, &user_token_ids),
118                ),
119                (
120                    "aes128-sha256-rsaoaep_sign_encrypt",
121                    ServerEndpoint::new_aes128_sha256_rsaoaep_sign_encrypt(path, &user_token_ids),
122                ),
123                (
124                    "aes256-sha256-rsapss_sign",
125                    ServerEndpoint::new_aes256_sha256_rsapss_sign(path, &user_token_ids),
126                ),
127                (
128                    "aes256-sha256-rsapss_sign_encrypt",
129                    ServerEndpoint::new_aes256_sha256_rsapss_sign_encrypt(path, &user_token_ids),
130                ),
131                (
132                    "basic256_sign",
133                    ServerEndpoint::new_basic256_sign(path, &user_token_ids),
134                ),
135                (
136                    "basic256_sign_encrypt",
137                    ServerEndpoint::new_basic256_sign_encrypt(path, &user_token_ids),
138                ),
139                (
140                    "basic256sha256_sign",
141                    ServerEndpoint::new_basic256sha256_sign(path, &user_token_ids),
142                ),
143                (
144                    "basic256sha256_sign_encrypt",
145                    ServerEndpoint::new_basic256sha256_sign_encrypt(path, &user_token_ids),
146                ),
147                ("no_access", ServerEndpoint::new_none("/noaccess", &[])),
148            ])
149            .discovery_urls(vec![DEFAULT_ENDPOINT_PATH.into()])
150    }
151
152    /// Yields a [`Client`] from the values set by the builder. If the builder is not in a valid state
153    /// it will return `None`.
154    ///
155    /// [`Server`]: ../server/struct.Server.html
156    pub fn server(self) -> Option<Server> {
157        if self.is_valid() {
158            Some(Server::new(self.config()))
159        } else {
160            None
161        }
162    }
163
164    /// Yields a [`ClientConfig`] from the values set by the builder.
165    ///
166    /// [`ServerConfig`]: ../config/struct.ServerConfig.html
167    pub fn config(self) -> ServerConfig {
168        self.config
169    }
170
171    /// Test if the builder can yield a server with the configuration supplied.
172    pub fn is_valid(&self) -> bool {
173        self.config.is_valid()
174    }
175
176    /// Sets the application name.
177    pub fn application_name<T>(mut self, application_name: T) -> Self
178    where
179        T: Into<String>,
180    {
181        self.config.application_name = application_name.into();
182        self
183    }
184
185    /// Sets the application uri
186    pub fn application_uri<T>(mut self, application_uri: T) -> Self
187    where
188        T: Into<String>,
189    {
190        self.config.application_uri = application_uri.into();
191        self
192    }
193
194    /// Sets the product uri.
195    pub fn product_uri<T>(mut self, product_uri: T) -> Self
196    where
197        T: Into<String>,
198    {
199        self.config.product_uri = product_uri.into();
200        self
201    }
202
203    /// Sets whether the client should generate its own key pair if there is none found in the pki
204    /// directory.
205    pub fn create_sample_keypair(mut self, create_sample_keypair: bool) -> Self {
206        self.config.create_sample_keypair = create_sample_keypair;
207        self
208    }
209
210    /// Sets a custom server certificate path. The path is required to be provided as a partial
211    /// path relative to the PKI directory. If set, this path will be used to read the server
212    /// certificate from disk. The certificate can be in either the .der or .pem format.
213    pub fn certificate_path<T>(mut self, certificate_path: T) -> Self
214    where
215        T: Into<PathBuf>,
216    {
217        self.config.certificate_path = Some(certificate_path.into());
218        self
219    }
220
221    /// Sets a custom private key path. The path is required to be provided as a partial path
222    /// relative to the PKI directory. If set, this path will be used to read the private key
223    /// from disk.
224    pub fn private_key_path<T>(mut self, private_key_path: T) -> Self
225    where
226        T: Into<PathBuf>,
227    {
228        self.config.private_key_path = Some(private_key_path.into());
229        self
230    }
231
232    /// Sets the pki directory where client's own key pair is stored and where `/trusted` and
233    /// `/rejected` server certificates are stored.
234    pub fn pki_dir<T>(mut self, pki_dir: T) -> Self
235    where
236        T: Into<PathBuf>,
237    {
238        self.config.pki_dir = pki_dir.into();
239        self
240    }
241
242    /// Adds an endpoint to the list of endpoints the client knows of.
243    pub fn endpoint<T>(mut self, endpoint_id: T, endpoint: ServerEndpoint) -> Self
244    where
245        T: Into<String>,
246    {
247        self.config.endpoints.insert(endpoint_id.into(), endpoint);
248        self
249    }
250
251    /// Adds multiple endpoints to the list of endpoints the client knows of.
252    pub fn endpoints<T>(mut self, endpoints: Vec<(T, ServerEndpoint)>) -> Self
253    where
254        T: Into<String>,
255    {
256        for e in endpoints {
257            self.config.endpoints.insert(e.0.into(), e.1);
258        }
259        self
260    }
261
262    /// Adds a user token to the server.
263    pub fn user_token<T>(mut self, user_token_id: T, user_token: ServerUserToken) -> Self
264    where
265        T: Into<String>,
266    {
267        self.config
268            .user_tokens
269            .insert(user_token_id.into(), user_token);
270        self
271    }
272
273    /// Sets the discovery server url that this server shall attempt to register itself with.
274    pub fn discovery_server_url(mut self, discovery_server_url: Option<String>) -> Self {
275        self.config.discovery_server_url = discovery_server_url;
276        self
277    }
278
279    /// Sets the hostname and port to listen on
280    pub fn host_and_port<T>(mut self, host: T, port: u16) -> Self
281    where
282        T: Into<String>,
283    {
284        self.config.tcp_config.host = host.into();
285        self.config.tcp_config.port = port;
286        self
287    }
288
289    /// Discovery endpoint urls - the urls of this server used by clients to get endpoints.
290    /// If the url is relative, e.g. "/" then the code will make a url for you using the port/host
291    /// settings as they are at the time this function is executed.
292    pub fn discovery_urls(mut self, discovery_urls: Vec<String>) -> Self {
293        self.config.discovery_urls = discovery_urls
294            .iter()
295            .map(|discovery_url| {
296                if discovery_url.starts_with('/') {
297                    // Turn into an opc url
298                    format!(
299                        "opc.tcp://{}:{}/",
300                        self.config.tcp_config.host, self.config.tcp_config.port
301                    )
302                } else {
303                    discovery_url.clone()
304                }
305            })
306            .collect();
307        self
308    }
309
310    /// Set the maximum number of subscriptions in a session
311    pub fn max_subscriptions(mut self, max_subscriptions: u32) -> Self {
312        self.config.limits.max_subscriptions = max_subscriptions;
313        self
314    }
315
316    /// Set the maximum number of monitored items per subscription
317    pub fn max_monitored_items_per_sub(mut self, max_monitored_items_per_sub: u32) -> Self {
318        self.config.limits.max_monitored_items_per_sub = max_monitored_items_per_sub;
319        self
320    }
321
322    /// Set the max array length in elements
323    pub fn max_array_length(mut self, max_array_length: u32) -> Self {
324        self.config.limits.max_array_length = max_array_length;
325        self
326    }
327
328    /// Set the max string length in characters, i.e. if you set max to 1000 characters, then with
329    /// UTF-8 encoding potentially that's 4000 bytes.
330    pub fn max_string_length(mut self, max_string_length: u32) -> Self {
331        self.config.limits.max_string_length = max_string_length;
332        self
333    }
334
335    /// Set the max bytestring length in bytes
336    pub fn max_byte_string_length(mut self, max_byte_string_length: u32) -> Self {
337        self.config.limits.max_byte_string_length = max_byte_string_length;
338        self
339    }
340
341    /// Sets the server to automatically trust client certs. This subverts the
342    /// authentication during handshake, so only do this if you understand the risks.
343    pub fn trust_client_certs(mut self) -> Self {
344        self.config.certificate_validation.trust_client_certs = true;
345        self
346    }
347
348    /// Set that clients can modify the address space, i.e. they can add or remove nodes through
349    /// the node management service. By default, they cannot.
350    pub fn clients_can_modify_address_space(mut self) -> Self {
351        self.config.limits.clients_can_modify_address_space = true;
352        self
353    }
354
355    /// Configures the server to use a single-threaded executor. The default executor uses a
356    /// thread pool with a worker thread for each CPU core available on the system.
357    pub fn single_threaded_executor(mut self) -> Self {
358        self.config.performance.single_threaded_executor = true;
359        self
360    }
361
362    /// Configures the server to use a multi-threaded executor.
363    pub fn multi_threaded_executor(mut self) -> Self {
364        self.config.performance.single_threaded_executor = false;
365        self
366    }
367}