using Quizzer.OpenIDConnect; using Newtonsoft.Json; using Quizzer.OpenIDConnect; namespace Quizzer.Implementations { public class KeyCloak { private bool isDebug; private bool isOK; private bool isTeacher; private string? accessToken; private string? classlessId; private string? teachersId; private string? developersId; private string? studentsId; /// /// This method uses the OAuth Resource Owners Credentials Flow to get an Access Token to provide /// Authorization to the APIs. /// /// private string GetAccessToken() { var client = new HttpClient(); // https://auth.c.ucnit.eu/realms/UCNit/protocol/openid-connect/token string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/realms/" + MyConfiguration.Get()["API_REALM"] + "/protocol/openid-connect/token"; var request = new HttpRequestMessage(HttpMethod.Post, theURL); var collection = new List>(); collection.Add(new("client_id", MyConfiguration.Get()["API_CLIENTID"])); collection.Add(new("client_secret", MyConfiguration.Get()["API_SECRET"])); collection.Add(new("grant_type", "client_credentials")); var content = new FormUrlEncodedContent(collection); request.Content = content; if (isDebug) { Console.WriteLine("GetAccessToken"); Console.WriteLine("(POST) " + theURL); Console.WriteLine("client_id: " + MyConfiguration.Get()["API_CLIENTID"]); Console.WriteLine("client_secret: " + MyConfiguration.Get()["API_SECRET"]); Console.WriteLine("grant_type: client_credentials"); } var response = client.SendAsync(request).Result; try { response.EnsureSuccessStatusCode(); string jsonString = response.Content.ReadAsStringAsync().Result; object responseData = JsonConvert.DeserializeObject(jsonString); // return the Access Token. accessToken = ((dynamic)responseData).access_token; } catch (Exception ex) { Console.WriteLine(request.RequestUri); Console.WriteLine(ex.Message); accessToken = null; } // return the Access Token. return accessToken; } public KeyCloak() { isDebug = MyConfiguration.Get()["DEBUG"] == "Y"; try { accessToken = GetAccessToken(); this.isOK = true; } catch { this.isOK = false; } } public bool KeyCloakIsOK() { return isOK; } public List KeyCloakGetGroups() { var client = new HttpClient(); // https://{{Server}}/admin/realms/{{Realm}}/groups string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/groups"; var request = new HttpRequestMessage(HttpMethod.Get, theURL); request.Headers.Add("Authorization", "Bearer " + accessToken); if (isDebug) { Console.WriteLine("KeyCloakGetGroups"); Console.WriteLine("(GET) " + theURL); Console.WriteLine("Authorization Bearer " + accessToken); } var response = client.SendAsync(request).Result; try { response.EnsureSuccessStatusCode(); } catch (HttpRequestException ex) { Console.WriteLine(ex.Message); Console.WriteLine("KeyCloakGetGroupsAsync"); } string jsonString = response.Content.ReadAsStringAsync().Result; List groups = JsonConvert.DeserializeObject>(jsonString); foreach (KCGroups group in groups) { if (group.name == "ClassLess") classlessId = group.id; if (group.name == "developer") developersId = group.id; if (group.name == "teacher") teachersId = group.id; if (group.name == "student") studentsId = group.id; } return groups; } public string? KeyCloakClassLess() { if (classlessId == null) _ = KeyCloakGetGroups(); return classlessId; } public string? KeyCloakTeacher() { if (teachersId == null) _ = KeyCloakGetGroups(); return teachersId; } public string? KeyCloakStudent() { if (studentsId == null) _ = KeyCloakGetGroups(); return studentsId; } public List KeyCloakGetUsersGroups(string theUser) { var client = new HttpClient(); // https://{{Server}}/admin/realms/{{Realm}}/users/{{kajeID}}/groups string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/users/" + theUser + "/groups"; var request = new HttpRequestMessage(HttpMethod.Get, theURL); request.Headers.Add("Authorization", "Bearer " + accessToken); if (isDebug) { Console.WriteLine("KeyCloakGetUsersGroups"); Console.WriteLine("(GET) " + theURL); Console.WriteLine("Authorization Bearer " + accessToken); } var response = client.SendAsync(request).Result; try { response.EnsureSuccessStatusCode(); } catch (HttpRequestException ex) { Console.WriteLine(ex.Message); Console.WriteLine("KeyCloakGetUsersGroupsAsync for user: [" + theUser + "]"); } string jsonString = response.Content.ReadAsStringAsync().Result; List groups = JsonConvert.DeserializeObject>(jsonString); isTeacher = false; foreach (KCGroups group in groups) { if (group.name == "teacher" || group.name == "developer") isTeacher = true; if (isDebug) { Console.WriteLine("in group: " + group.name); } } return groups; } public bool KeyCloakLeaveGroup(string theUser, string theGroup) { var client = new HttpClient(); string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/users/" + theUser + "/groups/" + theGroup; var request = new HttpRequestMessage(HttpMethod.Delete, theURL); request.Headers.Add("Authorization", "Bearer " + accessToken); if (isDebug) { Console.WriteLine("KeyCloakLeaveGroup"); Console.WriteLine("(DELETE) " + theURL); Console.WriteLine("Authorization Bearer " + accessToken); } var response = client.SendAsync(request).Result; try { response.EnsureSuccessStatusCode(); return true; } catch (Exception ex) { return false; } } public bool KeyCloakJoinGroup(string theUser, string theGroup) { var client = new HttpClient(); string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/users/" + theUser + "/groups/" + theGroup; var request = new HttpRequestMessage(HttpMethod.Put, theURL); request.Headers.Add("Authorization", "Bearer " + accessToken); if (isDebug) { Console.WriteLine("KeyCloakJoinGroup"); Console.WriteLine("(PUT) " + theURL); Console.WriteLine("Authorization Bearer " + accessToken); } var response = client.SendAsync(request).Result; try { response.EnsureSuccessStatusCode(); return true; } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine("KeyCloakJoinGroup: [" + theGroup + "] for user: [" + theUser + "]"); return false; } } public void KeyCloakToggleMembership(string theUser, string theGroup) { List myGroups = KeyCloakGetUsersGroups(theUser); if (isDebug) { foreach (KCGroups group in myGroups) { Console.WriteLine("{0} member of {1}", theUser, group.name); } } foreach (KCGroups group in myGroups) { if (group.id == theGroup) { KeyCloakLeaveGroup(theUser, theGroup); if (isDebug) Console.WriteLine("{0} left {1}", theUser, theGroup); return; } } // if we get here, then create membership KeyCloakJoinGroup(theUser, theGroup); if (isDebug) Console.WriteLine("{0} joined {1}", theUser, theGroup); } public bool KeyCloakIsTeacher() { return isTeacher; } } public class KCUserGroups { public string? id { get; set; } public string? name { get; set; } public string? path { get; set; } } public class KCGroups : KCUserGroups { public List subGroups { get; set; } } }