11using AuthServer . Authentication . Abstractions ;
2- using AuthServer . Cache . Abstractions ;
32using AuthServer . Core ;
3+ using AuthServer . Entities ;
44using AuthServer . TokenBuilders ;
55using AuthServer . TokenBuilders . Abstractions ;
66using Microsoft . Extensions . Logging ;
@@ -10,54 +10,68 @@ internal class ClientLogoutService : IClientLogoutService
1010{
1111 private readonly IHttpClientFactory _httpClientFactory ;
1212 private readonly ITokenBuilder < LogoutTokenArguments > _tokenBuilder ;
13- private readonly ICachedClientStore _cachedClientStore ;
1413 private readonly ILogger < ClientLogoutService > _logger ;
14+ private readonly AuthorizationDbContext _authorizationDbContext ;
1515
1616 public ClientLogoutService (
1717 IHttpClientFactory httpClientFactory ,
1818 ITokenBuilder < LogoutTokenArguments > tokenBuilder ,
19- ICachedClientStore cachedClientStore ,
20- ILogger < ClientLogoutService > logger )
19+ ILogger < ClientLogoutService > logger ,
20+ AuthorizationDbContext authorizationDbContext )
2121 {
2222 _httpClientFactory = httpClientFactory ;
2323 _tokenBuilder = tokenBuilder ;
24- _cachedClientStore = cachedClientStore ;
2524 _logger = logger ;
25+ _authorizationDbContext = authorizationDbContext ;
2626 }
2727
28- public async Task Logout ( string clientId , string ? sessionId , string ? subjectIdentifier , CancellationToken cancellationToken )
28+ public async Task Logout ( IReadOnlyCollection < string > clientIds , string ? sessionId , string ? subjectIdentifier , CancellationToken cancellationToken )
2929 {
30- var client = await _cachedClientStore . Get ( clientId , cancellationToken ) ;
31-
32- var httpClient = _httpClientFactory . CreateClient ( HttpClientNameConstants . Client ) ;
33- var logoutToken = await _tokenBuilder . BuildToken ( new LogoutTokenArguments
30+ var logoutRequests = new List < LogoutRequest > ( ) ;
31+ foreach ( var clientId in clientIds )
3432 {
35- ClientId = clientId ,
36- SessionId = sessionId ,
37- SubjectIdentifier = subjectIdentifier
38- } , cancellationToken ) ;
33+ var logoutToken = await _tokenBuilder . BuildToken (
34+ new LogoutTokenArguments
35+ {
36+ ClientId = clientId ,
37+ SessionId = sessionId ,
38+ SubjectIdentifier = subjectIdentifier
39+ } ,
40+ cancellationToken ) ;
3941
40- var body = new Dictionary < string , string >
41- {
42- { Parameter . LogoutToken , logoutToken }
43- } ;
42+ var client = ( await _authorizationDbContext . FindAsync < Client > ( [ clientId ] , cancellationToken ) ) ! ;
4443
45- var httpRequestMessage = new HttpRequestMessage ( HttpMethod . Post , client . BackchannelLogoutUri )
46- {
47- Content = new FormUrlEncodedContent ( body )
48- } ;
44+ logoutRequests . Add ( new LogoutRequest ( clientId , client . BackchannelLogoutUri ! , logoutToken ) ) ;
45+ }
4946
50- // TODO Implement retry for 5XX and 429
51- // TODO Implement Timeout to remove denial-of-service attacks
47+ await Parallel . ForEachAsync (
48+ logoutRequests ,
49+ cancellationToken ,
50+ async ( logoutRequest , innerToken ) =>
51+ {
52+ var httpClient = _httpClientFactory . CreateClient ( HttpClientNameConstants . Client ) ;
5253
53- try
54- {
55- var response = await httpClient . SendAsync ( httpRequestMessage , cancellationToken ) ;
56- response . EnsureSuccessStatusCode ( ) ;
57- }
58- catch ( HttpRequestException e )
59- {
60- _logger . LogWarning ( e , "Error occurred requesting logout for client {ClientId}" , clientId ) ;
61- }
54+ var body = new Dictionary < string , string >
55+ {
56+ { Parameter . LogoutToken , logoutRequest . LogoutToken }
57+ } ;
58+
59+ var httpRequestMessage = new HttpRequestMessage ( HttpMethod . Post , logoutRequest . LogoutUri )
60+ {
61+ Content = new FormUrlEncodedContent ( body )
62+ } ;
63+
64+ try
65+ {
66+ var response = await httpClient . SendAsync ( httpRequestMessage , innerToken ) ;
67+ response . EnsureSuccessStatusCode ( ) ;
68+ }
69+ catch ( HttpRequestException e )
70+ {
71+ _logger . LogWarning ( e , "Error occurred requesting logout for client {ClientId}" , logoutRequest . ClientId ) ;
72+ }
73+ } ) ;
6274 }
75+
76+ private sealed record LogoutRequest ( string ClientId , string LogoutUri , string LogoutToken ) ;
6377}
0 commit comments