diff --git a/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs b/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs index e3c290c85ffd..88d6858cb861 100644 --- a/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs +++ b/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs @@ -61,17 +61,15 @@ public async Task Get(Guid organizationId, Guid id) [HttpGet("")] public async Task Get( Guid organizationId, - [FromQuery] string filter, - [FromQuery] int? count, - [FromQuery] int? startIndex) + [FromQuery] GetGroupsQueryParamModel model) { - var groupsListQueryResult = await _getGroupsListQuery.GetGroupsListAsync(organizationId, filter, count, startIndex); + var groupsListQueryResult = await _getGroupsListQuery.GetGroupsListAsync(organizationId, model); var scimListResponseModel = new ScimListResponseModel { Resources = groupsListQueryResult.groupList.Select(g => new ScimGroupResponseModel(g)).ToList(), - ItemsPerPage = count.GetValueOrDefault(groupsListQueryResult.groupList.Count()), + ItemsPerPage = model.Count, TotalResults = groupsListQueryResult.totalResults, - StartIndex = startIndex.GetValueOrDefault(1), + StartIndex = model.StartIndex, }; return Ok(scimListResponseModel); } diff --git a/bitwarden_license/src/Scim/Groups/GetGroupsListQuery.cs b/bitwarden_license/src/Scim/Groups/GetGroupsListQuery.cs index cc6546700b70..f0a561a29f6c 100644 --- a/bitwarden_license/src/Scim/Groups/GetGroupsListQuery.cs +++ b/bitwarden_license/src/Scim/Groups/GetGroupsListQuery.cs @@ -4,6 +4,7 @@ using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Repositories; using Bit.Scim.Groups.Interfaces; +using Bit.Scim.Models; namespace Bit.Scim.Groups; @@ -16,10 +17,16 @@ public GetGroupsListQuery(IGroupRepository groupRepository) _groupRepository = groupRepository; } - public async Task<(IEnumerable groupList, int totalResults)> GetGroupsListAsync(Guid organizationId, string filter, int? count, int? startIndex) + public async Task<(IEnumerable groupList, int totalResults)> GetGroupsListAsync( + Guid organizationId, GetGroupsQueryParamModel groupQueryParams) { string nameFilter = null; string externalIdFilter = null; + + int count = groupQueryParams.Count; + int startIndex = groupQueryParams.StartIndex; + string filter = groupQueryParams.Filter; + if (!string.IsNullOrWhiteSpace(filter)) { if (filter.StartsWith("displayName eq ")) @@ -53,11 +60,11 @@ public GetGroupsListQuery(IGroupRepository groupRepository) } totalResults = groupList.Count; } - else if (string.IsNullOrWhiteSpace(filter) && startIndex.HasValue && count.HasValue) + else if (string.IsNullOrWhiteSpace(filter)) { groupList = groups.OrderBy(g => g.Name) - .Skip(startIndex.Value - 1) - .Take(count.Value) + .Skip(startIndex - 1) + .Take(count) .ToList(); totalResults = groups.Count; } diff --git a/bitwarden_license/src/Scim/Groups/Interfaces/IGetGroupsListQuery.cs b/bitwarden_license/src/Scim/Groups/Interfaces/IGetGroupsListQuery.cs index 07ff04470182..4b4ba09e1de7 100644 --- a/bitwarden_license/src/Scim/Groups/Interfaces/IGetGroupsListQuery.cs +++ b/bitwarden_license/src/Scim/Groups/Interfaces/IGetGroupsListQuery.cs @@ -1,8 +1,9 @@ using Bit.Core.AdminConsole.Entities; +using Bit.Scim.Models; namespace Bit.Scim.Groups.Interfaces; public interface IGetGroupsListQuery { - Task<(IEnumerable groupList, int totalResults)> GetGroupsListAsync(Guid organizationId, string filter, int? count, int? startIndex); + Task<(IEnumerable groupList, int totalResults)> GetGroupsListAsync(Guid organizationId, GetGroupsQueryParamModel model); } diff --git a/bitwarden_license/src/Scim/Models/GetGroupsQueryParamModel.cs b/bitwarden_license/src/Scim/Models/GetGroupsQueryParamModel.cs new file mode 100644 index 000000000000..538972791726 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/GetGroupsQueryParamModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Bit.Scim.Models; + +public class GetGroupsQueryParamModel +{ + public string Filter { get; init; } = string.Empty; + + [Range(1, int.MaxValue)] + public int Count { get; init; } = 50; + + [Range(1, int.MaxValue)] + public int StartIndex { get; init; } = 1; +} diff --git a/bitwarden_license/src/Scim/Models/GetUserQueryParamModel.cs b/bitwarden_license/src/Scim/Models/GetUsersQueryParamModel.cs similarity index 91% rename from bitwarden_license/src/Scim/Models/GetUserQueryParamModel.cs rename to bitwarden_license/src/Scim/Models/GetUsersQueryParamModel.cs index 27d7b6d9a1f5..cd50dbca611c 100644 --- a/bitwarden_license/src/Scim/Models/GetUserQueryParamModel.cs +++ b/bitwarden_license/src/Scim/Models/GetUsersQueryParamModel.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; +namespace Bit.Scim.Models; + public class GetUsersQueryParamModel { public string Filter { get; init; } = string.Empty; diff --git a/bitwarden_license/src/Scim/Users/GetUsersListQuery.cs b/bitwarden_license/src/Scim/Users/GetUsersListQuery.cs index a734635ebf27..c7085eb6b9d1 100644 --- a/bitwarden_license/src/Scim/Users/GetUsersListQuery.cs +++ b/bitwarden_license/src/Scim/Users/GetUsersListQuery.cs @@ -3,6 +3,7 @@ using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Repositories; +using Bit.Scim.Models; using Bit.Scim.Users.Interfaces; namespace Bit.Scim.Users; diff --git a/bitwarden_license/src/Scim/Users/Interfaces/IGetUsersListQuery.cs b/bitwarden_license/src/Scim/Users/Interfaces/IGetUsersListQuery.cs index f584cb8e7b56..04133c89ebb0 100644 --- a/bitwarden_license/src/Scim/Users/Interfaces/IGetUsersListQuery.cs +++ b/bitwarden_license/src/Scim/Users/Interfaces/IGetUsersListQuery.cs @@ -1,4 +1,5 @@ using Bit.Core.Models.Data.Organizations.OrganizationUsers; +using Bit.Scim.Models; namespace Bit.Scim.Users.Interfaces; diff --git a/bitwarden_license/test/Scim.IntegrationTest/Controllers/v2/GroupsControllerTests.cs b/bitwarden_license/test/Scim.IntegrationTest/Controllers/v2/GroupsControllerTests.cs index 5f562a30c524..9ad231a63de2 100644 --- a/bitwarden_license/test/Scim.IntegrationTest/Controllers/v2/GroupsControllerTests.cs +++ b/bitwarden_license/test/Scim.IntegrationTest/Controllers/v2/GroupsControllerTests.cs @@ -200,6 +200,38 @@ public async Task GetList_EmptyResult_Success() AssertHelper.AssertPropertyEqual(expectedResponse, responseModel); } + [Fact] + public async Task GetList_SearchDisplayNameWithoutOptionalParameters_Success() + { + string filter = "displayName eq Test Group 2"; + int? itemsPerPage = null; + int? startIndex = null; + var expectedResponse = new ScimListResponseModel + { + ItemsPerPage = 50, //default value + TotalResults = 1, + StartIndex = 1, //default value + Resources = new List + { + new ScimGroupResponseModel + { + Id = ScimApplicationFactory.TestGroupId2, + DisplayName = "Test Group 2", + ExternalId = "B", + Schemas = new List { ScimConstants.Scim2SchemaGroup } + } + }, + Schemas = new List { ScimConstants.Scim2SchemaListResponse } + }; + + var context = await _factory.GroupsGetListAsync(ScimApplicationFactory.TestOrganizationId1, filter, itemsPerPage, startIndex); + + Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); + + var responseModel = JsonSerializer.Deserialize>(context.Response.Body, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + AssertHelper.AssertPropertyEqual(expectedResponse, responseModel); + } + [Fact] public async Task Post_Success() { diff --git a/bitwarden_license/test/Scim.Test/Groups/GetGroupsListQueryTests.cs b/bitwarden_license/test/Scim.Test/Groups/GetGroupsListQueryTests.cs index 1599b6e39080..b835e1fe6bbe 100644 --- a/bitwarden_license/test/Scim.Test/Groups/GetGroupsListQueryTests.cs +++ b/bitwarden_license/test/Scim.Test/Groups/GetGroupsListQueryTests.cs @@ -1,6 +1,7 @@ using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Repositories; using Bit.Scim.Groups; +using Bit.Scim.Models; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.Helpers; @@ -24,7 +25,7 @@ public async Task GetGroupsList_Success(int count, int startIndex, SutProvider