From 89e5905fab54701012153fcea4558bfdaf338818 Mon Sep 17 00:00:00 2001 From: Alexander Simola Bergsten Date: Thu, 12 Jun 2025 10:14:58 +0200 Subject: [PATCH 1/3] Add possibility to search for groups with SCIM client --- .../SimpleIdServer.Scim.Client/SCIMClient.cs | 23 +++++++++++++++++-- .../SearchRequest.cs | 2 ++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs b/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs index 225081f7b..26025ed5d 100644 --- a/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs +++ b/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs @@ -76,7 +76,26 @@ public async Task> GetResourceTypes(Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(userEdp)}?{queryString}") }; - if(!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", $"Bearer {accessToken}"); + if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", accessToken); + var httpClient = GetHttpClient(); + var httpResult = await httpClient.SendAsync(request, cancellationToken); + httpResult.EnsureSuccessStatusCode(); + var json = await httpResult.Content.ReadAsStringAsync(cancellationToken); + var jsonObj = JsonObject.Parse(json).AsObject(); + return (RepresentationSerializer.DeserializeSearchRepresentations(jsonObj), json); + } + + public async Task<(SearchResult, string)> SearchGroups(SearchRequest searchRequest, string accessToken, CancellationToken cancellationToken) + { + if (_resourceTypes == null) await GetResourceTypes(cancellationToken); + var groupEdp = _resourceTypes.Resources.Single(r => r.Name == "Group").Endpoint; + var queryString = SerializeQueryString(searchRequest); + var request = new HttpRequestMessage + { + Method = HttpMethod.Get, + RequestUri = new Uri($"{GetPath(groupEdp)}?{queryString}") + }; + if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -94,7 +113,7 @@ public async Task GetGroup(string id, string accessToken, Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}/{id}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", $"Bearer {accessToken}"); + if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); diff --git a/src/Scim/SimpleIdServer.Scim.Client/SearchRequest.cs b/src/Scim/SimpleIdServer.Scim.Client/SearchRequest.cs index dd6388a30..4ed059d36 100644 --- a/src/Scim/SimpleIdServer.Scim.Client/SearchRequest.cs +++ b/src/Scim/SimpleIdServer.Scim.Client/SearchRequest.cs @@ -11,5 +11,7 @@ public class SearchRequest public int Count { get; set; } = 100; [JsonPropertyName("startIndex")] public int StartIndex { get; set; } + [JsonPropertyName("filter")] + public string Filter { get; set; } } } From 218d70f480170a6ea343f5d85a5eb2d94df6452a Mon Sep 17 00:00:00 2001 From: Alexander Simola Bergsten Date: Tue, 1 Jul 2025 12:38:18 +0200 Subject: [PATCH 2/3] Added possibility of setting AuthenticationScheme in SCIMClient --- .../SimpleIdServer.Scim.Client/SCIMClient.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs b/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs index 26025ed5d..71753ce5a 100644 --- a/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs +++ b/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs @@ -16,11 +16,15 @@ namespace SimpleIdServer.Scim.Client { public class SCIMClient : IDisposable { + private const string DefaultAuthenticationScheme = "Bearer"; + private readonly HttpClientHandler _handler = null; private readonly string _baseUrl; private HttpClient _httpClient; private SearchResult _resourceTypes; + public string AuthenticationScheme { get; set; } = DefaultAuthenticationScheme; + public SCIMClient(string baseUrl) { _baseUrl = baseUrl; @@ -76,7 +80,7 @@ public async Task> GetResourceTypes(Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(userEdp)}?{queryString}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -95,7 +99,7 @@ public async Task> GetResourceTypes(Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}?{queryString}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -113,7 +117,7 @@ public async Task GetGroup(string id, string accessToken, Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}/{id}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -131,7 +135,7 @@ public async Task GetUser(string id, string accessToken, Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}/{id}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", $"Bearer {accessToken}"); + if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -150,7 +154,7 @@ public async Task AddUser(JsonObject jsonObject, string RequestUri = new Uri(GetPath(userEdp)), Content = new StringContent(jsonObject.ToJsonString(), Encoding.UTF8, "application/json") }; - if (!string.IsNullOrWhiteSpace(accessToken)) request.Headers.Add("Authorization", $"Bearer {accessToken}"); + if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); if (httpResult.IsSuccessStatusCode) return null; @@ -158,6 +162,15 @@ public async Task AddUser(JsonObject jsonObject, string return JsonSerializer.Deserialize(content); } + private void AddAccessTokenToAuthorizationHeader(HttpRequestMessage request, string accessToken) + { + var headerValue = string.IsNullOrEmpty(AuthenticationScheme) + ? accessToken + : string.Join(" ", AuthenticationScheme, accessToken); + + request.Headers.Add("Authorization", headerValue); + } + private HttpClient GetHttpClient() { if (_httpClient != null) return _httpClient; From 4207874723568730fe4422b5fb31180e7d89d837 Mon Sep 17 00:00:00 2001 From: Alexander Simola Bergsten Date: Tue, 1 Jul 2025 12:40:15 +0200 Subject: [PATCH 3/3] AddAccessTokenToAuthorizationHeader renamed to SetAuthorizationHeader --- src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs b/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs index 71753ce5a..2aadd2ce5 100644 --- a/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs +++ b/src/Scim/SimpleIdServer.Scim.Client/SCIMClient.cs @@ -80,7 +80,7 @@ public async Task> GetResourceTypes(Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(userEdp)}?{queryString}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) SetAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -99,7 +99,7 @@ public async Task> GetResourceTypes(Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}?{queryString}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) SetAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -117,7 +117,7 @@ public async Task GetGroup(string id, string accessToken, Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}/{id}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) SetAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -135,7 +135,7 @@ public async Task GetUser(string id, string accessToken, Cancellatio Method = HttpMethod.Get, RequestUri = new Uri($"{GetPath(groupEdp)}/{id}") }; - if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) SetAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); httpResult.EnsureSuccessStatusCode(); @@ -154,7 +154,7 @@ public async Task AddUser(JsonObject jsonObject, string RequestUri = new Uri(GetPath(userEdp)), Content = new StringContent(jsonObject.ToJsonString(), Encoding.UTF8, "application/json") }; - if (!string.IsNullOrWhiteSpace(accessToken)) AddAccessTokenToAuthorizationHeader(request, accessToken); + if (!string.IsNullOrWhiteSpace(accessToken)) SetAuthorizationHeader(request, accessToken); var httpClient = GetHttpClient(); var httpResult = await httpClient.SendAsync(request, cancellationToken); if (httpResult.IsSuccessStatusCode) return null; @@ -162,7 +162,7 @@ public async Task AddUser(JsonObject jsonObject, string return JsonSerializer.Deserialize(content); } - private void AddAccessTokenToAuthorizationHeader(HttpRequestMessage request, string accessToken) + private void SetAuthorizationHeader(HttpRequestMessage request, string accessToken) { var headerValue = string.IsNullOrEmpty(AuthenticationScheme) ? accessToken