/// <summary> /// Uninstalls a UA application. /// </summary> public static async Task UninstallApplication(InstalledApplication application) { // 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); if (configurationFile != null) { // load the current configuration. Opc.Ua.Security.SecuredApplication security = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // delete the application certificates. if (application.DeleteCertificatesOnUninstall) { CertificateIdentifier id = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(security.ApplicationCertificate); // delete public key from trusted peers certificate store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(security.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2Collection peerCertificates = await store.FindByThumbprint(id.Thumbprint); if (peerCertificates.Count > 0) { await store.Delete(peerCertificates[0].Thumbprint); } } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // delete private key from application certificate store. try { using (ICertificateStore store = id.OpenStore()) { await store.Delete(id.Thumbprint); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // permentently delete any UA defined stores if they are now empty. try { WindowsCertificateStore store = new WindowsCertificateStore(); await store.Open("LocalMachine\\UA Applications"); X509Certificate2Collection collection = await store.Enumerate(); if (collection.Count == 0) { store.PermanentlyDeleteStore(); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } } // remove the permissions for the HTTP endpoints used by the application. if (application.BaseAddresses != null && application.BaseAddresses.Count > 0) { List <ApplicationAccessRule> noRules = new List <ApplicationAccessRule>(); for (int ii = 0; ii < application.BaseAddresses.Count; ii++) { Uri url = Utils.ParseUri(application.BaseAddresses[ii]); if (url != null) { try { HttpAccessRule.SetAccessRules(url, noRules, true); Utils.Trace("Removed HTTP access rules for URL: {0}", url); } catch (Exception e) { Utils.Trace("Could not remove HTTP access rules for URL: {0}. Error={1}", url, e.Message); } } } } } }
private void DeleteMI_Click(object sender, EventArgs e) { try { if (ItemsLV.SelectedItems.Count < 1) { return; } DialogResult result = MessageBox.Show( "Are you sure you wish to delete the rules from the list?", "Delete Certificate", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); if (result != DialogResult.Yes) { return; } // remove the items. Dictionary <string, List <HttpAccessRule> > rulesToDelete = new Dictionary <string, List <HttpAccessRule> >(); while (ItemsLV.SelectedItems.Count > 0) { HttpAccessRule rule = ItemsLV.SelectedItems[0].Tag as HttpAccessRule; List <HttpAccessRule> rules = null; if (!rulesToDelete.TryGetValue(rule.UrlPrefix, out rules)) { rulesToDelete[rule.UrlPrefix] = rules = new List <HttpAccessRule>(); } rules.Add(rule); ItemsLV.SelectedItems[0].Remove(); } // delete rules. foreach (KeyValuePair <string, List <HttpAccessRule> > pair in rulesToDelete) { IList <HttpAccessRule> existingRules = HttpAccessRule.GetAccessRules(pair.Key); List <HttpAccessRule> remainingRules = new List <HttpAccessRule>(); for (int ii = 0; ii < existingRules.Count; ii++) { HttpAccessRule existingRule = existingRules[ii]; bool found = false; for (int jj = 0; jj < pair.Value.Count; jj++) { HttpAccessRule ruleToDelete = pair.Value[jj]; if (ruleToDelete.IdentityName == existingRule.IdentityName) { continue; } if (ruleToDelete.Right == existingRule.Right) { continue; } found = true; break; } if (!found) { remainingRules.Add(existingRule); } } HttpAccessRule.SetAccessRules(pair.Key, remainingRules, true); } } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
/// <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); } } } }