mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-24 11:01:55 +08:00
enable server push in gds client, add a few test cases
This commit is contained in:
@@ -314,7 +314,7 @@ namespace Opc.Ua.Server
|
||||
|
||||
// TODO: role based access
|
||||
UserIdentity user = context.UserIdentity as UserIdentity;
|
||||
if (user.TokenType == UserTokenType.Anonymous)
|
||||
if (user?.TokenType == UserTokenType.Anonymous)
|
||||
{
|
||||
throw new ServiceResultException(StatusCodes.BadUserAccessDenied, "Secure Application Administrator access required.");
|
||||
}
|
||||
@@ -352,6 +352,7 @@ namespace Opc.Ua.Server
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Private Fields
|
||||
private class ServerCertificateGroup
|
||||
{
|
||||
public string BrowseName;
|
||||
@@ -363,7 +364,6 @@ namespace Opc.Ua.Server
|
||||
public string TrustedStorePath;
|
||||
};
|
||||
|
||||
#region Private Fields
|
||||
private ServerConfigurationState m_serverConfigurationNode;
|
||||
private IList<ServerCertificateGroup> m_certificateGroups;
|
||||
public readonly string m_rejectedStorePath;
|
||||
|
||||
@@ -174,10 +174,12 @@ namespace Opc.Ua.Gds.Client
|
||||
NodeId requestId = null;
|
||||
if (!string.IsNullOrEmpty(m_application.CertificateStorePath))
|
||||
{
|
||||
CertificateIdentifier id = new CertificateIdentifier();
|
||||
id.StoreType = CertificateStoreIdentifier.DetermineStoreType(m_application.CertificateStorePath);
|
||||
id.StorePath = m_application.CertificateStorePath;
|
||||
id.SubjectName = m_application.CertificateSubjectName.Replace("localhost", Utils.GetHostName());
|
||||
CertificateIdentifier id = new CertificateIdentifier
|
||||
{
|
||||
StoreType = CertificateStoreIdentifier.DetermineStoreType(m_application.CertificateStorePath),
|
||||
StorePath = m_application.CertificateStorePath,
|
||||
SubjectName = m_application.CertificateSubjectName.Replace("localhost", Utils.GetHostName())
|
||||
};
|
||||
m_certificate = await id.Find(true);
|
||||
if (m_certificate != null &&
|
||||
m_certificate.HasPrivateKey)
|
||||
@@ -216,7 +218,7 @@ namespace Opc.Ua.Gds.Client
|
||||
else
|
||||
{
|
||||
string absoluteCertificatePrivateKeyPath = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, false, false);
|
||||
byte [] pkcsData = File.ReadAllBytes(absoluteCertificatePrivateKeyPath);
|
||||
byte[] pkcsData = File.ReadAllBytes(absoluteCertificatePrivateKeyPath);
|
||||
if (m_application.GetPrivateKeyFormat(m_server?.GetSupportedKeyFormats()) == "PFX")
|
||||
{
|
||||
csrCertificate = CertificateFactory.CreateCertificateFromPKCS12(pkcsData, m_certificatePassword);
|
||||
@@ -261,7 +263,7 @@ namespace Opc.Ua.Gds.Client
|
||||
// request not done yet, try again in a few seconds
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CertificateRequestTimer.Enabled = false;
|
||||
RequestProgressLabel.Visible = false;
|
||||
|
||||
@@ -400,14 +402,13 @@ namespace Opc.Ua.Gds.Client
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TODO_SERVERPUSH
|
||||
if (privateKeyPFX != null && privateKeyPFX.Length > 0)
|
||||
{
|
||||
var x509 = new X509Certificate2(privateKeyPFX, m_certificatePassword, X509KeyStorageFlags.Exportable);
|
||||
privateKeyPFX = x509.Export(X509ContentType.Pfx);
|
||||
}
|
||||
bool applyChanges = m_server.UpdateCertificate(null, null, certificate, GetPrivateKeyFormat(), privateKeyPFX, issuerCertificates);
|
||||
|
||||
bool applyChanges = m_server.UpdateCertificate(null, null, certificate, (privateKeyPFX != null) ? "PFX" : null, privateKeyPFX, issuerCertificates);
|
||||
|
||||
if (applyChanges)
|
||||
{
|
||||
MessageBox.Show(
|
||||
@@ -419,9 +420,6 @@ namespace Opc.Ua.Gds.Client
|
||||
|
||||
ApplyChangesButton.Enabled = true;
|
||||
}
|
||||
#else
|
||||
throw new ServiceResultException("Server Push is not yet implemented.");
|
||||
#endif
|
||||
}
|
||||
|
||||
CertificateControl.ShowValue(null, "Application Certificate", new CertificateWrapper() { Certificate = m_certificate }, true);
|
||||
@@ -439,7 +437,7 @@ namespace Opc.Ua.Gds.Client
|
||||
CertificateRequestTimer.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ApplyChangesButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -53,9 +53,8 @@ namespace Opc.Ua.Gds.Client
|
||||
|
||||
RegistrationTypeComboBox.Items.Add("Client - Pull Management");
|
||||
RegistrationTypeComboBox.Items.Add("Server - Pull Management");
|
||||
#if TODO_SERVERPUSH
|
||||
RegistrationTypeComboBox.Items.Add("Server - Push Management");
|
||||
#endif
|
||||
|
||||
RegistrationTypeComboBox.SelectedIndex = ServerPullManagement;
|
||||
|
||||
m_promptOnRegistrationTypeChange = false;
|
||||
|
||||
@@ -408,7 +408,6 @@ namespace Opc.Ua.Gds.Client
|
||||
|
||||
private void UpdateStatus(bool error, DateTime time, string status, params object[] args)
|
||||
{
|
||||
#if TODO_SERVERPUSH
|
||||
if (error)
|
||||
{
|
||||
ServerStatusIcon.Image = global::Opc.Ua.Gds.Client.Properties.Resources.error;
|
||||
@@ -422,11 +421,6 @@ namespace Opc.Ua.Gds.Client
|
||||
ServerStatusLabel.ForeColor = (error) ? Color.Red : Color.Empty;
|
||||
ServerStatusTime.Text = (time != DateTime.MinValue) ? time.ToLocalTime().ToString("hh:mm:ss") : "---";
|
||||
ServerStatusTime.ForeColor = (error) ? Color.Red : Color.Empty;
|
||||
#else
|
||||
ServerStatusTime.Visible = false;
|
||||
ServerStatusLabel.Visible = false;
|
||||
ServerStatusIcon.Visible = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void DisconnectButton_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -624,7 +624,7 @@ namespace Opc.Ua.Gds.Client
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the trust lists method.
|
||||
/// Gets the certificate status.
|
||||
/// </summary>
|
||||
/// <param name="applicationId">The application id.</param>
|
||||
/// <param name="certificateGroupId">Type of the trust list.</param>
|
||||
|
||||
@@ -32,6 +32,7 @@ using System;
|
||||
using System.IO;
|
||||
using Opc.Ua.Client;
|
||||
using Opc.Ua.Configuration;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Opc.Ua.Gds.Client
|
||||
{
|
||||
@@ -75,6 +76,18 @@ namespace Opc.Ua.Gds.Client
|
||||
set { m_adminCredentials = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the endpoint URL.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The endpoint URL.
|
||||
/// </value>
|
||||
public string EndpointUrl
|
||||
{
|
||||
get { return m_endpointUrl; }
|
||||
set { m_endpointUrl = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when admin credentials are required.
|
||||
/// </summary>
|
||||
@@ -170,7 +183,7 @@ namespace Opc.Ua.Gds.Client
|
||||
/// </summary>
|
||||
public void Connect()
|
||||
{
|
||||
Connect((ConfiguredEndpoint)null);
|
||||
Connect(EndpointUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -311,8 +324,6 @@ namespace Opc.Ua.Gds.Client
|
||||
/// <summary>
|
||||
/// Gets the supported key formats.
|
||||
/// </summary>
|
||||
/// <param name="publicKeyFormats">The public key formats.</param>
|
||||
/// <param name="privateKeyFormats">The private key formats.</param>
|
||||
/// <exception cref="System.InvalidOperationException">Connection to server is not active.</exception>
|
||||
public string[] GetSupportedKeyFormats()
|
||||
{
|
||||
@@ -429,6 +440,7 @@ namespace Opc.Ua.Gds.Client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates the trust list.
|
||||
/// </summary>
|
||||
@@ -585,6 +597,40 @@ namespace Opc.Ua.Gds.Client
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the rejected list.
|
||||
/// </summary>
|
||||
public X509Certificate2Collection GetRejectedList()
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
Connect();
|
||||
}
|
||||
|
||||
IUserIdentity oldUser = ElevatePermissions();
|
||||
|
||||
try
|
||||
{
|
||||
var outputArguments = m_session.Call(
|
||||
ExpandedNodeId.ToNodeId(Opc.Ua.ObjectIds.ServerConfiguration, m_session.NamespaceUris),
|
||||
ExpandedNodeId.ToNodeId(Opc.Ua.MethodIds.ServerConfiguration_GetRejectedList, m_session.NamespaceUris)
|
||||
);
|
||||
|
||||
byte[][] rawCertificates = (byte[][])outputArguments[0];
|
||||
X509Certificate2Collection collection = new X509Certificate2Collection();
|
||||
foreach (var rawCertificate in rawCertificates)
|
||||
{
|
||||
collection.Add(new X509Certificate(rawCertificate));
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RevertPermissions(oldUser);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Restarts this instance.
|
||||
/// </summary>
|
||||
@@ -713,6 +759,7 @@ namespace Opc.Ua.Gds.Client
|
||||
private ApplicationInstance m_application;
|
||||
private ConfiguredEndpoint m_endpoint;
|
||||
private string[] m_preferredLocales;
|
||||
private string m_endpointUrl;
|
||||
private Session m_session;
|
||||
private UserIdentity m_adminCredentials;
|
||||
#endregion
|
||||
|
||||
@@ -38,17 +38,20 @@ namespace Opc.Ua.Gds.Test
|
||||
|
||||
public class GlobalDiscoveryTestClient
|
||||
{
|
||||
GlobalDiscoveryServerClient m_gds;
|
||||
GlobalDiscoveryServerClient m_gdsClient;
|
||||
ServerPushConfigurationClient m_pushClient;
|
||||
|
||||
static bool autoAccept = false;
|
||||
|
||||
public GlobalDiscoveryServerClient GDSClient { get { return m_gds; } }
|
||||
public GlobalDiscoveryServerClient GDSClient { get { return m_gdsClient; } }
|
||||
public ServerPushConfigurationClient PushClient { get { return m_pushClient; } }
|
||||
|
||||
public GlobalDiscoveryTestClient(bool _autoAccept)
|
||||
{
|
||||
autoAccept = _autoAccept;
|
||||
}
|
||||
|
||||
public async Task ConnectClient()
|
||||
public async Task ConnectClient(bool gdsClient = true)
|
||||
{
|
||||
ApplicationInstance.MessageDlg = new ApplicationMessageDlg();
|
||||
ApplicationInstance application = new ApplicationInstance
|
||||
@@ -70,25 +73,42 @@ namespace Opc.Ua.Gds.Test
|
||||
|
||||
config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);
|
||||
|
||||
// get the configuration.
|
||||
// use same server for gds and push tests
|
||||
GlobalDiscoveryClientConfiguration gdsClientConfiguration = application.ApplicationConfiguration.ParseExtension<GlobalDiscoveryClientConfiguration>();
|
||||
|
||||
m_gds = new GlobalDiscoveryServerClient(application, gdsClientConfiguration);
|
||||
|
||||
if (gdsClient)
|
||||
{
|
||||
// get the configuration.
|
||||
m_gdsClient = new GlobalDiscoveryServerClient(application, gdsClientConfiguration);
|
||||
m_gdsClient.EndpointUrl = gdsClientConfiguration.GlobalDiscoveryServerUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushClient = new ServerPushConfigurationClient(application);
|
||||
m_pushClient.EndpointUrl = gdsClientConfiguration.GlobalDiscoveryServerUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public void DisconnectClient()
|
||||
{
|
||||
if (m_gds != null)
|
||||
{
|
||||
Console.WriteLine("Disconnect Session. Waiting for exit...");
|
||||
|
||||
if (m_gdsClient != null)
|
||||
{
|
||||
Console.WriteLine("Disconnect Session. Waiting for exit...");
|
||||
GlobalDiscoveryServerClient gds = m_gds;
|
||||
m_gds = null;
|
||||
gds.Disconnect();
|
||||
GlobalDiscoveryServerClient gdsClient = m_gdsClient;
|
||||
m_gdsClient = null;
|
||||
gdsClient.Disconnect();
|
||||
}
|
||||
|
||||
if (m_pushClient != null)
|
||||
{
|
||||
ServerPushConfigurationClient pushClient = m_pushClient;
|
||||
m_pushClient = null;
|
||||
pushClient.Disconnect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
|
||||
{
|
||||
if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/* ========================================================================
|
||||
* Copyright (c) 2005-2017 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.RegularExpressions;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Gds;
|
||||
using Opc.Ua.Gds.Client;
|
||||
using Opc.Ua.Gds.Test;
|
||||
using Opc.Ua.Test;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace NUnit.Opc.Ua.Gds.Test
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class PushTest
|
||||
{
|
||||
#region Test Setup
|
||||
/// <summary>
|
||||
/// Set up a Global Discovery Server and Client instance and connect the session
|
||||
/// </summary>
|
||||
[OneTimeSetUp]
|
||||
protected void OneTimeSetUp()
|
||||
{
|
||||
_serverCapabilities = new ServerCapabilities();
|
||||
_randomSource = new RandomSource(randomStart);
|
||||
_dataGenerator = new DataGenerator(_randomSource);
|
||||
_server = new GlobalDiscoveryTestServer(true);
|
||||
_server.StartServer().Wait();
|
||||
_client = new GlobalDiscoveryTestClient(true);
|
||||
_client.ConnectClient(false).Wait();
|
||||
_client.PushClient.AdminCredentials = new UserIdentity("appadmin", "demo");
|
||||
_client.PushClient.Connect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tear down the Global Discovery Server and disconnect the Client
|
||||
/// </summary>
|
||||
[OneTimeTearDown]
|
||||
protected void OneTimeTearDown()
|
||||
{
|
||||
_client.DisconnectClient();
|
||||
_server.StopServer();
|
||||
}
|
||||
#endregion
|
||||
#region Test Methods
|
||||
[Test, Order(100)]
|
||||
public void GetSupportedKeyFormats()
|
||||
{
|
||||
_client.PushClient.GetSupportedKeyFormats();
|
||||
}
|
||||
|
||||
[Test, Order(200)]
|
||||
public void ReadTrustList()
|
||||
{
|
||||
TrustListDataType trustList = _client.PushClient.ReadTrustList();
|
||||
Assert.IsNotNull(trustList);
|
||||
Assert.IsNotNull(trustList.IssuerCertificates);
|
||||
Assert.IsNotNull(trustList.IssuerCrls);
|
||||
Assert.IsNotNull(trustList.TrustedCertificates);
|
||||
Assert.IsNotNull(trustList.TrustedCrls);
|
||||
}
|
||||
|
||||
[Test, Order(300)]
|
||||
public void UpdateTrustList()
|
||||
{
|
||||
TrustListDataType trustList = _client.PushClient.ReadTrustList();
|
||||
Assert.IsTrue(_client.PushClient.UpdateTrustList(trustList));
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test, Order(400)]
|
||||
public void CreateCertificateRequest()
|
||||
{
|
||||
byte [] csr = _client.PushClient.CreateCertificateRequest(null,null,null,false,null);
|
||||
Assert.IsNotNull(csr);
|
||||
}
|
||||
|
||||
[Test, Order(500)]
|
||||
public void UpdateCertificate()
|
||||
{
|
||||
X509Certificate2 cert = CertificateFactory.CreateCertificate(null, null, null, "uri:x:y:z", "TestApp", "CN=Push Server Test", null, 2048, DateTime.UtcNow, 1, 256);
|
||||
var success = _client.PushClient.UpdateCertificate(null, null, cert.RawData, null, null, null);
|
||||
}
|
||||
|
||||
[Test, Order(500)]
|
||||
public void GetRejectedList()
|
||||
{
|
||||
var collection = _client.PushClient.GetRejectedList();
|
||||
}
|
||||
|
||||
|
||||
[Test, Order(600)]
|
||||
public void ApplyChanges()
|
||||
{
|
||||
_client.PushClient.ApplyChanges();
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Private Methods
|
||||
|
||||
private string RandomLocalHost()
|
||||
{
|
||||
string localhost = Regex.Replace(_dataGenerator.GetRandomSymbol("en").Trim().ToLower(), @"[^\w\d]", "");
|
||||
if (localhost.Length >= 12)
|
||||
{
|
||||
localhost = localhost.Substring(0, 12);
|
||||
}
|
||||
return localhost;
|
||||
}
|
||||
|
||||
private string[] RandomDomainNames()
|
||||
{
|
||||
int count = _randomSource.NextInt32(8) + 1;
|
||||
var result = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
result[i] = RandomLocalHost();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private StringCollection RandomDiscoveryUrl(StringCollection domainNames, int port, string appUri)
|
||||
{
|
||||
var result = new StringCollection();
|
||||
foreach (var name in domainNames)
|
||||
{
|
||||
int random = _randomSource.NextInt32(7);
|
||||
if ((result.Count == 0) || (random & 1) == 0)
|
||||
{
|
||||
result.Add(String.Format("opc.tcp://{0}:{1}/{2}", name, (port++).ToString(), appUri));
|
||||
}
|
||||
if ((random & 2) == 0)
|
||||
{
|
||||
result.Add(String.Format("http://{0}:{1}/{2}", name, (port++).ToString(), appUri));
|
||||
}
|
||||
if ((random & 4) == 0)
|
||||
{
|
||||
result.Add(String.Format("https://{0}:{1}/{2}", name, (port++).ToString(), appUri));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private const int randomStart = 1;
|
||||
private RandomSource _randomSource;
|
||||
private DataGenerator _dataGenerator;
|
||||
private GlobalDiscoveryTestServer _server;
|
||||
private GlobalDiscoveryTestClient _client;
|
||||
private ServerCapabilities _serverCapabilities;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user