Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit e3e207a

Browse files
committed
#340 Split the Redirect event for Authentication and SignOut.
1 parent 9e8b056 commit e3e207a

File tree

8 files changed

+98
-79
lines changed

8 files changed

+98
-79
lines changed

src/Microsoft.AspNet.Authentication.OpenIdConnect/Events/IOpenIdConnectAuthenticationEvents.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ public interface IOpenIdConnectAuthenticationEvents
3636
Task MessageReceived(MessageReceivedContext context);
3737

3838
/// <summary>
39-
/// Invoked to manipulate redirects to the identity provider for SignIn, SignOut, or Challenge.
39+
/// Invoked before redirecting to the identity provider to authenticate.
4040
/// </summary>
41-
Task RedirectToIdentityProvider(RedirectToIdentityProviderContext context);
41+
Task RedirectForAuthentication(RedirectForAuthenticationContext context);
42+
43+
/// <summary>
44+
/// Invoked before redirecting to the identity provider to sign out.
45+
/// </summary>
46+
Task RedirectForSignOut(RedirectForSignOutContext context);
4247

4348
/// <summary>
4449
/// Invoked with the security token that has been extracted from the protocol message.

src/Microsoft.AspNet.Authentication.OpenIdConnect/Events/OpenIdConnectAuthenticationEvents.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ public class OpenIdConnectAuthenticationEvents : IOpenIdConnectAuthenticationEve
3737
public Func<MessageReceivedContext, Task> OnMessageReceived { get; set; } = context => Task.FromResult(0);
3838

3939
/// <summary>
40-
/// Invoked to manipulate redirects to the identity provider for SignIn, SignOut, or Challenge.
40+
/// Invoked before redirecting to the identity provider to authenticate.
4141
/// </summary>
42-
public Func<RedirectToIdentityProviderContext, Task> OnRedirectToIdentityProvider { get; set; } = context => Task.FromResult(0);
42+
public Func<RedirectForAuthenticationContext, Task> OnRedirectForAuthentication { get; set; } = context => Task.FromResult(0);
43+
44+
/// <summary>
45+
/// Invoked before redirecting to the identity provider to sign out.
46+
/// </summary>
47+
public Func<RedirectForSignOutContext, Task> OnRedirectForSignOut { get; set; } = context => Task.FromResult(0);
4348

4449
/// <summary>
4550
/// Invoked with the security token that has been extracted from the protocol message.
@@ -66,7 +71,9 @@ public class OpenIdConnectAuthenticationEvents : IOpenIdConnectAuthenticationEve
6671

6772
public virtual Task MessageReceived(MessageReceivedContext context) => OnMessageReceived(context);
6873

69-
public virtual Task RedirectToIdentityProvider(RedirectToIdentityProviderContext context) => OnRedirectToIdentityProvider(context);
74+
public virtual Task RedirectForAuthentication(RedirectForAuthenticationContext context) => OnRedirectForAuthentication(context);
75+
76+
public virtual Task RedirectForSignOut(RedirectForSignOutContext context) => OnRedirectForSignOut(context);
7077

7178
public virtual Task SecurityTokenReceived(SecurityTokenReceivedContext context) => OnSecurityTokenReceived(context);
7279

src/Microsoft.AspNet.Authentication.OpenIdConnect/Events/RedirectToIdentityProviderContext.cs renamed to src/Microsoft.AspNet.Authentication.OpenIdConnect/Events/RedirectForAuthenticationContext.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using System;
54
using Microsoft.AspNet.Http;
65
using Microsoft.Framework.Internal;
76
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
87

98
namespace Microsoft.AspNet.Authentication.OpenIdConnect
109
{
1110
/// <summary>
12-
/// When a user configures the <see cref="AuthenticationMiddleware{TOptions}"/> to be notified prior to redirecting to an IdentityProvider
13-
/// an instance of <see cref="RedirectToIdentityProviderContext"/> is passed to the 'RedirectToIdentityProvider" event.
11+
/// When a user configures the <see cref="OpenIdConnectAuthenticationMiddleware"/> to be notified prior to redirecting to an IdentityProvider
12+
/// an instance of <see cref="RedirectForAuthenticationContext"/> is passed to the 'RedirectForAuthentication" event.
1413
/// </summary>
15-
/// <typeparam name="TMessage">protocol specific message.</typeparam>
16-
/// <typeparam name="TOptions">protocol specific options.</typeparam>
17-
public class RedirectToIdentityProviderContext : BaseControlContext<OpenIdConnectAuthenticationOptions>
14+
public class RedirectForAuthenticationContext : BaseControlContext<OpenIdConnectAuthenticationOptions>
1815
{
19-
public RedirectToIdentityProviderContext([NotNull] HttpContext context, [NotNull] OpenIdConnectAuthenticationOptions options)
16+
public RedirectForAuthenticationContext([NotNull] HttpContext context, [NotNull] OpenIdConnectAuthenticationOptions options)
2017
: base(context, options)
2118
{
2219
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNet.Http;
5+
using Microsoft.Framework.Internal;
6+
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
7+
8+
namespace Microsoft.AspNet.Authentication.OpenIdConnect
9+
{
10+
/// <summary>
11+
/// When a user configures the <see cref="OpenIdConnectAuthenticationMiddleware"/> to be notified prior to redirecting to an IdentityProvider
12+
/// an instance of <see cref="RedirectForSignOutContext"/> is passed to the 'RedirectForSignOut" event.
13+
/// </summary>
14+
public class RedirectForSignOutContext : BaseControlContext<OpenIdConnectAuthenticationOptions>
15+
{
16+
public RedirectForSignOutContext([NotNull] HttpContext context, [NotNull] OpenIdConnectAuthenticationOptions options)
17+
: base(context, options)
18+
{
19+
}
20+
21+
/// <summary>
22+
/// Gets or sets the <see cref="OpenIdConnectMessage"/>.
23+
/// </summary>
24+
/// <exception cref="ArgumentNullException">if 'value' is null.</exception>
25+
public OpenIdConnectMessage ProtocolMessage { get; [param: NotNull] set; }
26+
}
27+
}

src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectAuthenticationHandler.cs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ protected override async Task HandleSignOutAsync(SignOutContext signout)
7676
var message = new OpenIdConnectMessage()
7777
{
7878
IssuerAddress = _configuration == null ? string.Empty : (_configuration.EndSessionEndpoint ?? string.Empty),
79-
RequestType = OpenIdConnectRequestType.LogoutRequest,
8079
};
8180

8281
// Set End_Session_Endpoint in order:
@@ -92,24 +91,24 @@ protected override async Task HandleSignOutAsync(SignOutContext signout)
9291
message.PostLogoutRedirectUri = Options.PostLogoutRedirectUri;
9392
}
9493

95-
var redirectToIdentityProviderContext = new RedirectToIdentityProviderContext(Context, Options)
94+
var redirectForSignOutContext = new RedirectForSignOutContext(Context, Options)
9695
{
9796
ProtocolMessage = message
9897
};
9998

100-
await Options.Events.RedirectToIdentityProvider(redirectToIdentityProviderContext);
101-
if (redirectToIdentityProviderContext.HandledResponse)
99+
await Options.Events.RedirectForSignOut(redirectForSignOutContext);
100+
if (redirectForSignOutContext.HandledResponse)
102101
{
103-
Logger.LogVerbose(Resources.OIDCH_0034_RedirectToIdentityProviderContextHandledResponse);
102+
Logger.LogVerbose("RedirectForSignOutContext.HandledResponse");
104103
return;
105104
}
106-
else if (redirectToIdentityProviderContext.Skipped)
105+
else if (redirectForSignOutContext.Skipped)
107106
{
108-
Logger.LogVerbose(Resources.OIDCH_0035_RedirectToIdentityProviderContextSkipped);
107+
Logger.LogVerbose("RedirectForSignOutContext.Skipped");
109108
return;
110109
}
111110

112-
message = redirectToIdentityProviderContext.ProtocolMessage;
111+
message = redirectForSignOutContext.ProtocolMessage;
113112

114113
if (Options.AuthenticationMethod == OpenIdConnectAuthenticationMethod.RedirectGet)
115114
{
@@ -185,8 +184,6 @@ protected override async Task<bool> HandleUnauthorizedAsync([NotNull] ChallengeC
185184
ClientId = Options.ClientId,
186185
IssuerAddress = _configuration?.AuthorizationEndpoint ?? string.Empty,
187186
RedirectUri = Options.RedirectUri,
188-
// [brentschmaltz] - #215 this should be a property on RedirectToIdentityProviderContext not on the OIDCMessage.
189-
RequestType = OpenIdConnectRequestType.AuthenticationRequest,
190187
Resource = Options.Resource,
191188
ResponseType = Options.ResponseType,
192189
Scope = string.Join(" ", Options.Scope)
@@ -225,24 +222,24 @@ protected override async Task<bool> HandleUnauthorizedAsync([NotNull] ChallengeC
225222

226223
GenerateCorrelationId(properties);
227224

228-
var redirectToIdentityProviderContext = new RedirectToIdentityProviderContext(Context, Options)
225+
var redirectForAuthenticationContext = new RedirectForAuthenticationContext(Context, Options)
229226
{
230227
ProtocolMessage = message
231228
};
232229

233-
await Options.Events.RedirectToIdentityProvider(redirectToIdentityProviderContext);
234-
if (redirectToIdentityProviderContext.HandledResponse)
230+
await Options.Events.RedirectForAuthentication(redirectForAuthenticationContext);
231+
if (redirectForAuthenticationContext.HandledResponse)
235232
{
236-
Logger.LogVerbose(Resources.OIDCH_0034_RedirectToIdentityProviderContextHandledResponse);
233+
Logger.LogVerbose("RedirectForAuthenticationContext.HandledResponse");
237234
return true;
238235
}
239-
else if (redirectToIdentityProviderContext.Skipped)
236+
else if (redirectForAuthenticationContext.Skipped)
240237
{
241-
Logger.LogVerbose(Resources.OIDCH_0035_RedirectToIdentityProviderContextSkipped);
238+
Logger.LogVerbose("RedirectForAuthenticationContext.Skipped");
242239
return false;
243240
}
244241

245-
message = redirectToIdentityProviderContext.ProtocolMessage;
242+
message = redirectForAuthenticationContext.ProtocolMessage;
246243

247244
if (!string.IsNullOrEmpty(message.State))
248245
{

src/Microsoft.AspNet.Authentication.OpenIdConnect/Properties/Resources.Designer.cs

Lines changed: 0 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Microsoft.AspNet.Authentication.OpenIdConnect/Resources.resx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,6 @@
150150
<data name="OIDCH_0033_NonceAlreadyExists" xml:space="preserve">
151151
<value>OIDCH_0033: ProtocolValidator.RequireNonce == true. The generated nonce already exists: this usually indicates the nonce is not unique or has been used. The nonce is: '{0}'.</value>
152152
</data>
153-
<data name="OIDCH_0034_RedirectToIdentityProviderContextHandledResponse" xml:space="preserve">
154-
<value>OIDCH_0034: RedirectToIdentityProviderContext.HandledResponse</value>
155-
</data>
156-
<data name="OIDCH_0035_RedirectToIdentityProviderContextSkipped" xml:space="preserve">
157-
<value>OIDCH_0035: RedirectToIdentityProviderContext.Skipped</value>
158-
</data>
159153
<data name="OIDCH_0036_UriIsNotWellFormed" xml:space="preserve">
160154
<value>OIDCH_0036: Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute) returned 'false', redirectUri is: '{0}'.</value>
161155
</data>

test/Microsoft.AspNet.Authentication.Test/OpenIdConnect/OpenIdConnectMiddlewareTests.cs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,30 +107,49 @@ public async Task ChallengeWillUseOptionsProperties()
107107
}
108108

109109
/// <summary>
110-
/// Tests RedirectToIdentityProviderContext replaces the OpenIdConnectMesssage correctly.
110+
/// Tests RedirectForAuthenticationContext replaces the OpenIdConnectMesssage correctly.
111111
/// </summary>
112112
/// <returns>Task</returns>
113-
[Theory]
114-
[InlineData(Challenge, OpenIdConnectRequestType.AuthenticationRequest)]
115-
[InlineData(Signout, OpenIdConnectRequestType.LogoutRequest)]
116-
public async Task ChallengeSettingMessage(string challenge, OpenIdConnectRequestType requestType)
113+
[Fact]
114+
public async Task ChallengeSettingMessage()
117115
{
118116
var configuration = new OpenIdConnectConfiguration
119117
{
120118
AuthorizationEndpoint = ExpectedAuthorizeRequest,
121-
EndSessionEndpoint = ExpectedLogoutRequest
122119
};
123120

124121
var queryValues = new ExpectedQueryValues(DefaultAuthority, configuration)
125122
{
126-
RequestType = requestType
123+
RequestType = OpenIdConnectRequestType.AuthenticationRequest
127124
};
128125
var server = CreateServer(SetProtocolMessageOptions);
129-
var transaction = await SendAsync(server, DefaultHost + challenge);
126+
var transaction = await SendAsync(server, DefaultHost + Challenge);
130127
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
131128
queryValues.CheckValues(transaction.Response.Headers.Location.AbsoluteUri, new string[] {});
132129
}
133130

131+
/// <summary>
132+
/// Tests RedirectForSignOutContext replaces the OpenIdConnectMesssage correctly.
133+
/// </summary>
134+
/// <returns>Task</returns>
135+
[Fact]
136+
public async Task SignOutSettingMessage()
137+
{
138+
var configuration = new OpenIdConnectConfiguration
139+
{
140+
EndSessionEndpoint = ExpectedLogoutRequest
141+
};
142+
143+
var queryValues = new ExpectedQueryValues(DefaultAuthority, configuration)
144+
{
145+
RequestType = OpenIdConnectRequestType.LogoutRequest
146+
};
147+
var server = CreateServer(SetProtocolMessageOptions);
148+
var transaction = await SendAsync(server, DefaultHost + Signout);
149+
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
150+
queryValues.CheckValues(transaction.Response.Headers.Location.AbsoluteUri, new string[] { });
151+
}
152+
134153
private static void SetProtocolMessageOptions(OpenIdConnectAuthenticationOptions options)
135154
{
136155
var mockOpenIdConnectMessage = new Mock<OpenIdConnectMessage>();
@@ -139,7 +158,12 @@ private static void SetProtocolMessageOptions(OpenIdConnectAuthenticationOptions
139158
options.AutomaticAuthentication = true;
140159
options.Events = new OpenIdConnectAuthenticationEvents()
141160
{
142-
OnRedirectToIdentityProvider = (context) =>
161+
OnRedirectForAuthentication = (context) =>
162+
{
163+
context.ProtocolMessage = mockOpenIdConnectMessage.Object;
164+
return Task.FromResult<object>(null);
165+
},
166+
OnRedirectForSignOut = (context) =>
143167
{
144168
context.ProtocolMessage = mockOpenIdConnectMessage.Object;
145169
return Task.FromResult<object>(null);
@@ -171,7 +195,7 @@ public async Task ChallengeSettingState(string userState, string challenge)
171195
options.AutomaticAuthentication = challenge.Equals(ChallengeWithOutContext);
172196
options.Events = new OpenIdConnectAuthenticationEvents()
173197
{
174-
OnRedirectToIdentityProvider = context =>
198+
OnRedirectForAuthentication = context =>
175199
{
176200
context.ProtocolMessage.State = userState;
177201
return Task.FromResult<object>(null);
@@ -222,7 +246,7 @@ public async Task ChallengeWillUseEvents()
222246
SetOptions(options, DefaultParameters(), queryValues);
223247
options.Events = new OpenIdConnectAuthenticationEvents()
224248
{
225-
OnRedirectToIdentityProvider = context =>
249+
OnRedirectForAuthentication = context =>
226250
{
227251
context.ProtocolMessage.ClientId = queryValuesSetInEvent.ClientId;
228252
context.ProtocolMessage.RedirectUri = queryValuesSetInEvent.RedirectUri;
@@ -345,7 +369,7 @@ private static TestServer CreateServer(Action<OpenIdConnectAuthenticationOptions
345369
{
346370
app.UseCookieAuthentication(options =>
347371
{
348-
options.AuthenticationScheme = OpenIdConnectAuthenticationDefaults.AuthenticationScheme;
372+
options.AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;
349373
});
350374
app.UseOpenIdConnectAuthentication(configureOptions);
351375
app.Use(async (context, next) =>

0 commit comments

Comments
 (0)