Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Libraries/Opc.Ua.Client/Session/ISession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,13 +645,15 @@ void Open(
/// Updates the preferred locales used for the session.
/// </summary>
/// <param name="preferredLocales">The preferred locales.</param>
[Obsolete("Use ChangePreferredLocalesAsync instead.")]
void ChangePreferredLocales(StringCollection preferredLocales);

/// <summary>
/// Updates the user identity and/or locales used for the session.
/// </summary>
/// <param name="identity">The user identity.</param>
/// <param name="preferredLocales">The preferred locales.</param>
[Obsolete("Use UpdateSessionAsync instead.")]
void UpdateSession(IUserIdentity identity, StringCollection preferredLocales);

/// <summary>
Expand Down Expand Up @@ -744,6 +746,26 @@ Task OpenAsync(
bool closeChannel,
CancellationToken ct);

/// <summary>
/// Updates the user identity and/or locales used for the session.
/// </summary>
/// <param name="identity">The user identity.</param>
/// <param name="preferredLocales">The preferred locales.</param>
/// <param name="ct">The cancellation token.</param>
Task UpdateSessionAsync(
IUserIdentity identity,
StringCollection preferredLocales,
CancellationToken ct = default);

/// <summary>
/// Changes the preferred locales used for the session.
/// </summary>
/// <param name="preferredLocales">The preferred locales.</param>
/// <param name="ct">The cancellation token.</param>
Task ChangePreferredLocalesAsync(
StringCollection preferredLocales,
CancellationToken ct = default);

/// <summary>
/// Reads the values for the node attributes and returns a node object collection.
/// </summary>
Expand Down
132 changes: 8 additions & 124 deletions Libraries/Opc.Ua.Client/Session/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2595,137 +2595,21 @@ SignedSoftwareCertificateCollection clientSoftwareCertificates
}

/// <inheritdoc/>
[Obsolete("Use ChangePreferredLocalesAsync instead.")]
public void ChangePreferredLocales(StringCollection preferredLocales)
{
UpdateSession(Identity, preferredLocales);
UpdateSessionAsync(Identity, preferredLocales)
.GetAwaiter()
.GetResult();
}

/// <inheritdoc/>
[Obsolete("Use UpdateSessionAsync instead.")]
public void UpdateSession(IUserIdentity identity, StringCollection preferredLocales)
{
byte[] serverNonce = null;

lock (SyncRoot)
{
// check connection state.
if (!Connected)
{
throw new ServiceResultException(
StatusCodes.BadInvalidState,
"Not connected to server.");
}

// get current nonce.
serverNonce = m_serverNonce;

preferredLocales ??= m_preferredLocales;
}

// get the identity token.
string securityPolicyUri = m_endpoint.Description.SecurityPolicyUri;

// create the client signature.
byte[] dataToSign = Utils.Append(m_serverCertificate?.RawData, serverNonce);
SignatureData clientSignature = SecurityPolicies.Sign(
m_instanceCertificate,
securityPolicyUri,
dataToSign);

// choose a default token.
identity ??= new UserIdentity();

// check that the user identity is supported by the endpoint.
UserTokenPolicy identityPolicy =
m_endpoint.Description.FindUserTokenPolicy(
identity.TokenType,
identity.IssuedTokenType,
securityPolicyUri)
?? throw ServiceResultException.Create(
StatusCodes.BadUserAccessDenied,
"Endpoint does not support the user identity type provided.");

// select the security policy for the user token.
string tokenSecurityPolicyUri = identityPolicy.SecurityPolicyUri;

if (string.IsNullOrEmpty(tokenSecurityPolicyUri))
{
tokenSecurityPolicyUri = m_endpoint.Description.SecurityPolicyUri;
}

bool requireEncryption = tokenSecurityPolicyUri != SecurityPolicies.None;

// validate the server certificate before encrypting tokens.
if (m_serverCertificate != null &&
requireEncryption &&
identity.TokenType != UserTokenType.Anonymous)
{
m_configuration.CertificateValidator.Validate(m_serverCertificate);
}

// validate server nonce and security parameters for user identity.
ValidateServerNonce(
identity,
serverNonce,
tokenSecurityPolicyUri,
m_previousServerNonce,
m_endpoint.Description.SecurityMode);

// sign data with user token.
UserIdentityToken identityToken = identity.GetIdentityToken();
identityToken.PolicyId = identityPolicy.PolicyId;
SignatureData userTokenSignature = identityToken.Sign(
dataToSign,
tokenSecurityPolicyUri);

m_userTokenSecurityPolicyUri = tokenSecurityPolicyUri;

// encrypt token.
identityToken.Encrypt(
m_serverCertificate,
serverNonce,
m_userTokenSecurityPolicyUri,
m_eccServerEphemeralKey,
m_instanceCertificate,
m_instanceCertificateChain,
m_endpoint.Description.SecurityMode != MessageSecurityMode.None);

// send the software certificates assigned to the client.
SignedSoftwareCertificateCollection clientSoftwareCertificates
= GetSoftwareCertificates();

// activate session.
ResponseHeader responseHeader = ActivateSession(
null,
clientSignature,
clientSoftwareCertificates,
preferredLocales,
new ExtensionObject(identityToken),
userTokenSignature,
out serverNonce,
out _,
out _);

ProcessResponseAdditionalHeader(responseHeader, m_serverCertificate);

// save nonce and new values.
lock (SyncRoot)
{
if (identity != null)
{
m_identity = identity;
}

m_previousServerNonce = m_serverNonce;
m_serverNonce = serverNonce;
m_preferredLocales = preferredLocales;

// update system context.
m_systemContext.PreferredLocales = m_preferredLocales;
m_systemContext.SessionId = SessionId;
m_systemContext.UserIdentity = identity;
}

IndicateSessionConfigurationChanged();
UpdateSessionAsync(identity, preferredLocales)
.GetAwaiter()
.GetResult();
}

/// <inheritdoc/>
Expand Down
138 changes: 138 additions & 0 deletions Libraries/Opc.Ua.Client/Session/SessionAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,144 @@ await base.CloseSessionAsync(null, false, CancellationToken.None)
}
}

/// <inheritdoc/>
public Task ChangePreferredLocalesAsync(
StringCollection preferredLocales,
CancellationToken ct)
{
return UpdateSessionAsync(Identity, preferredLocales, ct);
}

/// <inheritdoc/>
public async Task UpdateSessionAsync(
IUserIdentity identity,
StringCollection preferredLocales,
CancellationToken ct = default)
{
byte[] serverNonce = null;

lock (SyncRoot)
{
// check connection state.
if (!Connected)
{
throw new ServiceResultException(
StatusCodes.BadInvalidState,
"Not connected to server.");
}

// get current nonce.
serverNonce = m_serverNonce;

preferredLocales ??= m_preferredLocales;
}

// get the identity token.
string securityPolicyUri = m_endpoint.Description.SecurityPolicyUri;

// create the client signature.
byte[] dataToSign = Utils.Append(m_serverCertificate?.RawData, serverNonce);
SignatureData clientSignature = SecurityPolicies.Sign(
m_instanceCertificate,
securityPolicyUri,
dataToSign);

// choose a default token.
identity ??= new UserIdentity();

// check that the user identity is supported by the endpoint.
UserTokenPolicy identityPolicy =
m_endpoint.Description.FindUserTokenPolicy(
identity.TokenType,
identity.IssuedTokenType,
securityPolicyUri)
?? throw ServiceResultException.Create(
StatusCodes.BadUserAccessDenied,
"Endpoint does not support the user identity type provided.");

// select the security policy for the user token.
string tokenSecurityPolicyUri = identityPolicy.SecurityPolicyUri;

if (string.IsNullOrEmpty(tokenSecurityPolicyUri))
{
tokenSecurityPolicyUri = m_endpoint.Description.SecurityPolicyUri;
}

bool requireEncryption = tokenSecurityPolicyUri != SecurityPolicies.None;

// validate the server certificate before encrypting tokens.
if (m_serverCertificate != null &&
requireEncryption &&
identity.TokenType != UserTokenType.Anonymous)
{
m_configuration.CertificateValidator.Validate(m_serverCertificate);
}

// validate server nonce and security parameters for user identity.
ValidateServerNonce(
identity,
serverNonce,
tokenSecurityPolicyUri,
m_previousServerNonce,
m_endpoint.Description.SecurityMode);

// sign data with user token.
UserIdentityToken identityToken = identity.GetIdentityToken();
identityToken.PolicyId = identityPolicy.PolicyId;
SignatureData userTokenSignature = identityToken.Sign(
dataToSign,
tokenSecurityPolicyUri);

m_userTokenSecurityPolicyUri = tokenSecurityPolicyUri;

// encrypt token.
identityToken.Encrypt(
m_serverCertificate,
serverNonce,
m_userTokenSecurityPolicyUri,
m_eccServerEphemeralKey,
m_instanceCertificate,
m_instanceCertificateChain,
m_endpoint.Description.SecurityMode != MessageSecurityMode.None);

// send the software certificates assigned to the client.
SignedSoftwareCertificateCollection clientSoftwareCertificates
= GetSoftwareCertificates();

ActivateSessionResponse response = await ActivateSessionAsync(
null,
clientSignature,
clientSoftwareCertificates,
preferredLocales,
new ExtensionObject(identityToken),
userTokenSignature,
ct).ConfigureAwait(false);

serverNonce = response.ServerNonce;

ProcessResponseAdditionalHeader(response.ResponseHeader, m_serverCertificate);

// save nonce and new values.
lock (SyncRoot)
{
if (identity != null)
{
m_identity = identity;
}

m_previousServerNonce = m_serverNonce;
m_serverNonce = serverNonce;
m_preferredLocales = preferredLocales;

// update system context.
m_systemContext.PreferredLocales = m_preferredLocales;
m_systemContext.SessionId = SessionId;
m_systemContext.UserIdentity = identity;
}

IndicateSessionConfigurationChanged();
}

/// <inheritdoc/>
public async Task<bool> RemoveSubscriptionAsync(
Subscription subscription,
Expand Down
23 changes: 23 additions & 0 deletions Libraries/Opc.Ua.Client/Session/TraceableSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -607,19 +607,42 @@ public void Open(
}

/// <inheritdoc/>
[Obsolete("Use ChangePreferredLocalesAsync instead.")]
public void ChangePreferredLocales(StringCollection preferredLocales)
{
using Activity activity = ActivitySource.StartActivity();
Session.ChangePreferredLocales(preferredLocales);
}

/// <inheritdoc/>
public async Task ChangePreferredLocalesAsync(
StringCollection preferredLocales,
CancellationToken ct)
{
using Activity activity = ActivitySource.StartActivity();
await Session.ChangePreferredLocalesAsync(preferredLocales, ct)
.ConfigureAwait(false);
}

/// <inheritdoc/>
[Obsolete("Use UpdateSessionAsync instead.")]
public void UpdateSession(IUserIdentity identity, StringCollection preferredLocales)
{
using Activity activity = ActivitySource.StartActivity();
Session.UpdateSession(identity, preferredLocales);
}

/// <inheritdoc/>
public async Task UpdateSessionAsync(
IUserIdentity identity,
StringCollection preferredLocales,
CancellationToken ct)
{
using Activity activity = ActivitySource.StartActivity();
await Session.UpdateSessionAsync(identity, preferredLocales, ct)
.ConfigureAwait(false);
}

/// <inheritdoc/>
public void FindComponentIds(
NodeId instanceId,
Expand Down
Loading