diff --git a/src/Open.IdentityServer/src/IdentityServerTools.cs b/src/Open.IdentityServer/src/IdentityServerTools.cs index fcaf5820..f28f2c3e 100644 --- a/src/Open.IdentityServer/src/IdentityServerTools.cs +++ b/src/Open.IdentityServer/src/IdentityServerTools.cs @@ -10,6 +10,7 @@ using System.Security.Claims; using Open.IdentityServer.Services; using System; +using System.Linq; namespace Open.IdentityServer; @@ -50,16 +51,7 @@ public virtual async Task IssueJwtAsync(int lifetime, IEnumerable var issuer = ContextAccessor.HttpContext.GetIdentityServerIssuerUri(); - var token = new Token - { - CreationTime = _clock.GetUtcNow().UtcDateTime, - Issuer = issuer, - Lifetime = lifetime, - - Claims = new HashSet(claims, new ClaimComparer()) - }; - - return await _tokenCreation.CreateTokenAsync(token); + return await IssueJwtAsync(lifetime, issuer, claims); } /// @@ -77,13 +69,15 @@ public virtual async Task IssueJwtAsync(int lifetime, string issuer, IEn if (String.IsNullOrWhiteSpace(issuer)) throw new ArgumentNullException(nameof(issuer)); if (claims == null) throw new ArgumentNullException(nameof(claims)); + var audiences = claims.Where(c => c.Type == JwtClaimTypes.Audience).Select(c => c.Value).ToList(); + var token = new Token { CreationTime = _clock.GetUtcNow().UtcDateTime, Issuer = issuer, Lifetime = lifetime, - - Claims = new HashSet(claims, new ClaimComparer()) + Claims = new HashSet(claims, new ClaimComparer()), + Audiences = audiences }; return await _tokenCreation.CreateTokenAsync(token); diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/IdentityServerToolsTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/IdentityServerToolsTests.cs new file mode 100644 index 00000000..10c8832f --- /dev/null +++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/IdentityServerToolsTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using IdentityServer.UnitTests.Common; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Time.Testing; +using Moq; +using Open.IdentityServer.Models; +using Open.IdentityServer.Services; +using Xunit; + +namespace Open.IdentityServer.UnitTests; + +public class IdentityServerToolsTests +{ + private readonly Mock _tokenCreationService = new(); + + private IdentityServerTools CreateSut() + { + return new IdentityServerTools(new MockHttpContextAccessor(), _tokenCreationService.Object, new FakeTimeProvider()); + } + + [Fact] + public async Task IssueJwtAsync_WhenCalledWithClaimsContainingAudience_ShouldSetAudienceOnToken() + { + var audience = "audience"; + + var sut = CreateSut(); + + await sut.IssueJwtAsync(3600, "https://localhost:5000", + new List + { + new(JwtClaimTypes.Audience, audience), + new(JwtClaimTypes.GivenName, "Joe") + }); + + _tokenCreationService.Verify(x => x.CreateTokenAsync(It.Is(t => + t.Audiences.Count == 1 && + t.Audiences.Contains(audience))), + Times.Once); + } + + [Fact] + public async Task IssueJwtAsync_WhenCalledWithMultipleClaimsContainingAudience_ShouldSetAllAudiencesOnToken() + { + var audience1 = "audience1"; + var audience2 = "audience2"; + var audience3 = "audience3"; + + var sut = CreateSut(); + + await sut.IssueJwtAsync(3600, "https://localhost:5000", new List + { + new(JwtClaimTypes.Audience, audience1), + new(JwtClaimTypes.Audience, audience2), + new(JwtClaimTypes.Audience, audience3), + new(JwtClaimTypes.GivenName, "Joe") + }); + + _tokenCreationService.Verify(x => x.CreateTokenAsync(It.Is(t => + t.Audiences.Count == 3 && + t.Audiences.Contains(audience1) && + t.Audiences.Contains(audience2) && + t.Audiences.Contains(audience3))), + Times.Once); + } +} \ No newline at end of file