/// <summary> /// Fetch all Users in PIMS and update keycloak so they have the same roles and claims. /// </summary> /// <param name="log"></param> /// <returns></returns> private async Task SyncUsersAsync(StringBuilder log) { // Fetch all users in keycloak so that they can be synced. // This is useful when the database has been refreshed. var kusers = await _client.HandleGetAsync <KModel.UserModel[]>(_client.AdminRoute($"users")); var page = 1; var quantity = 50; var users = new List <UserModel>(); var pageOfUsers = await _client.HandleRequestAsync <PageModel <UserModel> >(HttpMethod.Get, $"{_options.Api.Uri}/admin/users?page={page}&quantity={quantity}"); // TODO: Replace paging with specific requests for a user. users.AddRange(pageOfUsers.Items); // Keep asking for pages of users until we have them all. while (pageOfUsers.Items.Count() == quantity) { pageOfUsers = await _client.HandleRequestAsync <PageModel <UserModel> >(HttpMethod.Get, $"{_options.Api.Uri}/admin/users?page={++page}&quantity={quantity}"); users.AddRange(pageOfUsers.Items); } foreach (var user in users) { var kuser = await GetUserAsync(user); // Ignore users that only exist in PIMS. if (kuser == null) { continue; } // Sync user agencies. if (kuser.Attributes == null) { kuser.Attributes = new Dictionary <string, string[]>(); } kuser.Enabled = !user.IsDisabled; kuser.FirstName = user.FirstName; kuser.LastName = user.LastName; kuser.EmailVerified = user.EmailVerified; kuser.Attributes["displayName"] = new[] { user.DisplayName }; kuser.Attributes["position"] = new[] { user.Position }; kuser.Attributes["agencies"] = user.Agencies.Select(a => a.Id.ToString()).ToArray(); _logger.LogInformation($"Updating User in Keycloak '{user.Username}'."); log.Append($"Keycloak - User updated '{user.Username}'{Environment.NewLine}"); var userResponse = await _client.SendJsonAsync($"{_options.Auth.Keycloak.Admin.Authority}/users/{kuser.Id}", HttpMethod.Put, kuser); if (!userResponse.IsSuccessStatusCode) { throw new HttpClientRequestException(userResponse, $"Failed to update the user '{user.Username}' in keycloak"); } // Sync user roles. foreach (var role in user.Roles) { var groupResponse = await _client.SendAsync($"{_options.Auth.Keycloak.Admin.Authority}/users/{kuser.Id}/groups/{role.KeycloakGroupId}", HttpMethod.Put); if (!groupResponse.IsSuccessStatusCode) { throw new HttpClientRequestException(groupResponse, $"Failed to add the group '{role.Name}' to the user '{user.Username}' keycloak"); } } } // Add keycloak users to PIMS. // Only add users who don't exist. foreach (var kuser in kusers.Where(u => !users.Any(pu => pu.Username == u.Username))) { try { if (String.IsNullOrWhiteSpace(kuser.Email) || String.IsNullOrWhiteSpace(kuser.FirstName) || String.IsNullOrWhiteSpace(kuser.LastName)) { _logger.LogInformation($"Unable to add user to PIMS '{kuser.Username}'."); continue; } _logger.LogInformation($"Adding User to PIMS '{kuser.Username}'."); var user = new UserModel(kuser); var uRoles = user.Roles as List <RoleModel>; // Check if the agencies listed in Keycloak exist in PIMS. If they don't report the issue in the summary. var removeAgencies = new List <AgencyModel>(); if (user.Agencies?.Any() == true) { var agencies = user.Agencies.ToArray(); foreach (var agency in agencies) { var aexists = await _client.HandleRequestAsync <AgencyModel>(HttpMethod.Get, $"{_options.Api.Uri}/admin/agencies/{agency.Id}", r => { _logger.LogError($"Agency '{agency.Id}' does not exist in PIMS.", user); log.Append($"PIMS - Agency missing '{agency.Id}'{Environment.NewLine}"); removeAgencies.Add(agency); return(true); }); } } // Remove any agencies. removeAgencies.ForEach(a => ((List <AgencyModel>)user.Agencies).Remove(a)); // Fetch the users groups from keycloak. var kgroups = await _client.HandleGetAsync <KModel.GroupModel[]>(_client.AdminRoute($"users/{kuser.Id}/groups")); // Fetch the group from PIMS. foreach (var kgroup in kgroups) { var role = await _client.HandleGetAsync <RoleModel>($"{_options.Api.Uri}/admin/roles/name/{kgroup.Name}", r => true); if (role != null) { uRoles.Add(role); } } user.Roles = uRoles; // Add the user to PIMS. user = await _client.HandleRequestAsync <UserModel, UserModel>(HttpMethod.Post, $"{_options.Api.Uri}/admin/users", user); log.Append($"Keycloak User added to PIMS '{user.Username}'{Environment.NewLine}"); } catch (HttpClientRequestException ex) { _logger.LogError($"Failed to add keycloak user '{kuser.Email}' to PIMS.", ex); } } }
/// <summary> /// Update the realm information. /// </summary> /// <returns></returns> private async Task UpdateRealmAsync() { _logger.LogInformation($"Updating realm '{_options.Realm.Name}'"); // Determine if realm exists, it will throw an exception if it doesn't. var realm = await _client.HandleGetAsync <KModel.RealmModel>(_client.AdminRoute()); realm.DisplayName = _options.Realm.DisplayName; realm.DisplayNameHtml = _options.Realm.DisplayNameHtml; var rRes = await _client.SendJsonAsync(_client.AdminRoute(), HttpMethod.Put, realm); if (!rRes.IsSuccessStatusCode) { throw new HttpClientRequestException(rRes); } await AddUpdateRealmRolesAsync(); await AddUpdateGroupsAsync(); await AddUpdateClientsAsync(); }