From 3e16a00c90721c38f9725e5d9a7b7d300fd1ea2b Mon Sep 17 00:00:00 2001 From: Mohammed Ahmed Hussien Date: Fri, 1 Mar 2024 11:20:04 +0300 Subject: [PATCH] Add User Info Endpoint --- Sample/ClientApp_OpenId/Program.cs | 1 + .../Controllers/DiscoveryEndpointController.cs | 2 +- .../Controllers/UserInfoController.cs | 11 +++++++++-- .../OAuthResponse/UserInfoResponse.cs | 16 +++++++++++++++- .../OauthResponse/DiscoveryResponse.cs | 2 +- Server/src/OAuth20.Server/Program.cs | 2 ++ .../OAuth20.Server/Services/UserInfoService.cs | 18 ++++++++++++------ 7 files changed, 41 insertions(+), 11 deletions(-) diff --git a/Sample/ClientApp_OpenId/Program.cs b/Sample/ClientApp_OpenId/Program.cs index 68d77b2..72be4fc 100644 --- a/Sample/ClientApp_OpenId/Program.cs +++ b/Sample/ClientApp_OpenId/Program.cs @@ -23,6 +23,7 @@ options.CallbackPath = "/signin-oidc"; options.SaveTokens = true; options.Scope.Add("jwtapitestapp.read"); + // options.GetClaimsFromUserInfoEndpoint = true; }); diff --git a/Server/src/OAuth20.Server/Controllers/DiscoveryEndpointController.cs b/Server/src/OAuth20.Server/Controllers/DiscoveryEndpointController.cs index a28e1a5..3119116 100644 --- a/Server/src/OAuth20.Server/Controllers/DiscoveryEndpointController.cs +++ b/Server/src/OAuth20.Server/Controllers/DiscoveryEndpointController.cs @@ -28,7 +28,7 @@ public JsonResult GetConfiguration() acr_values_supported = new string[] {"urn:mace:incommon:iap:silver", "urn:mace:incommon:iap:bronze"}, response_types_supported = new string[] { "code", "code id_token", "id_token", "token id_token" }, subject_types_supported = new string[] { "public", "pairwise" }, - + user_info_endpoint = "https://localhost:7275/UserInfo/GetUserInfo", userinfo_encryption_enc_values_supported = new string[] { "A128CBC-HS256", "A128GCM" }, id_token_signing_alg_values_supported = new string[] { "RS256", "ES256", "HS256" , "SHA256" }, id_token_encryption_alg_values_supported = new string[] { "RSA1_5", "A128KW" }, diff --git a/Server/src/OAuth20.Server/Controllers/UserInfoController.cs b/Server/src/OAuth20.Server/Controllers/UserInfoController.cs index 22d19d2..1155da1 100644 --- a/Server/src/OAuth20.Server/Controllers/UserInfoController.cs +++ b/Server/src/OAuth20.Server/Controllers/UserInfoController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using OAuth20.Server.Services; using System.Threading.Tasks; namespace OAuth20.Server.Controllers @@ -7,10 +8,16 @@ namespace OAuth20.Server.Controllers [ApiController] public class UserInfoController : ControllerBase { + private readonly IUserInfoService _userInfoService; + public UserInfoController(IUserInfoService userInfoService) + { + _userInfoService = userInfoService; + } [HttpGet, HttpPost] - public async Task UserInfo() + public async Task GetUserInfo() { - return Ok(); + var userInfo = await _userInfoService.GetUserInfoAsync(); + return Ok(userInfo); } } } diff --git a/Server/src/OAuth20.Server/OAuthResponse/UserInfoResponse.cs b/Server/src/OAuth20.Server/OAuthResponse/UserInfoResponse.cs index 85ec92a..70a690e 100644 --- a/Server/src/OAuth20.Server/OAuthResponse/UserInfoResponse.cs +++ b/Server/src/OAuth20.Server/OAuthResponse/UserInfoResponse.cs @@ -1,4 +1,6 @@ -namespace OAuth20.Server.OAuthResponse +using System.Text.Json.Serialization; + +namespace OAuth20.Server.OAuthResponse { public class UserInfoResponse { @@ -13,5 +15,17 @@ public class UserInfoResponse /// Returned result as json. /// public string Claims { get; set; } + + [JsonPropertyName("sub")] + public string Sub { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("email")] + public string Email { get; set; } + + [JsonPropertyName("email_verified")] + public bool EmailVerified { get; set; } } } diff --git a/Server/src/OAuth20.Server/OauthResponse/DiscoveryResponse.cs b/Server/src/OAuth20.Server/OauthResponse/DiscoveryResponse.cs index da63497..536c7d5 100644 --- a/Server/src/OAuth20.Server/OauthResponse/DiscoveryResponse.cs +++ b/Server/src/OAuth20.Server/OauthResponse/DiscoveryResponse.cs @@ -17,7 +17,7 @@ public class DiscoveryResponse public string token_endpoint { get; set; } public IList token_endpoint_auth_methods_supported { get; set; } public IList token_endpoint_auth_signing_alg_values_supported { get; set; } - public string userinfo_endpoint { get; set; } + public string user_info_endpoint { get; set; } public string check_session_iframe { get; set; } public string end_session_endpoint { get; set; } public string jwks_uri { get; set; } diff --git a/Server/src/OAuth20.Server/Program.cs b/Server/src/OAuth20.Server/Program.cs index 62e5209..db0ca30 100644 --- a/Server/src/OAuth20.Server/Program.cs +++ b/Server/src/OAuth20.Server/Program.cs @@ -62,6 +62,8 @@ Everyone is permitted to copy and distribute verbatim copies builder.Services.TryAddScoped(); builder.Services.TryAddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddHttpContextAccessor(); builder.Services.Configure(options => diff --git a/Server/src/OAuth20.Server/Services/UserInfoService.cs b/Server/src/OAuth20.Server/Services/UserInfoService.cs index f044b68..069899e 100644 --- a/Server/src/OAuth20.Server/Services/UserInfoService.cs +++ b/Server/src/OAuth20.Server/Services/UserInfoService.cs @@ -7,16 +7,14 @@ Everyone is permitted to copy and distribute verbatim copies */ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; -using NuGet.Versioning; using OAuth20.Server.Configuration; -using OAuth20.Server.OauthRequest; using OAuth20.Server.OAuthResponse; using OAuth20.Server.Services.Users; using OAuth20.Server.Validations; using System; -using System.ComponentModel.DataAnnotations; using System.IdentityModel.Tokens.Jwt; using System.IO; using System.Linq; @@ -27,27 +25,30 @@ namespace OAuth20.Server.Services; public interface IUserInfoService { - + Task GetUserInfoAsync(); } -public class UserInfoService +public class UserInfoService : IUserInfoService { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IBearerTokenUsageTypeValidation _bearerTokenUsageTypeValidation; private readonly OAuthServerOptions _optionsMonitor; private readonly IClientService _clientService; private readonly IUserManagerService _userManagerService; + private readonly ILogger _logger; public UserInfoService(IHttpContextAccessor httpContextAccessor, IBearerTokenUsageTypeValidation bearerTokenUsageTypeValidation, IOptionsMonitor optionsMonitor, IClientService clientService, - IUserManagerService userManagerService) + IUserManagerService userManagerService, + ILogger logger) { _httpContextAccessor = httpContextAccessor; _bearerTokenUsageTypeValidation = bearerTokenUsageTypeValidation; _optionsMonitor = optionsMonitor.CurrentValue ?? new OAuthServerOptions(); _clientService = clientService; _userManagerService = userManagerService; + _logger = logger; } public async Task GetUserInfoAsync() @@ -113,6 +114,10 @@ public async Task GetUserInfoAsync() string scope = (tokenValidationReslt.Claims.FirstOrDefault(x => x.Key == "scope").Value).ToString(); + response.Sub = userId; + response.EmailVerified = user.EmailConfirmed; + response.Email = user.Email; + response.Name = user.Email; //response.Active = true; //response.TokenType = "access_token"; @@ -126,6 +131,7 @@ public async Task GetUserInfoAsync() } catch (Exception ex) // maybe SecurityTokenException { + _logger.LogCritical("There is an exception during fetching the user info, {exception}", ex); response.Claims = null; response.Succeeded = false; response.Error = "invalid_token";