/// <summary> /// Remove roles from the group in keycloak. /// </summary> /// <param name="group"></param> /// <param name="role"></param> /// <returns></returns> private async Task RemoveRolesFromGroupInKeycloak(KModel.GroupModel group, PModel.RoleModel role) { var removeRoles = group.RealmRoles?.Where(r => !role.Claims.Select(c => c.Name).Contains(r)) ?? new string[0]; foreach (var rname in removeRoles) { // Get the matching role from keycloak. var krole = await _client.HandleRequestAsync <KModel.RoleModel>(HttpMethod.Get, $"{_options.Auth.Keycloak.Admin.Authority}/roles/{rname}"); var roles = new[] { new KModel.RoleModel() { Id = krole.Id, Name = krole.Name, Composite = false, ClientRole = false, ContainerId = _options.Auth.Keycloak.Realm, Description = krole.Description } }; // Update the group in keycloak. var response = await _client.SendJsonAsync($"{_options.Auth.Keycloak.Admin.Authority}/groups/{group.Id}/role-mappings/realm", HttpMethod.Delete, roles); if (!response.IsSuccessStatusCode) { throw new HttpClientRequestException(response, $"Failed to update the group '{role.Name}' removing role '{rname}' in keycloak"); } } }
/// <summary> /// Add a group to keycloak. /// </summary> /// <param name="role"></param> /// <returns></returns> private async Task <KModel.GroupModel> AddGroupToKeycloak(PModel.RoleModel role) { var addGroup = new KModel.GroupModel() { Name = role.Name, Path = $"/{role.Name}", RealmRoles = role.Claims.Select(c => c.Name).ToArray() }; // Add the group to keycloak and sync with PIMS. var response = await _client.SendJsonAsync($"{_options.Auth.Keycloak.Admin.Authority}/groups", HttpMethod.Post, addGroup); if (response.StatusCode == HttpStatusCode.Created) { // Get the Group Id var groups = await _client.HandleRequestAsync <IEnumerable <KModel.GroupModel> >(HttpMethod.Get, $"{_options.Auth.Keycloak.Admin.Authority}/groups?search={role.Name}"); role.KeycloakGroupId = groups.FirstOrDefault().Id; role.Key = role.KeycloakGroupId.Value; return(await GetKeycloakGroupAsync(role, false)); } else { throw new HttpClientRequestException(response, $"Failed to add the group '{role.Name}' to keycloak"); } }
/// <summary> /// Get the keycloak group that matches the PIMS role. /// If it doesn't exist, create it in keycloak. /// </summary> /// <param name="role"></param> /// <param name="update"></param> /// <returns></returns> private async Task <KModel.GroupModel> GetKeycloakGroupAsync(PModel.RoleModel role, bool update = true) { try { // Make a request to keycloak to find a matching group. // If one is found, sync both keycloak and PIMS. // If one is not found, add it to keycloak and sync with PIMS. var group = await _client.HandleRequestAsync <KModel.GroupModel>(HttpMethod.Get, $"{_options.Auth.Keycloak.Admin.Authority}/groups/{role.KeycloakGroupId ?? role.Key}"); // If the roles match the claims, return it. if (update) { return(await UpdateGroupInKeycloak(group, role)); } return(group); } catch (HttpClientRequestException ex) { if (ex.StatusCode == HttpStatusCode.NotFound) { // Check if the group exists as a different name. var groups = await _client.HandleRequestAsync <IEnumerable <KModel.GroupModel> >(HttpMethod.Get, $"{_options.Auth.Keycloak.Admin.Authority}/groups?search={role.Name}"); var existingGroup = groups.FirstOrDefault(g => g.Name == role.Name); if (existingGroup != null) { role.Key = existingGroup.Id.Value; role.KeycloakGroupId = existingGroup.Id; if (update) { return(await UpdateGroupInKeycloak(existingGroup, role)); } return(existingGroup); } else { return(await AddGroupToKeycloak(role)); } } throw; } }
/// <summary> /// Add roles to the group in keycloak. /// </summary> /// <param name="group"></param> /// <param name="role"></param> /// <returns></returns> private async Task AddRolesToGroupInKeycloak(KModel.GroupModel group, PModel.RoleModel role) { // Get the matching role from keycloak. //var krole = await HandleRequestAsync<KModel.RoleModel>(HttpMethod.Get, $"{_options.Auth.Keycloak.Admin.Authority}/roles/{claim.Name}"); var roles = role.Claims.Select(c => new KModel.RoleModel() { Id = c.KeycloakRoleId.Value, Name = c.Name, Composite = false, ClientRole = false, ContainerId = _options.Auth.Keycloak.Realm, Description = c.Description }).ToArray(); // Update the group in keycloak. var response = await _client.SendJsonAsync($"{_options.Auth.Keycloak.Admin.Authority}/groups/{group.Id}/role-mappings/realm", HttpMethod.Post, roles); if (!response.IsSuccessStatusCode) { throw new HttpClientRequestException(response, $"Failed to update the group '{role.Name}' with the roles '{String.Join(",", roles.Select(r => r.Name).ToArray())}' in keycloak"); } }
/// <summary> /// Update a group in keycloak. /// </summary> /// <param name="group"></param> /// <param name="role"></param> /// <returns></returns> private async Task <KModel.GroupModel> UpdateGroupInKeycloak(KModel.GroupModel group, PModel.RoleModel role) { // Update the group in keycloak. var response = await _client.SendJsonAsync($"{_options.Auth.Keycloak.Admin.Authority}/groups/{group.Id}", HttpMethod.Put, group); if (response.IsSuccessStatusCode) { await RemoveRolesFromGroupInKeycloak(group, role); await AddRolesToGroupInKeycloak(group, role); return(await GetKeycloakGroupAsync(role, false)); } else { throw new HttpClientRequestException(response, $"Failed to update the group '{role.Name}' in keycloak"); } }