#define TRACE using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Security; using System.ServiceModel; using System.ServiceModel.Discovery; using System.Text; using System.Xml; using ArchestrAServices.Common; using ArchestrAServices.Contract; using ArchestrAServices.Proxy; namespace ASBClientAccessLayer; public class ASBClient : IASBClient1, IASBClient { private ManageASBSecurityProxy AsbSecurityProxy; public bool Connected { get { if (AsbSecurityProxy != null && AsbSecurityProxy.State == CommunicationState.Opened) { return AsbSecurityProxy.SecureSessionEstablished; } return false; } } public ASBClient() { AsbSecurityProxy = null; } public ASBClient(string SrNodeName) { AsbSecurityProxy = new ManageASBSecurityProxy(SrNodeName); string errorMessage = string.Empty; if (!AsbSecurityProxy.Connect(string.Empty, out errorMessage)) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, "Error opening persistent endpoint to System Authentication service on node {0}: {1}", SrNodeName, errorMessage); } } public bool Reconnect() { if (AsbSecurityProxy != null) { AsbSecurityProxy.Disconnect(); string errorMessage = string.Empty; if (!AsbSecurityProxy.Connect(string.Empty, out errorMessage)) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, "Error re-opening persistent endpoint to System Authentication service on node {0}: {1}", AsbSecurityProxy.SRNodeName, errorMessage); return false; } return true; } return false; } public bool Disconnect() { if (AsbSecurityProxy != null) { AsbSecurityProxy.Disconnect(); return true; } return false; } public ArchestrAResult OpenTemporaryRegistrationEndpoint(string repositoryNode, SecureString passphrase) { ArchestrAResult archestrAResult = ResultFactory.MakeResult(ArchestrAError.BadNoCommunication, 0); string errorMessage = string.Empty; ManageASBSecurityProxy asbSecurityProxy = AsbSecurityProxy; if (asbSecurityProxy == null) { using (asbSecurityProxy = new ManageASBSecurityProxy(repositoryNode)) { asbSecurityProxy.Connect(string.Empty, out errorMessage); EnableRegistration(archestrAResult, asbSecurityProxy, passphrase, out errorMessage); } } else { EnableRegistration(archestrAResult, asbSecurityProxy, passphrase, out errorMessage); } return archestrAResult; } private ArchestrAResult EnableRegistration(ArchestrAResult archestrAResult, ManageASBSecurityProxy Proxy, SecureString passphrase, out string errorMessage) { errorMessage = string.Empty; if (Proxy.State == CommunicationState.Opened && Proxy.SecureSessionEstablished) { archestrAResult = Proxy.RegisterServiceBusEnable(new SystemAuthenticationASBConfiguration { solutionName = "EnableRegistration", EncryptedSharedSecret = Encoding.ASCII.GetBytes(ConvertToString(passphrase)) }); if (archestrAResult.Status != 0) { errorMessage = "failed to open registration endpoint"; } } return archestrAResult; } public ArchestrAResult CloseTemporaryRegistrationEndpoint(string repositoryNode) { ArchestrAResult archestrAResult = ResultFactory.MakeResult(ArchestrAError.BadNoCommunication, 0); string errorMessage = string.Empty; ManageASBSecurityProxy asbSecurityProxy = AsbSecurityProxy; if (asbSecurityProxy == null) { using (asbSecurityProxy = new ManageASBSecurityProxy(repositoryNode)) { asbSecurityProxy.Connect(string.Empty, out errorMessage); DisableRegistration(archestrAResult, asbSecurityProxy, out errorMessage); } } else { DisableRegistration(archestrAResult, asbSecurityProxy, out errorMessage); } return archestrAResult; } private ArchestrAResult DisableRegistration(ArchestrAResult archestrAResult, ManageASBSecurityProxy Proxy, out string errorMessage) { errorMessage = string.Empty; if (Proxy.State == CommunicationState.Opened && Proxy.SecureSessionEstablished) { archestrAResult = Proxy.RegisterServiceBusEnable(new SystemAuthenticationASBConfiguration { solutionName = "DisableRegistration", EncryptedSharedSecret = null }); if (archestrAResult.Status != 0) { errorMessage = "failed to close registration endpoint"; } } return archestrAResult; } public ArchestrAResult OpenTemporaryPairingEndpoint(string repositoryNode, SecureString passphrase) { ArchestrAResult archestrAResult = ResultFactory.MakeResult(ArchestrAError.BadNoCommunication, 0); string errorMessage = string.Empty; ManageASBSecurityProxy asbSecurityProxy = AsbSecurityProxy; if (asbSecurityProxy == null) { using (asbSecurityProxy = new ManageASBSecurityProxy(repositoryNode)) { asbSecurityProxy.Connect(string.Empty, out errorMessage); EnablePairing(archestrAResult, asbSecurityProxy, passphrase, out errorMessage); } } else { EnablePairing(archestrAResult, asbSecurityProxy, passphrase, out errorMessage); } return archestrAResult; } private ArchestrAResult EnablePairing(ArchestrAResult archestrAResult, ManageASBSecurityProxy Proxy, SecureString passphrase, out string errorMessage) { errorMessage = string.Empty; if (Proxy.State == CommunicationState.Opened && Proxy.SecureSessionEstablished) { archestrAResult = Proxy.RegisterServiceBusEnable(new SystemAuthenticationASBConfiguration { solutionName = "EnablePairing", EncryptedSharedSecret = Encoding.ASCII.GetBytes(ConvertToString(passphrase)) }); if (archestrAResult.Status != 0) { errorMessage = "failed to open pairing endpoint"; } } return archestrAResult; } public ArchestrAResult CloseTemporaryPairingEndpoint(string repositoryNode) { ArchestrAResult archestrAResult = ResultFactory.MakeResult(ArchestrAError.BadNoCommunication, 0); string errorMessage = string.Empty; ManageASBSecurityProxy asbSecurityProxy = AsbSecurityProxy; if (asbSecurityProxy == null) { using (asbSecurityProxy = new ManageASBSecurityProxy(repositoryNode)) { asbSecurityProxy.Connect(string.Empty, out errorMessage); DisablePairing(archestrAResult, asbSecurityProxy, out errorMessage); } } else { DisablePairing(archestrAResult, asbSecurityProxy, out errorMessage); } return archestrAResult; } private ArchestrAResult DisablePairing(ArchestrAResult archestrAResult, ManageASBSecurityProxy Proxy, out string errorMessage) { errorMessage = string.Empty; if (Proxy.State == CommunicationState.Opened && Proxy.SecureSessionEstablished) { archestrAResult = Proxy.RegisterServiceBusEnable(new SystemAuthenticationASBConfiguration { solutionName = "DisablePairing", EncryptedSharedSecret = null }); if (archestrAResult.Status != 0) { errorMessage = "failed to close pairing endpoint"; } } return archestrAResult; } public ArchestrAResult GetRegistrationEndpointStatus(string repositoryNode, out List ConfigurationData) { ConfigurationData = new List(); ArchestrAResult archestrAResult = ResultFactory.MakeResult(ArchestrAError.BadNoCommunication, 0); string errorMessage = string.Empty; SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "GetRegistrationEndpointStatus: Creating new ManageASBSecurityProxy for {0}", repositoryNode); ManageASBSecurityProxy asbSecurityProxy = AsbSecurityProxy; if (asbSecurityProxy == null) { using (asbSecurityProxy = new ManageASBSecurityProxy(repositoryNode)) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "GetRegistrationEndpointStatus: Calling Connect with empty passphrase"); asbSecurityProxy.Connect(string.Empty, out errorMessage); RetrieveTemporaryEndpoint(archestrAResult, asbSecurityProxy, ConfigurationData, out errorMessage); } } else { RetrieveTemporaryEndpoint(archestrAResult, asbSecurityProxy, ConfigurationData, out errorMessage); } return archestrAResult; } private ArchestrAResult RetrieveTemporaryEndpoint(ArchestrAResult archestrAResult, ManageASBSecurityProxy Proxy, List ConfigurationData, out string errorMessage) { errorMessage = string.Empty; if (Proxy.State == CommunicationState.Opened && Proxy.SecureSessionEstablished) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "GetRegistrationEndpointStatus: Calling GetRegistrationEndpointStatus"); archestrAResult = Proxy.GetRegistrationEndpointStatus(out var ConfigurationData2); if (archestrAResult.Status != 0) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "GetRegistrationEndpointStatus: failed to retrieve temporary endpoint status: {0}", archestrAResult.Status); errorMessage = "failed to retrieve temporary endpoint status"; } else { StatusTemporaryEndpoint[] array = ConfigurationData2; for (int i = 0; i < array.Length; i++) { StatusTemporaryEndpoint statusTemporaryEndpoint = array[i]; ConfigurationData.Add(new TemporaryEndpointStatus { EndpointName = statusTemporaryEndpoint.EndpointName, EndpointState = (TemporaryEndpointState)Enum.Parse(typeof(TemporaryEndpointState), statusTemporaryEndpoint.EndpointState, ignoreCase: true) }); } } } return archestrAResult; } public RegistrationResult RegisterWithSR(string repositoryNode, SecureString passphrase) { string value = new ManageSecurityConfiguration().Registration(AsbSecurityProxy, repositoryNode, ConvertToString(passphrase), null, isRegister: true); RegistrationResult result = RegistrationResult.Success; if (!string.IsNullOrEmpty(value)) { result = RegistrationResult.RepositoryNodeNotConfigured; } return result; } public RegistrationResult CopySolutionFromSR(string repositoryNode, SecureString passphrase, string solutionName) { string value = new ManageSecurityConfiguration().Registration(AsbSecurityProxy, repositoryNode, ConvertToString(passphrase), solutionName, isRegister: false); RegistrationResult result = RegistrationResult.Success; if (!string.IsNullOrEmpty(value)) { result = RegistrationResult.RepositoryNodeNotConfigured; } return result; } public RegistrationResult RemoveSolutionFromThisNode(string solutionName) { if (string.IsNullOrEmpty(solutionName)) { return RegistrationResult.NodeInaccessible; } string value = RegistryHandler.DeleteFromRegistry(solutionName); RegistrationResult result = RegistrationResult.Success; if (!string.IsNullOrEmpty(value)) { result = RegistrationResult.RepositoryNodeNotConfigured; } return result; } public string GetPassphraseForSolution(string solutionName) { return new ManageSecurityConfiguration().GetPassphraseForSolution(solutionName); } public RegistrationResult UnregisterWithSR(string repositoryNode) { string text = new ManageSecurityConfiguration().UnRegistration(repositoryNode); RegistrationResult result = RegistrationResult.Success; if (!string.IsNullOrEmpty(text)) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, string.Format("UnregisterWithSR({0}) failed: {1}", string.IsNullOrEmpty(repositoryNode) ? "" : repositoryNode, text)); result = RegistrationResult.RepositoryNodeNotConfigured; } return result; } public RegistrationResult PairSRNodes(string remoteRepositoryNode, SecureString passphrase) { RegistrationResult result = RegistrationResult.Success; SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, $"PairSRNodes Enter: {remoteRepositoryNode}"); ManageSecurityConfiguration manageSecurityConfiguration = new ManageSecurityConfiguration(); string SRNodeName = string.Empty; RegistryHandler.GetSrNode(out SRNodeName); if (HostNameValidator.IsRemoteNodeSameasSRNode(remoteRepositoryNode, SRNodeName)) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "PairSRNodes failed: Pairing to same SRNode is not allowed"); result = RegistrationResult.NodeInaccessible; } else { string text = manageSecurityConfiguration.PairDefaultSRwithRemoteSR(remoteRepositoryNode, ConvertToString(passphrase)); if (!string.IsNullOrEmpty(text)) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, $"PairSRNodes failed: {text}"); result = RegistrationResult.RepositoryNodeNotConfigured; } } return result; } public RegistrationResult UnpairSRNodes(string remoteRepositoryNode) { string SRNodeName = string.Empty; RegistryHandler.GetSrNode(out SRNodeName); RegistrationResult result = RegistrationResult.Success; if (HostNameValidator.IsRemoteNodeSameasSRNode(remoteRepositoryNode, SRNodeName)) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "UnPairSRNode failed: Un-pairing to same SRNode is not allowed"); result = RegistrationResult.NodeInaccessible; } else { string remoteSolutionName = "Archestra_" + remoteRepositoryNode; SvcTrace.DiagControl.TraceEvent(TraceEventType.Information, 0, string.Format("UnpairSRNodes called for solution '{0}'", string.IsNullOrEmpty(remoteRepositoryNode) ? "" : remoteRepositoryNode)); SynchronizeSolutionsWithSR(); string text = new ManageSecurityConfiguration().UnpairDefaultSRfromRemoteSR(remoteSolutionName); if (!string.IsNullOrEmpty(text)) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, $"UnpairSRNodes failed: {text}"); result = RegistrationResult.RepositoryNodeNotConfigured; } } return result; } public string GetChangedASBExtraInfo() { SynchronizeSolutionsWithSR(); string empty = string.Empty; string XMLExtraInfo = string.Empty; string SRNodeName = string.Empty; empty = RegistryHandler.GetSrNode(out SRNodeName); if (!string.IsNullOrEmpty(SRNodeName)) { ManageASBSecurityProxy asbSecurityProxy = AsbSecurityProxy; if (asbSecurityProxy == null) { using (asbSecurityProxy = new ManageASBSecurityProxy(SRNodeName)) { asbSecurityProxy.Connect(string.Empty, out empty); RetrieveExtraInfoChanges(asbSecurityProxy, out XMLExtraInfo, out empty); } } else { RetrieveExtraInfoChanges(asbSecurityProxy, out XMLExtraInfo, out empty); } } else { empty = "No repository node is registered"; } return XMLExtraInfo; } private void RetrieveExtraInfoChanges(ManageASBSecurityProxy Proxy, out string XMLExtraInfo, out string errorMessage) { XMLExtraInfo = string.Empty; errorMessage = string.Empty; if (Proxy.State == CommunicationState.Opened && Proxy.SecureSessionEstablished && Proxy.QueryExtraInfoChanges(out XMLExtraInfo, Environment.MachineName).Status != 0) { errorMessage = "failed to retrieve temporary endpoint status"; } } private void SynchronizeSolutionsWithSR() { if (!string.IsNullOrEmpty(RegistryHandler.GetDefaultSolutionName(out var DefaultSolutionName)) || !string.IsNullOrEmpty(RegistryHandler.GetSrNode(DefaultSolutionName, out var SRNodeName)) || !string.IsNullOrEmpty(RegistryHandler.GetSolutionPassphrase(DefaultSolutionName, out var passphrase))) { return; } using SecureString secureString = new SecureString(); string text = passphrase; foreach (char c in text) { secureString.AppendChar(c); } List pairedSolutionsInSR = GetPairedSolutionsInSR(SRNodeName); List solutionsAtThisNode = GetSolutionsAtThisNode(); if (!pairedSolutionsInSR.Any() || !solutionsAtThisNode.Any()) { return; } Dictionary dictionary = new Dictionary(); foreach (string item in pairedSolutionsInSR) { dictionary.Add(item, 0); } Dictionary dictionary2 = new Dictionary(); foreach (string item2 in solutionsAtThisNode) { dictionary2.Add(item2, 0); } int value; foreach (string item3 in pairedSolutionsInSR) { if (item3 != DefaultSolutionName && !dictionary2.TryGetValue(item3, out value)) { CopySolutionFromSR(SRNodeName, secureString, item3); } } foreach (string item4 in solutionsAtThisNode) { if (item4 != DefaultSolutionName && !dictionary.TryGetValue(item4, out value)) { RemoveSolutionFromThisNode(item4); } } } public List GetPairedSolutionsInSR(string repositoryNode) { List SolutionNames = new List(); new ManageSecurityConfiguration().GetSolutionsPairedWithSR(AsbSecurityProxy, repositoryNode, out SolutionNames); return SolutionNames; } public List GetSolutionsAtThisNode() { return RegistryHandler.EnumerateSolutionsAtThisNode(); } public string GetDiscoveryEndpoint() { return SvcUtilities.GetDiscoveryEndpoint(); } public FindResponse FindServices(FindCriteria findCriteria, out ASBDiscoveryResult Result) { Result = ASBDiscoveryResult.Unknown; string text = SvcUtilities.GetDiscoveryEndpoint(); if (!string.IsNullOrEmpty(text)) { if (!text.ToLower().EndsWith("/probe")) { text += "/Probe"; } return InternalFindServices(text, findCriteria, out Result); } Result = ASBDiscoveryResult.DiscoveryNotAvailable; return null; } public EndpointDiscoveryMetadata FindServiceEndpoint(Type ContractType, Uri[] Scopes, out ASBDiscoveryResult Result) { Result = ASBDiscoveryResult.Unknown; string text = SvcUtilities.GetDiscoveryEndpoint(); if (!string.IsNullOrEmpty(text)) { if (!text.ToLower().EndsWith("/probe")) { text += "/Probe"; } Uri probeEndpointAddress = new Uri(text); return InternalFindServiceEndpoint(ContractType.Name, Scopes, probeEndpointAddress, out Result); } Result = ASBDiscoveryResult.DiscoveryNotAvailable; return null; } public RegistrationResult UnPairRemoteSR(string RemoteRepositoryNode, out string errorMessage) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Information, 0, "UnPairRemoteSR Entered"); string SRNodeName = string.Empty; errorMessage = string.Empty; RegistryHandler.GetSrNode(out SRNodeName); RegistrationResult registrationResult = RegistrationResult.Success; if (HostNameValidator.IsRemoteNodeSameasSRNode(RemoteRepositoryNode, SRNodeName)) { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "UnPairRemoteSR failed: Un-pairing to same SRNode is not allowed"); registrationResult = RegistrationResult.NodeInaccessible; } else { string remoteSolutionName = "Archestra_" + RemoteRepositoryNode; SvcTrace.DiagControl.TraceEvent(TraceEventType.Information, 0, string.Format("UnPairRemoteSR called for solution '{0}'", string.IsNullOrEmpty(RemoteRepositoryNode) ? "" : RemoteRepositoryNode)); SynchronizeSolutionsWithSR(); registrationResult = new ManageSecurityConfiguration().UnPairRemoteSR(remoteSolutionName, out errorMessage); if (registrationResult != RegistrationResult.Success) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, $"UnPairRemoteSR failed: {errorMessage}"); } } SvcTrace.DiagControl.TraceEvent(TraceEventType.Information, 0, "UnPairRemoteSR Exit"); return registrationResult; } public static string ConvertToString(SecureString password) { if (password == null) { return string.Empty; } IntPtr intPtr = IntPtr.Zero; try { intPtr = Marshal.SecureStringToGlobalAllocUnicode(password); return Marshal.PtrToStringUni(intPtr); } finally { Marshal.ZeroFreeGlobalAllocUnicode(intPtr); } } private FindResponse InternalFindServices(string discoveryendpoint, FindCriteria findiCriteria, out ASBDiscoveryResult Result) { if (string.IsNullOrEmpty(discoveryendpoint)) { Result = ASBDiscoveryResult.DiscoveryBadParameters; return null; } if (findiCriteria == null) { Result = ASBDiscoveryResult.DiscoveryBadParameters; return null; } Result = ASBDiscoveryResult.Unknown; try { Uri uri = new Uri(discoveryendpoint); EndpointAddress endpointAddress = new EndpointAddress(uri); using DiscoveryClient discoveryClient = new DiscoveryClient(new DiscoveryEndpoint(SvcUtilities.GetBinding(uri.ToString()), endpointAddress)); FindResponse findResponse = discoveryClient.Find(findiCriteria); if (findResponse != null && findResponse.Endpoints.Count > 0) { Result = ASBDiscoveryResult.Success; } else { Result = ASBDiscoveryResult.DiscoveryReturnedNoEndpoints; } return findResponse; } catch (Exception) { } return null; } private EndpointDiscoveryMetadata InternalFindServiceEndpoint(string ContractName, Uri[] Scopes, Uri probeEndpointAddress, out ASBDiscoveryResult Result) { if (string.IsNullOrEmpty(ContractName)) { Result = ASBDiscoveryResult.DiscoveryBadParameters; return null; } if (probeEndpointAddress == null) { Result = ASBDiscoveryResult.DiscoveryBadParameters; return null; } EndpointAddress endpointAddress = new EndpointAddress(probeEndpointAddress); using (DiscoveryClient discoveryClient = new DiscoveryClient(new DiscoveryEndpoint(SvcUtilities.GetBinding(probeEndpointAddress.ToString()), endpointAddress))) { FindCriteria findCriteria = new FindCriteria(); Result = ASBDiscoveryResult.Unknown; try { XmlQualifiedName item = new XmlQualifiedName(ContractName, "http://ArchestrAServices.Contract"); findCriteria.ContractTypeNames.Add(item); findCriteria.Scopes.Concat(Scopes.ToList()); FindResponse findResponse = discoveryClient.Find(findCriteria); if (findResponse != null && findResponse.Endpoints.Count > 0) { Result = ASBDiscoveryResult.Success; return findResponse.Endpoints[0]; } Result = ASBDiscoveryResult.DiscoveryReturnedNoEndpoints; } catch (TargetInvocationException) { } catch (UriFormatException) { } } return null; } }