diff --git a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Controllers/AuthorizationController.cs b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Controllers/AuthorizationController.cs index d6d894d8f..1719f2ca8 100644 --- a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Controllers/AuthorizationController.cs +++ b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Controllers/AuthorizationController.cs @@ -1,4 +1,5 @@ using ClassifiedAds.Domain.Entities; +using ClassifiedAds.IdentityServer.Extensions; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; @@ -19,13 +20,16 @@ public class AuthorizationController : Controller { private readonly UserManager _userManager; private readonly SignInManager _signInManager; + private readonly IOpenIddictScopeManager _scopeManager; public AuthorizationController( UserManager userManager, - SignInManager signInManager) + SignInManager signInManager, + IOpenIddictScopeManager scopeManager) { _userManager = userManager; _signInManager = signInManager; + _scopeManager = scopeManager; } [HttpGet("~/connect/authorize")] @@ -66,6 +70,7 @@ public async Task Authorize() // Set requested scopes (this is not done automatically) claimsPrincipal.SetScopes(request.GetScopes()); + claimsPrincipal.SetResources(await _scopeManager.ListResourcesAsync(claimsPrincipal.GetScopes()).ToListAsync()); // Signing in with the OpenIddict authentiction scheme trigger OpenIddict to issue a code (which can be exchanged for an access token) return SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); diff --git a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/PrincipalExtensions.cs b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/Extensions.cs similarity index 59% rename from src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/PrincipalExtensions.cs rename to src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/Extensions.cs index 198399a43..e7c9ea5e8 100644 --- a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/PrincipalExtensions.cs +++ b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Extensions/Extensions.cs @@ -1,9 +1,11 @@ using OpenIddict.Abstractions; +using System.Collections.Generic; using System.Security.Claims; +using System.Threading.Tasks; namespace ClassifiedAds.IdentityServer.Extensions; -public static class PrincipalExtensions +public static class Extensions { public static string GetDisplayName(this ClaimsPrincipal principal) { @@ -21,4 +23,12 @@ public static string GetDisplayName(this ClaimsPrincipal principal) return string.Empty; } + + public static async Task> ToListAsync(this IAsyncEnumerable items) + { + var evaluatedItems = new List(); + await foreach (var item in items) + evaluatedItems.Add(item); + return evaluatedItems; + } } diff --git a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/HostedServices/SeedDataHostedService.cs b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/HostedServices/SeedDataHostedService.cs index 67cc2ee14..c5956c0d0 100644 --- a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/HostedServices/SeedDataHostedService.cs +++ b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/HostedServices/SeedDataHostedService.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Hosting; using OpenIddict.Abstractions; using System; +using System.Globalization; using System.Threading; using System.Threading.Tasks; @@ -20,6 +21,13 @@ public async Task StartAsync(CancellationToken cancellationToken) { using var scope = _serviceProvider.CreateScope(); + await RegisterApplicationsAsync(scope, cancellationToken); + + await RegisterScopesAsync(scope.ServiceProvider); + } + + private static async Task RegisterApplicationsAsync(IServiceScope scope, CancellationToken cancellationToken) + { var manager = scope.ServiceProvider.GetRequiredService(); await UpsertClientApplication(manager, new OpenIddictApplicationDescriptor @@ -320,4 +328,30 @@ private static async Task UpsertClientApplication(IOpenIddictApplicationManager await manager.UpdateAsync(client, openIddictApplicationDescriptor, cancellationToken); } } + + static async Task RegisterScopesAsync(IServiceProvider provider) + { + var manager = provider.GetRequiredService(); + + var scope = await manager.FindByNameAsync("ClassifiedAds.WebAPI"); + + if (scope is null) + { + await manager.CreateAsync(new OpenIddictScopeDescriptor + { + Name = "ClassifiedAds.WebAPI", + DisplayName = "ClassifiedAds WebAPI", + Resources = { "ClassifiedAds.WebAPI" } + }); + } + else + { + await manager.UpdateAsync(scope, new OpenIddictScopeDescriptor + { + Name = "ClassifiedAds.WebAPI", + DisplayName = "ClassifiedAds WebAPI", + Resources = { "ClassifiedAds.WebAPI" } + }); + } + } } diff --git a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Startup.cs b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Startup.cs index 0d01c8944..41395a4f3 100644 --- a/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Startup.cs +++ b/src/IdentityServer/OpenIddict/ClassifiedAds.IdentityServer/Startup.cs @@ -117,6 +117,8 @@ public void ConfigureServices(IServiceCollection services) .EnableAuthorizationEndpointPassthrough() .EnableLogoutEndpointPassthrough() .EnableUserinfoEndpointPassthrough(); + + options.DisableAccessTokenEncryption(); }) .AddValidation(options => { diff --git a/src/IdentityServer/OpenIddict/ClassifiedAds.Infrastructure/ClassifiedAds.Infrastructure.csproj b/src/IdentityServer/OpenIddict/ClassifiedAds.Infrastructure/ClassifiedAds.Infrastructure.csproj index 969ea7d82..d149bf5c1 100644 --- a/src/IdentityServer/OpenIddict/ClassifiedAds.Infrastructure/ClassifiedAds.Infrastructure.csproj +++ b/src/IdentityServer/OpenIddict/ClassifiedAds.Infrastructure/ClassifiedAds.Infrastructure.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Monolith/.helm/monolith/charts/webapi/templates/webapi.deployment.yaml b/src/Monolith/.helm/monolith/charts/webapi/templates/webapi.deployment.yaml index fd1c9270a..5403c86eb 100644 --- a/src/Monolith/.helm/monolith/charts/webapi/templates/webapi.deployment.yaml +++ b/src/Monolith/.helm/monolith/charts/webapi/templates/webapi.deployment.yaml @@ -17,9 +17,9 @@ spec: spec: containers: - env: - - name: IdentityServerAuthentication__Authority + - name: Authentication__IdentityServer__Authority value: http://{{ .Release.Name}}-identityserver - - name: IdentityServerAuthentication__RequireHttpsMetadata + - name: Authentication__IdentityServer__RequireHttpsMetadata value: "false" envFrom: - configMapRef: diff --git a/src/Monolith/.k8s/webapi.deployment.yaml b/src/Monolith/.k8s/webapi.deployment.yaml index 3ba565270..e925c0e0d 100644 --- a/src/Monolith/.k8s/webapi.deployment.yaml +++ b/src/Monolith/.k8s/webapi.deployment.yaml @@ -17,9 +17,9 @@ spec: spec: containers: - env: - - name: IdentityServerAuthentication__Authority + - name: Authentication__IdentityServer__Authority value: http://identityserver - - name: IdentityServerAuthentication__RequireHttpsMetadata + - name: Authentication__IdentityServer__RequireHttpsMetadata value: "false" envFrom: - configMapRef: diff --git a/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AppSettings.cs b/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AppSettings.cs index 655a482ac..22d9b57db 100644 --- a/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AppSettings.cs +++ b/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AppSettings.cs @@ -17,7 +17,7 @@ public class AppSettings public MonitoringOptions Monitoring { get; set; } - public IdentityServerAuthentication IdentityServerAuthentication { get; set; } + public AuthenticationOptions Authentication { get; set; } public string AllowedHosts { get; set; } diff --git a/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/IdentityServerAuthentication.cs b/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AuthenticationOptions.cs similarity index 60% rename from src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/IdentityServerAuthentication.cs rename to src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AuthenticationOptions.cs index db3c95156..6d77265e1 100644 --- a/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/IdentityServerAuthentication.cs +++ b/src/Monolith/ClassifiedAds.WebAPI/ConfigurationOptions/AuthenticationOptions.cs @@ -2,23 +2,30 @@ namespace ClassifiedAds.WebAPI.ConfigurationOptions; -public class IdentityServerAuthentication +public class AuthenticationOptions { public string Provider { get; set; } + public IdentityServerOptions IdentityServer { get; set; } + + public JwtOptions Jwt { get; set; } +} + +public class IdentityServerOptions +{ public string Authority { get; set; } - public string ApiName { get; set; } + public string Audience { get; set; } public bool RequireHttpsMetadata { get; set; } - - public OpenIddictOptions OpenIddict { get; set; } } -public class OpenIddictOptions +public class JwtOptions { public string IssuerUri { get; set; } + public string Audience { get; set; } + public CertificateOption TokenDecryptionCertificate { get; set; } public CertificateOption IssuerSigningCertificate { get; set; } diff --git a/src/Monolith/ClassifiedAds.WebAPI/Controllers/UsersController.cs b/src/Monolith/ClassifiedAds.WebAPI/Controllers/UsersController.cs index 64c273081..c6f6d6081 100644 --- a/src/Monolith/ClassifiedAds.WebAPI/Controllers/UsersController.cs +++ b/src/Monolith/ClassifiedAds.WebAPI/Controllers/UsersController.cs @@ -158,7 +158,7 @@ public async Task SendResetPasswordEmail(Guid id) if (user != null) { var token = await _userManager.GeneratePasswordResetTokenAsync(user); - var resetUrl = $"{_appSettings.IdentityServerAuthentication.Authority}/Account/ResetPassword?token={HttpUtility.UrlEncode(token)}&email={user.Email}"; + var resetUrl = $"{_appSettings.Authentication.IdentityServer.Authority}/Account/ResetPassword?token={HttpUtility.UrlEncode(token)}&email={user.Email}"; await _dispatcher.DispatchAsync(new AddOrUpdateEntityCommand(new EmailMessage { @@ -186,7 +186,7 @@ public async Task SendConfirmationEmailAddressEmail(Guid id) { var token = await _userManager.GenerateEmailConfirmationTokenAsync(user); - var confirmationEmail = $"{_appSettings.IdentityServerAuthentication.Authority}/Account/ConfirmEmailAddress?token={HttpUtility.UrlEncode(token)}&email={user.Email}"; + var confirmationEmail = $"{_appSettings.Authentication.IdentityServer.Authority}/Account/ConfirmEmailAddress?token={HttpUtility.UrlEncode(token)}&email={user.Email}"; await _dispatcher.DispatchAsync(new AddOrUpdateEntityCommand(new EmailMessage { diff --git a/src/Monolith/ClassifiedAds.WebAPI/Program.cs b/src/Monolith/ClassifiedAds.WebAPI/Program.cs index 9c791f112..d67793a9d 100644 --- a/src/Monolith/ClassifiedAds.WebAPI/Program.cs +++ b/src/Monolith/ClassifiedAds.WebAPI/Program.cs @@ -110,26 +110,26 @@ services.AddAuthentication(options => { - options.DefaultScheme = appSettings.IdentityServerAuthentication.Provider switch + options.DefaultScheme = appSettings.Authentication.Provider switch { - "OpenIddict" => "OpenIddict", + "Jwt" => "Jwt", _ => JwtBearerDefaults.AuthenticationScheme }; }) .AddJwtBearer(options => { - options.Authority = appSettings.IdentityServerAuthentication.Authority; - options.Audience = appSettings.IdentityServerAuthentication.ApiName; - options.RequireHttpsMetadata = appSettings.IdentityServerAuthentication.RequireHttpsMetadata; + options.Authority = appSettings.Authentication.IdentityServer.Authority; + options.Audience = appSettings.Authentication.IdentityServer.Audience; + options.RequireHttpsMetadata = appSettings.Authentication.IdentityServer.RequireHttpsMetadata; }) -.AddJwtBearer("OpenIddict", options => +.AddJwtBearer("Jwt", options => { options.TokenValidationParameters = new TokenValidationParameters { - ValidateAudience = false, - ValidIssuer = appSettings.IdentityServerAuthentication.OpenIddict.IssuerUri, - TokenDecryptionKey = new X509SecurityKey(appSettings.IdentityServerAuthentication.OpenIddict.TokenDecryptionCertificate.FindCertificate()), - IssuerSigningKey = new X509SecurityKey(appSettings.IdentityServerAuthentication.OpenIddict.IssuerSigningCertificate.FindCertificate()), + ValidIssuer = appSettings.Authentication.Jwt.IssuerUri, + ValidAudience = appSettings.Authentication.Jwt.Audience, + TokenDecryptionKey = new X509SecurityKey(appSettings.Authentication.Jwt.TokenDecryptionCertificate.FindCertificate()), + IssuerSigningKey = new X509SecurityKey(appSettings.Authentication.Jwt.IssuerSigningCertificate.FindCertificate()), }; }); @@ -178,8 +178,8 @@ { AuthorizationCode = new OpenApiOAuthFlow { - TokenUrl = new Uri(appSettings.IdentityServerAuthentication.Authority + "/connect/token", UriKind.Absolute), - AuthorizationUrl = new Uri(appSettings.IdentityServerAuthentication.Authority + "/connect/authorize", UriKind.Absolute), + TokenUrl = new Uri(appSettings.Authentication.IdentityServer.Authority + "/connect/token", UriKind.Absolute), + AuthorizationUrl = new Uri(appSettings.Authentication.IdentityServer.Authority + "/connect/authorize", UriKind.Absolute), Scopes = new Dictionary { { "openid", "OpenId" }, @@ -189,7 +189,7 @@ }, ClientCredentials = new OpenApiOAuthFlow { - TokenUrl = new Uri(appSettings.IdentityServerAuthentication.Authority + "/connect/token", UriKind.Absolute), + TokenUrl = new Uri(appSettings.Authentication.IdentityServer.Authority + "/connect/token", UriKind.Absolute), Scopes = new Dictionary { { "ClassifiedAds.WebAPI", "ClassifiedAds WebAPI" }, @@ -230,7 +230,7 @@ healthQuery: "SELECT 1;", name: "Sql Server", failureStatus: HealthStatus.Degraded) - .AddHttp(appSettings.IdentityServerAuthentication.Authority, + .AddHttp(appSettings.Authentication.IdentityServer.Authority, name: "Identity Server", failureStatus: HealthStatus.Degraded) .AddStorageManagerHealthCheck(appSettings.Storage); diff --git a/src/Monolith/ClassifiedAds.WebAPI/appsettings.json b/src/Monolith/ClassifiedAds.WebAPI/appsettings.json index 73ad9b03d..703412a3c 100644 --- a/src/Monolith/ClassifiedAds.WebAPI/appsettings.json +++ b/src/Monolith/ClassifiedAds.WebAPI/appsettings.json @@ -2,13 +2,16 @@ "ConnectionStrings": { "ClassifiedAds": "Server=127.0.0.1;Database=ClassifiedAds;User Id=sa;Password=sqladmin123!@#;MultipleActiveResultSets=true;Encrypt=False" }, - "IdentityServerAuthentication": { - "Provider": "IdentityServer4", - "Authority": "https://localhost:44367", - "ApiName": "ClassifiedAds.WebAPI", - "RequireHttpsMetadata": "true", - "OpenIddict": { + "Authentication": { + "Provider": "IdentityServer", + "IdentityServer": { + "Authority": "https://localhost:44367", + "Audience": "ClassifiedAds.WebAPI", + "RequireHttpsMetadata": "true" + }, + "Jwt": { "IssuerUri": "https://localhost:44367/", + "Audience": "ClassifiedAds.WebAPI", "TokenDecryptionCertificate": { "Thumbprint": null, "Path": "Certs/classifiedads.identityserver.pfx", diff --git a/src/Monolith/ClassifiedAds.WebMVC/appsettings.json b/src/Monolith/ClassifiedAds.WebMVC/appsettings.json index 45eff43a4..718c384eb 100644 --- a/src/Monolith/ClassifiedAds.WebMVC/appsettings.json +++ b/src/Monolith/ClassifiedAds.WebMVC/appsettings.json @@ -20,10 +20,6 @@ "Endpoint": "https://localhost:44312", "PublicEndpoint": "https://localhost:44312" }, - "NotificationServer": { - "Endpoint": "https://localhost:44390", - "PublicEndpoint": "https://localhost:44390" - }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/src/Monolith/docker-compose.yml b/src/Monolith/docker-compose.yml index 06e882c1d..1a83f1665 100644 --- a/src/Monolith/docker-compose.yml +++ b/src/Monolith/docker-compose.yml @@ -80,8 +80,8 @@ services: environment: ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT} ConnectionStrings__ClassifiedAds: ${ConnectionStrings__ClassifiedAds} - IdentityServerAuthentication__Authority: "http://host.docker.internal:9000" - IdentityServerAuthentication__RequireHttpsMetadata: "false" + Authentication__IdentityServer__Authority: "http://host.docker.internal:9000" + Authentication__IdentityServer__RequireHttpsMetadata: "false" Storage__Provider: ${Storage__Provider} Storage__Local__Path: ${Storage__Local__Path} Storage__Azure__ConnectionString: ${Storage__Azure__ConnectionString}