Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HOSTSD-189 Add file system endpoints #35

Merged
merged 1 commit into from
Dec 29, 2023
Merged
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
7 changes: 7 additions & 0 deletions HSB.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HSB.CSS", "src\libs\css\HSB
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HSB.DataService", "src\data-service\HSB.DataService.csproj", "{87E5B721-F9FD-485F-A393-6C28EAB50BE7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HSB.CSS.API", "src\api-css\HSB.CSS.API.csproj", "{54C182FA-0B79-487E-92F9-7EB0D7164DCC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -64,6 +66,10 @@ Global
{87E5B721-F9FD-485F-A393-6C28EAB50BE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87E5B721-F9FD-485F-A393-6C28EAB50BE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87E5B721-F9FD-485F-A393-6C28EAB50BE7}.Release|Any CPU.Build.0 = Release|Any CPU
{54C182FA-0B79-487E-92F9-7EB0D7164DCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54C182FA-0B79-487E-92F9-7EB0D7164DCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54C182FA-0B79-487E-92F9-7EB0D7164DCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54C182FA-0B79-487E-92F9-7EB0D7164DCC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{57BA1694-AD4C-4DEE-8D6B-144DE51DE27B} = {EF08BB60-A463-4B2B-8413-A70292255338}
Expand All @@ -75,5 +81,6 @@ Global
{68EB92A0-8809-41CA-A27C-71FD8A05F82A} = {57BA1694-AD4C-4DEE-8D6B-144DE51DE27B}
{B54E3181-664D-4974-9E95-77CED12D2239} = {57BA1694-AD4C-4DEE-8D6B-144DE51DE27B}
{87E5B721-F9FD-485F-A393-6C28EAB50BE7} = {EF08BB60-A463-4B2B-8413-A70292255338}
{54C182FA-0B79-487E-92F9-7EB0D7164DCC} = {EF08BB60-A463-4B2B-8413-A70292255338}
EndGlobalSection
EndGlobal
216 changes: 108 additions & 108 deletions src/api-css/Controllers/RoleMappingsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,51 @@ namespace HSB.CSS.API.Controllers;
[Route("v{version:apiVersion}/integrations/{integrationId}/{environment}/user-role-mappings")]
public class RoleMappingsController : ControllerBase
{
#region Variables
private readonly IKeycloakService _service;
private readonly CssOptions _options;
#endregion
#region Variables
private readonly IKeycloakService _service;
private readonly CssOptions _options;
#endregion

#region Constructors
/// <summary>
///
/// </summary>
/// <param name="service"></param>
/// <param name="options"></param>
public RoleMappingsController(IKeycloakService service, IOptions<CssOptions> options)
{
_service = service;
_options = options.Value;
}
#endregion

#region Endpoints
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(typeof(IEnumerable<RoleModel>), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.UnprocessableEntity)]
[SwaggerOperation(Tags = new[] { "RoleMappings" })]
public async Task<IActionResult> GetUserRoleMappingsAsync(string? roleName, string? username)
{
var clientId = _options.ClientId ?? throw new ConfigurationException("Keycloak 'ClientId' is not configured.");
#region Constructors
/// <summary>
///
/// </summary>
/// <param name="service"></param>
/// <param name="options"></param>
public RoleMappingsController(IKeycloakService service, IOptions<CssOptions> options)
{
_service = service;
_options = options.Value;
}
#endregion

if (!String.IsNullOrWhiteSpace(username))
#region Endpoints
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(typeof(IEnumerable<RoleModel>), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.UnprocessableEntity)]
[SwaggerOperation(Tags = new[] { "RoleMappings" })]
public async Task<IActionResult> GetUserRoleMappingsAsync(string? roleName, string? username)
{
var users = await _service.GetUsersAsync(0, 10, new HSB.Keycloak.UserFilter() { Username = username, Exact = true });
if (users.Length == 0) return NotFound(new ErrorResponseModel());
var clientId = _options.ClientId ?? throw new ConfigurationException("Keycloak 'ClientId' is not configured.");

if (!String.IsNullOrWhiteSpace(username))
{
var users = await _service.GetUsersAsync(0, 10, new HSB.Keycloak.UserFilter() { Username = username, Exact = true });
if (users.Length == 0) return NotFound(new ErrorResponseModel());

var user = users.First();
var roles = await _service.GetUserClientRolesAsync(user.Id, clientId);
var user = users.First();
var roles = await _service.GetUserClientRolesAsync(user.Id, clientId);

return new JsonResult(new UserRoleResponseModel()
{
Users = new[] {
return new JsonResult(new UserRoleResponseModel()
{
Users = new[] {
new UserModel() {
Username = user.Username ?? "",
Email = user.Email ?? "",
Expand All @@ -71,66 +71,66 @@ public async Task<IActionResult> GetUserRoleMappingsAsync(string? roleName, stri
Attributes = user.Attributes ?? new Dictionary<string, string[]>()
}
},
Roles = roles.Select(r => new RoleModel(r.Name ?? "", r.Composite)).ToArray()
});
}
else if (!String.IsNullOrWhiteSpace(roleName))
{
var role = await _service.GetRoleAsync(clientId, roleName);
if (role == null) return NotFound(new ErrorResponseModel());
Roles = roles.Select(r => new RoleModel(r.Name ?? "", r.Composite)).ToArray()
});
}
else if (!String.IsNullOrWhiteSpace(roleName))
{
var role = await _service.GetRoleAsync(clientId, roleName);
if (role == null) return NotFound(new ErrorResponseModel());

var users = await _service.GetRoleMembersAsync(clientId, roleName, 0, 100);
var users = await _service.GetRoleMembersAsync(clientId, roleName, 0, 100);

return new JsonResult(new UserRoleResponseModel()
{
Users = users.Select(u => new UserModel()
{
Username = u.Username ?? "",
Email = u.Email ?? "",
FirstName = u.FirstName ?? "",
LastName = u.LastName ?? "",
Attributes = u.Attributes ?? new Dictionary<string, string[]>()
}).ToArray(),
Roles = new[] {
return new JsonResult(new UserRoleResponseModel()
{
Users = users.Select(u => new UserModel()
{
Username = u.Username ?? "",
Email = u.Email ?? "",
FirstName = u.FirstName ?? "",
LastName = u.LastName ?? "",
Attributes = u.Attributes ?? new Dictionary<string, string[]>()
}).ToArray(),
Roles = new[] {
new RoleModel(role.Name ?? "", role.Composite)
}
});
});
}
return BadRequest(new ErrorResponseModel());
}
return BadRequest(new ErrorResponseModel());
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpPost]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(typeof(UserRoleResponseModel), (int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.UnprocessableEntity)]
[SwaggerOperation(Tags = new[] { "RoleMappings" })]
public async Task<IActionResult> UpdateUserRoleMappingsAsync(UserRoleModel mapping, ApiVersion version)
{
var clientId = _options.ClientId ?? throw new ConfigurationException("Keycloak 'ClientId' is not configured.");
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpPost]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(typeof(UserRoleResponseModel), (int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.UnprocessableEntity)]
[SwaggerOperation(Tags = new[] { "RoleMappings" })]
public async Task<IActionResult> UpdateUserRoleMappingsAsync(UserRoleModel mapping, ApiVersion version)
{
var clientId = _options.ClientId ?? throw new ConfigurationException("Keycloak 'ClientId' is not configured.");

var users = await _service.GetUsersAsync(0, 10, new Keycloak.UserFilter() { Username = mapping.Username });
if (users.Length == 0) return NotFound(new ErrorResponseModel());
else if (users.Length > 1) return BadRequest(new ErrorResponseModel());
var users = await _service.GetUsersAsync(0, 10, new Keycloak.UserFilter() { Username = mapping.Username, Exact = true });
if (users.Length == 0) return NotFound(new ErrorResponseModel("User does not exist"));
else if (users.Length > 1) return BadRequest(new ErrorResponseModel("User information matches more than one account"));

var user = users.First();
var role = await _service.GetRoleAsync(clientId, mapping.RoleName);
if (role == null) return NotFound(new ErrorResponseModel());
var user = users.First();
var role = await _service.GetRoleAsync(clientId, mapping.RoleName);
if (role == null) return NotFound(new ErrorResponseModel($"Role does not exist: {mapping.RoleName}"));

if (mapping.Operation.Value == UserRoleOperation.Add.Value)
{
await _service.AddUserClientRolesAsync(user.Id, clientId, new[] { role });
if (mapping.Operation.Value == UserRoleOperation.Add.Value)
{
await _service.AddUserClientRolesAsync(user.Id, clientId, new[] { role });

var roles = await _service.GetUserClientRolesAsync(user.Id, clientId);
var model = new UserRoleResponseModel()
{
Users = new[] {
var roles = await _service.GetUserClientRolesAsync(user.Id, clientId);
var model = new UserRoleResponseModel()
{
Users = new[] {
new UserModel() {
Username = user.Username ?? "",
Email = user.Email ?? "",
Expand All @@ -139,23 +139,23 @@ public async Task<IActionResult> UpdateUserRoleMappingsAsync(UserRoleModel mappi
Attributes = user.Attributes ?? new Dictionary<string, string[]>()
}
},
Roles = roles.Select(r => new RoleModel(r.Name ?? "", r.Composite)).ToArray()
};
return CreatedAtAction("GetUserRoleMappings", new
{
username = mapping.Username,
version = version.ToString(),
integrationId = this.RouteData.Values["integrationId"],
environment = this.RouteData.Values["environment"]
}, model);
}
else if (mapping.Operation.Value == UserRoleOperation.Delete.Value)
{
await _service.RemoveUserClientRolesAsync(user.Id, clientId, new[] { role });
return NoContent();
}
Roles = roles.Select(r => new RoleModel(r.Name ?? "", r.Composite)).ToArray()
};
return CreatedAtAction("GetUserRoleMappings", new
{
username = mapping.Username,
version = version.ToString(),
integrationId = this.RouteData.Values["integrationId"],
environment = this.RouteData.Values["environment"]
}, model);
}
else if (mapping.Operation.Value == UserRoleOperation.Delete.Value)
{
await _service.RemoveUserClientRolesAsync(user.Id, clientId, new[] { role });
return NoContent();
}

return BadRequest(new ErrorResponseModel());
}
#endregion
return BadRequest(new ErrorResponseModel($"Operation specified is invalid: {mapping.Operation.Value}"));
}
#endregion
}
21 changes: 16 additions & 5 deletions src/api/Areas/Admin/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class UserController : ControllerBase
{
#region Variables
private readonly IUserService _userService;
private readonly IGroupService _groupService;
private readonly ICssHelper _cssHelper;
private readonly JsonSerializerOptions _serializerOptions;
#endregion
Expand All @@ -36,14 +37,17 @@ public class UserController : ControllerBase
/// Creates a new instance of a UserController object, initializes with specified parameters.
/// </summary>
/// <param name="userService"></param>
/// <param name="groupService"></param>
/// <param name="cssHelper"></param>
/// <param name="serializerOptions"></param>
public UserController(
IUserService userService,
IGroupService groupService,
ICssHelper cssHelper,
IOptions<JsonSerializerOptions> serializerOptions)
{
_userService = userService;
_groupService = groupService;
_cssHelper = cssHelper;
_serializerOptions = serializerOptions.Value;
}
Expand All @@ -63,7 +67,7 @@ public IActionResult Find()
var uri = new Uri(this.Request.GetDisplayUrl());
var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
var filter = new HSB.Models.Filters.UserFilter(query);
var result = _userService.Find(filter.GeneratePredicate(), filter.Sort);
var result = _userService.Find(filter);
return new JsonResult(result.Select(u => new UserModel(u)).ToArray());
}

Expand All @@ -80,9 +84,7 @@ public IActionResult Find()
public IActionResult GetForId(int id)
{
var result = _userService.FindForId(id);

if (result == null) return new NoContentResult();

return new JsonResult(new UserModel(result));
}

Expand Down Expand Up @@ -120,9 +122,18 @@ public IActionResult Add(UserModel model)
public async Task<IActionResult> UpdateAsync(UserModel model)
{
var entry = _userService.Update((Entities.User)model);
var roles = entry.Entity.Groups.SelectMany(g => g.Roles.Select(r => r.Name)).Distinct().ToArray();

await _cssHelper.UpdateUserRolesAsync(model.Key.ToString(), roles);
// Fetch groups from database to get roles associated with them.
var roles = new List<string>();
foreach (var group in entry.Entity.GroupsManyToMany)
{
var entity = _groupService.FindForId(group.GroupId);
if (entity != null)
roles.AddRange(entity.RolesManyToMany.Select(r => r.Role!.Name));
}
roles = roles.Distinct().ToList();

await _cssHelper.UpdateUserRolesAsync(model.Key.ToString(), roles.ToArray());
_userService.CommitTransaction();
return new JsonResult(new UserModel(entry.Entity));
}
Expand Down
7 changes: 2 additions & 5 deletions src/api/Controllers/AuthController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,16 @@ public class AuthController : ControllerBase
{
#region Variables
private readonly ICssHelper _cssHelper;
private readonly JsonSerializerOptions _serializerOptions;
#endregion

#region Constructors
/// <summary>
/// Creates a new instance of a AuthController object, initializes with specified parameters.
/// </summary>
/// <param name="cssHelper"></param>
/// <param name="serializerOptions"></param>
public AuthController(ICssHelper cssHelper, IOptions<JsonSerializerOptions> serializerOptions)
public AuthController(ICssHelper cssHelper)
{
_cssHelper = cssHelper;
_serializerOptions = serializerOptions.Value;
}
#endregion

Expand All @@ -54,7 +51,7 @@ public AuthController(ICssHelper cssHelper, IOptions<JsonSerializerOptions> seri
public async Task<IActionResult> UserInfoAsync()
{
var user = await _cssHelper.ActivateAsync(this.User);
return new JsonResult(new PrincipalModel(this.User, user, _serializerOptions));
return new JsonResult(new PrincipalModel(this.User, user));
}
#endregion
}
Loading
Loading