1use std::collections::{BTreeMap, BTreeSet};
7use std::path::{Path, PathBuf};
8use std::str::FromStr;
9
10use opcua_core::{comms::url::url_matches_except_host, config::Config};
11use opcua_crypto::{CertificateStore, SecurityPolicy, Thumbprint};
12use opcua_types::{
13 constants as opcua_types_constants, service_types::ApplicationType, DecodingOptions,
14 MessageSecurityMode, UAString,
15};
16
17use crate::constants;
18
19pub const ANONYMOUS_USER_TOKEN_ID: &str = "ANONYMOUS";
20
21#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
22pub struct TcpConfig {
23 pub hello_timeout: u32,
25 pub host: String,
27 pub port: u16,
29}
30
31#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
32pub struct ServerUserToken {
33 pub user: String,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub pass: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub x509: Option<String>,
41 #[serde(skip)]
42 pub thumbprint: Option<Thumbprint>,
43}
44
45impl ServerUserToken {
46 pub fn user_pass<T>(user: T, pass: T) -> Self
48 where
49 T: Into<String>,
50 {
51 ServerUserToken {
52 user: user.into(),
53 pass: Some(pass.into()),
54 x509: None,
55 thumbprint: None,
56 }
57 }
58
59 pub fn x509<T>(user: T, cert_path: &Path) -> Self
61 where
62 T: Into<String>,
63 {
64 ServerUserToken {
65 user: user.into(),
66 pass: None,
67 x509: Some(cert_path.to_string_lossy().to_string()),
68 thumbprint: None,
69 }
70 }
71
72 pub fn read_thumbprint(&mut self) {
74 if self.is_x509() && self.thumbprint.is_none() {
75 if let Some(ref x509_path) = self.x509 {
78 let path = PathBuf::from(x509_path);
79 if let Ok(x509) = CertificateStore::read_cert(&path) {
80 self.thumbprint = Some(x509.thumbprint());
81 }
82 }
83 }
84 }
85
86 pub fn is_valid(&self, id: &str) -> bool {
89 let mut valid = true;
90 if id == ANONYMOUS_USER_TOKEN_ID {
91 error!(
92 "User token {} is invalid because id is a reserved value, use another value.",
93 id
94 );
95 valid = false;
96 }
97 if self.user.is_empty() {
98 error!("User token {} has an empty user name.", id);
99 valid = false;
100 }
101 if self.pass.is_some() && self.x509.is_some() {
102 error!(
103 "User token {} holds a password and certificate info - it cannot be both.",
104 id
105 );
106 valid = false;
107 } else if self.pass.is_none() && self.x509.is_none() {
108 error!(
109 "User token {} fails to provide a password or certificate info.",
110 id
111 );
112 valid = false;
113 }
114 valid
115 }
116
117 pub fn is_user_pass(&self) -> bool {
118 self.x509.is_none()
119 }
120
121 pub fn is_x509(&self) -> bool {
122 self.x509.is_some()
123 }
124}
125
126#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
127pub struct Limits {
128 pub clients_can_modify_address_space: bool,
132 pub max_subscriptions: u32,
134 pub max_monitored_items_per_sub: u32,
136 pub max_monitored_item_queue_size: u32,
138 pub max_array_length: u32,
140 pub max_string_length: u32,
142 pub max_byte_string_length: u32,
144 pub min_sampling_interval: f64,
146 pub min_publishing_interval: f64,
148}
149
150impl Default for Limits {
151 fn default() -> Self {
152 Self {
153 max_array_length: opcua_types_constants::MAX_ARRAY_LENGTH as u32,
154 max_string_length: opcua_types_constants::MAX_STRING_LENGTH as u32,
155 max_byte_string_length: opcua_types_constants::MAX_BYTE_STRING_LENGTH as u32,
156 max_subscriptions: constants::DEFAULT_MAX_SUBSCRIPTIONS,
157 max_monitored_items_per_sub: constants::DEFAULT_MAX_MONITORED_ITEMS_PER_SUB,
158 max_monitored_item_queue_size: constants::MAX_DATA_CHANGE_QUEUE_SIZE as u32,
159 clients_can_modify_address_space: false,
160 min_sampling_interval: constants::MIN_SAMPLING_INTERVAL,
161 min_publishing_interval: constants::MIN_PUBLISHING_INTERVAL,
162 }
163 }
164}
165
166#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
167pub struct CertificateValidation {
168 pub trust_client_certs: bool,
171 pub check_time: bool,
173}
174
175#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
176pub struct ServerEndpoint {
177 pub path: String,
179 pub security_policy: String,
181 pub security_mode: String,
183 pub security_level: u8,
185 pub password_security_policy: Option<String>,
187 pub user_token_ids: BTreeSet<String>,
189}
190
191impl<'a> From<(&'a str, SecurityPolicy, MessageSecurityMode, &'a [&'a str])> for ServerEndpoint {
193 fn from(v: (&'a str, SecurityPolicy, MessageSecurityMode, &'a [&'a str])) -> ServerEndpoint {
194 ServerEndpoint {
195 path: v.0.into(),
196 security_policy: v.1.to_string(),
197 security_mode: v.2.to_string(),
198 security_level: Self::security_level(v.1, v.2),
199 password_security_policy: None,
200 user_token_ids: v.3.iter().map(|id| id.to_string()).collect(),
201 }
202 }
203}
204
205impl ServerEndpoint {
206 pub fn new<T>(
207 path: T,
208 security_policy: SecurityPolicy,
209 security_mode: MessageSecurityMode,
210 user_token_ids: &[String],
211 ) -> Self
212 where
213 T: Into<String>,
214 {
215 ServerEndpoint {
216 path: path.into(),
217 security_policy: security_policy.to_string(),
218 security_mode: security_mode.to_string(),
219 security_level: Self::security_level(security_policy, security_mode),
220 password_security_policy: None,
221 user_token_ids: user_token_ids.iter().cloned().collect(),
222 }
223 }
224
225 fn security_level(security_policy: SecurityPolicy, security_mode: MessageSecurityMode) -> u8 {
227 let security_level = match security_policy {
228 SecurityPolicy::Basic128Rsa15 => 1,
229 SecurityPolicy::Aes128Sha256RsaOaep => 2,
230 SecurityPolicy::Basic256 => 3,
231 SecurityPolicy::Basic256Sha256 => 4,
232 SecurityPolicy::Aes256Sha256RsaPss => 5,
233 _ => 0,
234 };
235 if security_mode == MessageSecurityMode::SignAndEncrypt {
236 security_level + 10
237 } else {
238 security_level
239 }
240 }
241
242 pub fn new_none<T>(path: T, user_token_ids: &[String]) -> Self
243 where
244 T: Into<String>,
245 {
246 Self::new(
247 path,
248 SecurityPolicy::None,
249 MessageSecurityMode::None,
250 user_token_ids,
251 )
252 }
253
254 pub fn new_basic128rsa15_sign<T>(path: T, user_token_ids: &[String]) -> Self
255 where
256 T: Into<String>,
257 {
258 Self::new(
259 path,
260 SecurityPolicy::Basic128Rsa15,
261 MessageSecurityMode::Sign,
262 user_token_ids,
263 )
264 }
265
266 pub fn new_basic128rsa15_sign_encrypt<T>(path: T, user_token_ids: &[String]) -> Self
267 where
268 T: Into<String>,
269 {
270 Self::new(
271 path,
272 SecurityPolicy::Basic128Rsa15,
273 MessageSecurityMode::SignAndEncrypt,
274 user_token_ids,
275 )
276 }
277
278 pub fn new_basic256_sign<T>(path: T, user_token_ids: &[String]) -> Self
279 where
280 T: Into<String>,
281 {
282 Self::new(
283 path,
284 SecurityPolicy::Basic256,
285 MessageSecurityMode::Sign,
286 user_token_ids,
287 )
288 }
289
290 pub fn new_basic256_sign_encrypt<T>(path: T, user_token_ids: &[String]) -> Self
291 where
292 T: Into<String>,
293 {
294 Self::new(
295 path,
296 SecurityPolicy::Basic256,
297 MessageSecurityMode::SignAndEncrypt,
298 user_token_ids,
299 )
300 }
301
302 pub fn new_basic256sha256_sign<T>(path: T, user_token_ids: &[String]) -> Self
303 where
304 T: Into<String>,
305 {
306 Self::new(
307 path,
308 SecurityPolicy::Basic256Sha256,
309 MessageSecurityMode::Sign,
310 user_token_ids,
311 )
312 }
313
314 pub fn new_basic256sha256_sign_encrypt<T>(path: T, user_token_ids: &[String]) -> Self
315 where
316 T: Into<String>,
317 {
318 Self::new(
319 path,
320 SecurityPolicy::Basic256Sha256,
321 MessageSecurityMode::SignAndEncrypt,
322 user_token_ids,
323 )
324 }
325
326 pub fn new_aes128_sha256_rsaoaep_sign<T>(path: T, user_token_ids: &[String]) -> Self
327 where
328 T: Into<String>,
329 {
330 Self::new(
331 path,
332 SecurityPolicy::Aes128Sha256RsaOaep,
333 MessageSecurityMode::Sign,
334 user_token_ids,
335 )
336 }
337
338 pub fn new_aes128_sha256_rsaoaep_sign_encrypt<T>(path: T, user_token_ids: &[String]) -> Self
339 where
340 T: Into<String>,
341 {
342 Self::new(
343 path,
344 SecurityPolicy::Aes128Sha256RsaOaep,
345 MessageSecurityMode::SignAndEncrypt,
346 user_token_ids,
347 )
348 }
349
350 pub fn new_aes256_sha256_rsapss_sign<T>(path: T, user_token_ids: &[String]) -> Self
351 where
352 T: Into<String>,
353 {
354 Self::new(
355 path,
356 SecurityPolicy::Aes256Sha256RsaPss,
357 MessageSecurityMode::Sign,
358 user_token_ids,
359 )
360 }
361
362 pub fn new_aes256_sha256_rsapss_sign_encrypt<T>(path: T, user_token_ids: &[String]) -> Self
363 where
364 T: Into<String>,
365 {
366 Self::new(
367 path,
368 SecurityPolicy::Aes256Sha256RsaPss,
369 MessageSecurityMode::SignAndEncrypt,
370 user_token_ids,
371 )
372 }
373
374 pub fn is_valid(&self, id: &str, user_tokens: &BTreeMap<String, ServerUserToken>) -> bool {
375 let mut valid = true;
376
377 for id in &self.user_token_ids {
379 if id == ANONYMOUS_USER_TOKEN_ID {
381 continue;
382 }
383 if !user_tokens.contains_key(id) {
384 error!("Cannot find user token with id {}", id);
385 valid = false;
386 }
387 }
388
389 if let Some(ref password_security_policy) = self.password_security_policy {
390 let password_security_policy =
391 SecurityPolicy::from_str(password_security_policy).unwrap();
392 if password_security_policy == SecurityPolicy::Unknown {
393 error!("Endpoint {} is invalid. Password security policy \"{}\" is invalid. Valid values are None, Basic128Rsa15, Basic256, Basic256Sha256", id, password_security_policy);
394 valid = false;
395 }
396 }
397
398 let security_policy = SecurityPolicy::from_str(&self.security_policy).unwrap();
400 let security_mode = MessageSecurityMode::from(self.security_mode.as_ref());
401 if security_policy == SecurityPolicy::Unknown {
402 error!("Endpoint {} is invalid. Security policy \"{}\" is invalid. Valid values are None, Basic128Rsa15, Basic256, Basic256Sha256, Aes128Sha256RsaOaep, Aes256Sha256RsaPss,", id, self.security_policy);
403 valid = false;
404 } else if security_mode == MessageSecurityMode::Invalid {
405 error!("Endpoint {} is invalid. Security mode \"{}\" is invalid. Valid values are None, Sign, SignAndEncrypt", id, self.security_mode);
406 valid = false;
407 } else if (security_policy == SecurityPolicy::None
408 && security_mode != MessageSecurityMode::None)
409 || (security_policy != SecurityPolicy::None
410 && security_mode == MessageSecurityMode::None)
411 {
412 error!("Endpoint {} is invalid. Security policy and security mode must both contain None or neither of them should (1).", id);
413 valid = false;
414 } else if security_policy != SecurityPolicy::None
415 && security_mode == MessageSecurityMode::None
416 {
417 error!("Endpoint {} is invalid. Security policy and security mode must both contain None or neither of them should (2).", id);
418 valid = false;
419 }
420 valid
421 }
422
423 pub fn security_policy(&self) -> SecurityPolicy {
424 SecurityPolicy::from_str(&self.security_policy).unwrap()
425 }
426
427 pub fn message_security_mode(&self) -> MessageSecurityMode {
428 MessageSecurityMode::from(self.security_mode.as_ref())
429 }
430
431 pub fn endpoint_url(&self, base_endpoint: &str) -> String {
432 format!("{}{}", base_endpoint, self.path)
433 }
434
435 pub fn password_security_policy(&self) -> SecurityPolicy {
438 let mut password_security_policy = self.security_policy();
439 if let Some(ref security_policy) = self.password_security_policy {
440 match SecurityPolicy::from_str(security_policy).unwrap() {
441 SecurityPolicy::Unknown => {
442 panic!(
443 "Password security policy {} is unrecognized",
444 security_policy
445 );
446 }
447 security_policy => {
448 password_security_policy = security_policy;
449 }
450 }
451 }
452 password_security_policy
453 }
454
455 pub fn supports_anonymous(&self) -> bool {
457 self.supports_user_token_id(ANONYMOUS_USER_TOKEN_ID)
458 }
459
460 pub fn supports_user_pass(&self, server_tokens: &BTreeMap<String, ServerUserToken>) -> bool {
463 for user_token_id in &self.user_token_ids {
464 if user_token_id != ANONYMOUS_USER_TOKEN_ID {
465 if let Some(user_token) = server_tokens.get(user_token_id) {
466 if user_token.is_user_pass() {
467 return true;
468 }
469 }
470 }
471 }
472 false
473 }
474
475 pub fn supports_x509(&self, server_tokens: &BTreeMap<String, ServerUserToken>) -> bool {
478 for user_token_id in &self.user_token_ids {
479 if user_token_id != ANONYMOUS_USER_TOKEN_ID {
480 if let Some(user_token) = server_tokens.get(user_token_id) {
481 if user_token.is_x509() {
482 return true;
483 }
484 }
485 }
486 }
487 false
488 }
489
490 pub fn supports_user_token_id(&self, id: &str) -> bool {
491 self.user_token_ids.contains(id)
492 }
493}
494
495#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
496pub struct Performance {
497 pub single_threaded_executor: bool,
500}
501
502#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
503pub struct ServerConfig {
504 pub application_name: String,
506 pub application_uri: String,
508 pub product_uri: String,
510 pub create_sample_keypair: bool,
513 pub certificate_path: Option<PathBuf>,
515 pub private_key_path: Option<PathBuf>,
517 pub certificate_validation: CertificateValidation,
519 pub pki_dir: PathBuf,
521 pub discovery_server_url: Option<String>,
524 pub tcp_config: TcpConfig,
526 pub limits: Limits,
528 pub performance: Performance,
530 pub locale_ids: Vec<String>,
532 pub user_tokens: BTreeMap<String, ServerUserToken>,
534 pub discovery_urls: Vec<String>,
536 pub default_endpoint: Option<String>,
538 pub endpoints: BTreeMap<String, ServerEndpoint>,
540}
541
542impl Config for ServerConfig {
543 fn is_valid(&self) -> bool {
544 let mut valid = true;
545 if self.application_name.is_empty() {
546 warn!("No application was set");
547 }
548 if self.application_uri.is_empty() {
549 warn!("No application uri was set");
550 }
551 if self.product_uri.is_empty() {
552 warn!("No product uri was set");
553 }
554 if self.endpoints.is_empty() {
555 error!("Server configuration is invalid. It defines no endpoints");
556 valid = false;
557 }
558 for (id, endpoint) in &self.endpoints {
559 if !endpoint.is_valid(id, &self.user_tokens) {
560 valid = false;
561 }
562 }
563 if let Some(ref default_endpoint) = self.default_endpoint {
564 if !self.endpoints.contains_key(default_endpoint) {
565 valid = false;
566 }
567 }
568 for (id, user_token) in &self.user_tokens {
569 if !user_token.is_valid(id) {
570 valid = false;
571 }
572 }
573 if self.limits.max_array_length == 0 {
574 error!("Server configuration is invalid. Max array length is invalid");
575 valid = false;
576 }
577 if self.limits.max_string_length == 0 {
578 error!("Server configuration is invalid. Max string length is invalid");
579 valid = false;
580 }
581 if self.limits.max_byte_string_length == 0 {
582 error!("Server configuration is invalid. Max byte string length is invalid");
583 valid = false;
584 }
585 if self.discovery_urls.is_empty() {
586 error!("Server configuration is invalid. Discovery urls not set");
587 valid = false;
588 }
589 valid
590 }
591
592 fn application_name(&self) -> UAString {
593 UAString::from(&self.application_name)
594 }
595
596 fn application_uri(&self) -> UAString {
597 UAString::from(&self.application_uri)
598 }
599
600 fn product_uri(&self) -> UAString {
601 UAString::from(&self.product_uri)
602 }
603
604 fn application_type(&self) -> ApplicationType {
605 ApplicationType::Server
606 }
607
608 fn discovery_urls(&self) -> Option<Vec<UAString>> {
609 let discovery_urls: Vec<UAString> =
610 self.discovery_urls.iter().map(UAString::from).collect();
611 Some(discovery_urls)
612 }
613}
614
615impl Default for ServerConfig {
616 fn default() -> Self {
617 let mut pki_dir = std::env::current_dir().unwrap();
618 pki_dir.push(Self::PKI_DIR);
619
620 ServerConfig {
621 application_name: String::new(),
622 application_uri: String::new(),
623 product_uri: String::new(),
624 create_sample_keypair: false,
625 certificate_path: None,
626 private_key_path: None,
627 pki_dir,
628 certificate_validation: CertificateValidation {
629 trust_client_certs: false,
630 check_time: true,
631 },
632 discovery_server_url: None,
633 tcp_config: TcpConfig {
634 host: "127.0.0.1".to_string(),
635 port: constants::DEFAULT_RUST_OPC_UA_SERVER_PORT,
636 hello_timeout: constants::DEFAULT_HELLO_TIMEOUT_SECONDS,
637 },
638 limits: Limits::default(),
639 user_tokens: BTreeMap::new(),
640 locale_ids: vec!["en".to_string()],
641 discovery_urls: Vec::new(),
642 default_endpoint: None,
643 endpoints: BTreeMap::new(),
644 performance: Performance {
645 single_threaded_executor: false,
646 },
647 }
648 }
649}
650
651impl ServerConfig {
652 pub const PKI_DIR: &'static str = "pki";
654
655 pub fn new<T>(
656 application_name: T,
657 user_tokens: BTreeMap<String, ServerUserToken>,
658 endpoints: BTreeMap<String, ServerEndpoint>,
659 ) -> Self
660 where
661 T: Into<String>,
662 {
663 let host = "127.0.0.1".to_string();
664 let port = constants::DEFAULT_RUST_OPC_UA_SERVER_PORT;
665
666 let application_name = application_name.into();
667 let application_uri = format!("urn:{}", application_name);
668 let product_uri = format!("urn:{}", application_name);
669 let discovery_server_url = Some(constants::DEFAULT_DISCOVERY_SERVER_URL.to_string());
670 let discovery_urls = vec![format!("opc.tcp://{}:{}/", host, port)];
671 let locale_ids = vec!["en".to_string()];
672
673 let mut pki_dir = std::env::current_dir().unwrap();
674 pki_dir.push(Self::PKI_DIR);
675
676 ServerConfig {
677 application_name,
678 application_uri,
679 product_uri,
680 create_sample_keypair: false,
681 certificate_path: None,
682 private_key_path: None,
683 certificate_validation: CertificateValidation {
684 trust_client_certs: false,
685 check_time: true,
686 },
687 pki_dir,
688 discovery_server_url,
689 tcp_config: TcpConfig {
690 host,
691 port,
692 hello_timeout: constants::DEFAULT_HELLO_TIMEOUT_SECONDS,
693 },
694 limits: Limits::default(),
695 locale_ids,
696 user_tokens,
697 discovery_urls,
698 default_endpoint: None,
699 endpoints,
700 performance: Performance {
701 single_threaded_executor: false,
702 },
703 }
704 }
705
706 pub fn decoding_options(&self) -> DecodingOptions {
707 DecodingOptions {
708 client_offset: chrono::Duration::zero(),
709 max_chunk_count: 0,
710 max_string_length: self.limits.max_string_length as usize,
711 max_byte_string_length: self.limits.max_byte_string_length as usize,
712 max_array_length: self.limits.max_array_length as usize,
713 }
714 }
715
716 pub fn add_endpoint(&mut self, id: &str, endpoint: ServerEndpoint) {
717 self.endpoints.insert(id.to_string(), endpoint);
718 }
719
720 pub fn read_x509_thumbprints(&mut self) {
721 self.user_tokens
722 .iter_mut()
723 .for_each(|(_, token)| token.read_thumbprint());
724 }
725
726 pub fn base_endpoint_url(&self) -> String {
728 format!(
729 "opc.tcp://{}:{}",
730 self.tcp_config.host, self.tcp_config.port
731 )
732 }
733
734 pub fn default_endpoint(&self) -> Option<&ServerEndpoint> {
736 if let Some(ref default_endpoint) = self.default_endpoint {
737 self.endpoints.get(default_endpoint)
738 } else {
739 None
740 }
741 }
742
743 pub fn find_endpoint(
746 &self,
747 endpoint_url: &str,
748 security_policy: SecurityPolicy,
749 security_mode: MessageSecurityMode,
750 ) -> Option<&ServerEndpoint> {
751 let base_endpoint_url = self.base_endpoint_url();
752 let endpoint = self.endpoints.iter().find(|&(_, e)| {
753 if url_matches_except_host(&e.endpoint_url(&base_endpoint_url), endpoint_url) {
755 if e.security_policy() == security_policy
756 && e.message_security_mode() == security_mode
757 {
758 trace!("Found matching endpoint for url {} - {:?}", endpoint_url, e);
759 true
760 } else {
761 false
762 }
763 } else {
764 false
765 }
766 });
767 endpoint.map(|endpoint| endpoint.1)
768 }
769}