public bool TestPluginVaultConnection(ISafeguardConnection sgConnection, string pluginName) { var plugin = _configDb.GetPluginByName(pluginName); if (plugin?.VaultAccountId != null) { var pluginInstance = LoadedPlugins[pluginName]; if (pluginInstance != null) { try { RefreshPluginCredential(sgConnection, plugin); if (pluginInstance.TestVaultConnection()) { _logger.Error($"Test connection for plugin {pluginName} successful."); return(true); } } catch (Exception ex) { _logger.Error(ex, $"Failed to test the connection for plugin {pluginName}. {ex.Message}"); } } else { _logger.Error($"Failed to test the connection for plugin {pluginName}. Plugin information is missing."); } } else { _logger.Error($"Failed to test the connection for plugin {pluginName}. Missing login or vault account information."); } return(false); }
private void RefreshPluginCredential(ISafeguardConnection sgConnection, Plugin plugin) { if (plugin.VaultAccountId.HasValue) { try { var a2aAccount = _safeguardLogic.GetA2ARetrievableAccount(sgConnection, plugin.VaultAccountId.Value, A2ARegistrationType.Vault); if (a2aAccount != null) { SendPluginVaultCredentials(plugin.Name, a2aAccount.ApiKey); return; } _logger.Error( $"Failed to refresh the credential for plugin {plugin.Name} account {plugin.VaultAccountId}."); } catch (Exception ex) { var msg = $"Failed to refresh the api key for {plugin.Name} account {plugin.VaultAccountId}: {ex.Message}"; _logger.Error(ex, msg); } } else if (plugin.IsSystemOwned) { var addon = _configDb.GetAllAddons().FirstOrDefault(a => a.Manifest.PluginName.Equals(plugin.Name)); if (addon != null && addon.VaultCredentials.ContainsKey(WellKnownData.DevOpsCredentialName(addon.VaultAccountName, _configDb.SvcId))) { SendPluginVaultCredentialOnly(plugin.Name, addon.VaultCredentials[WellKnownData.DevOpsCredentialName(addon.VaultAccountName, _configDb.SvcId)]); } } }
public IEnumerable <RetrievableAccount> GetRetrievableAccounts() { var configuration = _configurationRepository.GetConfiguration(); if (configuration == null) { _logger.Error("No configuration was found. DevOps service must be configured first"); return(null); } ISafeguardConnection connection = null; try { connection = Safeguard.Connect(configuration.SppAddress, configuration.CertificateUserThumbPrint, _safeguardApiVersion, _safeguardIgnoreSsl); var rawJson = connection.InvokeMethod(Service.Core, Method.Get, $"A2ARegistrations/{configuration.A2ARegistrationId}/RetrievableAccounts"); var retrievableAccounts = JsonHelper.DeserializeObject <IEnumerable <RetrievableAccount> >(rawJson); return(retrievableAccounts.ToList()); } catch (Exception ex) { _logger.Error($"Failed to get the retrievable accounts from SPP: {ex.Message}."); } finally { connection?.Dispose(); } return(null); }
private IEnumerable <AccountMapping> GetAccountMappings(Configuration configuration) { ISafeguardConnection connection = null; try { connection = Safeguard.Connect(configuration.SppAddress, configuration.CertificateUserThumbPrint, _safeguardApiVersion, _safeguardIgnoreSsl); var rawJson = connection.InvokeMethod(Service.Core, Method.Get, $"A2ARegistrations/{configuration.A2ARegistrationId}/RetrievableAccounts"); var retrievableAccounts = JsonHelper.DeserializeObject <IEnumerable <RetrievableAccount> >(rawJson); var accountMappings = new List <AccountMapping>(); foreach (var account in retrievableAccounts) { accountMappings.Add(new AccountMapping() { AccountName = account.AccountName, ApiKey = account.ApiKey, VaultName = "" }); } return(accountMappings); } finally { connection?.Dispose(); } }
public A2ARetrievableAccount GetPluginVaultAccount(ISafeguardConnection sgConnection, string name) { var plugin = _configDb.GetPluginByName(name); if (plugin == null) { throw LogAndException($"Plugin {name} not found"); } if (plugin.IsSystemOwned && !plugin.VaultAccountId.HasValue) { var account = new A2ARetrievableAccount() { AccountName = WellKnownData.DevOpsCredentialName(plugin.Name, _configDb.SvcId), AccountDescription = "Internal account", SystemName = WellKnownData.DevOpsAssetName(_configDb.SvcId), SystemDescription = WellKnownData.DevOpsAssetName(_configDb.SvcId) }; var addon = _configDb.GetAllAddons().FirstOrDefault(a => a.Manifest.PluginName.Equals(plugin.Name)); if (addon != null) { account.AccountName = addon.VaultAccountName; account.SystemName = addon.Name; account.SystemDescription = addon.Name; } return(account); } if (!plugin.VaultAccountId.HasValue) { return(null); } return(_safeguardLogic.GetA2ARetrievableAccount(sgConnection, plugin.VaultAccountId.Value, A2ARegistrationType.Vault)); }
public Task Authenticate(string appliance) { if (_safeguardConnection != null) { _safeguardConnection.LogOut(); _safeguardConnection.Dispose(); } _safeguardConnection = LoginWindow.Connect(appliance); return(Task.CompletedTask); }
public Task Logout() { return(Task.Run(() => { if (_safeguardConnection != null) { _safeguardConnection.LogOut(); _safeguardConnection.Dispose(); _safeguardConnection = null; } })); }
public bool TestPluginConnectionByName(ISafeguardConnection sgConnection, string name) { var plugin = _configDb.GetPluginByName(name); if (plugin == null) { var msg = $"Failed to test the safeguardConnection. No plugin {name} was found."; _logger.Error(msg); throw new DevOpsException(msg, HttpStatusCode.NotFound); } return(_pluginManager.TestPluginVaultConnection(sgConnection, name)); }
public void Stop() { _eventListener.Stop(); _eventListener?.Dispose(); _connection?.Dispose(); _serviceNowPassword?.Dispose(); _validator?.Dispose(); _eventListener = null; _connection = null; _serviceNowPassword = null; _validator = null; }
public A2ARetrievableAccount SavePluginVaultAccount(ISafeguardConnection sgConnection, string name, AssetAccount sppAccount) { var plugin = _configDb.GetPluginByName(name); if (plugin == null) { throw LogAndException($"Plugin {name} not found."); } if (sppAccount == null) { throw LogAndException("Invalid account."); } var account = _safeguardLogic.GetAssetAccount(sgConnection, sppAccount.Id); if (account == null) { throw LogAndException($"Account {sppAccount.Id} not found."); } // Make sure that the vault account isn't being used by another plugin before we delete it. if (plugin.VaultAccountId != null && (VaultAccountUsage(plugin.VaultAccountId.Value) <= 1)) { _safeguardLogic.DeleteA2ARetrievableAccount(sgConnection, plugin.VaultAccountId.Value, A2ARegistrationType.Vault); } var accounts = _safeguardLogic.AddA2ARetrievableAccounts(sgConnection, new List <SppAccount>() { new SppAccount() { Id = account.Id, Name = account.Name } }, A2ARegistrationType.Vault); var a2aAccount = accounts.FirstOrDefault(x => x.AccountId == account.Id); if (a2aAccount != null) { plugin.VaultAccountId = a2aAccount.AccountId; _configDb.SavePluginConfiguration(plugin); } else { throw LogAndException($"Failed to add the account to the A2A vault registration. {account.Id} - {account.Name}."); } return(a2aAccount); }
private static string HandleStreamingRequest(ToolOptions opts, ISafeguardConnection connection) { if (opts.Method == Method.Post) { using FileStream fs = File.OpenRead(opts.File); var progress = opts.Verbose ? new Progress <TransferProgress>(p => { Console.Write("\rUploading: {0,3}% ({1}/{2}) ", p.PercentComplete, p.BytesTransferred, p.BytesTotal); }) : null; return(connection.Streaming.UploadAsync(opts.Service, opts.RelativeUrl, fs, progress, cancellationToken: Cts.Token).Result); } else if (opts.Method == Method.Get) { if (File.Exists(opts.File)) { throw new Exception($"File exists, remove it first: {opts.File}"); } var progress = opts.Verbose ? new Progress <TransferProgress>(p => { if (p.BytesTotal == 0) { Console.Write("\rDownloading: {0}", p.BytesTransferred); } else { Console.Write("\rDownloading: {0,3}% ({1}/{2}) ", p.PercentComplete, p.BytesTransferred, p.BytesTotal); } }) : null; // This is the alternate way to download directly to a file: // connection.Streaming.DownloadAsync(opts.Service, opts.RelativeUrl, opts.File, progress: progress, cancellationToken: Cts.Token).Wait(); using (var streamResult = connection.Streaming.DownloadStreamAsync(opts.Service, opts.RelativeUrl, progress: progress, cancellationToken: Cts.Token).Result) { using (var fs = new FileStream(opts.File, FileMode.Create, FileAccess.ReadWrite)) { var downloadStream = streamResult.GetStream().Result; downloadStream.CopyToAsync(fs, 81920).Wait(); } } return($"Download written to {opts.File}"); } else { throw new Exception($"Streaming is not supported for HTTP method: {opts.Method}"); } }
public void Start() { _eventListener = Safeguard.Event.GetPersistentEventListener(_safeguardAddress, _safeguardClientCertificateThumbprint, _safeguardApiVersion, _safeguardIgnoreSsl); _connection = Safeguard.Connect(_safeguardAddress, _safeguardClientCertificateThumbprint, _safeguardApiVersion, _safeguardIgnoreSsl); using (var a2AContext = Safeguard.A2A.GetContext(_safeguardAddress, _safeguardClientCertificateThumbprint, _safeguardApiVersion, _safeguardIgnoreSsl)) { _serviceNowPassword = a2AContext.RetrievePassword(_safeguardA2AApiKeyForServiceNowPassword); } _validator = new ServiceNowTicketValidator(_serviceNowDnsName, _serviceNowClientSecret, _serviceNowUserName, _serviceNowPassword); _eventListener.RegisterEventHandler("AccessRequestPendingApproval", HandlePendingApprovalNotification); _eventListener.Start(); }
private RetrievableAccount GetRetrievableAccount(Configuration configuration, string apiKey) { var apiKeyInfo = _configurationRepository.GetSetting(apiKey); ISafeguardConnection connection = null; try { connection = Safeguard.Connect(configuration.SppAddress, configuration.CertificateUserThumbPrint, _safeguardApiVersion, _safeguardIgnoreSsl); var rawJson = connection.InvokeMethod(Service.Core, Method.Get, $"A2ARegistrations/{configuration.A2ARegistrationId}/RetrievableAccounts/{apiKeyInfo.Value}"); var retrievableAccount = JsonHelper.DeserializeObject <IEnumerable <RetrievableAccount> >(rawJson); return(retrievableAccount?.FirstOrDefault()); } finally { connection?.Dispose(); } }
public void Start() { // connect to Safeguard _connection = Safeguard.Connect(_safeguardAddress, _safeguardClientCertificateThumbprint, _safeguardApiVersion, _safeguardIgnoreSsl); _a2AContext = Safeguard.A2A.GetContext(_safeguardAddress, _safeguardClientCertificateThumbprint, _safeguardApiVersion, _safeguardIgnoreSsl); // figure out what API keys to monitor GetApiKeysFromA2ARegistrations(); if (_monitoredPasswords.Count == 0) { throw new Exception("No API keys found in A2A registrations. Nothing to do."); } Log.Information("Found {MonitoredPasswordCount} API keys to monitor for password changes", _monitoredPasswords.Count); // start the listeners foreach (var monitored in _monitoredPasswords) { StartListener(monitored); } }
private static string HandleStreamingRequest(ToolOptions opts, ISafeguardConnection connection) { if (opts.Method == Method.Post) { using FileStream fs = File.OpenRead(opts.File); var progress = opts.Verbose ? new Progress <TransferProgress>(p => { Console.Write("\rUploading: {0,3}% ({1}/{2}) ", p.PercentComplete, p.BytesTransferred, p.BytesTotal); }) : null; return(connection.Streaming.UploadAsync(opts.Service, opts.RelativeUrl, fs, progress, cancellationToken: Cts.Token).Result); } else if (opts.Method == Method.Get) { if (File.Exists(opts.File)) { throw new Exception($"File exists, remove it first: {opts.File}"); } var progress = opts.Verbose ? new Progress <TransferProgress>(p => { if (p.BytesTotal == 0) { Console.Write("\rDownloading: {0}", p.BytesTransferred); } else { Console.Write("\rDownloading: {0,3}% ({1}/{2}) ", p.PercentComplete, p.BytesTransferred, p.BytesTotal); } }) : null; connection.Streaming.DownloadAsync(opts.Service, opts.RelativeUrl, opts.File, progress: progress, cancellationToken: Cts.Token).Wait(Cts.Token); return($"Download written to {opts.File}"); } else { throw new Exception($"Streaming is not supported for HTTP method: {opts.Method}"); } }
public Configuration InitialConfiguration(InitialConfiguration initialConfig) { //TODO: Create a new configuration element here //TODO: Check to see if there is already a configuration. If so, throw. //TODO: Get the registration and store the configuration in the database if (initialConfig == null) { throw new Exception("The initial configuration cannot be null."); } if (initialConfig.CertificateUserThumbprint == null) { throw new Exception("The user certificate thumbprint cannot be null."); } if (initialConfig.SppAddress == null) { throw new Exception("The SPP network address cannot be null."); } ISafeguardConnection connection = null; try { connection = Safeguard.Connect(initialConfig.SppAddress, initialConfig.CertificateUserThumbprint, _safeguardApiVersion, _safeguardIgnoreSsl); var rawJson = connection.InvokeMethod(Service.Core, Method.Get, "A2ARegistrations"); var registrations = JsonHelper.DeserializeObject <IEnumerable <SppRegistration> >(rawJson); // TODO: Assume that we only have one registration that belongs to the cert user var registration = registrations?.FirstOrDefault(); if (registration != null) { var configuration = new Configuration { SppAddress = initialConfig.SppAddress, A2ARegistrationId = registration.Id, A2ARegistrationName = registration.AppName, CertificateUser = registration.CertificateUser, CertificateUserThumbPrint = registration.CertificateUserThumbPrint, CreatedByUserId = registration.CreatedByUserId, CreatedByUserDisplayName = registration.CreatedByUserDisplayName, CreatedDate = registration.CreatedDate, AccountMapping = new List <AccountMapping>() }; _configurationRepository.SaveConfiguration(configuration); return(configuration); } else { _logger.Error("No A2A registrations were found for the configured certificate user"); } } catch (Exception ex) { _logger.Error($"Failed to initialize the DevOps Serivce: {ex.Message}"); } finally { connection?.Dispose(); } throw new Exception("Failed to configure devops."); }
public PersistentSafeguardConnection(ISafeguardConnection connection) => _connection = connection;
private static void TestApiExceptions(ISafeguardConnection connection) { Console.WriteLine("Test catching one with no response body"); try { connection.InvokeMethod(Service.Core, Method.Get, "This/Does/nt/Exist"); throw new Exception("Nonexistent URL did not throw an exception"); } catch (SafeguardDotNetException ex) { if (ex.HttpStatusCode != HttpStatusCode.NotFound) { throw; } if (!ex.HasResponse) { throw; } if (ex.ErrorCode != null) { throw; } if (ex.ErrorMessage != null) { throw; } } Console.WriteLine("Test catching one for bad request no filter"); try { connection.InvokeMethod(Service.Core, Method.Get, "Me/RequestableAssets", parameters: new Dictionary <string, string>() { ["filter"] = "This eq 'broken'" }); throw new Exception("Bad filter did not throw an exception"); } catch (SafeguardDotNetException ex) { if (ex.HttpStatusCode != HttpStatusCode.BadRequest) { throw; } if (!ex.HasResponse) { throw; } if (ex.ErrorCode != 70009) { throw; } if (!string.Equals(ex.ErrorMessage, "Invalid filter property - 'This' is not a valid filter property name.")) { throw; } } Console.WriteLine("Test catching one with model state issues"); try { connection.InvokeMethod(Service.Appliance, Method.Put, "NetworkInterfaces/X1", "{\"Name\":\"X1\",\"LinkDuplex\":\"FakeValue\"}"); throw new Exception("Bad model state did not throw an exception"); } catch (SafeguardDotNetException ex) { if (ex.HttpStatusCode != HttpStatusCode.BadRequest) { throw; } if (!ex.HasResponse) { throw; } if (ex.ErrorCode != 70000) { throw; } if (!string.Equals(ex.ErrorMessage, "The request is invalid.")) { throw; } } }
public PersistentSafeguardEventListener(ISafeguardConnection connection) { _connection = connection; Log.Debug("Persistent event listener successfully created."); }
public Task <DataTable> Execute(ISafeguardConnection connection) { throw new NotImplementedException(); }
bool InitSafeguardClient() { Log.Info("Initializing Safeguard Client"); if (Config.SafeguardAppliance == null) { Log.Error("Config value for SafeguardAppliance must be set hostname or IP address"); return(false); } ISafeguardConnection safeguardConnection = null; try { if (Config.SafeguardCertificateThumbprint != null) { safeguardConnection = Safeguard.Connect(Config.SafeguardAppliance, Config.SafeguardCertificateThumbprint, 3, true); } else if (Config.SafeguardCertificateFile != null) { safeguardConnection = Safeguard.Connect(Config.SafeguardAppliance, Config.SafeguardCertificateFile, Config.SafeguardCertificatePassword, 3, true); } else if (Config.SafeguardUsername != null && Config.SafeguardPassword != null) { safeguardConnection = Safeguard.Connect(Config.SafeguardAppliance, "Local", Config.SafeguardUsername, Config.SafeguardPassword, 3, true); } else { Log.Error("Missing Safeguard credentials. Please edit configuration to set one of: SafeguardCertificateFile, SafeguardCertificateThumbprint or SafeguardUsername"); return(false); } SafeguardClient = new SafeguardRestApiClient(safeguardConnection); var user = SafeguardClient.GetCurrentUser(); Log.Info("Connected to Safeguard as: " + user.Username); if (!user.AdminRoles.Contains("Auditor")) { Log.Error($"{user.Username} does not have AdminRole: \"Auditor\""); return(false); } if (user.AdminRoles.Count() > 1) { Log.Warn($"{user.Username} has additional Admin Roles. Only \"Auditor\" is required."); } var eventSubscriptions = SafeguardClient.GetEventSubscriptionsForUser(user); if (eventSubscriptions.Where(e => e.Description == "ARSJITAccess").Count() == 0) { var eventSubscription = new SafeguardEventSubscription() { UserId = user.Id, Description = "ARSJITAccess", Type = "Signalr", Events = Events }; SafeguardClient.CreateEventSubscription(eventSubscription); } return(true); } catch (SafeguardDotNetException e) { Log.Error(e.Message); } return(false); }
public IEnumerable <AccountMapping> SaveAccountMappings(ISafeguardConnection sgConnection, string name, IEnumerable <A2ARetrievableAccount> accounts) { if (_configDb.A2aRegistrationId == null) { var msg = "A2A registration not configured"; _logger.Error(msg); throw new DevOpsException(msg); } if (_configDb.GetPluginByName(name) == null) { var msg = $"Plugin {name} not found"; _logger.Error(msg); throw new DevOpsException(msg, HttpStatusCode.NotFound); } var retrievableAccounts = accounts.ToArray(); if (retrievableAccounts.All(x => x.AccountId == 0)) { var msg = "Invalid list of accounts. Expecting a list of retrievable accounts."; _logger.Error(msg); throw new DevOpsException(msg); } var allAccounts = _configDb.GetAccountMappings().ToArray(); foreach (var account in retrievableAccounts) { if (!string.IsNullOrEmpty(account.AltAccountName)) { // Make sure that no other existing account has the same altAccountName // Make sure that none of the accounts that are being added, have the same altAccountName if (allAccounts.Any(x => x.AltAccountName != null && x.AltAccountName.Equals(account.AltAccountName, StringComparison.OrdinalIgnoreCase) && !x.VaultName.Equals(name, StringComparison.OrdinalIgnoreCase)) || retrievableAccounts.Any(x => x.AccountId != account.AccountId && x.AltAccountName != null && x.AltAccountName.Equals(account.AltAccountName, StringComparison.OrdinalIgnoreCase))) { var msg = $"Invalid alternate account name. The account name {account.AltAccountName} is already in use."; _logger.Error(msg); throw new DevOpsException(msg); } } } var sg = sgConnection ?? _safeguardLogic.Connect(); try { var newAccounts = new List <AccountMapping>(); foreach (var account in retrievableAccounts) { try { var retrievableAccount = _safeguardLogic.GetA2ARetrievableAccountById(sg, A2ARegistrationType.Account, account.AccountId); if (retrievableAccount != null) { var accountMapping = new AccountMapping() { AccountName = retrievableAccount.AccountName, AltAccountName = account.AltAccountName, AccountId = retrievableAccount.AccountId, ApiKey = retrievableAccount.ApiKey, AssetName = retrievableAccount.SystemName, SystemId = retrievableAccount.SystemId, DomainName = retrievableAccount.DomainName, NetworkAddress = retrievableAccount.NetworkAddress, VaultName = name }; newAccounts.Add(accountMapping); } } catch (Exception ex) { var msg = $"Failed to add account {account.AccountId} - {account.AccountName}: {ex.Message}"; _logger.Error(ex, msg); } } if (newAccounts.Count > 0) { _configDb.SaveAccountMappings(newAccounts); } return(GetAccountMappings(name)); } finally { if (sgConnection == null) { sg.Dispose(); } } }
public SafeguardRestApiClient(ISafeguardConnection connection) { Connection = connection; }