/// <summary>
/// Installs a UA application.
/// </summary>
public static async Task InstallApplication(
InstalledApplication application,
bool autostart,
bool configureFirewall)
{
// validate the executable file.
string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false);
// get the default application name from the executable file.
FileInfo executableFileInfo = new FileInfo(executableFile);
string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length - 4);
// choose a default configuration file.
if (String.IsNullOrEmpty(application.ConfigurationFile))
{
application.ConfigurationFile = Utils.Format(
"{0}\\{1}.Config.xml",
executableFileInfo.DirectoryName,
applicationName);
}
// validate the configuration file.
string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false);
// create a new file if one does not exist.
bool useExisting = true;
if (configurationFile == null)
{
configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, true, true);
useExisting = false;
}
// create the default configuration file.
if (useExisting)
{
try
{
Opc.Ua.Security.SecuredApplication existingSettings = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile);
// copy current settings
application.ApplicationType = existingSettings.ApplicationType;
application.BaseAddresses = existingSettings.BaseAddresses;
application.ApplicationCertificate = existingSettings.ApplicationCertificate;
application.ApplicationName = existingSettings.ApplicationName;
application.ProductName = existingSettings.ProductName;
application.RejectedCertificatesStore = existingSettings.RejectedCertificatesStore;
application.TrustedCertificateStore = existingSettings.TrustedCertificateStore;
application.TrustedCertificates = existingSettings.TrustedCertificates;
application.IssuerCertificateStore = existingSettings.IssuerCertificateStore;
application.IssuerCertificates = application.IssuerCertificates;
application.UseDefaultCertificateStores = false;
}
catch (Exception e)
{
useExisting = false;
Utils.Trace("WARNING. Existing configuration file could not be loaded: {0}.\r\nReplacing with default: {1}", e.Message, configurationFile);
File.Copy(configurationFile, configurationFile + ".bak", true);
}
}
// create the configuration file from the default.
if (!useExisting)
{
try
{
string installationFile = Utils.Format(
"{0}\\Install\\{1}.Config.xml",
executableFileInfo.Directory.Parent.FullName,
applicationName);
if (!File.Exists(installationFile))
{
Utils.Trace("Could not find default configuation at: {0}", installationFile);
}
File.Copy(installationFile, configurationFile, true);
Utils.Trace("File.Copy({0}, {1})", installationFile, configurationFile);
}
catch (Exception e)
{
Utils.Trace("Could not copy default configuation to: {0}. Error={1}.", configurationFile, e.Message);
}
}
// create a default application name.
if (String.IsNullOrEmpty(application.ApplicationName))
{
application.ApplicationName = applicationName;
}
// create a default product name.
if (String.IsNullOrEmpty(application.ProductName))
{
application.ProductName = application.ApplicationName;
}
// create a default uri.
if (String.IsNullOrEmpty(application.ApplicationUri))
{
application.ApplicationUri = Utils.Format("http://localhost/{0}/{1}", applicationName, Guid.NewGuid());
}
// make the uri specify the local machine.
application.ApplicationUri = Utils.ReplaceLocalhost(application.ApplicationUri);
// set a default application store.
if (application.ApplicationCertificate == null)
{
application.ApplicationCertificate = new Opc.Ua.Security.CertificateIdentifier();
application.ApplicationCertificate.StoreType = Utils.DefaultStoreType;
application.ApplicationCertificate.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault";
}
if (application.UseDefaultCertificateStores)
{
if (application.IssuerCertificateStore == null)
{
application.IssuerCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier();
application.IssuerCertificateStore.StoreType = Utils.DefaultStoreType;
application.IssuerCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault";
}
if (application.TrustedCertificateStore == null)
{
application.TrustedCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier();
application.TrustedCertificateStore.StoreType = Utils.DefaultStoreType;
application.TrustedCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault";
}
try
{
Utils.GetAbsoluteDirectoryPath(application.TrustedCertificateStore.StorePath, true, true, true);
}
catch (Exception e)
{
Utils.Trace("Could not access the machine directory: {0} '{1}'", application.RejectedCertificatesStore.StorePath, e);
}
if (application.RejectedCertificatesStore == null)
{
application.RejectedCertificatesStore = new Opc.Ua.Security.CertificateStoreIdentifier();
application.RejectedCertificatesStore.StoreType = CertificateStoreType.Directory;
application.RejectedCertificatesStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\RejectedCertificates";
StringBuilder buffer = new StringBuilder();
buffer.Append(ApplicationData.Current.LocalFolder.Path);
buffer.Append("\\OPC Foundation");
buffer.Append("\\RejectedCertificates");
string folderPath = buffer.ToString();
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
}
}
// check for valid certificate (discard invalid certificates).
CertificateIdentifier applicationCertificate = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(application.ApplicationCertificate);
X509Certificate2 certificate = await applicationCertificate.Find(true);
if (certificate == null)
{
certificate = await applicationCertificate.Find(false);
if (certificate != null)
{
Utils.Trace(
"Found existing certificate but it does not have a private key: Store={0}, Certificate={1}",
application.ApplicationCertificate.StorePath,
application.ApplicationCertificate);
}
else
{
Utils.Trace(
"Existing certificate could not be found: Store={0}, Certificate={1}",
application.ApplicationCertificate.StorePath,
application.ApplicationCertificate);
}
}
// check if no certificate exists.
if (certificate == null)
{
certificate = await CreateCertificateForApplication(application);
}
// ensure the application certificate is in the trusted peers store.
try
{
CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.TrustedCertificateStore);
using (ICertificateStore store = certificateStore.OpenStore())
{
X509Certificate2Collection peerCertificates = await store.FindByThumbprint(certificate.Thumbprint);
if (peerCertificates.Count == 0)
{
await store.Add(new X509Certificate2(certificate.RawData));
}
}
}
catch (Exception e)
{
Utils.Trace(
"Could not add certificate '{0}' to trusted peer store '{1}'. Error={2}",
certificate.Subject,
application.TrustedCertificateStore,
e.Message);
}
// update configuration file location.
UpdateConfigurationLocation(executableFile, configurationFile);
// update configuration file.
new Opc.Ua.Security.SecurityConfigurationManager().WriteConfiguration(configurationFile, application);
ApplicationAccessRuleCollection accessRules = application.AccessRules;
bool noRulesDefined = application.AccessRules == null || application.AccessRules.Count == 0;
// add the default access rules.
if (noRulesDefined)
{
ApplicationAccessRule rule = new ApplicationAccessRule();
rule.IdentityName = WellKnownSids.Administrators;
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Configure;
accessRules.Add(rule);
rule = new ApplicationAccessRule();
rule.IdentityName = WellKnownSids.Users;
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Update;
accessRules.Add(rule);
}
// ensure the service account has priviledges.
if (application.InstallAsService)
{
// check if a specific account is assigned.
AccountInfo accountInfo = null;
if (!String.IsNullOrEmpty(application.ServiceUserName))
{
accountInfo = AccountInfo.Create(application.ServiceUserName);
}
// choose a built-in service account.
if (accountInfo == null)
{
accountInfo = AccountInfo.Create(WellKnownSids.NetworkService);
if (accountInfo == null)
{
accountInfo = AccountInfo.Create(WellKnownSids.LocalSystem);
}
}
ApplicationAccessRule rule = new ApplicationAccessRule();
rule.IdentityName = accountInfo.ToString();
rule.RuleType = AccessControlType.Allow;
rule.Right = ApplicationAccessRight.Run;
accessRules.Add(rule);
}
// set the permissions for the HTTP endpoints used by the application.
if (configureFirewall && application.BaseAddresses != null && application.BaseAddresses.Count > 0)
{
for (int ii = 0; ii < application.BaseAddresses.Count; ii++)
{
Uri url = Utils.ParseUri(application.BaseAddresses[ii]);
if (url != null)
{
try
{
HttpAccessRule.SetAccessRules(url, accessRules, true);
Utils.Trace("Added HTTP access rules for URL: {0}", url);
}
catch (Exception e)
{
Utils.Trace("Could not set HTTP access rules for URL: {0}. Error={1}", url, e.Message);
for (int jj = 0; jj < accessRules.Count; jj++)
{
ApplicationAccessRule rule = accessRules[jj];
Utils.Trace(
(int)Utils.TraceMasks.Error,
"IdentityName={0}, Right={1}, RuleType={2}",
rule.IdentityName,
rule.Right,
rule.RuleType);
}
}
}
}
}
// set permissions on the local certificate store.
SetCertificatePermissions(
application,
applicationCertificate,
accessRules,
false);
// set permissions on the local certificate store.
if (application.RejectedCertificatesStore != null)
{
// need to grant full control to certificates in the RejectedCertificatesStore.
foreach (ApplicationAccessRule rule in accessRules)
{
if (rule.RuleType == AccessControlType.Allow)
{
rule.Right = ApplicationAccessRight.Configure;
}
}
CertificateStoreIdentifier rejectedCertificates = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.RejectedCertificatesStore);
using (ICertificateStore store = rejectedCertificates.OpenStore())
{
if (store.SupportsAccessControl)
{
store.SetAccessRules(accessRules, false);
}
}
}
}