mirror of
https://github.com/bitwarden/server.git
synced 2025-07-13 05:38:25 -05:00
[PM-17562] API For Organization Integrations/Configurations, Refactored Distributed Events, Slack Integration (#5654)
* [PM-17562] Slack Event Investigation * Refactored Slack and Webhook integrations to pull configurations dynamically from a new Repository * Added new TemplateProcessor and added/updated unit tests * SlackService improvements, testing, integration configurations * Refactor SlackService to use a dedicated model to parse responses * Refactored SlackOAuthController to use SlackService as an injected dependency; added tests for SlackService * Remove unnecessary methods from the IOrganizationIntegrationConfigurationRepository * Moved Slack OAuth to take into account the Organization it's being stored for. Added methods to store the top level integration for Slack * Organization integrations and configuration database schemas * Format EF files * Initial buildout of basic repositories * [PM-17562] Add Dapper Repositories For Organization Integrations and Configurations * Update Slack and Webhook handlers to use new Repositories * Update SlackOAuth tests to new signatures * Added EF Repositories * Update handlers to use latest repositories * [PM-17562] Add Dapper and EF Repositories For Ogranization Integrations and Configurations * Updated with changes from PR comments * Adjusted Handlers to new repository method names; updated tests to naming convention * Adjust URL structure; add delete for Slack, add tests * Added Webhook Integration Controller * Add tests for WebhookIntegrationController * Added Create/Delete for OrganizationIntegrationConfigurations * Prepend ConnectionTypes into IntegrationType so we don't run into issues later * Added Update to OrganizationIntegrationConfigurtionController * Moved Webhook-specific integration code to being a generic controller for everything but Slack * Removed delete from SlackController - Deletes should happen through the normal Integration controller * Fixed SlackController, reworked OIC Controller to use ids from URL and update the returned object * Added parse/type checking for integration and integration configuration JSONs, Cleaned up GlobalSettings to remove old values * Cleanup and fixes for Azure Service Bus support * Clean up naming on TemplateProcessorTests * Address SonarQube warnings/suggestions * Expanded test coverage; Cleaned up tests * Respond to PR Feedback * Rename TemplateProcessor to IntegrationTemplateProcessor --------- Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
This commit is contained in:
@ -0,0 +1,73 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data.Integrations;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
|
||||
public class OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
public string? Configuration { get; set; }
|
||||
|
||||
[Required]
|
||||
public EventType EventType { get; set; }
|
||||
|
||||
public string? Template { get; set; }
|
||||
|
||||
public bool IsValidForType(IntegrationType integrationType)
|
||||
{
|
||||
switch (integrationType)
|
||||
{
|
||||
case IntegrationType.CloudBillingSync or IntegrationType.Scim:
|
||||
return false;
|
||||
case IntegrationType.Slack:
|
||||
return !string.IsNullOrWhiteSpace(Template) && IsConfigurationValid<SlackIntegrationConfiguration>();
|
||||
case IntegrationType.Webhook:
|
||||
return !string.IsNullOrWhiteSpace(Template) && IsConfigurationValid<WebhookIntegrationConfiguration>();
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public OrganizationIntegrationConfiguration ToOrganizationIntegrationConfiguration(Guid organizationIntegrationId)
|
||||
{
|
||||
return new OrganizationIntegrationConfiguration()
|
||||
{
|
||||
OrganizationIntegrationId = organizationIntegrationId,
|
||||
Configuration = Configuration,
|
||||
EventType = EventType,
|
||||
Template = Template
|
||||
};
|
||||
}
|
||||
|
||||
public OrganizationIntegrationConfiguration ToOrganizationIntegrationConfiguration(OrganizationIntegrationConfiguration currentConfiguration)
|
||||
{
|
||||
currentConfiguration.Configuration = Configuration;
|
||||
currentConfiguration.EventType = EventType;
|
||||
currentConfiguration.Template = Template;
|
||||
|
||||
return currentConfiguration;
|
||||
}
|
||||
|
||||
private bool IsConfigurationValid<T>()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Configuration))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var config = JsonSerializer.Deserialize<T>(Configuration);
|
||||
return config is not null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
|
||||
public class OrganizationIntegrationRequestModel : IValidatableObject
|
||||
{
|
||||
public string? Configuration { get; set; }
|
||||
|
||||
public IntegrationType Type { get; set; }
|
||||
|
||||
public OrganizationIntegration ToOrganizationIntegration(Guid organizationId)
|
||||
{
|
||||
return new OrganizationIntegration()
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Configuration = Configuration,
|
||||
Type = Type,
|
||||
};
|
||||
}
|
||||
|
||||
public OrganizationIntegration ToOrganizationIntegration(OrganizationIntegration currentIntegration)
|
||||
{
|
||||
currentIntegration.Configuration = Configuration;
|
||||
return currentIntegration;
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case IntegrationType.CloudBillingSync or IntegrationType.Scim:
|
||||
yield return new ValidationResult($"{nameof(Type)} integrations are not yet supported.", new[] { nameof(Type) });
|
||||
break;
|
||||
case IntegrationType.Slack:
|
||||
yield return new ValidationResult($"{nameof(Type)} integrations cannot be created directly.", new[] { nameof(Type) });
|
||||
break;
|
||||
case IntegrationType.Webhook:
|
||||
if (Configuration is not null)
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
"Webhook integrations must not include configuration.",
|
||||
new[] { nameof(Configuration) });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
yield return new ValidationResult(
|
||||
$"Integration type '{Type}' is not recognized.",
|
||||
new[] { nameof(Type) });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
|
||||
public class OrganizationIntegrationConfigurationResponseModel : ResponseModel
|
||||
{
|
||||
public OrganizationIntegrationConfigurationResponseModel(OrganizationIntegrationConfiguration organizationIntegrationConfiguration, string obj = "organizationIntegrationConfiguration")
|
||||
: base(obj)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(organizationIntegrationConfiguration);
|
||||
|
||||
Id = organizationIntegrationConfiguration.Id;
|
||||
Configuration = organizationIntegrationConfiguration.Configuration;
|
||||
CreationDate = organizationIntegrationConfiguration.CreationDate;
|
||||
EventType = organizationIntegrationConfiguration.EventType;
|
||||
Template = organizationIntegrationConfiguration.Template;
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string? Configuration { get; set; }
|
||||
public DateTime CreationDate { get; set; }
|
||||
public EventType EventType { get; set; }
|
||||
public string? Template { get; set; }
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Api;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
|
||||
public class OrganizationIntegrationResponseModel : ResponseModel
|
||||
{
|
||||
public OrganizationIntegrationResponseModel(OrganizationIntegration organizationIntegration, string obj = "organizationIntegration")
|
||||
: base(obj)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(organizationIntegration);
|
||||
|
||||
Id = organizationIntegration.Id;
|
||||
Type = organizationIntegration.Type;
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public IntegrationType Type { get; set; }
|
||||
}
|
Reference in New Issue
Block a user