Skip to main content

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