/* ======================================================================== * Copyright (c) 2005-2019 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Xml; using System.IO; using System.Threading; using System.Reflection; using Opc.Ua; using Opc.Ua.Server; namespace Quickstarts.UserAuthenticationServer { /// /// A node manager for a server that exposes several variables. /// public class UserAuthenticationNodeManager : CustomNodeManager2 { #region Constructors /// /// Initializes the node manager. /// public UserAuthenticationNodeManager(IServerInternal server, ApplicationConfiguration configuration) : base(server, Namespaces.UserAuthentication) { SystemContext.NodeIdFactory = this; // get the configuration for the node manager. m_configuration = configuration.ParseExtension(); // use suitable defaults if no configuration exists. if (m_configuration == null) { m_configuration = new UserAuthenticationServerConfiguration(); } } #endregion #region IDisposable Members /// /// An overrideable version of the Dispose. /// protected override void Dispose(bool disposing) { if (disposing) { // TBD } } #endregion #region INodeIdFactory Members /// /// Creates the NodeId for the specified node. /// public override NodeId New(ISystemContext context, NodeState node) { return node.NodeId; } #endregion #region INodeManager Members /// /// Does any initialization required before the address space can be used. /// /// /// The externalReferences is an out parameter that allows the node manager to link to nodes /// in other node managers. For example, the 'Objects' node is managed by the CoreNodeManager and /// should have a reference to the root folder node(s) exposed by this node manager. /// public override void CreateAddressSpace(IDictionary> externalReferences) { lock (Lock) { // create a object to represent the process being controlled. BaseObjectState process = new BaseObjectState(null); process.NodeId = new NodeId(1, NamespaceIndex); process.BrowseName = new QualifiedName("My Process", NamespaceIndex); process.DisplayName = process.BrowseName.Name; process.TypeDefinitionId = ObjectTypeIds.BaseObjectType; // ensure the process object can be found via the server object. IList references = null; if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references)) { externalReferences[ObjectIds.ObjectsFolder] = references = new List(); } process.AddReference(ReferenceTypeIds.Organizes, true, ObjectIds.ObjectsFolder); references.Add(new NodeStateReference(ReferenceTypeIds.Organizes, false, process.NodeId)); // a property to report the process state. PropertyState state = new PropertyState(process); state.NodeId = new NodeId(2, NamespaceIndex); state.BrowseName = new QualifiedName("LogFilePath", NamespaceIndex); state.DisplayName = state.BrowseName.Name; state.TypeDefinitionId = VariableTypeIds.PropertyType; state.ReferenceTypeId = ReferenceTypeIds.HasProperty; state.DataType = DataTypeIds.String; state.ValueRank = ValueRanks.Scalar; state.AccessLevel = AccessLevels.CurrentReadOrWrite; state.UserAccessLevel = AccessLevels.CurrentRead; state.Value = ".\\Log.txt"; process.AddChild(state); state.OnReadUserAccessLevel = OnReadUserAccessLevel; state.OnSimpleWriteValue = OnWriteValue; // save in dictionary. AddPredefinedNode(SystemContext, process); } } public ServiceResult OnWriteValue(ISystemContext context, NodeState node, ref object value) { if (context.UserIdentity == null || context.UserIdentity.TokenType == UserTokenType.Anonymous) { TranslationInfo info = new TranslationInfo( "BadUserAccessDenied", "en-US", "User cannot change value."); return new ServiceResult(StatusCodes.BadUserAccessDenied, new LocalizedText(info)); } // attempt to update file system. try { string filePath = value as string; PropertyState variable = node as PropertyState; if (!String.IsNullOrEmpty(variable.Value)) { FileInfo file = new FileInfo(variable.Value); if (file.Exists) { file.Delete(); } } if (!String.IsNullOrEmpty(filePath)) { FileInfo file = new FileInfo(filePath); using (StreamWriter writer = file.CreateText()) { writer.WriteLine(System.Security.Principal.WindowsIdentity.GetCurrent().Name); } } value = filePath; } catch (Exception e) { return ServiceResult.Create(e, StatusCodes.BadUserAccessDenied, "Could not update file system."); } return ServiceResult.Good; } public ServiceResult OnReadUserAccessLevel(ISystemContext context, NodeState node, ref byte value) { if (context.UserIdentity == null || context.UserIdentity.TokenType == UserTokenType.Anonymous) { value = AccessLevels.CurrentRead; } else { value = AccessLevels.CurrentReadOrWrite; } return ServiceResult.Good; } /// /// Frees any resources allocated for the address space. /// public override void DeleteAddressSpace() { lock (Lock) { // TBD } } /// /// Returns a unique handle for the node. /// protected override NodeHandle GetManagerHandle(ServerSystemContext context, NodeId nodeId, IDictionary cache) { lock (Lock) { // quickly exclude nodes that are not in the namespace. if (!IsNodeIdInNamespace(nodeId)) { return null; } NodeState node = null; if (!PredefinedNodes.TryGetValue(nodeId, out node)) { return null; } NodeHandle handle = new NodeHandle(); handle.NodeId = nodeId; handle.Node = node; handle.Validated = true; return handle; } } /// /// Verifies that the specified node exists. /// protected override NodeState ValidateNode( ServerSystemContext context, NodeHandle handle, IDictionary cache) { // not valid if no root. if (handle == null) { return null; } // check if previously validated. if (handle.Validated) { return handle.Node; } // TBD return null; } #endregion #region Overridden UserAuthentication #endregion #region Private Fields private UserAuthenticationServerConfiguration m_configuration; #endregion } }