Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
๏ปฟusing System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;

namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;

Expand Down Expand Up @@ -36,13 +36,18 @@ public class IntegrationTemplateContext(EventMessage eventMessage)
public string DateIso8601 => Date.ToString("o");
public string EventMessage => JsonSerializer.Serialize(Event);

public User? User { get; set; }
public OrganizationUserUserDetails? User { get; set; }
public string? UserName => User?.Name;
public string? UserEmail => User?.Email;
public OrganizationUserType? UserType => User?.Type;

public User? ActingUser { get; set; }
public OrganizationUserUserDetails? ActingUser { get; set; }
public string? ActingUserName => ActingUser?.Name;
public string? ActingUserEmail => ActingUser?.Email;
public OrganizationUserType? ActingUserType => ActingUser?.Type;

public Group? Group { get; set; }
public string? GroupName => Group?.Name;

public Organization? Organization { get; set; }
public string? OrganizationName => Organization?.DisplayName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,15 @@ UpdateEncryptedDataForKeyRotation UpdateForKeyRotation(Guid userId,
/// <param name="organizationUser">Accepted OrganizationUser to confirm</param>
/// <returns>True, if the user was updated. False, if not performed.</returns>
Task<bool> ConfirmOrganizationUserAsync(OrganizationUser organizationUser);

/// <summary>
/// Returns the OrganizationUserUserDetails if found.
/// </summary>
/// <param name="organizationId">The id of the organization</param>
/// <param name="userId">The id of the User to fetch</param>
/// <returns>OrganizationUserUserDetails of the specified user or null if not found</returns>
/// <remarks>
/// Similar to GetByOrganizationAsync, but returns the user details.
/// </remarks>
Task<OrganizationUserUserDetails?> GetDetailsByOrganizationUserAsync(Guid organizationId, Guid userId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
๏ปฟusing System.Text.Json;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Utilities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
Expand All @@ -13,8 +14,9 @@ public class EventIntegrationHandler<T>(
IEventIntegrationPublisher eventIntegrationPublisher,
IIntegrationFilterService integrationFilterService,
IIntegrationConfigurationDetailsCache configurationCache,
IUserRepository userRepository,
IGroupRepository groupRepository,
IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository,
ILogger<EventIntegrationHandler<T>> logger)
: IEventMessageHandler
{
Expand Down Expand Up @@ -89,19 +91,35 @@ private async Task<IntegrationTemplateContext> BuildContextAsync(EventMessage ev
{
var context = new IntegrationTemplateContext(eventMessage);

if (IntegrationTemplateProcessor.TemplateRequiresGroup(template) && eventMessage.GroupId.HasValue)
{
context.Group = await groupRepository.GetByIdAsync(eventMessage.GroupId.Value);
}

if (eventMessage.OrganizationId is not Guid organizationId)
{
return context;
}

if (IntegrationTemplateProcessor.TemplateRequiresUser(template) && eventMessage.UserId.HasValue)
{
context.User = await userRepository.GetByIdAsync(eventMessage.UserId.Value);
context.User = await organizationUserRepository.GetDetailsByOrganizationUserAsync(
organizationId: organizationId,
userId: eventMessage.UserId.Value
);
}

if (IntegrationTemplateProcessor.TemplateRequiresActingUser(template) && eventMessage.ActingUserId.HasValue)
{
context.ActingUser = await userRepository.GetByIdAsync(eventMessage.ActingUserId.Value);
context.ActingUser = await organizationUserRepository.GetDetailsByOrganizationUserAsync(
organizationId: organizationId,
userId: eventMessage.ActingUserId.Value
);
}

if (IntegrationTemplateProcessor.TemplateRequiresOrganization(template) && eventMessage.OrganizationId.HasValue)
if (IntegrationTemplateProcessor.TemplateRequiresOrganization(template))
{
context.Organization = await organizationRepository.GetByIdAsync(eventMessage.OrganizationId.Value);
context.Organization = await organizationRepository.GetByIdAsync(organizationId);
}

return context;
Expand Down
18 changes: 15 additions & 3 deletions src/Core/AdminConsole/Utilities/IntegrationTemplateProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static string ReplaceTokens(string template, object values)
return match.Value; // Return unknown keys as keys - i.e. #Key#
}

return property?.GetValue(values)?.ToString() ?? "";
return property.GetValue(values)?.ToString() ?? string.Empty;
});
}

Expand All @@ -38,7 +38,8 @@ public static bool TemplateRequiresUser(string template)
}

return template.Contains("#UserName#", StringComparison.Ordinal)
|| template.Contains("#UserEmail#", StringComparison.Ordinal);
|| template.Contains("#UserEmail#", StringComparison.Ordinal)
|| template.Contains("#UserType#", StringComparison.Ordinal);
}

public static bool TemplateRequiresActingUser(string template)
Expand All @@ -49,7 +50,18 @@ public static bool TemplateRequiresActingUser(string template)
}

return template.Contains("#ActingUserName#", StringComparison.Ordinal)
|| template.Contains("#ActingUserEmail#", StringComparison.Ordinal);
|| template.Contains("#ActingUserEmail#", StringComparison.Ordinal)
|| template.Contains("#ActingUserType#", StringComparison.Ordinal);
}

public static bool TemplateRequiresGroup(string template)
{
if (string.IsNullOrEmpty(template))
{
return false;
}

return template.Contains("#GroupName#", StringComparison.Ordinal);
}

public static bool TemplateRequiresOrganization(string template)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -686,4 +686,17 @@ public async Task<bool> ConfirmOrganizationUserAsync(OrganizationUser organizati

return rowCount > 0;
}

public async Task<OrganizationUserUserDetails?> GetDetailsByOrganizationUserAsync(Guid organizationId, Guid userId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<OrganizationUserUserDetails>(
"[dbo].[OrganizationUserUserDetails_ReadByOrganizationId]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);

return results.FirstOrDefault(u => u.UserId == userId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -962,4 +962,17 @@ public async Task<bool> ConfirmOrganizationUserAsync(Core.Entities.OrganizationU
return true;

}

public async Task<OrganizationUserUserDetails> GetDetailsByOrganizationUserAsync(Guid organizationId, Guid userId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var view = new OrganizationUserUserDetailsViewQuery();
var entity = await view.Run(dbContext).FirstOrDefaultAsync(ou => ou.OrganizationId == organizationId && ou.UserId == userId);
return entity;
}
}


}
7 changes: 5 additions & 2 deletions src/SharedWeb/Utilities/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.AdminConsole.Models.Teams;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.AdminConsole.Services.Implementations;
using Bit.Core.AdminConsole.Services.NoopImplementations;
Expand Down Expand Up @@ -898,8 +899,9 @@ private static IServiceCollection AddAzureServiceBusIntegration<TConfig, TListen
eventIntegrationPublisher: provider.GetRequiredService<IEventIntegrationPublisher>(),
integrationFilterService: provider.GetRequiredService<IIntegrationFilterService>(),
configurationCache: provider.GetRequiredService<IIntegrationConfigurationDetailsCache>(),
userRepository: provider.GetRequiredService<IUserRepository>(),
groupRepository: provider.GetRequiredService<IGroupRepository>(),
organizationRepository: provider.GetRequiredService<IOrganizationRepository>(),
organizationUserRepository: provider.GetRequiredService<IOrganizationUserRepository>(),
logger: provider.GetRequiredService<ILogger<EventIntegrationHandler<TConfig>>>()
)
);
Expand Down Expand Up @@ -1025,8 +1027,9 @@ private static IServiceCollection AddRabbitMqIntegration<TConfig, TListenerConfi
eventIntegrationPublisher: provider.GetRequiredService<IEventIntegrationPublisher>(),
integrationFilterService: provider.GetRequiredService<IIntegrationFilterService>(),
configurationCache: provider.GetRequiredService<IIntegrationConfigurationDetailsCache>(),
userRepository: provider.GetRequiredService<IUserRepository>(),
groupRepository: provider.GetRequiredService<IGroupRepository>(),
organizationRepository: provider.GetRequiredService<IOrganizationRepository>(),
organizationUserRepository: provider.GetRequiredService<IOrganizationUserRepository>(),
logger: provider.GetRequiredService<ILogger<EventIntegrationHandler<TConfig>>>()
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
using Bit.Core.Entities;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;

Expand Down Expand Up @@ -35,7 +35,7 @@ public void DateIso8601_ReturnsIso8601FormattedDate(EventMessage eventMessage)
}

[Theory, BitAutoData]
public void UserName_WhenUserIsSet_ReturnsName(EventMessage eventMessage, User user)
public void UserName_WhenUserIsSet_ReturnsName(EventMessage eventMessage, OrganizationUserUserDetails user)
{
var sut = new IntegrationTemplateContext(eventMessage) { User = user };

Expand All @@ -51,7 +51,7 @@ public void UserName_WhenUserIsNull_ReturnsNull(EventMessage eventMessage)
}

[Theory, BitAutoData]
public void UserEmail_WhenUserIsSet_ReturnsEmail(EventMessage eventMessage, User user)
public void UserEmail_WhenUserIsSet_ReturnsEmail(EventMessage eventMessage, OrganizationUserUserDetails user)
{
var sut = new IntegrationTemplateContext(eventMessage) { User = user };

Expand All @@ -67,7 +67,23 @@ public void UserEmail_WhenUserIsNull_ReturnsNull(EventMessage eventMessage)
}

[Theory, BitAutoData]
public void ActingUserName_WhenActingUserIsSet_ReturnsName(EventMessage eventMessage, User actingUser)
public void UserType_WhenUserIsSet_ReturnsType(EventMessage eventMessage, OrganizationUserUserDetails user)
{
var sut = new IntegrationTemplateContext(eventMessage) { User = user };

Assert.Equal(user.Type, sut.UserType);
}

[Theory, BitAutoData]
public void UserType_WhenUserIsNull_ReturnsNull(EventMessage eventMessage)
{
var sut = new IntegrationTemplateContext(eventMessage) { User = null };

Assert.Null(sut.UserType);
}

[Theory, BitAutoData]
public void ActingUserName_WhenActingUserIsSet_ReturnsName(EventMessage eventMessage, OrganizationUserUserDetails actingUser)
{
var sut = new IntegrationTemplateContext(eventMessage) { ActingUser = actingUser };

Expand All @@ -83,7 +99,7 @@ public void ActingUserName_WhenActingUserIsNull_ReturnsNull(EventMessage eventMe
}

[Theory, BitAutoData]
public void ActingUserEmail_WhenActingUserIsSet_ReturnsEmail(EventMessage eventMessage, User actingUser)
public void ActingUserEmail_WhenActingUserIsSet_ReturnsEmail(EventMessage eventMessage, OrganizationUserUserDetails actingUser)
{
var sut = new IntegrationTemplateContext(eventMessage) { ActingUser = actingUser };

Expand All @@ -98,6 +114,22 @@ public void ActingUserEmail_WhenActingUserIsNull_ReturnsNull(EventMessage eventM
Assert.Null(sut.ActingUserEmail);
}

[Theory, BitAutoData]
public void ActingUserType_WhenActingUserIsSet_ReturnsType(EventMessage eventMessage, OrganizationUserUserDetails actingUser)
{
var sut = new IntegrationTemplateContext(eventMessage) { ActingUser = actingUser };

Assert.Equal(actingUser.Type, sut.ActingUserType);
}

[Theory, BitAutoData]
public void ActingUserType_WhenActingUserIsNull_ReturnsNull(EventMessage eventMessage)
{
var sut = new IntegrationTemplateContext(eventMessage) { ActingUser = null };

Assert.Null(sut.ActingUserType);
}

[Theory, BitAutoData]
public void OrganizationName_WhenOrganizationIsSet_ReturnsDisplayName(EventMessage eventMessage, Organization organization)
{
Expand All @@ -113,4 +145,20 @@ public void OrganizationName_WhenOrganizationIsNull_ReturnsNull(EventMessage eve

Assert.Null(sut.OrganizationName);
}

[Theory, BitAutoData]
public void GroupName_WhenGroupIsSet_ReturnsName(EventMessage eventMessage, Group group)
{
var sut = new IntegrationTemplateContext(eventMessage) { Group = group };

Assert.Equal(group.Name, sut.GroupName);
}

[Theory, BitAutoData]
public void GroupName_WhenGroupIsNull_ReturnsNull(EventMessage eventMessage)
{
var sut = new IntegrationTemplateContext(eventMessage) { Group = null };

Assert.Null(sut.GroupName);
}
}
Loading
Loading