Esempio n. 1
0
 private void GetApiKeysFromA2ARegistrations()
 {
     // optionally you can have Safeguard look up all A2A registrations for a given certificate user thumbprint
     // currently this requires auditor permission, but we will enhance A2A to include read ability without it
     try
     {
         var a2AJson = _connection.InvokeMethod(Service.Core, Method.Get, "A2ARegistrations", parameters: new Dictionary <string, string> {
             { "filter", $"CertificateUserThumbprint ieq '{_safeguardClientCertificateThumbprint}'" }
         });
         var a2AArray = JArray.Parse(a2AJson);
         foreach (dynamic a2A in a2AArray)
         {
             var credsJson  = _connection.InvokeMethod(Service.Core, Method.Get, $"A2ARegistrations/{a2A.Id}/RetrievableAccounts");
             var credsArray = JArray.Parse(credsJson);
             foreach (dynamic cred in credsArray)
             {
                 _monitoredPasswords.Add(new MonitoredPassword
                 {
                     ApiKey      = ExtensionMethods.ToSecureString(cred.ApiKey.ToString()),
                     AssetName   = cred.SystemName,
                     AccountName = cred.AccountName
                 });
             }
         }
     }
     catch (Exception ex)
     {
         throw new Exception("Unable to get API keys using certificate user, did you grant auditor permissions?", ex);
     }
 }
Esempio n. 2
0
        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();
            }
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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();
            }
        }
Esempio n. 5
0
        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.");
        }
        private void HandlePendingApprovalNotification(string eventName, string eventBody)
        {
            if (eventName != "AccessRequestPendingApproval")
            {
                Log.Information("Received {EventName} event, ignoring it", eventName);
                return;
            }

            try
            {
                var approvalEvent   = JsonConvert.DeserializeObject <AccessRequestApprovalPendingEvent>(eventBody);
                var accessRequestId = approvalEvent.RequestId;
                if (string.IsNullOrEmpty(accessRequestId))
                {
                    Log.Warning("Unable to parse access requestId for event {EventBody}", eventBody);
                    return;
                }
                var accessRequestJson =
                    _connection.InvokeMethod(Service.Core, Method.Get, $"AccessRequests/{accessRequestId}");
                var accessRequest = JsonConvert.DeserializeObject <AccessRequest>(accessRequestJson);

                // Only ServiceNow and Remedy are supported in Safeguard. We will be adding a generic ticket system
                // that will allow for arbitrary ticket numbers. Until then, you could overload the comment with
                // the ticket number. TODO: remove this comment when it becomes obselete
                var ticketNumber = accessRequest.TicketNumber;
                if (string.IsNullOrEmpty(ticketNumber))
                {
                    Log.Information("Ignoring access request {AccessRequestId} without ticket number", accessRequestId);
                    return;
                }

                if (_connection.GetAccessTokenLifetimeRemaining() == 0)
                {
                    _connection.RefreshAccessToken();
                }

                switch (_validator.CheckTicket(ticketNumber, accessRequest))
                {
                case ValidationResult.Approve:
                    Log.Information("Approving access request {AccessRequestId} with ticket number {TicketNumber}",
                                    accessRequestId, ticketNumber);
                    _connection.InvokeMethod(Service.Core, Method.Post, $"AccessRequests/{accessRequestId}/Approve");
                    break;

                case ValidationResult.Deny:
                    Log.Information("Denying access request {AccessRequestId} with ticket number {TicketNumber}",
                                    accessRequestId, ticketNumber);
                    _connection.InvokeMethod(Service.Core, Method.Post, $"AccessRequests/{accessRequestId}/Deny");
                    break;

                default:
                    Log.Information("Ignoring access request {AccessRequestId} with ticket number {TicketNumber}",
                                    accessRequestId, ticketNumber);
                    break;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Exception occured while handling event {EventName}, data={EventBody}", eventName, eventBody);
            }
        }
Esempio n. 7
0
        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;
                }
            }
        }