Skip to content

Commit

Permalink
Replace IdentityServer4 with Duende.IdentityServer (#3008)
Browse files Browse the repository at this point in the history
  • Loading branch information
pseudometalhead committed Dec 2, 2024
1 parent 6b5633c commit 6958989
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 55 deletions.
21 changes: 9 additions & 12 deletions test/WebSites/OAuth2Integration/AuthServer/Config.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System.Collections.Generic;
using IdentityServer4.Models;
using IdentityServer4.Test;
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Test;

namespace OAuth2Integration.AuthServer
{
public static class Config
internal static class Config
{
internal static IEnumerable<Client> Clients()
public static IEnumerable<Client> Clients()
{
yield return new Client
{
Expand All @@ -31,15 +31,12 @@ internal static IEnumerable<Client> Clients()

internal static IEnumerable<ApiResource> ApiResources()
{
yield return new ApiResource
return new List<ApiResource>
{
Name = "api",
DisplayName = "API",
Scopes =
[
new Scope("readAccess", "Access read operations"),
new Scope("writeAccess", "Access write operations")
]
new ApiResource("api", "API")
{
Scopes = { "readAccess", "writeAccess" }
}
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Duende.IdentityServer;
using Duende.IdentityServer.Test;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using IdentityServer4;
using IdentityServer4.Test;
using Microsoft.AspNetCore.Mvc;

namespace OAuth2Integration.AuthServer.Controllers
{
Expand All @@ -22,12 +22,11 @@ public AccountController()
public IActionResult Login(string returnUrl)
{
var viewModel = new LoginViewModel { Username = "joebloggs", Password = "pass123", ReturnUrl = returnUrl };

return View("/AuthServer/Views/Login.cshtml", viewModel);
}

[HttpPost("login")]
public async Task<IActionResult> Login([FromForm]LoginViewModel viewModel)
public async Task<IActionResult> Login([FromForm] LoginViewModel viewModel)
{
if (!_userStore.ValidateCredentials(viewModel.Username, viewModel.Password))
{
Expand All @@ -36,9 +35,9 @@ public async Task<IActionResult> Login([FromForm]LoginViewModel viewModel)
return View("/AuthServer/Views/Login.cshtml", viewModel);
}

// Use an IdentityServer-compatible ClaimsPrincipal
var identityServerUser = new IdentityServerUser(viewModel.Username);
identityServerUser.DisplayName = viewModel.Username;

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, identityServerUser.CreatePrincipal());

return Redirect(viewModel.ReturnUrl);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Services;
using Duende.IdentityServer.Stores;
using Microsoft.AspNetCore.Mvc;

namespace OAuth2Integration.AuthServer.Controllers
Expand All @@ -29,29 +29,39 @@ public ConsentController(
public async Task<IActionResult> Consent(string returnUrl)
{
var request = await _interaction.GetAuthorizationContextAsync(returnUrl);
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
var resource = await _resourceStore.FindApiResourceAsync("api");

var viewModel = new ConsentViewModel
{
ReturnUrl = returnUrl,
ClientName = client.ClientName,
ScopesRequested = resource.Scopes.Where(s => request.ScopesRequested.Contains(s.Name))
ClientName = request.Client.ClientName,
ScopesRequested = request.ValidatedResources?.Resources?.ApiScopes ?? new List<ApiScope>()
};

return View("/AuthServer/Views/Consent.cshtml", viewModel);
}

[HttpPost("consent")]
public async Task<IActionResult> Consent([FromForm]ConsentViewModel viewModel)
public async Task<IActionResult> Consent([FromForm] ConsentViewModel viewModel)
{
var request = await _interaction.GetAuthorizationContextAsync(viewModel.ReturnUrl);

// Communicate outcome of consent back to identityserver
var consentResponse = new ConsentResponse
ConsentResponse consentResponse;
if (viewModel.ScopesConsented != null && viewModel.ScopesConsented.Any())
{
ScopesConsented = viewModel.ScopesConsented
};
consentResponse = new ConsentResponse
{
RememberConsent = true,
ScopesValuesConsented = viewModel.ScopesConsented.ToList()
};
}
else
{
consentResponse = new ConsentResponse
{
Error = AuthorizationError.AccessDenied
};
}

await _interaction.GrantConsentAsync(request, consentResponse);

return Redirect(viewModel.ReturnUrl);
Expand All @@ -62,7 +72,7 @@ public class ConsentViewModel
{
public string ReturnUrl { get; set; }
public string ClientName { get; set; }
public IEnumerable<Scope> ScopesRequested { get; set; }
public IEnumerable<ApiScope> ScopesRequested { get; set; }
public string[] ScopesConsented { get; set; }
}
}
29 changes: 16 additions & 13 deletions test/WebSites/OAuth2Integration/OAuth2Integration.csproj
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>net9.0;net8.0;net6.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="IdentityServer4" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Swashbuckle.AspNetCore.Swagger\Swashbuckle.AspNetCore.Swagger.csproj" />
<ProjectReference Include="..\..\..\src\Swashbuckle.AspNetCore.SwaggerGen\Swashbuckle.AspNetCore.SwaggerGen.csproj" />
<ProjectReference Include="..\..\..\src\Swashbuckle.AspNetCore.SwaggerUI\Swashbuckle.AspNetCore.SwaggerUI.csproj" />
</ItemGroup>

<!--
This is just a sample for testing - updating to Duende.IdentityServer can be done at some point in the future.
See https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/3008.
-->
<ItemGroup>
<NuGetAuditSuppress Include="https://github.com/advisories/GHSA-55p7-v223-x366" />
<NuGetAuditSuppress Include="https://github.com/advisories/GHSA-ff4q-64jc-gx98" />

<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" VersionOverride="6.0.5" />
<PackageReference Include="Duende.IdentityServer" VersionOverride="6.0.5" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" VersionOverride="8.0.11" />
<PackageReference Include="Duende.IdentityServer" VersionOverride="7.0.8" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" VersionOverride="8.0.11" />
<PackageReference Include="Duende.IdentityServer" VersionOverride="7.0.8" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace OAuth2Integration.ResourceServer.Controllers
{
Expand Down Expand Up @@ -33,7 +33,7 @@ public Product GetProduct(int id)

[HttpPost]
[Authorize("writeAccess")]
public void CreateProduct([FromBody]Product product)
public void CreateProduct([FromBody] Product product)
{
}

Expand All @@ -53,6 +53,6 @@ public class Product

public enum ProductStatus
{
InStock, ComingSoon
InStock, ComingSoon
}
}
}
20 changes: 13 additions & 7 deletions test/WebSites/OAuth2Integration/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -24,7 +23,7 @@ public Startup(IConfiguration configuration)
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Register IdentityServer services to power OAuth2.0 flows
// Register Duende IdentityServer services to power OAuth2.0 flows
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryClients(AuthServer.Config.Clients())
Expand All @@ -36,11 +35,19 @@ public void ConfigureServices(IServiceCollection services)
// See https://learn.microsoft.com/aspnet/core/security/authorization/limitingidentitybyscheme
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddIdentityServerAuthentication(c =>
.AddJwtBearer("Bearer", options =>
{
c.Authority = "https://localhost:5001/auth-server/";
c.RequireHttpsMetadata = false;
c.ApiName = "api";
options.Authority = "https://localhost:5001/auth-server/";
options.RequireHttpsMetadata = false;
options.Audience = "api";
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidAudience = "api",
ValidIssuer = "https://localhost:5001/auth-server/",
};
});

// Configure named auth policies that map directly to OAuth2.0 scopes
Expand All @@ -56,7 +63,6 @@ public void ConfigureServices(IServiceCollection services)
{
c.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "Test API V1" });

// Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Expand Down

0 comments on commit 6958989

Please sign in to comment.