Skip to content

Commit 09e31bc

Browse files
authored
Merge pull request #184 from gao-artur/revert-cancellation-token
Revert #173 + add unit tests
2 parents 697ca97 + 1c7660e commit 09e31bc

File tree

3 files changed

+107
-2
lines changed

3 files changed

+107
-2
lines changed

src/OAuth2IntrospectionHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ private static async Task<TokenIntrospectionResponse> LoadClaimsForToken(
187187

188188
await events.SendingRequest(requestSendingContext);
189189

190-
return await introspectionClient.IntrospectTokenAsync(request, context.RequestAborted).ConfigureAwait(false);
190+
return await introspectionClient.IntrospectTokenAsync(request).ConfigureAwait(false);
191191
}
192192

193193
private static TokenIntrospectionRequest CreateTokenIntrospectionRequest(

test/Tests/Introspection.cs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using System;
1313
using System.Collections.Generic;
1414
using System.Net;
15+
using System.Net.Http;
16+
using System.Threading;
1517
using System.Threading.Tasks;
1618
using Tests.Util;
1719
using Xunit;
@@ -61,6 +63,109 @@ public async Task ActiveToken()
6163
request.Should().ContainKey("client_secret").WhichValue.Should().Be(clientSecret);
6264
}
6365

66+
[Theory]
67+
[InlineData(IntrospectionEndpointHandler.Behavior.Active, HttpStatusCode.OK)]
68+
[InlineData(IntrospectionEndpointHandler.Behavior.Unauthorized, HttpStatusCode.Unauthorized)]
69+
public async Task TwoConcurrentCalls_FirstIntrospectDoesNotThrow_SecondShouldNotBeCalled(
70+
IntrospectionEndpointHandler.Behavior behavior,
71+
HttpStatusCode expectedStatusCode)
72+
{
73+
const string token = "sometoken";
74+
var waitForTheFirstIntrospectionToStart = new ManualResetEvent(initialState: false);
75+
var waitForTheSecondRequestToStart = new ManualResetEvent(initialState: false);
76+
var handler = new IntrospectionEndpointHandler(behavior);
77+
78+
var requestCount = 0;
79+
80+
var messageHandler = PipelineFactory.CreateHandler(o =>
81+
{
82+
_options(o);
83+
84+
o.Events.OnSendingRequest = async context =>
85+
{
86+
requestCount += 1;
87+
88+
if (requestCount == 1)
89+
{
90+
waitForTheSecondRequestToStart.WaitOne();
91+
waitForTheFirstIntrospectionToStart.Set();
92+
await Task.Delay(200); // wait for second request to reach the IntrospectionDictionary
93+
}
94+
};
95+
}, handler);
96+
97+
var client1 = new HttpClient(messageHandler);
98+
var request1 = Task.Run(async () =>
99+
{
100+
client1.SetBearerToken(token);
101+
return await client1.GetAsync("http://test");
102+
});
103+
104+
var client2 = new HttpClient(messageHandler);
105+
var request2 = Task.Run(async () =>
106+
{
107+
waitForTheSecondRequestToStart.Set();
108+
waitForTheFirstIntrospectionToStart.WaitOne();
109+
client2.SetBearerToken(token);
110+
return await client2.GetAsync("http://test");
111+
});
112+
113+
await Task.WhenAll(request1, request2);
114+
115+
var result1 = await request1;
116+
result1.StatusCode.Should().Be(expectedStatusCode);
117+
118+
requestCount.Should().Be(1);
119+
120+
var result2 = await request2;
121+
result2.StatusCode.Should().Be(expectedStatusCode);
122+
}
123+
124+
[Fact]
125+
public async Task ActiveToken_WithTwoConcurrentCalls_FirstCancelled_SecondShouldNotBeCancelled()
126+
{
127+
const string token = "sometoken";
128+
var cts = new CancellationTokenSource();
129+
var waitForTheFirstIntrospectionToStart = new ManualResetEvent(initialState: false);
130+
var waitForTheSecondRequestToStart = new ManualResetEvent(initialState: false);
131+
var handler = new IntrospectionEndpointHandler(IntrospectionEndpointHandler.Behavior.Active);
132+
133+
var messageHandler = PipelineFactory.CreateHandler(o =>
134+
{
135+
_options(o);
136+
137+
o.Events.OnSendingRequest = async context =>
138+
{
139+
waitForTheSecondRequestToStart.WaitOne();
140+
waitForTheFirstIntrospectionToStart.Set();
141+
cts.Cancel();
142+
await Task.Delay(200); // wait for second request to reach the IntrospectionDictionary
143+
};
144+
}, handler);
145+
146+
var client1 = new HttpClient(messageHandler);
147+
var request1 = Task.Run(async () =>
148+
{
149+
client1.SetBearerToken(token);
150+
var doRequest = () => client1.GetAsync("http://test", cts.Token);
151+
await doRequest.Should().ThrowAsync<OperationCanceledException>();
152+
});
153+
154+
var client2 = new HttpClient(messageHandler);
155+
var request2 = Task.Run(async () =>
156+
{
157+
waitForTheSecondRequestToStart.Set();
158+
waitForTheFirstIntrospectionToStart.WaitOne();
159+
client2.SetBearerToken(token);
160+
return await client2.GetAsync("http://test");
161+
});
162+
163+
await Task.WhenAll(request1, request2);
164+
165+
var result2 = await request2;
166+
result2.StatusCode.Should().Be(HttpStatusCode.OK);
167+
}
168+
64169
[Theory]
65170
[InlineData(5000, "testAssertion1", "testAssertion1")]
66171
[InlineData(-5000, "testAssertion1", "testAssertion2")]

test/Tests/Util/IntrospectionEndpointHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace Tests.Util
1414
{
15-
internal class IntrospectionEndpointHandler : DelegatingHandler
15+
public class IntrospectionEndpointHandler : DelegatingHandler
1616
{
1717
private readonly Behavior _behavior;
1818

0 commit comments

Comments
 (0)