Skip to content

Commit

Permalink
Add a no file fluent API for application configuration. (#1422)
Browse files Browse the repository at this point in the history
* Add no file configuration fluent API
* ensure secure settings are produced by default
* most if not all settings can be reached by .Set/.Add functions
* switched gds tests to use no file config (also good as starter)
  • Loading branch information
mregen committed Jun 15, 2021
1 parent 24f90c4 commit 96ecb4d
Show file tree
Hide file tree
Showing 19 changed files with 2,157 additions and 160 deletions.
880 changes: 880 additions & 0 deletions Libraries/Opc.Ua.Configuration/ApplicationConfigurationBuilder.cs

Large diffs are not rendered by default.

173 changes: 126 additions & 47 deletions Libraries/Opc.Ua.Configuration/ApplicationInstance.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ========================================================================
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
Expand Down Expand Up @@ -29,31 +29,14 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace Opc.Ua.Configuration
{
/// <summary>
/// Interface to create application callbacks.
/// </summary>
public abstract class IApplicationMessageDlg
{
/// <summary>
/// The application message.
/// </summary>
/// <param name="text">The text of the message.</param>
/// <param name="ask">If the application should ask the user.</param>
public abstract void Message(string text, Boolean ask = false);

/// <summary>
/// Show the message and return result.
/// </summary>
public abstract Task<bool> ShowAsync();
}

/// <summary>
/// A class that install, configures and runs a UA application.
/// </summary>
Expand Down Expand Up @@ -133,12 +116,6 @@ public ApplicationConfiguration ApplicationConfiguration
set { m_applicationConfiguration = value; }
}

/// <summary>
/// Gets or sets a flag that indicates whether the application will be set up for management with the GDS agent.
/// </summary>
/// <value>If true the application will not be visible to the GDS local agent after installation.</value>
public bool NoGdsAgentAdmin { get; set; }

/// <summary>
/// Get or set the message dialog.
/// </summary>
Expand Down Expand Up @@ -195,48 +172,76 @@ public void Stop()
{
m_server.Stop();
}
#endregion

#region Static Methods
/// <summary>
/// Helper to replace localhost with the hostname
/// in the application uri and base adresses of the
/// configuration.
/// Loads the configuration.
/// </summary>
/// <param name="configuration"></param>
public static ApplicationConfiguration FixupAppConfig(
ApplicationConfiguration configuration)
public async Task<ApplicationConfiguration> LoadAppConfig(
bool silent,
string filePath,
ApplicationType applicationType,
Type configurationType,
bool applyTraceSettings,
ICertificatePasswordProvider certificatePasswordProvider = null)
{
configuration.ApplicationUri = Utils.ReplaceLocalhost(configuration.ApplicationUri);
if (configuration.ServerConfiguration != null)
Utils.Trace(Utils.TraceMasks.Information, "Loading application configuration file. {0}", filePath);

try
{
for (int i = 0; i < configuration.ServerConfiguration.BaseAddresses.Count; i++)
// load the configuration file.
ApplicationConfiguration configuration = await ApplicationConfiguration.Load(
new System.IO.FileInfo(filePath),
applicationType,
configurationType,
applyTraceSettings,
certificatePasswordProvider)
.ConfigureAwait(false);

if (configuration == null)
{
configuration.ServerConfiguration.BaseAddresses[i] =
Utils.ReplaceLocalhost(configuration.ServerConfiguration.BaseAddresses[i]);
return null;
}

return configuration;
}
catch (Exception e)
{
Utils.Trace(e, "Could not load configuration file. {0}", filePath);

// warn user.
if (!silent)
{
if (MessageDlg != null)
{
MessageDlg.Message("Load Application Configuration: " + e.Message);
await MessageDlg.ShowAsync().ConfigureAwait(false);
}

throw;
}

return null;
}
return configuration;
}

/// <summary>
/// Loads the configuration.
/// </summary>
public static async Task<ApplicationConfiguration> LoadAppConfig(
public async Task<ApplicationConfiguration> LoadAppConfig(
bool silent,
string filePath,
Stream stream,
ApplicationType applicationType,
Type configurationType,
bool applyTraceSettings,
ICertificatePasswordProvider certificatePasswordProvider = null)
{
Utils.Trace(Utils.TraceMasks.Information, "Loading application configuration file. {0}", filePath);
Utils.Trace(Utils.TraceMasks.Information, "Loading application from stream.");

try
{
// load the configuration file.
ApplicationConfiguration configuration = await ApplicationConfiguration.Load(
new System.IO.FileInfo(filePath),
stream,
applicationType,
configurationType,
applyTraceSettings,
Expand All @@ -252,7 +257,7 @@ public void Stop()
}
catch (Exception e)
{
Utils.Trace(e, "Could not load configuration file. {0}", filePath);
Utils.Trace(e, "Could not load configuration from stream.");

// warn user.
if (!silent)
Expand All @@ -270,6 +275,33 @@ public void Stop()
}
}

/// <summary>
/// Loads the application configuration.
/// </summary>
public async Task<ApplicationConfiguration> LoadApplicationConfiguration(Stream stream, bool silent)
{
ApplicationConfiguration configuration = null;

try
{
configuration = await LoadAppConfig(
silent, stream, ApplicationType, ConfigurationType, true, CertificatePasswordProvider)
.ConfigureAwait(false);
}
catch (Exception) when (silent)
{
}

if (configuration == null)
{
throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "Could not load configuration.");
}

m_applicationConfiguration = FixupAppConfig(configuration);

return configuration;
}

/// <summary>
/// Loads the application configuration.
/// </summary>
Expand Down Expand Up @@ -307,6 +339,32 @@ public async Task<ApplicationConfiguration> LoadApplicationConfiguration(bool si
return await LoadApplicationConfiguration(filePath, silent).ConfigureAwait(false);
}

/// <summary>
/// Create a builder for a UA application configuration.
/// </summary>
public IApplicationConfigurationBuilderTypes Build(
string applicationUri,
string productUri
)
{
// App Uri and cert subject
ApplicationConfiguration = new ApplicationConfiguration {
ApplicationName = this.ApplicationName,
ApplicationType = this.ApplicationType,
ApplicationUri = applicationUri,
ProductUri = productUri,
TraceConfiguration = new TraceConfiguration {
TraceMasks = Utils.TraceMasks.None
},
TransportQuotas = new TransportQuotas()
};

// Trace off
ApplicationConfiguration.TraceConfiguration.ApplySettings();

return new ApplicationConfigurationBuilder(this);
}

/// <summary>
/// Checks for a valid application instance certificate.
/// </summary>
Expand Down Expand Up @@ -436,7 +494,7 @@ public async Task<ApplicationConfiguration> LoadApplicationConfiguration(bool si
/// <summary>
/// Creates an application instance certificate if one does not already exist.
/// </summary>
private static async Task<bool> CheckApplicationInstanceCertificate(
private async Task<bool> CheckApplicationInstanceCertificate(
ApplicationConfiguration configuration,
X509Certificate2 certificate,
bool silent,
Expand Down Expand Up @@ -513,7 +571,7 @@ public async Task<ApplicationConfiguration> LoadApplicationConfiguration(bool si
/// <summary>
/// Checks that the domains in the server addresses match the domains in the certificates.
/// </summary>
private static async Task<bool> CheckDomainsInCertificate(
private async Task<bool> CheckDomainsInCertificate(
ApplicationConfiguration configuration,
X509Certificate2 certificate,
bool silent)
Expand Down Expand Up @@ -783,7 +841,7 @@ private static async Task AddToTrustedStore(ApplicationConfiguration configurati
/// <param name="message"></param>
/// <param name="silent"></param>
/// <returns>True if approved, false otherwise.</returns>
private static async Task<bool> ApproveMessage(string message, bool silent)
private async Task<bool> ApproveMessage(string message, bool silent)
{
if (!silent && MessageDlg != null)
{
Expand All @@ -796,6 +854,27 @@ private static async Task<bool> ApproveMessage(string message, bool silent)
return false;
}
}

/// <summary>
/// Helper to replace localhost with the hostname
/// in the application uri and base adresses of the
/// configuration.
/// </summary>
/// <param name="configuration"></param>
private static ApplicationConfiguration FixupAppConfig(
ApplicationConfiguration configuration)
{
configuration.ApplicationUri = Utils.ReplaceLocalhost(configuration.ApplicationUri);
if (configuration.ServerConfiguration != null)
{
for (int i = 0; i < configuration.ServerConfiguration.BaseAddresses.Count; i++)
{
configuration.ServerConfiguration.BaseAddresses[i] =
Utils.ReplaceLocalhost(configuration.ServerConfiguration.BaseAddresses[i]);
}
}
return configuration;
}
#endregion

#region Private Fields
Expand Down

0 comments on commit 96ecb4d

Please sign in to comment.