opc服务端

OpcUaServer.cs

using Opc.Ua;
using Opc.Ua.Configuration;
using Opc.Ua.Server;
using System.Security.Cryptography.X509Certificates;

namespace OpcServerCore.Util
{
    public class OpcUaServer : StandardServer
    {  
        public ApplicationInstance Application { get; private set; } 

        public bool AutoAccept { get; set; }

        /// <summary>
        /// 认证方式
        /// </summary>
        public UserTokenType UserTokenType { get; set; }

        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName { get; set; } = "admin";

        /// <summary>
        /// 密码
        /// </summary>
        public string Password { get; set; } = "123456";

        ICertificateValidator m_userCertificateValidator;

        public OpcUaNodeManager OpcuaNode1 { get; set; }

        protected override MasterNodeManager CreateMasterNodeManager(IServerInternal server, ApplicationConfiguration configuration)
        {
            OpcuaNode1 = new OpcUaNodeManager(server, configuration);

            List<INodeManager> nodeManagers = new List<INodeManager>();
            nodeManagers.Add(OpcuaNode1);

            return new MasterNodeManager(server, configuration, null, nodeManagers.ToArray());
        }

        public async Task LoadAsync(string applicationName, string configSectionName)
        {
            try
            {
                CertificatePasswordProvider passwordProvider = new CertificatePasswordProvider(Password);

                Application = new ApplicationInstance
                {
                    ApplicationName = applicationName,
                    ApplicationType = ApplicationType.Server,
                    ConfigSectionName = configSectionName,
                    CertificatePasswordProvider = passwordProvider
                };

                await Application.LoadApplicationConfiguration(false);
            }
            catch (Exception ex)
            {
                throw new Exception($"Load async error: {ex.Message}", ex);
            }
        }
         
        public async Task CheckCertificateAsync(bool renewCertificate)
        {
            try
            {
                ApplicationConfiguration config = Application.ApplicationConfiguration;

                if (renewCertificate)
                {
                    await Application.DeleteApplicationInstanceCertificate();
                }

                bool haveAppCertificate = await Application.CheckApplicationInstanceCertificate(false, minimumKeySize: 0);
                if (!haveAppCertificate)
                {
                    throw new Exception("Application instance certificate invalid!");
                }

                if (!config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
                {
                    config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);
                }

                // 指定认证方式
                config.ServerConfiguration.UserTokenPolicies.Clear();
                UserTokenPolicy utp = new UserTokenPolicy();
                utp.TokenType = UserTokenType;
                utp.PolicyId = utp.TokenType.ToString();
                config.ServerConfiguration.UserTokenPolicies.Add(utp);

                for (int ii = 0; ii < config.ServerConfiguration.UserTokenPolicies.Count; ii++)
                {
                    UserTokenPolicy policy = config.ServerConfiguration.UserTokenPolicies[ii];

                    if (policy.TokenType == UserTokenType.Certificate)
                    { 
                        if (config.SecurityConfiguration.TrustedUserCertificates != null && config.SecurityConfiguration.UserIssuerCertificates != null)
                        {
                            CertificateValidator certificateValidator = new CertificateValidator();
                            certificateValidator.Update(config.SecurityConfiguration).Wait();
                            certificateValidator.Update(config.SecurityConfiguration.UserIssuerCertificates, config.SecurityConfiguration.TrustedUserCertificates, config.SecurityConfiguration.RejectedCertificateStore);
                            m_userCertificateValidator = certificateValidator.GetChannelValidator();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"CheckCertificateAsync: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Create server instance and add node managers.
        /// </summary>
        public void Create(IList<INodeManagerFactory> nodeManagerFactories)
        {
            try
            {
                if (nodeManagerFactories != null)
                {
                    foreach (INodeManagerFactory factory in nodeManagerFactories)
                    {
                        this.AddNodeManager(factory);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Create Node manager Factories: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Start the server.
        /// </summary>
        public async Task StartAsync()
        {
            try
            { 
                await Application.Start(this); 

                this.CurrentInstance.SessionManager.ImpersonateUser += new ImpersonateEventHandler(ImpersonateUser);
                this.CurrentInstance.SessionManager.SessionActivated += EventStatus;
                this.CurrentInstance.SessionManager.SessionClosing += EventStatus;
                this.CurrentInstance.SessionManager.SessionCreated += EventStatus;
            }
            catch (Exception ex)
            {
                throw new Exception($"Start async: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Stops the server.
        /// </summary>
        public async Task StopAsync()
        {
            try
            {
                this.Stop();
            }
            catch (Exception ex)
            {
                throw new Exception($"Stop async: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// The certificate validator is used
        /// if auto accept is not selected in the configuration.
        /// </summary>
        private void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
        {
            if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
            {
                if (AutoAccept)
                {
                    Logger.Info($"Accepted Certificate: [{e.Certificate.Subject}] [{e.Certificate.Thumbprint}]");
                    e.Accept = true;
                    return;
                }
            }
            Logger.Info($"Rejected Certificate: {e.Error} [{e.Certificate.Subject}] [{e.Certificate.Thumbprint}]");
        }

        private void EventStatus(Session session, SessionEventReason reason)
        { 
             
        }

        private void ImpersonateUser(Session session, ImpersonateEventArgs args)
        { 
            UserNameIdentityToken? userNameToken = args.NewIdentity as UserNameIdentityToken;

            if (userNameToken != null)
            {
                args.Identity = VerifyPassword(userNameToken);
                return;
            }

            X509IdentityToken? x509Token = args.NewIdentity as X509IdentityToken;

            if (x509Token != null)
            {
                VerifyUserTokenCertificate(x509Token.Certificate);
                args.Identity = new UserIdentity(x509Token);
                Utils.Trace("X509 Token Accepted: {0}", args.Identity.DisplayName);
                return;
            }
        }

        /// <summary>
        /// Validates the password for a username token.
        /// </summary>
        private IUserIdentity VerifyPassword(UserNameIdentityToken userNameToken)
        {
            var userName = userNameToken.UserName;
            var password = userNameToken.DecryptedPassword;

            if (string.IsNullOrEmpty(userName))
            {
                throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, "Security token is not a valid username token. An empty username is not accepted.");
            }

            if (string.IsNullOrEmpty(password))
            {
                throw ServiceResultException.Create(StatusCodes.BadIdentityTokenRejected, "Security token is not a valid username token. An empty password is not accepted.");
            }

            if (!(userName == "admin" && password == "123456"))
            {
                TranslationInfo info = new TranslationInfo("InvalidPassword", "en-US", "Invalid username or password.", userName); 
                throw new ServiceResultException(new ServiceResult(StatusCodes.BadUserAccessDenied, "InvalidPassword", "http://opcfoundation.org/Quickstart/ReferenceServer/v1.03", new LocalizedText(info)));
            }

            return new UserIdentity(userNameToken);
        }

        /// <summary>
        /// Verifies that a certificate user token is trusted.
        /// </summary>
        private void VerifyUserTokenCertificate(X509Certificate2 certificate)
        {
            try
            {
                if (m_userCertificateValidator != null)
                {
                    m_userCertificateValidator.Validate(certificate);
                }
                else
                {
                    new CertificateValidator().Validate(certificate);
                }
            }
            catch (Exception e)
            {
                TranslationInfo info;
                StatusCode result = StatusCodes.BadIdentityTokenRejected;
                ServiceResultException se = e as ServiceResultException;
                if (se != null && se.StatusCode == StatusCodes.BadCertificateUseNotAllowed)
                {
                    info = new TranslationInfo("InvalidCertificate", "en-US", "'{0}' is an invalid user certificate.", certificate.Subject); 
                    result = StatusCodes.BadIdentityTokenInvalid;
                }
                else
                {
                    info = new TranslationInfo("UntrustedCertificate", "en-US", "'{0}' is not a trusted user certificate.", certificate.Subject);
                } 
                throw new ServiceResultException(new ServiceResult(result, info.Key, "http://opcfoundation.org/Quickstart/ReferenceServer/v1.04", new LocalizedText(info)));
            }
        }
    }
}

  

 

posted @ 2024-04-08 16:22  CHHC  阅读(136)  评论(0)    收藏  举报