+ support for response_mode=form_post and
new Hook in OAuthAuthorizationServerProvider: OnAuthorizationEndpointResponse
This commit is contained in:
Родитель
d0fbf8fc45
Коммит
d9ed49eb5c
|
@ -35,6 +35,12 @@ namespace Microsoft.Owin.Security.OAuth.Messages
|
|||
/// </summary>
|
||||
public string ResponseType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The "response_mode" query string parameter of the Authorize request. Known values are "query", "fragment" and "form_post"
|
||||
/// See also, http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
|
||||
/// </summary>
|
||||
public string ResponseMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The "client_id" query string parameter of the Authorize request.
|
||||
/// </summary>
|
||||
|
@ -58,13 +64,32 @@ namespace Microsoft.Owin.Security.OAuth.Messages
|
|||
/// </summary>
|
||||
public string State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the "response_type" query string contains the passed responseType.
|
||||
/// See also, http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html
|
||||
/// </summary>
|
||||
/// <param name="responseType">The responseType that is expected within the "response_type" query string</param>
|
||||
/// <returns>True if the "response_type" query string contains the passed responseType.</returns>
|
||||
public bool ContainsGrantType(string responseType)
|
||||
{
|
||||
var parts = ResponseType.Split(' ');
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (string.Equals(part, responseType, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the "response_type" query string parameter is "code".
|
||||
/// See also, http://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
/// </summary>
|
||||
public bool IsAuthorizationCodeGrantType
|
||||
{
|
||||
get { return string.Equals(ResponseType, Constants.ResponseTypes.Code, StringComparison.Ordinal); }
|
||||
get { return ContainsGrantType(Constants.ResponseTypes.Code); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -73,7 +98,12 @@ namespace Microsoft.Owin.Security.OAuth.Messages
|
|||
/// </summary>
|
||||
public bool IsImplicitGrantType
|
||||
{
|
||||
get { return string.Equals(ResponseType, Constants.ResponseTypes.Token, StringComparison.Ordinal); }
|
||||
get { return ContainsGrantType(Constants.ResponseTypes.Token); }
|
||||
}
|
||||
|
||||
public bool IsFormPostResponseMode
|
||||
{
|
||||
get { return string.Equals(ResponseMode, Constants.ResponseModes.FormPost, StringComparison.Ordinal); }
|
||||
}
|
||||
|
||||
private void AddParameter(string name, string value)
|
||||
|
@ -98,6 +128,10 @@ namespace Microsoft.Owin.Security.OAuth.Messages
|
|||
{
|
||||
State = value;
|
||||
}
|
||||
else if (string.Equals(name, Constants.Parameters.ResponseMode, StringComparison.Ordinal))
|
||||
{
|
||||
ResponseMode = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,11 +70,13 @@
|
|||
<Compile Include="OAuthBearerAuthenticationOptions.cs" />
|
||||
<Compile Include="OAuthConstants.cs" />
|
||||
<Compile Include="OAuthDefaults.cs" />
|
||||
<Compile Include="Provider\OAuthTokenEndpointResponseContext.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Provider\BaseValidatingClientContext.cs" />
|
||||
<Compile Include="Provider\BaseValidatingContext.cs" />
|
||||
<Compile Include="Provider\BaseValidatingTicketContext.cs" />
|
||||
<Compile Include="Provider\DefaultBehavior.cs" />
|
||||
<Compile Include="Provider\OAuthAuthorizeEndpointResponseContext.cs" />
|
||||
<Compile Include="Provider\OAuthAuthorizeEndpointContext.cs" />
|
||||
<Compile Include="Provider\IOAuthAuthorizationServerProvider.cs" />
|
||||
<Compile Include="Provider\OAuthAuthorizationServerProvider.cs" />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
@ -12,6 +13,7 @@ using Microsoft.Owin.Security.Infrastructure;
|
|||
using Microsoft.Owin.Security.OAuth.Messages;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace Microsoft.Owin.Security.OAuth
|
||||
{
|
||||
internal class OAuthAuthorizationServerHandler : AuthenticationHandler<OAuthAuthorizationServerOptions>
|
||||
|
@ -172,7 +174,7 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
return;
|
||||
}
|
||||
|
||||
string location = _clientContext.RedirectUri;
|
||||
var returnParameter = new Dictionary<string, string>();
|
||||
|
||||
if (_authorizeEndpointRequest.IsAuthorizationCodeGrantType)
|
||||
{
|
||||
|
@ -204,15 +206,51 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
await SendErrorRedirectAsync(_clientContext, errorContext);
|
||||
}
|
||||
|
||||
location = WebUtilities.AddQueryString(location, Constants.Parameters.Code, code);
|
||||
var authResponseContext = new OAuthAuthorizationEndpointResponseContext(
|
||||
Context,
|
||||
Options,
|
||||
new AuthenticationTicket(signin.Identity, signin.Properties),
|
||||
_authorizeEndpointRequest,
|
||||
null,
|
||||
code);
|
||||
|
||||
await Options.Provider.AuthorizationEndpointResponse(authResponseContext);
|
||||
|
||||
foreach (var parameter in authResponseContext.AdditionalResponseParameters)
|
||||
{
|
||||
returnParameter[parameter.Key] = parameter.Value.ToString();
|
||||
}
|
||||
|
||||
returnParameter[Constants.Parameters.Code] = code;
|
||||
|
||||
if (!String.IsNullOrEmpty(_authorizeEndpointRequest.State))
|
||||
{
|
||||
location = WebUtilities.AddQueryString(location, Constants.Parameters.State, _authorizeEndpointRequest.State);
|
||||
returnParameter[Constants.Parameters.State] = _authorizeEndpointRequest.State;
|
||||
}
|
||||
|
||||
string location = "";
|
||||
if (_authorizeEndpointRequest.IsFormPostResponseMode)
|
||||
{
|
||||
location = Options.FormPostEndpoint.ToString();
|
||||
returnParameter[Constants.Parameters.RedirectUri] = _clientContext.RedirectUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
location = _clientContext.RedirectUri;
|
||||
}
|
||||
|
||||
foreach (var key in returnParameter.Keys)
|
||||
{
|
||||
location = WebUtilities.AddQueryString(location, key, returnParameter[key]);
|
||||
}
|
||||
|
||||
Response.Redirect(location);
|
||||
}
|
||||
else if (_authorizeEndpointRequest.IsImplicitGrantType)
|
||||
{
|
||||
|
||||
string location = _clientContext.RedirectUri;
|
||||
|
||||
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
|
||||
signin.Properties.IssuedUtc = currentUtc;
|
||||
signin.Properties.ExpiresUtc = currentUtc.Add(Options.AccessTokenExpireTimeSpan);
|
||||
|
@ -249,10 +287,28 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
{
|
||||
appender.Append(Constants.Parameters.State, _authorizeEndpointRequest.State);
|
||||
}
|
||||
|
||||
var authResponseContext = new OAuthAuthorizationEndpointResponseContext(
|
||||
Context,
|
||||
Options,
|
||||
new AuthenticationTicket(signin.Identity, signin.Properties),
|
||||
_authorizeEndpointRequest,
|
||||
accessToken,
|
||||
null);
|
||||
|
||||
await Options.Provider.AuthorizationEndpointResponse(authResponseContext);
|
||||
|
||||
foreach (var parameter in authResponseContext.AdditionalResponseParameters)
|
||||
{
|
||||
appender.Append(parameter.Key, parameter.Value.ToString());
|
||||
}
|
||||
|
||||
Response.Redirect(appender.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task InvokeTokenEndpointAsync()
|
||||
{
|
||||
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
|
||||
|
@ -375,6 +431,16 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
await Options.RefreshTokenProvider.CreateAsync(refreshTokenCreateContext);
|
||||
string refreshToken = refreshTokenCreateContext.Token;
|
||||
|
||||
var tokenEndpointResponseContext = new OAuthTokenEndpointResponseContext(
|
||||
Context,
|
||||
Options,
|
||||
ticket,
|
||||
tokenEndpointRequest,
|
||||
accessToken,
|
||||
tokenEndpointContext.AdditionalResponseParameters);
|
||||
|
||||
await Options.Provider.TokenEndpointResponse(tokenEndpointResponseContext);
|
||||
|
||||
var memory = new MemoryStream();
|
||||
byte[] body;
|
||||
using (var writer = new JsonTextWriter(new StreamWriter(memory)))
|
||||
|
@ -399,7 +465,7 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
writer.WritePropertyName(Constants.Parameters.RefreshToken);
|
||||
writer.WriteValue(refreshToken);
|
||||
}
|
||||
foreach (var additionalResponseParameter in tokenEndpointContext.AdditionalResponseParameters)
|
||||
foreach (var additionalResponseParameter in tokenEndpointResponseContext.AdditionalResponseParameters)
|
||||
{
|
||||
writer.WritePropertyName(additionalResponseParameter.Key);
|
||||
writer.WriteValue(additionalResponseParameter.Value);
|
||||
|
|
|
@ -120,5 +120,12 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
/// redirect_uri authorize request parameter to have http URI addresses.
|
||||
/// </summary>
|
||||
public bool AllowInsecureHttp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint responsible for Form Post Response Mode
|
||||
/// See also, http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
|
||||
/// </summary>
|
||||
public PathString FormPostEndpoint { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
public const string ExpiresIn = "expires_in";
|
||||
public const string AccessToken = "access_token";
|
||||
public const string TokenType = "token_type";
|
||||
|
||||
public const string ResponseMode = "response_mode";
|
||||
}
|
||||
|
||||
public static class ResponseTypes
|
||||
|
@ -59,5 +61,10 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
public const string ClientId = "client_id";
|
||||
public const string RedirectUri = "redirect_uri";
|
||||
}
|
||||
|
||||
public static class ResponseModes
|
||||
{
|
||||
public const string FormPost = "form_post";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,5 +150,23 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
/// <param name="context">The context of the event carries information in and results out.</param>
|
||||
/// <returns>Task to enable asynchronous execution</returns>
|
||||
Task TokenEndpoint(OAuthTokenEndpointContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Called before the AuthorizationEndpoint redirects its response to the caller. The response could be the
|
||||
/// token, when using implicit flow or the AuthorizationEndpoint when using authorization code flow.
|
||||
/// An application may implement this call in order to do any final modification of the claims being used
|
||||
/// to issue access or refresh tokens. This call may also be used in order to add additional
|
||||
/// response parameters to the authorization endpoint's response.
|
||||
/// </summary>
|
||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
||||
/// <returns>Task to enable asynchronous execution</returns>
|
||||
Task AuthorizationEndpointResponse(OAuthAuthorizationEndpointResponseContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Called before the TokenEndpoint redirects its response to the caller.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
|
||||
OnAuthorizeEndpoint = context => Task.FromResult<object>(null);
|
||||
OnTokenEndpoint = context => Task.FromResult<object>(null);
|
||||
|
||||
OnAuthorizationEndpointResponse = context => Task.FromResult<object>(null);
|
||||
|
||||
OnTokenEndpointResponse = context => Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -152,6 +156,24 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
/// </summary>
|
||||
public Func<OAuthTokenEndpointContext, Task> OnTokenEndpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called before the AuthorizationEndpoint redirects its response to the caller. The response could be the
|
||||
/// token, when using implicit flow or the AuthorizationEndpoint when using authorization code flow.
|
||||
/// An application may implement this call in order to do any final modification of the claims being used
|
||||
/// to issue access or refresh tokens. This call may also be used in order to add additional
|
||||
/// response parameters to the authorization endpoint's response.
|
||||
/// </summary>
|
||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
||||
/// <returns>Task to enable asynchronous execution</returns>
|
||||
public Func<OAuthAuthorizationEndpointResponseContext, Task> OnAuthorizationEndpointResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called before the TokenEndpoint redirects its response to the caller.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public Func<OAuthTokenEndpointResponseContext, Task> OnTokenEndpointResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called to determine if an incoming request is treated as an Authorize or Token
|
||||
/// endpoint. If Options.AuthorizeEndpointPath or Options.TokenEndpointPath
|
||||
|
@ -328,5 +350,29 @@ namespace Microsoft.Owin.Security.OAuth
|
|||
{
|
||||
return OnTokenEndpoint.Invoke(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before the AuthorizationEndpoint redirects its response to the caller. The response could be the
|
||||
/// token, when using implicit flow or the AuthorizationEndpoint when using authorization code flow.
|
||||
/// An application may implement this call in order to do any final modification of the claims being used
|
||||
/// to issue access or refresh tokens. This call may also be used in order to add additional
|
||||
/// response parameters to the authorization endpoint's response.
|
||||
/// </summary>
|
||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
||||
/// <returns>Task to enable asynchronous execution</returns>
|
||||
public virtual Task AuthorizationEndpointResponse(OAuthAuthorizationEndpointResponseContext context)
|
||||
{
|
||||
return OnAuthorizationEndpointResponse.Invoke(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before the TokenEndpoint redirects its response to the caller.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
|
||||
{
|
||||
return OnTokenEndpointResponse.Invoke(context); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.Owin.Security.OAuth.Messages;
|
||||
using Microsoft.Owin.Security.Provider;
|
||||
|
||||
namespace Microsoft.Owin.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides context information when processing an Authorization Response
|
||||
/// </summary>
|
||||
public class OAuthAuthorizationEndpointResponseContext: EndpointContext<OAuthAuthorizationServerOptions>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OAuthAuthorizationEndpointResponseContext"/> class
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="ticket"></param>
|
||||
/// <param name="tokenEndpointRequest"></param>
|
||||
public OAuthAuthorizationEndpointResponseContext(
|
||||
IOwinContext context,
|
||||
OAuthAuthorizationServerOptions options,
|
||||
AuthenticationTicket ticket,
|
||||
AuthorizeEndpointRequest authorizeEndpointRequest,
|
||||
string accessToken,
|
||||
string authorizationCode)
|
||||
: base(context, options)
|
||||
{
|
||||
if (ticket == null)
|
||||
{
|
||||
throw new ArgumentNullException("ticket");
|
||||
}
|
||||
|
||||
Identity = ticket.Identity;
|
||||
Properties = ticket.Properties;
|
||||
AuthorizeEndpointRequest = authorizeEndpointRequest;
|
||||
AdditionalResponseParameters = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
AccessToken = accessToken;
|
||||
AuthorizationCode = authorizationCode;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identity of the resource owner.
|
||||
/// </summary>
|
||||
public ClaimsIdentity Identity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary containing the state of the authentication session.
|
||||
/// </summary>
|
||||
public AuthenticationProperties Properties { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the authorize endpoint request.
|
||||
/// </summary>
|
||||
public AuthorizeEndpointRequest AuthorizeEndpointRequest { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables additional values to be appended to the token response.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AdditionalResponseParameters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The serialized Access-Token. Depending on the flow, it can be null.
|
||||
/// </summary>
|
||||
public string AccessToken { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The created Authorization-Code. Depending on the flow, it can be null.
|
||||
/// </summary>
|
||||
public string AuthorizationCode { get; private set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.Owin.Security.OAuth.Messages;
|
||||
using Microsoft.Owin.Security.Provider;
|
||||
|
||||
namespace Microsoft.Owin.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides context information used at the end of a token-endpoint-request.
|
||||
/// </summary>
|
||||
public class OAuthTokenEndpointResponseContext : EndpointContext<OAuthAuthorizationServerOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OAuthTokenEndpointResponseContext"/> class
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="ticket"></param>
|
||||
/// <param name="tokenEndpointRequest"></param>
|
||||
public OAuthTokenEndpointResponseContext(
|
||||
IOwinContext context,
|
||||
OAuthAuthorizationServerOptions options,
|
||||
AuthenticationTicket ticket,
|
||||
TokenEndpointRequest tokenEndpointRequest,
|
||||
string accessToken,
|
||||
IDictionary<string, object> additionalResponseParameters)
|
||||
: base(context, options)
|
||||
{
|
||||
if (ticket == null)
|
||||
{
|
||||
throw new ArgumentNullException("ticket");
|
||||
}
|
||||
|
||||
Identity = ticket.Identity;
|
||||
Properties = ticket.Properties;
|
||||
TokenEndpointRequest = tokenEndpointRequest;
|
||||
AdditionalResponseParameters = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
TokenIssued = Identity != null;
|
||||
AccessToken = accessToken;
|
||||
AdditionalResponseParameters = additionalResponseParameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identity of the resource owner.
|
||||
/// </summary>
|
||||
public ClaimsIdentity Identity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary containing the state of the authentication session.
|
||||
/// </summary>
|
||||
public AuthenticationProperties Properties { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The issued Access-Token
|
||||
/// </summary>
|
||||
public string AccessToken { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the token endpoint request.
|
||||
/// </summary>
|
||||
public TokenEndpointRequest TokenEndpointRequest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the token should be issued.
|
||||
/// </summary>
|
||||
public bool TokenIssued { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables additional values to be appended to the token response.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AdditionalResponseParameters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Issues the token.
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
/// <param name="properties"></param>
|
||||
public void Issue(ClaimsIdentity identity, AuthenticationProperties properties)
|
||||
{
|
||||
Identity = identity;
|
||||
Properties = properties;
|
||||
TokenIssued = true;
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче