Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add response_mode=query support for OpenID Connect #297

Merged
merged 6 commits into from
Aug 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Notifications\AuthorizationCodeReceivedNotification.cs" />
<Compile Include="Notifications\TokenResponseReceivedNotification.cs" />
<Compile Include="OpenIdConnectAuthenticationDefaults.cs" />
<Compile Include="OpenIdConnectAuthenticationExtensions.cs" />
<Compile Include="OpenidConnectAuthenticationHandler.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public AuthorizationCodeReceivedNotification(IOwinContext context, OpenIdConnect
/// </summary>
public JwtSecurityToken JwtSecurityToken { get; set; }

/// <summary>
/// The request that will be sent to the token endpoint and is available for customization.
/// </summary>
public OpenIdConnectMessage TokenEndpointRequest { get; set; }

/// <summary>
/// Gets or sets the <see cref="OpenIdConnectMessage"/>.
/// </summary>
Expand All @@ -47,5 +52,57 @@ public AuthorizationCodeReceivedNotification(IOwinContext context, OpenIdConnect
/// <remarks>This is the redirect_uri that was sent in the id_token + code OpenIdConnectRequest.</remarks>
[SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "user controlled, not necessarily a URI")]
public string RedirectUri { get; set; }

/// <summary>
/// If the developer chooses to redeem the code themselves then they can provide the resulting tokens here. This is the
/// same as calling HandleCodeRedemption. If set then the handler will not attempt to redeem the code. An IdToken
/// is required if one had not been previously received in the authorization response.
/// </summary>
public OpenIdConnectMessage TokenEndpointResponse { get; set; }

/// <summary>
/// Indicates if the developer choose to handle (or skip) the code redemption. If true then the handler will not attempt
/// to redeem the code. See HandleCodeRedemption and TokenEndpointResponse.
/// </summary>
public bool HandledCodeRedemption
{
get
{
return TokenEndpointResponse != null;
}
}

/// <summary>
/// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or
/// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then
/// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received
/// in the authorization response. Calling this is the same as setting TokenEndpointResponse.
/// </summary>
public void HandleCodeRedemption()
{
TokenEndpointResponse = new OpenIdConnectMessage();
}

/// <summary>
/// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or
/// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then
/// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received
/// in the authorization response. Calling this is the same as setting TokenEndpointResponse.
/// </summary>
public void HandleCodeRedemption(string accessToken, string idToken)
{
TokenEndpointResponse = new OpenIdConnectMessage() { AccessToken = accessToken, IdToken = idToken };
}

/// <summary>
/// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or
/// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then
/// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received
/// in the authorization response. Calling this is the same as setting TokenEndpointResponse.
/// </summary>
public void HandleCodeRedemption(OpenIdConnectMessage tokenEndpointResponse)
{
TokenEndpointResponse = tokenEndpointResponse;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.Owin.Security.OpenIdConnect;

namespace Microsoft.Owin.Security.Notifications
{
/// <summary>
/// This Notification can be used to be informed when an 'AuthorizationCode' is redeemed for tokens at the token endpoint.
/// </summary>
public class TokenResponseReceivedNotification : BaseNotification<OpenIdConnectAuthenticationOptions>
{
/// <summary>
/// Creates a <see cref="TokenResponseReceivedNotification"/>
/// </summary>
public TokenResponseReceivedNotification(IOwinContext context, OpenIdConnectAuthenticationOptions options)
: base(context, options)
{
}

/// <summary>
/// Gets or sets the <see cref="OpenIdConnectMessage"/> that contains the code redeemed for tokens at the token endpoint.
/// </summary>
public OpenIdConnectMessage ProtocolMessage { get; set; }

/// <summary>
/// Gets or sets the <see cref="OpenIdConnectMessage"/> that contains the tokens received after redeeming the code at the token endpoint.
/// </summary>
public OpenIdConnectMessage TokenEndpointResponse { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ public OpenIdConnectAuthenticationMiddleware(OwinMiddleware next, IAppBuilder ap
Options.TokenValidationParameters.ValidAudience = Options.ClientId;
}

if (Options.Backchannel == null)
{
Options.Backchannel = new HttpClient(ResolveHttpMessageHandler(Options));
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect middleware");
Options.Backchannel.Timeout = Options.BackchannelTimeout;
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
}

if (Options.ConfigurationManager == null)
{
if (Options.Configuration != null)
Expand All @@ -91,13 +99,8 @@ public OpenIdConnectAuthenticationMiddleware(OwinMiddleware next, IAppBuilder ap
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
}

var backchannel = new HttpClient(ResolveHttpMessageHandler(Options));
backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect middleware");
backchannel.Timeout = Options.BackchannelTimeout;
backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB

Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever(backchannel) { RequireHttps = Options.RequireHttpsMetadata });
new HttpDocumentRetriever(Options.Backchannel) { RequireHttps = Options.RequireHttpsMetadata });
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public OpenIdConnectAuthenticationNotifications()
SecurityTokenReceived = notification => Task.FromResult(0);
SecurityTokenValidated = notification => Task.FromResult(0);
RedirectToIdentityProvider = notification => Task.FromResult(0);
TokenResponseReceived = notification => Task.FromResult(0);
}

/// <summary>
Expand Down Expand Up @@ -55,5 +56,10 @@ public OpenIdConnectAuthenticationNotifications()
/// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
public Func<SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>, Task> SecurityTokenValidated { get; set; }

/// <summary>
/// Invoked after "authorization code" is redeemed for tokens at the token endpoint.
/// </summary>
public Func<TokenResponseReceivedNotification, Task> TokenResponseReceived { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ public OpenIdConnectAuthenticationOptions()
/// <para>Caption: <see cref="OpenIdConnectAuthenticationDefaults.Caption"/>.</para>
/// <para>ProtocolValidator: new <see cref="OpenIdConnectProtocolValidator"/>.</para>
/// <para>RefreshOnIssuerKeyNotFound: true</para>
/// <para>ResponseMode: <see cref="OpenIdConnectResponseMode.FormPost"/></para>
/// <para>ResponseType: <see cref="OpenIdConnectResponseTypes.CodeIdToken"/></para>
/// <para>Scope: <see cref="OpenIdConnectScopes.OpenIdProfile"/>.</para>
/// <para>TokenValidationParameters: new <see cref="TokenValidationParameters"/> with AuthenticationType = authenticationType.</para>
/// <para>UseTokenLifetime: true.</para>
/// <para>RedeemCode: false.</para>
/// </remarks>
/// <param name="authenticationType"> will be used to when creating the <see cref="System.Security.Claims.ClaimsIdentity"/> for the AuthenticationType property.</param>
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationOptions.set_Caption(System.String)", Justification = "Not a LOC field")]
Expand All @@ -60,13 +62,15 @@ public OpenIdConnectAuthenticationOptions(string authenticationType)
NonceLifetime = TimeSpan.FromMinutes(15)
};
RefreshOnIssuerKeyNotFound = true;
ResponseMode = OpenIdConnectResponseMode.FormPost;
ResponseType = OpenIdConnectResponseType.CodeIdToken;
Scope = OpenIdConnectScope.OpenIdProfile;
SecurityTokenValidator = new JwtSecurityTokenHandler();
RequireHttpsMetadata = true;
TokenValidationParameters = new TokenValidationParameters();
UseTokenLifetime = true;
CookieManager = new CookieManager();
RedeemCode = false;
}

/// <summary>
Expand Down Expand Up @@ -122,6 +126,11 @@ public TimeSpan BackchannelTimeout
}
}

/// <summary>
/// Used to communicate with the remote identity provider.
/// </summary>
public HttpClient Backchannel { get; set; }

/// <summary>
/// Get or sets the text that the user can display on a sign in user interface.
/// </summary>
Expand Down Expand Up @@ -216,6 +225,11 @@ public OpenIdConnectProtocolValidator ProtocolValidator
/// </summary>
public string Resource { get; set; }

/// <summary>
/// Gets or sets the 'response_mode'.
/// </summary>
public string ResponseMode { get; set; }

/// <summary>
/// Gets or sets the 'response_type'.
/// </summary>
Expand Down Expand Up @@ -290,9 +304,23 @@ public bool UseTokenLifetime
set;
}

/// <summary>
/// Defines whether access and refresh tokens should be stored in the
/// <see cref="AuthenticationProperties"/> after a successful authorization.
/// This property is set to <c>false</c> by default to reduce
/// the size of the final authentication cookie.
/// </summary>
public bool SaveTokens { get; set; }

/// <summary>
/// An abstraction for reading and setting cookies during the authentication process.
/// </summary>
public ICookieManager CookieManager { get; set; }

/// <summary>
/// When set to <c>true</c> the authorization code will be redeemed for tokens at the token endpoint.
/// This property is set to <c>false</c> by default.
/// </summary>
public bool RedeemCode { get; set; }
}
}
Loading