Merge pull request #1194 from AlinMoldovean/master

Fix for validation of endpoints from GetEndpoints and  CreateSession responses.
This commit is contained in:
Alin Moldovean
2020-12-02 10:53:55 +02:00
committed by GitHub
+38 -29
View File
@@ -67,44 +67,31 @@ namespace Opc.Ua.Client
/// </summary>
/// <param name="channel">The channel used to communicate with the server.</param>
/// <param name="configuration">The configuration for the client application.</param>
/// <param name="endpoint">The endpoint use to initialize the channel.</param>
/// <param name="endpoint">The endpoint used to initialize the channel.</param>
/// <param name="clientCertificate">The certificate to use for the client.</param>
/// <param name="availableEndpoints">The list of available endpoints returned by server in GetEndpoints() response.</param>
/// <param name="discoveryProfileUris">The value of profileUris used in GetEndpoints() request.</param>
/// <remarks>
/// The application configuration is used to look up the certificate if none is provided.
/// The clientCertificate must have the private key. This will require that the certificate
/// be loaded from a certicate store. Converting a DER encoded blob to a X509Certificate2
/// will not include a private key.
/// The <i>availableEndpoints</i> and <i>discoveryProfileUris</i> parameters are used to validate
/// that the list of EndpointDescriptions returned at GetEndpoints matches the list returned at CreateSession.
/// </remarks>
public Session(
ITransportChannel channel,
ApplicationConfiguration configuration,
ConfiguredEndpoint endpoint,
X509Certificate2 clientCertificate)
:
base(channel)
{
Initialize(channel, configuration, endpoint, clientCertificate);
}
/// <summary>
/// Constructs a new instance of the <see cref="Session"/> class.
/// </summary>
/// <param name="channel">The channel used to communicate with the server.</param>
/// <param name="configuration">The configuration for the client application.</param>
/// <param name="endpoint">The endpoint use to initialize the channel.</param>
/// <param name="clientCertificate">The certificate to use for the client.</param>
/// <param name="availableEndpoints">A collection of available endpoints to connect to the server.</param>
public Session(
ITransportChannel channel,
ApplicationConfiguration configuration,
ConfiguredEndpoint endpoint,
X509Certificate2 clientCertificate,
EndpointDescriptionCollection availableEndpoints)
EndpointDescriptionCollection availableEndpoints = null,
StringCollection discoveryProfileUris = null)
:
base(channel)
{
Initialize(channel, configuration, endpoint, clientCertificate);
m_expectedServerEndpoints = availableEndpoints;
m_discoveryServerEndpoints = availableEndpoints;
m_discoveryProfileUris = discoveryProfileUris;
}
/// <summary>
@@ -2585,20 +2572,41 @@ namespace Opc.Ua.Client
// "Server signature is null or empty.");
}
if (m_expectedServerEndpoints != null && m_expectedServerEndpoints.Count > 0)
if (m_discoveryServerEndpoints != null && m_discoveryServerEndpoints.Count > 0)
{
// verify that the list of endpoints returned by CreateSession matches the list returned at GetEndpoints.
if (m_expectedServerEndpoints.Count != serverEndpoints.Count)
// Compare EndpointDescriptions returned at GetEndpoints with values returned at CreateSession
EndpointDescriptionCollection expectedServerEndpoints = null;
if (m_discoveryProfileUris != null && m_discoveryProfileUris.Count > 0)
{
// Select EndpointDescriptions with a transportProfileUri that matches the
// profileUris specified in the original GetEndpoints() request.
expectedServerEndpoints = new EndpointDescriptionCollection();
foreach (EndpointDescription serverEndpoint in serverEndpoints)
{
if (m_discoveryProfileUris.Contains(serverEndpoint.TransportProfileUri))
{
expectedServerEndpoints.Add(serverEndpoint);
}
}
}
else
{
expectedServerEndpoints = serverEndpoints;
}
if (m_discoveryServerEndpoints.Count != expectedServerEndpoints.Count)
{
throw ServiceResultException.Create(
StatusCodes.BadSecurityChecksFailed,
"Server did not return a number of ServerEndpoints that matches the one from GetEndpoints.");
}
for (int ii = 0; ii < serverEndpoints.Count; ii++)
for (int ii = 0; ii < expectedServerEndpoints.Count; ii++)
{
EndpointDescription serverEndpoint = serverEndpoints[ii];
EndpointDescription expectedServerEndpoint = m_expectedServerEndpoints[ii];
EndpointDescription serverEndpoint = expectedServerEndpoints[ii];
EndpointDescription expectedServerEndpoint = m_discoveryServerEndpoints[ii];
if (serverEndpoint.SecurityMode != expectedServerEndpoint.SecurityMode ||
serverEndpoint.SecurityPolicyUri != expectedServerEndpoint.SecurityPolicyUri ||
@@ -4679,7 +4687,8 @@ namespace Opc.Ua.Client
private bool m_reconnecting;
private LinkedList<AsyncRequestState> m_outstandingRequests;
private EndpointDescriptionCollection m_expectedServerEndpoints;
private EndpointDescriptionCollection m_discoveryServerEndpoints;
private StringCollection m_discoveryProfileUris;
private class AsyncRequestState
{