-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathUsersController.cs
More file actions
145 lines (131 loc) · 5.95 KB
/
UsersController.cs
File metadata and controls
145 lines (131 loc) · 5.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using Bit.Core.AdminConsole.Models.Data;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.RestoreUser.v1;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.RevokeUser.v2;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Scim.Models;
using Bit.Scim.Users.Interfaces;
using Bit.Scim.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using IRevokeOrganizationUserCommandV2 = Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.RevokeUser.v2.IRevokeOrganizationUserCommand;
namespace Bit.Scim.Controllers.v2;
[Authorize("Scim")]
[Route("v2/{organizationId}/users")]
[Produces("application/scim+json")]
[ExceptionHandlerFilter]
public class UsersController : Controller
{
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IGetUsersListQuery _getUsersListQuery;
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
private readonly IPatchUserCommand _patchUserCommand;
private readonly IPostUserCommand _postUserCommand;
private readonly IRestoreOrganizationUserCommand _restoreOrganizationUserCommand;
private readonly IRevokeOrganizationUserCommandV2 _revokeOrganizationUserCommandV2;
public UsersController(IOrganizationUserRepository organizationUserRepository,
IGetUsersListQuery getUsersListQuery,
IRemoveOrganizationUserCommand removeOrganizationUserCommand,
IPatchUserCommand patchUserCommand,
IPostUserCommand postUserCommand,
IRestoreOrganizationUserCommand restoreOrganizationUserCommand,
IRevokeOrganizationUserCommandV2 revokeOrganizationUserCommandV2)
{
_organizationUserRepository = organizationUserRepository;
_getUsersListQuery = getUsersListQuery;
_removeOrganizationUserCommand = removeOrganizationUserCommand;
_patchUserCommand = patchUserCommand;
_postUserCommand = postUserCommand;
_restoreOrganizationUserCommand = restoreOrganizationUserCommand;
_revokeOrganizationUserCommandV2 = revokeOrganizationUserCommandV2;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(Guid organizationId, Guid id)
{
var orgUser = await _organizationUserRepository.GetDetailsByIdAsync(id);
if (orgUser == null || orgUser.OrganizationId != organizationId)
{
throw new NotFoundException("User not found.");
}
return Ok(new ScimUserResponseModel(orgUser));
}
[HttpGet("")]
public async Task<IActionResult> Get(
Guid organizationId,
[FromQuery] GetUsersQueryParamModel model)
{
var usersListQueryResult = await _getUsersListQuery.GetUsersListAsync(organizationId, model);
var scimListResponseModel = new ScimListResponseModel<ScimUserResponseModel>
{
Resources = usersListQueryResult.userList.Select(u => new ScimUserResponseModel(u)).ToList(),
ItemsPerPage = model.Count,
TotalResults = usersListQueryResult.totalResults,
StartIndex = model.StartIndex,
};
return Ok(scimListResponseModel);
}
[HttpPost("")]
public async Task<IActionResult> Post(Guid organizationId, [FromBody] ScimUserRequestModel model)
{
var orgUser = await _postUserCommand.PostUserAsync(organizationId, model);
var scimUserResponseModel = new ScimUserResponseModel(orgUser);
return new CreatedResult(Url.Action(nameof(Get), new { orgUser.OrganizationId, orgUser.Id }), scimUserResponseModel);
}
[HttpPut("{id}")]
public async Task<IActionResult> Put(Guid organizationId, Guid id, [FromBody] ScimUserRequestModel model)
{
var orgUser = await _organizationUserRepository.GetByIdAsync(id);
if (orgUser == null || orgUser.OrganizationId != organizationId)
{
return new NotFoundObjectResult(new ScimErrorResponseModel
{
Status = 404,
Detail = "User not found."
});
}
if (model.Active && orgUser.Status == OrganizationUserStatusType.Revoked)
{
await _restoreOrganizationUserCommand.RestoreUserAsync(orgUser, EventSystemUser.SCIM);
}
else if (!model.Active && orgUser.Status != OrganizationUserStatusType.Revoked)
{
var results = await _revokeOrganizationUserCommandV2.RevokeUsersAsync(
new RevokeOrganizationUsersRequest(
organizationId,
[id],
new SystemUser(EventSystemUser.SCIM)));
var errors = results.Select(x => x.Result.Match(
y => $"{y.Message} for user {x.Id}",
_ => null))
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToList();
if (errors.Count != 0)
{
return new BadRequestObjectResult(new ScimErrorResponseModel
{
Status = 400,
Detail = string.Join(", ", errors)
});
}
}
// Have to get full details object for response model
var orgUserDetails = await _organizationUserRepository.GetDetailsByIdAsync(id);
return new ObjectResult(new ScimUserResponseModel(orgUserDetails));
}
[HttpPatch("{id}")]
public async Task<IActionResult> Patch(Guid organizationId, Guid id, [FromBody] ScimPatchModel model)
{
await _patchUserCommand.PatchUserAsync(organizationId, id, model);
return new NoContentResult();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(Guid organizationId, Guid id)
{
await _removeOrganizationUserCommand.RemoveUserAsync(organizationId, id, EventSystemUser.SCIM);
return new NoContentResult();
}
}