opcua_server/
info.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2024 Adam Lock
4
5//! Provides server state information, such as status, configuration, running servers and so on.
6
7use std::sync::atomic::{AtomicU16, AtomicU8, Ordering};
8use std::sync::Arc;
9
10use arc_swap::ArcSwap;
11use opcua_nodes::DefaultTypeTree;
12use tracing::{debug, error, warn};
13
14use crate::authenticator::{user_pass_security_policy_id, Password};
15use crate::diagnostics::{ServerDiagnostics, ServerDiagnosticsSummary};
16use crate::node_manager::TypeTreeForUser;
17use opcua_core::comms::url::{hostname_from_url, url_matches_except_host};
18use opcua_core::handle::AtomicHandle;
19use opcua_core::sync::RwLock;
20use opcua_crypto::{user_identity, PrivateKey, SecurityPolicy, X509};
21use opcua_types::{
22    profiles, status_code::StatusCode, ActivateSessionRequest, AnonymousIdentityToken,
23    ApplicationDescription, ApplicationType, EndpointDescription, RegisteredServer,
24    ServerState as ServerStateType, SignatureData, UserNameIdentityToken, UserTokenType,
25    X509IdentityToken,
26};
27use opcua_types::{
28    ByteString, ContextOwned, DateTime, DecodingOptions, Error, ExtensionObject,
29    IssuedIdentityToken, LocalizedText, MessageSecurityMode, NamespaceMap, TypeLoader,
30    TypeLoaderCollection, UAString,
31};
32
33use crate::config::{ServerConfig, ServerEndpoint};
34
35use super::authenticator::{AuthManager, UserToken};
36use super::identity_token::{IdentityToken, POLICY_ID_ANONYMOUS, POLICY_ID_X509};
37use super::{OperationalLimits, ServerCapabilities, ANONYMOUS_USER_TOKEN_ID};
38
39/// Server state is any configuration associated with the server as a whole that individual sessions might
40/// be interested in.
41pub struct ServerInfo {
42    /// The application URI
43    pub application_uri: UAString,
44    /// The product URI
45    pub product_uri: UAString,
46    /// The application name
47    pub application_name: LocalizedText,
48    /// The time the server started
49    pub start_time: ArcSwap<DateTime>,
50    /// The list of servers (by urn)
51    pub servers: Vec<String>,
52    /// Server configuration
53    pub config: Arc<ServerConfig>,
54    /// Server public certificate read from config location or null if there is none
55    pub server_certificate: Option<X509>,
56    /// Server private key
57    pub server_pkey: Option<PrivateKey>,
58    /// Operational limits
59    pub(crate) operational_limits: OperationalLimits,
60    /// Current state
61    pub state: ArcSwap<ServerStateType>,
62    /// Audit log
63    // pub(crate) audit_log: Arc<RwLock<AuditLog>>,
64    /// Diagnostic information
65    // pub(crate) diagnostics: Arc<RwLock<ServerDiagnostics>>,
66    /// Size of the send buffer in bytes
67    pub send_buffer_size: usize,
68    /// Size of the receive buffer in bytes
69    pub receive_buffer_size: usize,
70    /// Authenticator to use when verifying user identities, and checking for user access.
71    pub authenticator: Arc<dyn AuthManager>,
72    /// Structure containing type metadata shared by the entire server.
73    pub type_tree: Arc<RwLock<DefaultTypeTree>>,
74    /// Wrapper to get a type tree for a specific user.
75    pub type_tree_getter: Arc<dyn TypeTreeForUser>,
76    /// Generator for subscription IDs.
77    pub subscription_id_handle: AtomicHandle,
78    /// Generator for monitored item IDs.
79    pub monitored_item_id_handle: AtomicHandle,
80    /// Generator for secure channel IDs.
81    pub secure_channel_id_handle: Arc<AtomicHandle>,
82    /// Server capabilities
83    pub capabilities: ServerCapabilities,
84    /// Service level observer.
85    pub service_level: Arc<AtomicU8>,
86    /// Currently active local port.
87    pub port: AtomicU16,
88    /// List of active type loaders
89    pub type_loaders: RwLock<TypeLoaderCollection>,
90    /// Current server diagnostics.
91    pub diagnostics: ServerDiagnostics,
92}
93
94impl ServerInfo {
95    /// Get the list of endpoints that match the provided filters.
96    pub fn endpoints(
97        &self,
98        endpoint_url: &UAString,
99        transport_profile_uris: &Option<Vec<UAString>>,
100    ) -> Option<Vec<EndpointDescription>> {
101        // Filter endpoints based on profile_uris
102        debug!(
103            "Endpoints requested, transport profile uris {:?}",
104            transport_profile_uris
105        );
106        if let Some(ref transport_profile_uris) = *transport_profile_uris {
107            // Note - some clients pass an empty array
108            if !transport_profile_uris.is_empty() {
109                // As we only support binary transport, the result is None if the supplied profile_uris does not contain that profile
110                let found_binary_transport = transport_profile_uris.iter().any(|profile_uri| {
111                    profile_uri.as_ref() == profiles::TRANSPORT_PROFILE_URI_BINARY
112                });
113                if !found_binary_transport {
114                    error!(
115                        "Client wants to connect with a non binary transport {:#?}",
116                        transport_profile_uris
117                    );
118                    return None;
119                }
120            }
121        }
122
123        if let Ok(hostname) = hostname_from_url(endpoint_url.as_ref()) {
124            if !hostname.eq_ignore_ascii_case(&self.config.tcp_config.host) {
125                debug!("Endpoint url \"{}\" hostname supplied by caller does not match server's hostname \"{}\"", endpoint_url, &self.config.tcp_config.host);
126            }
127            let endpoints = self
128                .config
129                .endpoints
130                .values()
131                .map(|e| self.new_endpoint_description(e, true))
132                .collect();
133            Some(endpoints)
134        } else {
135            warn!(
136                "Endpoint url \"{}\" is unrecognized, using default",
137                endpoint_url
138            );
139            if let Some(e) = self.config.default_endpoint() {
140                Some(vec![self.new_endpoint_description(e, true)])
141            } else {
142                Some(vec![])
143            }
144        }
145    }
146
147    /// Check if the endpoint given by `endpoint_url`, `security_policy`, and `security_mode`
148    /// exists on the server.
149    pub fn endpoint_exists(
150        &self,
151        endpoint_url: &str,
152        security_policy: SecurityPolicy,
153        security_mode: MessageSecurityMode,
154    ) -> bool {
155        self.config
156            .find_endpoint(
157                endpoint_url,
158                &self.base_endpoint(),
159                security_policy,
160                security_mode,
161            )
162            .is_some()
163    }
164
165    /// Make matching endpoint descriptions for the specified url.
166    /// If none match then None will be passed, therefore if Some is returned it will be guaranteed
167    /// to contain at least one result.
168    pub fn new_endpoint_descriptions(
169        &self,
170        endpoint_url: &str,
171    ) -> Option<Vec<EndpointDescription>> {
172        debug!("find_endpoint, url = {}", endpoint_url);
173        let base_endpoint_url = self.base_endpoint();
174        let endpoints: Vec<EndpointDescription> = self
175            .config
176            .endpoints
177            .iter()
178            .filter(|&(_, e)| {
179                // Test end point's security_policy_uri and matching url
180                url_matches_except_host(&e.endpoint_url(&base_endpoint_url), endpoint_url)
181            })
182            .map(|(_, e)| self.new_endpoint_description(e, false))
183            .collect();
184        if endpoints.is_empty() {
185            None
186        } else {
187            Some(endpoints)
188        }
189    }
190
191    /// Constructs a new endpoint description using the server's info and that in an Endpoint
192    fn new_endpoint_description(
193        &self,
194        endpoint: &ServerEndpoint,
195        all_fields: bool,
196    ) -> EndpointDescription {
197        let base_endpoint_url = self.base_endpoint();
198
199        let user_identity_tokens = self.authenticator.user_token_policies(endpoint);
200
201        // CreateSession doesn't need all the endpoint description
202        // and docs say not to bother sending the server and server
203        // certificate info.
204        let (server, server_certificate) = if all_fields {
205            (
206                ApplicationDescription {
207                    application_uri: self.application_uri.clone(),
208                    product_uri: self.product_uri.clone(),
209                    application_name: self.application_name.clone(),
210                    application_type: self.application_type(),
211                    gateway_server_uri: self.gateway_server_uri(),
212                    discovery_profile_uri: UAString::null(),
213                    discovery_urls: self.discovery_urls(),
214                },
215                self.server_certificate_as_byte_string(),
216            )
217        } else {
218            (
219                ApplicationDescription {
220                    application_uri: self.application_uri.clone(),
221                    product_uri: UAString::null(),
222                    application_name: LocalizedText::null(),
223                    application_type: self.application_type(),
224                    gateway_server_uri: self.gateway_server_uri(),
225                    discovery_profile_uri: UAString::null(),
226                    discovery_urls: self.discovery_urls(),
227                },
228                ByteString::null(),
229            )
230        };
231
232        EndpointDescription {
233            endpoint_url: endpoint.endpoint_url(&base_endpoint_url).into(),
234            server,
235            server_certificate,
236            security_mode: endpoint.message_security_mode(),
237            security_policy_uri: UAString::from(endpoint.security_policy().to_uri()),
238            user_identity_tokens: Some(user_identity_tokens),
239            transport_profile_uri: UAString::from(profiles::TRANSPORT_PROFILE_URI_BINARY),
240            security_level: endpoint.security_level,
241        }
242    }
243
244    /// Get the list of discovery URLs on the server.
245    pub fn discovery_urls(&self) -> Option<Vec<UAString>> {
246        if self.config.discovery_urls.is_empty() {
247            None
248        } else {
249            Some(
250                self.config
251                    .discovery_urls
252                    .iter()
253                    .map(UAString::from)
254                    .collect(),
255            )
256        }
257    }
258
259    /// Get the application type, will be `Server`.
260    pub fn application_type(&self) -> ApplicationType {
261        ApplicationType::Server
262    }
263
264    /// Get the gateway server URI.
265    pub fn gateway_server_uri(&self) -> UAString {
266        UAString::null()
267    }
268
269    /// Get the current server state.
270    pub fn state(&self) -> ServerStateType {
271        **self.state.load()
272    }
273
274    /// Check if the server state indicates the server is running.
275    pub fn is_running(&self) -> bool {
276        self.state() == ServerStateType::Running
277    }
278
279    /// Get the base endpoint, i.e. the configured host + current port.
280    pub fn base_endpoint(&self) -> String {
281        format!(
282            "opc.tcp://{}:{}",
283            self.config.tcp_config.host,
284            self.port.load(Ordering::Relaxed)
285        )
286    }
287
288    /// Get the server certificate as a byte string.
289    pub fn server_certificate_as_byte_string(&self) -> ByteString {
290        if let Some(ref server_certificate) = self.server_certificate {
291            server_certificate.as_byte_string()
292        } else {
293            ByteString::null()
294        }
295    }
296
297    /// Get a representation of this server as a `RegisteredServer` object.
298    pub fn registered_server(&self) -> RegisteredServer {
299        let server_uri = self.application_uri.clone();
300        let product_uri = self.product_uri.clone();
301        let gateway_server_uri = self.gateway_server_uri();
302        let discovery_urls = self.discovery_urls();
303        let server_type = self.application_type();
304        let is_online = self.is_running();
305        let server_names = Some(vec![self.application_name.clone()]);
306        // Server names
307        RegisteredServer {
308            server_uri,
309            product_uri,
310            server_names,
311            server_type,
312            gateway_server_uri,
313            discovery_urls,
314            semaphore_file_path: UAString::null(),
315            is_online,
316        }
317    }
318
319    /// Authenticates access to an endpoint. The endpoint is described by its path, policy, mode and
320    /// the token is supplied in an extension object that must be extracted and authenticated.
321    ///
322    /// It is possible that the endpoint does not exist, or that the token is invalid / unsupported
323    /// or that the token cannot be used with the end point. The return codes reflect the responses
324    /// that ActivateSession would expect from a service call.
325    pub async fn authenticate_endpoint(
326        &self,
327        request: &ActivateSessionRequest,
328        endpoint_url: &str,
329        security_policy: SecurityPolicy,
330        security_mode: MessageSecurityMode,
331        user_identity_token: ExtensionObject,
332        server_nonce: &ByteString,
333    ) -> Result<UserToken, Error> {
334        // Get security from endpoint url
335        if let Some(endpoint) = self.config.find_endpoint(
336            endpoint_url,
337            &self.base_endpoint(),
338            security_policy,
339            security_mode,
340        ) {
341            // Now validate the user identity token
342            match IdentityToken::new(user_identity_token) {
343                IdentityToken::None => {
344                    error!("User identity token type unsupported");
345                    Err(Error::new(
346                        StatusCode::BadIdentityTokenInvalid,
347                        "User identity token type unsupported",
348                    ))
349                }
350                IdentityToken::Anonymous(token) => {
351                    self.authenticate_anonymous_token(endpoint, &token).await
352                }
353                IdentityToken::UserName(token) => {
354                    self.authenticate_username_identity_token(
355                        endpoint,
356                        &token,
357                        &self.server_pkey,
358                        server_nonce,
359                    )
360                    .await
361                }
362                IdentityToken::X509(token) => {
363                    self.authenticate_x509_identity_token(
364                        endpoint,
365                        &token,
366                        &request.user_token_signature,
367                        &self.server_certificate,
368                        server_nonce,
369                    )
370                    .await
371                }
372                IdentityToken::IssuedToken(token) => {
373                    self.authenticate_issued_identity_token(
374                        endpoint,
375                        &token,
376                        &self.server_pkey,
377                        server_nonce,
378                    )
379                    .await
380                }
381                IdentityToken::Invalid(o) => Err(Error::new(
382                    StatusCode::BadIdentityTokenInvalid,
383                    format!(
384                        "User identity token type {} is unsupported",
385                        o.body.map(|b| b.type_name()).unwrap_or("None")
386                    ),
387                )),
388            }
389        } else {
390            Err(Error::new(StatusCode::BadIdentityTokenRejected, format!(
391                "Cannot find endpoint that matches path \"{endpoint_url}\", security policy {security_policy:?}, and security mode {security_mode:?}"
392            )))
393        }
394    }
395
396    /// Returns the decoding options of the server
397    pub fn decoding_options(&self) -> DecodingOptions {
398        self.config.decoding_options()
399    }
400
401    /// Authenticates an anonymous token, i.e. does the endpoint support anonymous access or not
402    async fn authenticate_anonymous_token(
403        &self,
404        endpoint: &ServerEndpoint,
405        token: &AnonymousIdentityToken,
406    ) -> Result<UserToken, Error> {
407        if token.policy_id.as_ref() != POLICY_ID_ANONYMOUS {
408            return Err(Error::new(
409                StatusCode::BadIdentityTokenInvalid,
410                format!(
411                    "Token doesn't possess the correct policy id. Got {}, expected {}",
412                    token.policy_id.as_ref(),
413                    POLICY_ID_ANONYMOUS
414                ),
415            ));
416        }
417        self.authenticator
418            .authenticate_anonymous_token(endpoint)
419            .await?;
420
421        Ok(UserToken(ANONYMOUS_USER_TOKEN_ID.to_string()))
422    }
423
424    /// Authenticates the username identity token with the supplied endpoint. The function returns the user token identifier
425    /// that matches the identity token.
426    async fn authenticate_username_identity_token(
427        &self,
428        endpoint: &ServerEndpoint,
429        token: &UserNameIdentityToken,
430        server_key: &Option<PrivateKey>,
431        server_nonce: &ByteString,
432    ) -> Result<UserToken, Error> {
433        if !self.authenticator.supports_user_pass(endpoint) {
434            Err(Error::new(
435                StatusCode::BadIdentityTokenRejected,
436                "Endpoint doesn't support username password tokens",
437            ))
438        } else if token.policy_id != user_pass_security_policy_id(endpoint) {
439            Err(Error::new(
440                StatusCode::BadIdentityTokenRejected,
441                "Token doesn't possess the correct policy id",
442            ))
443        } else if token.user_name.is_empty() {
444            Err(Error::new(
445                StatusCode::BadIdentityTokenRejected,
446                "User identify token supplied no username",
447            ))
448        } else {
449            debug!(
450                "policy id = {}, encryption algorithm = {}",
451                token.policy_id.as_ref(),
452                token.encryption_algorithm.as_ref()
453            );
454            let token_password = if !token.encryption_algorithm.is_empty() {
455                if let Some(ref server_key) = server_key {
456                    let decrypted = user_identity::legacy_decrypt_secret(
457                        token,
458                        server_nonce.as_ref(),
459                        server_key,
460                    )?;
461                    String::from_utf8(decrypted.value.unwrap_or_default()).map_err(|e| {
462                        Error::new(
463                            StatusCode::BadIdentityTokenInvalid,
464                            format!("Failed to decode identity token to string: {e}"),
465                        )
466                    })?
467                } else {
468                    error!("Identity token password is encrypted but no server private key was supplied");
469                    return Err(Error::new(
470                        StatusCode::BadIdentityTokenInvalid,
471                        "Failed to decrypt identity token password",
472                    ));
473                }
474            } else {
475                token.plaintext_password()?
476            };
477
478            self.authenticator
479                .authenticate_username_identity_token(
480                    endpoint,
481                    token.user_name.as_ref(),
482                    &Password::new(token_password),
483                )
484                .await
485        }
486    }
487
488    /// Authenticate the x509 token against the endpoint. The function returns the user token identifier
489    /// that matches the identity token.
490    async fn authenticate_x509_identity_token(
491        &self,
492        endpoint: &ServerEndpoint,
493        token: &X509IdentityToken,
494        user_token_signature: &SignatureData,
495        server_certificate: &Option<X509>,
496        server_nonce: &ByteString,
497    ) -> Result<UserToken, Error> {
498        if !self.authenticator.supports_x509(endpoint) {
499            error!("Endpoint doesn't support x509 tokens");
500            Err(Error::new(
501                StatusCode::BadIdentityTokenRejected,
502                "Endpoint doesn't support x509 tokens",
503            ))
504        } else if token.policy_id.as_ref() != POLICY_ID_X509 {
505            error!("Token doesn't possess the correct policy id");
506            Err(Error::new(
507                StatusCode::BadIdentityTokenRejected,
508                "Token doesn't possess the correct policy id",
509            ))
510        } else {
511            match server_certificate {
512                Some(ref server_certificate) => {
513                    // Find the security policy used for verifying tokens
514                    let user_identity_tokens = self.authenticator.user_token_policies(endpoint);
515                    let security_policy = user_identity_tokens
516                        .iter()
517                        .find(|t| t.token_type == UserTokenType::Certificate)
518                        .map(|t| SecurityPolicy::from_uri(t.security_policy_uri.as_ref()))
519                        .unwrap_or_else(|| endpoint.security_policy());
520
521                    // The security policy has to be something that can encrypt
522                    match security_policy {
523                        SecurityPolicy::Unknown | SecurityPolicy::None => Err(Error::new(
524                            StatusCode::BadIdentityTokenInvalid,
525                            "Bad security policy",
526                        )),
527                        security_policy => {
528                            // Verify token
529                            user_identity::verify_x509_identity_token(
530                                token,
531                                user_token_signature,
532                                security_policy,
533                                server_certificate,
534                                server_nonce.as_ref(),
535                            )
536                        }
537                    }
538                }
539                None => Err(Error::new(
540                    StatusCode::BadIdentityTokenInvalid,
541                    "Server certificate missing, cannot validate X509 tokens",
542                )),
543            }?;
544
545            // Check the endpoint to see if this token is supported
546            let signing_cert = X509::from_byte_string(&token.certificate_data)?;
547            let signing_thumbprint = signing_cert.thumbprint();
548
549            self.authenticator
550                .authenticate_x509_identity_token(endpoint, &signing_thumbprint)
551                .await
552        }
553    }
554
555    async fn authenticate_issued_identity_token(
556        &self,
557        endpoint: &ServerEndpoint,
558        token: &IssuedIdentityToken,
559        server_key: &Option<PrivateKey>,
560        server_nonce: &ByteString,
561    ) -> Result<UserToken, Error> {
562        if !self.authenticator.supports_issued_token(endpoint) {
563            Err(Error::new(
564                StatusCode::BadIdentityTokenRejected,
565                "Endpoint doesn't support issued tokens",
566            ))
567        } else if token.policy_id != user_pass_security_policy_id(endpoint) {
568            Err(Error::new(
569                StatusCode::BadIdentityTokenRejected,
570                "Token doesn't possess the correct policy id",
571            ))
572        } else {
573            debug!(
574                "policy id = {}, encryption algorithm = {}",
575                token.policy_id.as_ref(),
576                token.encryption_algorithm.as_ref()
577            );
578            let decrypted_token = if !token.encryption_algorithm.is_empty() {
579                if let Some(ref server_key) = server_key {
580                    user_identity::legacy_decrypt_secret(token, server_nonce.as_ref(), server_key)?
581                } else {
582                    error!("Identity token password is encrypted but no server private key was supplied");
583                    return Err(Error::new(
584                        StatusCode::BadIdentityTokenInvalid,
585                        "Failed to decrypt identity token issued token",
586                    ));
587                }
588            } else {
589                token.token_data.clone()
590            };
591
592            self.authenticator
593                .authenticate_issued_identity_token(endpoint, &decrypted_token)
594                .await
595        }
596    }
597
598    pub(crate) fn initial_encoding_context(&self) -> ContextOwned {
599        // The namespace map is populated later, once the session is connected.
600        ContextOwned::new(
601            NamespaceMap::new(),
602            self.type_loaders.read().clone(),
603            self.decoding_options(),
604        )
605    }
606
607    /// Add a type loader to the server.
608    /// Note that there is no mechanism to ensure uniqueness,
609    /// you should avoid adding the same type loader more than once, it will
610    /// work, but there will be a small performance overhead.
611    pub fn add_type_loader(&self, type_loader: Arc<dyn TypeLoader>) {
612        self.type_loaders.write().add(type_loader);
613    }
614
615    /// Convenience method to get the diagnostics summary.
616    pub fn summary(&self) -> &ServerDiagnosticsSummary {
617        &self.diagnostics.summary
618    }
619
620    /* pub(crate) fn raise_and_log<T>(&self, event: T) -> Result<NodeId, ()>
621    where
622        T: AuditEvent + Event,
623    {
624        let audit_log = trace_write_lock!(self.audit_log);
625        audit_log.raise_and_log(event)
626    } */
627}