From cab2a9a1c257f791bd9028d2a3eabc90c786bebd Mon Sep 17 00:00:00 2001 From: Adam Lock Date: Thu, 12 Mar 2020 20:42:56 +0000 Subject: [PATCH] Put some TODOs where audit events should go. Put getters on address space to separate the concept of default namespace from internal and audit namespace. --- server/src/address_space/address_space.rs | 23 +++++++++++++++++++---- server/src/services/attribute.rs | 2 ++ server/src/services/audit.rs | 4 ++-- server/src/services/discovery.rs | 2 ++ server/src/services/method.rs | 5 +++++ server/src/services/node_management.rs | 8 ++++++-- 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/server/src/address_space/address_space.rs b/server/src/address_space/address_space.rs index 21a4d9d8f..1bc03f2fb 100644 --- a/server/src/address_space/address_space.rs +++ b/server/src/address_space/address_space.rs @@ -111,6 +111,8 @@ macro_rules! server_diagnostics_summary { pub(crate) type MethodCallback = Box; +const OPCUA_INTERNAL_NAMESPACE_IDX: u16 = 1; + #[derive(PartialEq, Eq, Clone, Debug, Hash)] struct MethodKey { object_id: NodeId, @@ -151,8 +153,12 @@ pub struct AddressSpace { last_modified: DateTimeUtc, /// Access to server diagnostics server_diagnostics: Option>>, - /// This is the namespace to create sequential node ids + /// The namespace to create sequential node ids default_namespace: u16, + /// The namespace to generate sequential audit node ids + audit_namespace: u16, + /// The namespace to generate sequential internal node ids + internal_namespace: u16, /// The list of all registered namespaces. namespaces: Vec, } @@ -164,8 +170,12 @@ impl Default for AddressSpace { references: References::default(), last_modified: Utc::now(), server_diagnostics: None, - default_namespace: 1, - // By default, there will be two standard namespaces + default_namespace: OPCUA_INTERNAL_NAMESPACE_IDX, + audit_namespace: OPCUA_INTERNAL_NAMESPACE_IDX, + internal_namespace: OPCUA_INTERNAL_NAMESPACE_IDX, + // By default, there will be two standard namespaces. The first is the default + // OPC UA namespace for its standard nodes. The second is the internal namespace used + // by this implementation. namespaces: vec!["http://opcfoundation.org/UA/".to_string(), "urn:OPCUA-Rust-Internal".to_string()], } } @@ -479,7 +489,12 @@ impl AddressSpace { /// Get the default namespace for audit events pub fn audit_namespace(&self) -> u16 { - self.default_namespace + self.audit_namespace + } + + /// Get the internal namespace + pub fn internal_namespace(&self) -> u16 { + self.internal_namespace } /// Inserts a node into the address space node map and its references to other target nodes. diff --git a/server/src/services/attribute.rs b/server/src/services/attribute.rs index 7037b801c..d0e77d5ed 100644 --- a/server/src/services/attribute.rs +++ b/server/src/services/attribute.rs @@ -110,6 +110,7 @@ impl AttributeService { debug!("Empty list passed to write {:?}", request); self.service_fault(&request.request_header, StatusCode::BadNothingToDo) } else { + // TODO audit - generate AuditWriteUpdateEventType event let session = trace_read_lock_unwrap!(session); let mut address_space = trace_write_lock_unwrap!(address_space); let results = request.nodes_to_write.as_ref().unwrap().iter().map(|node_to_write| { @@ -130,6 +131,7 @@ impl AttributeService { if is_empty_option_vec!(request.history_update_details) { self.service_fault(&request.request_header, StatusCode::BadNothingToDo) } else { + // TODO audit - generate AuditHistoryUpdateEventType event let decoding_limits = { let server_state = trace_read_lock_unwrap!(server_state); server_state.decoding_limits() diff --git a/server/src/services/audit.rs b/server/src/services/audit.rs index 9df65ca41..6c44aad66 100644 --- a/server/src/services/audit.rs +++ b/server/src/services/audit.rs @@ -15,11 +15,11 @@ use crate::{ }; fn next_node_id(address_space: Arc>) -> NodeId { - let default_namespace = { + let audit_namespace = { let address_space = trace_read_lock_unwrap!(address_space); address_space.audit_namespace() }; - NodeId::next_numeric(default_namespace) + NodeId::next_numeric(audit_namespace) } pub fn audit_log_create_session(server_state: &ServerState, session: &Session, address_space: Arc>, status: bool, revised_session_timeout: Duration, request: &CreateSessionRequest) { diff --git a/server/src/services/discovery.rs b/server/src/services/discovery.rs index 9c5744c19..817a3ed8f 100644 --- a/server/src/services/discovery.rs +++ b/server/src/services/discovery.rs @@ -23,6 +23,8 @@ impl DiscoveryService { // TODO some of the arguments in the request are ignored // localeIds - list of locales to use for human readable strings (in the endpoint descriptions) + // TODO audit - generate event for failed service invocation + let endpoints = server_state.endpoints(&request.endpoint_url, &request.profile_uris); GetEndpointsResponse { response_header: ResponseHeader::new_good(&request.request_header), diff --git a/server/src/services/method.rs b/server/src/services/method.rs index 7f6812ddb..86f3ee381 100644 --- a/server/src/services/method.rs +++ b/server/src/services/method.rs @@ -33,6 +33,11 @@ impl MethodService { let results: Vec = calls.iter().map(|request| { trace!("Calling to {:?} on {:?}", request.method_id, request.object_id); + + // Note: Method invocations that modify the address space, write a value, or modify the + // state of the system (acknowledge, batch sequencing or other system changes) must + // generate an AuditUpdateMethodEventType or a subtype of it. + // Call the method via whatever is registered in the address space match address_space.call_method(&server_state, &mut session, request) { Ok(response) => response, diff --git a/server/src/services/node_management.rs b/server/src/services/node_management.rs index 139a40afa..8b0f972c4 100644 --- a/server/src/services/node_management.rs +++ b/server/src/services/node_management.rs @@ -3,12 +3,12 @@ use std::{ sync::{Arc, RwLock}, }; +use opcua_core::supported_message::SupportedMessage; use opcua_types::{ *, node_ids::ObjectId, status_code::StatusCode, }; -use opcua_core::supported_message::SupportedMessage; use crate::{ address_space::{ @@ -34,6 +34,7 @@ impl NodeManagementService { /// Implements the AddNodes service pub fn add_nodes(&self, server_state: Arc>, session: Arc>, address_space: Arc>, request: &AddNodesRequest) -> SupportedMessage { + // TODO audit - generate AuditAddNodesEventType event if let Some(ref nodes_to_add) = request.nodes_to_add { if !nodes_to_add.is_empty() { let server_state = trace_read_lock_unwrap!(server_state); @@ -68,6 +69,7 @@ impl NodeManagementService { /// Implements the AddReferences service pub fn add_references(&self, server_state: Arc>, session: Arc>, address_space: Arc>, request: &AddReferencesRequest) -> SupportedMessage { + // TODO audit - generate AuditAddReferencesEventType event if let Some(ref references_to_add) = request.references_to_add { if !references_to_add.is_empty() { let server_state = trace_read_lock_unwrap!(server_state); @@ -95,6 +97,7 @@ impl NodeManagementService { /// Implements the DeleteNodes service pub fn delete_nodes(&self, server_state: Arc>, session: Arc>, address_space: Arc>, request: &DeleteNodesRequest) -> SupportedMessage { + // TODO audit - generate AuditDeleteNodesEventType event if let Some(ref nodes_to_delete) = request.nodes_to_delete { if !nodes_to_delete.is_empty() { let server_state = trace_read_lock_unwrap!(server_state); @@ -123,6 +126,7 @@ impl NodeManagementService { /// Implements the DeleteReferences service pub fn delete_references(&self, server_state: Arc>, session: Arc>, address_space: Arc>, request: &DeleteReferencesRequest) -> SupportedMessage { + // TODO audit - generate AuditDeleteReferencesEventType event if let Some(ref references_to_delete) = request.references_to_delete { if !references_to_delete.is_empty() { let server_state = trace_read_lock_unwrap!(server_state); @@ -282,7 +286,7 @@ impl NodeManagementService { if let Ok(reference_type_id) = item.reference_type_id.as_reference_type_id() { // Node Id was either supplied or will be generated let new_node_id = if requested_new_node_id.is_null() { - NodeId::next_numeric(1) + NodeId::next_numeric(address_space.internal_namespace()) } else { requested_new_node_id.node_id.clone() };