Skip to content

Commit

Permalink
HTTP Session and more GDS Push bug fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
barnstee committed Aug 25, 2024
1 parent 1801bac commit 57fa158
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 54 deletions.
72 changes: 27 additions & 45 deletions Controllers/BrowserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ namespace Opc.Ua.Cloud.Publisher.Controllers
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Cloud.Publisher;
using Opc.Ua.Cloud.Publisher.Interfaces;
using Opc.Ua.Cloud.Publisher.Models;
using Opc.Ua.Gds.Client;
using Opc.Ua.Security.Certificates;
using Opc.Ua.Server;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand Down Expand Up @@ -40,7 +38,7 @@ public IActionResult DownloadUACert()
{
try
{
return File(_helper.GetCert(), "APPLICATION/octet-stream", "cert.der");
return File(_helper.GetAppCert().Export(X509ContentType.Cert), "APPLICATION/octet-stream", "cert.der");
}
catch (Exception ex)
{
Expand Down Expand Up @@ -75,7 +73,13 @@ public ActionResult UserPassword(string endpointUrl)
[HttpPost]
public async Task<ActionResult> ConnectAsync(string username, string password, string endpointUrl)
{
SessionModel sessionModel = new SessionModel { UserName = username, Password = password, EndpointUrl = endpointUrl };
SessionModel sessionModel = new()
{
UserName = username,
Password = password,
EndpointUrl = endpointUrl,
SessionId = HttpContext.Session.Id
};

Client.Session session = null;

Expand All @@ -99,17 +103,6 @@ public async Task<ActionResult> ConnectAsync(string username, string password, s
HttpContext.Session.SetString("EndpointUrl", endpointUrl);
}

if (!string.IsNullOrEmpty(username) && (password != null))
{
HttpContext.Session.SetString("UserName", username);
HttpContext.Session.SetString("Password", password);
}
else
{
HttpContext.Session.Remove("UserName");
HttpContext.Session.Remove("Password");
}

if (session == null)
{
sessionModel.StatusMessage = "Unable to create session!";
Expand Down Expand Up @@ -267,24 +260,20 @@ public async Task<ActionResult> PushCert()
false,
unusedNonce);

X509Certificate2 certificate = await ProcessSigningRequestAsync(
X509Certificate2 certificate = ProcessSigningRequest(
serverPushClient.Session.ServerUris.ToArray()[0],
null,
certificateRequest).ConfigureAwait(false);

X509Certificate2 x509 = new X509Certificate2(certificate.Export(X509ContentType.Pfx), string.Empty, X509KeyStorageFlags.Exportable);
byte[] privateKeyPFX = x509.Export(X509ContentType.Pfx);

certificateRequest);

byte[][] issuerCertificates = new byte[1][];
issuerCertificates[0] = _helper.GetCert();
issuerCertificates[0] = _helper.GetAppCert().Export(X509ContentType.Cert);

byte[] unusedPrivateKey = new byte[0];
serverPushClient.UpdateCertificate(
NodeId.Null,
serverPushClient.ApplicationCertificateType,
certificate.Export(X509ContentType.Pfx),
(privateKeyPFX != null) ? "pfx" : string.Empty,
(privateKeyPFX != null) ? privateKeyPFX : unusedPrivateKey,
string.Empty,
new byte[0],
issuerCertificates);

// store in our own trust list
Expand All @@ -307,7 +296,7 @@ public async Task<ActionResult> PushCert()
return View("Browse", sessionModel);
}

private async Task<X509Certificate2> ProcessSigningRequestAsync(string applicationUri, string[] domainNames, byte[] certificateRequest)
private X509Certificate2 ProcessSigningRequest(string applicationUri, string[] domainNames, byte[] certificateRequest)
{
try
{
Expand Down Expand Up @@ -349,18 +338,17 @@ private async Task<X509Certificate2> ProcessSigningRequestAsync(string applicati
}

DateTime yesterday = DateTime.Today.AddDays(-1);
using (var signingKey = await LoadSigningKeyAsync().ConfigureAwait(false))
{
X500DistinguishedName subjectName = new X500DistinguishedName(info.Subject.GetEncoded());
return CertificateBuilder.Create(subjectName)
.AddExtension(new X509SubjectAltNameExtension(applicationUri, domainNames))
.SetNotBefore(yesterday)
.SetLifeTime(12)
.SetHashAlgorithm(X509Utils.GetRSAHashAlgorithmName(2048))
.SetIssuer(signingKey)
.SetRSAPublicKey(info.SubjectPublicKeyInfo.GetEncoded())
.CreateForRSA();
}
X509Certificate2 signingKey = _helper.GetAppCert();
X500DistinguishedName subjectName = new X500DistinguishedName(info.Subject.GetEncoded());

return CertificateBuilder.Create(subjectName)
.AddExtension(new X509SubjectAltNameExtension(applicationUri, domainNames))
.SetNotBefore(yesterday)
.SetLifeTime(12)
.SetHashAlgorithm(X509Utils.GetRSAHashAlgorithmName(2048))
.SetIssuer(signingKey)
.SetRSAPublicKey(info.SubjectPublicKeyInfo.GetEncoded())
.CreateForRSA();
}
catch (Exception ex)
{
Expand Down Expand Up @@ -400,12 +388,6 @@ protected X509SubjectAltNameExtension GetAltNameExtensionFromCSRInfo(Org.BouncyC
return null;
}

private async Task<X509Certificate2> LoadSigningKeyAsync()
{
CertificateIdentifier certIdentifier = _app.UAApplicationInstance.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate;
return await certIdentifier.LoadPrivateKey(string.Empty).ConfigureAwait(false);
}

private TrustListDataType GetTrustLists()
{
ByteStringCollection trusted = new ByteStringCollection();
Expand All @@ -419,7 +401,7 @@ private TrustListDataType GetTrustLists()
trusted.Add(cert.Export(X509ContentType.Cert));
}

issuers.Add(_helper.GetCert());
issuers.Add(_helper.GetAppCert().Export(X509ContentType.Cert));

TrustListDataType trustList = new TrustListDataType()
{
Expand Down
8 changes: 4 additions & 4 deletions OpcSessionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ public class OpcSessionHelper

private readonly IUAApplication _app;

private byte[] _appCertBytes = null;
private X509Certificate2 _appCert = null;

public OpcSessionHelper(IUAApplication app)
{
_app = app;
_configuration = app.UAApplicationInstance.ApplicationConfiguration;
_appCertBytes = _configuration.SecurityConfiguration.ApplicationCertificate.Certificate.Export(X509ContentType.Cert);
_appCert = _configuration.SecurityConfiguration.ApplicationCertificate.Certificate;
}

public byte[] GetCert()
public X509Certificate2 GetAppCert()
{
return _appCertBytes;
return _appCert;
}

public void Disconnect(string sessionID)
Expand Down
10 changes: 6 additions & 4 deletions Pages/UABrowser.razor
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
[Parameter]
public string Password { get; set; } = string.Empty;

[Parameter]
public string StatusMessage { get; set; } = string.Empty;

[Parameter]
public string SessionId { get; set; } = string.Empty;

private class UANode
{
public string Text { get; set; } = string.Empty;
Expand All @@ -64,10 +70,6 @@
private string NodeValue { get; set; } = string.Empty;
private bool NodeNotPublishable { get; set; } = true;

private string StatusMessage { get; set; } = string.Empty;

private string SessionId { get; set; } = Guid.NewGuid().ToString();

protected override void OnInitialized()
{
UANodes = GetRootNodeAsync().GetAwaiter().GetResult();
Expand Down
10 changes: 9 additions & 1 deletion Views/Browser/Browse.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@
<br />

<p>
<component>@(await Html.RenderComponentAsync<UABrowser>(RenderMode.Server, new { EndpointUrl = Model.EndpointUrl, Username = Model.UserName, Password = Model.Password }).ConfigureAwait(false))</component>
<component>@(await Html.RenderComponentAsync<UABrowser>(
RenderMode.Server,
new {
EndpointUrl = Model.EndpointUrl,
Username = Model.UserName,
Password = Model.Password,
SessionId = Model.SessionId,
StatusMessage = Model.StatusMessage
}).ConfigureAwait(false))</component>
</p>

<p>
Expand Down

0 comments on commit 57fa158

Please sign in to comment.