#39 - Port the OAuth Bearer middleware from Katana.
This commit is contained in:
parent
3426034bcb
commit
4853554147
|
|
@ -21,7 +21,7 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>50113</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>12345</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -28,7 +28,6 @@ namespace CookieSample
|
|||
{
|
||||
services.ConfigureOptions<ExternalAuthenticationOptions>(options =>
|
||||
{
|
||||
|
||||
options.SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"Microsoft.AspNet.Security.Google": "1.0.0-*",
|
||||
"Microsoft.AspNet.Security.MicrosoftAccount": "1.0.0-*",
|
||||
"Microsoft.AspNet.Security.Twitter": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
|
||||
"Microsoft.Framework.OptionsModel": "1.0.0-*"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Security.Notifications;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class used for certain event contexts
|
||||
/// </summary>
|
||||
public abstract class BaseValidatingContext<TOptions> : BaseContext<TOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes base class used for certain event contexts
|
||||
/// </summary>
|
||||
protected BaseValidatingContext(
|
||||
HttpContext context,
|
||||
TOptions options)
|
||||
: base(context, options)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if application code has called any of the Validate methods on this context.
|
||||
/// </summary>
|
||||
public bool IsValidated { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if application code has called any of the SetError methods on this context.
|
||||
/// </summary>
|
||||
public bool HasError { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The error argument provided when SetError was called on this context. This is eventually
|
||||
/// returned to the client app as the OAuth "error" parameter.
|
||||
/// </summary>
|
||||
public string Error { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The optional errorDescription argument provided when SetError was called on this context. This is eventually
|
||||
/// returned to the client app as the OAuth "error_description" parameter.
|
||||
/// </summary>
|
||||
public string ErrorDescription { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The optional errorUri argument provided when SetError was called on this context. This is eventually
|
||||
/// returned to the client app as the OAuth "error_uri" parameter.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "error_uri is a string value in the protocol")]
|
||||
public string ErrorUri { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Marks this context as validated by the application. IsValidated becomes true and HasError becomes false as a result of calling.
|
||||
/// </summary>
|
||||
/// <returns>True if the validation has taken effect.</returns>
|
||||
public virtual bool Validated()
|
||||
{
|
||||
IsValidated = true;
|
||||
HasError = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this context as not validated by the application. IsValidated and HasError become false as a result of calling.
|
||||
/// </summary>
|
||||
public virtual void Rejected()
|
||||
{
|
||||
IsValidated = false;
|
||||
HasError = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this context as not validated by the application and assigns various error information properties.
|
||||
/// HasError becomes true and IsValidated becomes false as a result of calling.
|
||||
/// </summary>
|
||||
/// <param name="error">Assigned to the Error property</param>
|
||||
public void SetError(string error)
|
||||
{
|
||||
SetError(error, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this context as not validated by the application and assigns various error information properties.
|
||||
/// HasError becomes true and IsValidated becomes false as a result of calling.
|
||||
/// </summary>
|
||||
/// <param name="error">Assigned to the Error property</param>
|
||||
/// <param name="errorDescription">Assigned to the ErrorDescription property</param>
|
||||
public void SetError(string error,
|
||||
string errorDescription)
|
||||
{
|
||||
SetError(error, errorDescription, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this context as not validated by the application and assigns various error information properties.
|
||||
/// HasError becomes true and IsValidated becomes false as a result of calling.
|
||||
/// </summary>
|
||||
/// <param name="error">Assigned to the Error property</param>
|
||||
/// <param name="errorDescription">Assigned to the ErrorDescription property</param>
|
||||
/// <param name="errorUri">Assigned to the ErrorUri property</param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "error_uri is a string value in the protocol")]
|
||||
public void SetError(string error,
|
||||
string errorDescription,
|
||||
string errorUri)
|
||||
{
|
||||
Error = error;
|
||||
ErrorDescription = errorDescription;
|
||||
ErrorUri = errorUri;
|
||||
Rejected();
|
||||
HasError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class used for certain event contexts
|
||||
/// </summary>
|
||||
public abstract class BaseValidatingTicketContext<TOptions> : BaseValidatingContext<TOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes base class used for certain event contexts
|
||||
/// </summary>
|
||||
protected BaseValidatingTicketContext(
|
||||
HttpContext context,
|
||||
TOptions options,
|
||||
AuthenticationTicket ticket)
|
||||
: base(context, options)
|
||||
{
|
||||
Ticket = ticket;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains the identity and properties for the application to authenticate. If the Validated method
|
||||
/// is invoked with an AuthenticationTicket or ClaimsIdentity argument, that new value is assigned to
|
||||
/// this property in addition to changing IsValidated to true.
|
||||
/// </summary>
|
||||
public AuthenticationTicket Ticket { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the ticket information on this context and marks it as as validated by the application.
|
||||
/// IsValidated becomes true and HasError becomes false as a result of calling.
|
||||
/// </summary>
|
||||
/// <param name="ticket">Assigned to the Ticket property</param>
|
||||
/// <returns>True if the validation has taken effect.</returns>
|
||||
public bool Validated(AuthenticationTicket ticket)
|
||||
{
|
||||
Ticket = ticket;
|
||||
return Validated();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alters the ticket information on this context and marks it as as validated by the application.
|
||||
/// IsValidated becomes true and HasError becomes false as a result of calling.
|
||||
/// </summary>
|
||||
/// <param name="identity">Assigned to the Ticket.Identity property</param>
|
||||
/// <returns>True if the validation has taken effect.</returns>
|
||||
public bool Validated(ClaimsIdentity identity)
|
||||
{
|
||||
AuthenticationProperties properties = Ticket != null ? Ticket.Properties : new AuthenticationProperties();
|
||||
return Validated(new AuthenticationTicket(identity, properties));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies callback methods which the <see cref="OAuthBearerAuthenticationMiddleware"></see> invokes to enable developer control over the authentication process. />
|
||||
/// </summary>
|
||||
public interface IOAuthBearerAuthenticationNotifications
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked before the <see cref="System.Security.Claims.ClaimsIdentity"/> is created. Gives the application an
|
||||
/// opportunity to find the identity from a different location, adjust, or reject the token.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains the token string.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
|
||||
Task RequestToken(OAuthRequestTokenContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a request identity has been validated by the middleware. By implementing this method the
|
||||
/// application may alter or reject the identity which has arrived with the request.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
|
||||
Task ValidateIdentity(OAuthValidateIdentityContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a challenge is being sent to the client. By implementing this method the application
|
||||
/// may modify the challenge as needed.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains the default challenge.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
|
||||
Task ApplyChallenge(OAuthChallengeContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// OAuth bearer token middleware provider
|
||||
/// </summary>
|
||||
public class OAuthBearerAuthenticationNotifications : IOAuthBearerAuthenticationNotifications
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OAuthBearerAuthenticationProvider"/> class
|
||||
/// </summary>
|
||||
public OAuthBearerAuthenticationNotifications()
|
||||
{
|
||||
OnRequestToken = context => Task.FromResult<object>(null);
|
||||
OnValidateIdentity = context => Task.FromResult<object>(null);
|
||||
OnApplyChallenge = context =>
|
||||
{
|
||||
context.HttpContext.Response.Headers.AppendValues("WWW-Authenticate", context.Challenge);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles processing OAuth bearer token.
|
||||
/// </summary>
|
||||
public Func<OAuthRequestTokenContext, Task> OnRequestToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handles validating the identity produced from an OAuth bearer token.
|
||||
/// </summary>
|
||||
public Func<OAuthValidateIdentityContext, Task> OnValidateIdentity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handles applying the authentication challenge to the response message.
|
||||
/// </summary>
|
||||
public Func<OAuthChallengeContext, Task> OnApplyChallenge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handles processing OAuth bearer token.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task RequestToken(OAuthRequestTokenContext context)
|
||||
{
|
||||
return OnRequestToken(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles validating the identity produced from an OAuth bearer token.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task ValidateIdentity(OAuthValidateIdentityContext context)
|
||||
{
|
||||
return OnValidateIdentity.Invoke(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles applying the authentication challenge to the response message.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public Task ApplyChallenge(OAuthChallengeContext context)
|
||||
{
|
||||
return OnApplyChallenge(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Security.Notifications;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the HTTP response header for the bearer authentication scheme.
|
||||
/// </summary>
|
||||
public class OAuthChallengeContext : BaseContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="OAuthRequestTokenContext"/>
|
||||
/// </summary>
|
||||
/// <param name="context">HTTP environment</param>
|
||||
/// <param name="challenge">The www-authenticate header value.</param>
|
||||
public OAuthChallengeContext(
|
||||
HttpContext context,
|
||||
string challenge)
|
||||
: base(context)
|
||||
{
|
||||
Challenge = challenge;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The www-authenticate header value.
|
||||
/// </summary>
|
||||
public string Challenge { get; protected set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ using System.Security.Claims;
|
|||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.AspNet.Security.Notifications;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Security.Notifications;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the HTTP request header for the bearer authentication scheme.
|
||||
/// </summary>
|
||||
public class OAuthRequestTokenContext : BaseContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="OAuthRequestTokenContext"/>
|
||||
/// </summary>
|
||||
/// <param name="context">HTTP environment</param>
|
||||
/// <param name="token">The authorization header value.</param>
|
||||
public OAuthRequestTokenContext(
|
||||
HttpContext context,
|
||||
string token)
|
||||
: base(context)
|
||||
{
|
||||
Token = token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authorization header value
|
||||
/// </summary>
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the authentication ticket data from an OAuth bearer token.
|
||||
/// </summary>
|
||||
public class OAuthValidateIdentityContext : BaseValidatingTicketContext<OAuthBearerAuthenticationOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OAuthValidateIdentityContext"/> class
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="ticket"></param>
|
||||
public OAuthValidateIdentityContext(
|
||||
HttpContext context,
|
||||
OAuthBearerAuthenticationOptions options,
|
||||
AuthenticationTicket ticket) : base(context, options, ticket)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Default values used by authorization server and bearer authentication.
|
||||
/// </summary>
|
||||
public static class OAuthBearerAuthenticationDefaults
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for AuthenticationType property in the OAuthBearerAuthenticationOptions and
|
||||
/// OAuthAuthorizationServerOptions.
|
||||
/// </summary>
|
||||
public const string AuthenticationType = "Bearer";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Security.OAuth;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods to add OAuth Bearer authentication capabilities to an HTTP application pipeline
|
||||
/// </summary>
|
||||
public static class OAuthBearerAuthenticationExtensions
|
||||
{
|
||||
public static IServiceCollection ConfigureOAuthBearerAuthentication([NotNull] this IServiceCollection services, [NotNull] Action<OAuthBearerAuthenticationOptions> configure)
|
||||
{
|
||||
return services.ConfigureOptions(configure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Bearer token processing to an HTTP application pipeline. This middleware understands appropriately
|
||||
/// formatted and secured tokens which appear in the request header. If the Options.AuthenticationMode is Active, the
|
||||
/// claims within the bearer token are added to the current request's IPrincipal User. If the Options.AuthenticationMode
|
||||
/// is Passive, then the current request is not modified, but IAuthenticationManager AuthenticateAsync may be used at
|
||||
/// any time to obtain the claims from the request's bearer token.
|
||||
/// See also http://tools.ietf.org/html/rfc6749
|
||||
/// </summary>
|
||||
/// <param name="app">The application builder</param>
|
||||
/// <param name="options">Options which control the processing of the bearer header.</param>
|
||||
/// <returns>The application builder</returns>
|
||||
public static IApplicationBuilder UseOAuthBearerAuthentication([NotNull] this IApplicationBuilder app, Action<OAuthBearerAuthenticationOptions> configureOptions = null, string optionsName = "")
|
||||
{
|
||||
return app.UseMiddleware<OAuthBearerAuthenticationMiddleware>(
|
||||
new OptionsAction<OAuthBearerAuthenticationOptions>(configureOptions ?? (o => { }))
|
||||
{
|
||||
Name = optionsName
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Security.Infrastructure;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
internal class OAuthBearerAuthenticationHandler : AuthenticationHandler<OAuthBearerAuthenticationOptions>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly string _challenge;
|
||||
|
||||
public OAuthBearerAuthenticationHandler(ILogger logger, string challenge)
|
||||
{
|
||||
_logger = logger;
|
||||
_challenge = challenge;
|
||||
}
|
||||
|
||||
protected override AuthenticationTicket AuthenticateCore()
|
||||
{
|
||||
return AuthenticateCoreAsync().Result;
|
||||
}
|
||||
|
||||
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Find token in default location
|
||||
string requestToken = null;
|
||||
string authorization = Request.Headers.Get("Authorization");
|
||||
if (!string.IsNullOrEmpty(authorization))
|
||||
{
|
||||
if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
requestToken = authorization.Substring("Bearer ".Length).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Give application opportunity to find from a different location, adjust, or reject token
|
||||
var requestTokenContext = new OAuthRequestTokenContext(Context, requestToken);
|
||||
await Options.Notifications.RequestToken(requestTokenContext);
|
||||
|
||||
// If no token found, no further work possible
|
||||
if (string.IsNullOrEmpty(requestTokenContext.Token))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Call provider to process the token into data
|
||||
var tokenReceiveContext = new AuthenticationTokenReceiveContext(
|
||||
Context,
|
||||
Options.AccessTokenFormat,
|
||||
requestTokenContext.Token);
|
||||
|
||||
await Options.AccessTokenProvider.ReceiveAsync(tokenReceiveContext);
|
||||
if (tokenReceiveContext.Ticket == null)
|
||||
{
|
||||
tokenReceiveContext.DeserializeTicket(tokenReceiveContext.Token);
|
||||
}
|
||||
|
||||
AuthenticationTicket ticket = tokenReceiveContext.Ticket;
|
||||
if (ticket == null)
|
||||
{
|
||||
_logger.WriteWarning("invalid bearer token received");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate expiration time if present
|
||||
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
|
||||
|
||||
if (ticket.Properties.ExpiresUtc.HasValue &&
|
||||
ticket.Properties.ExpiresUtc.Value < currentUtc)
|
||||
{
|
||||
_logger.WriteWarning("expired bearer token received");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Give application final opportunity to override results
|
||||
var context = new OAuthValidateIdentityContext(Context, Options, ticket);
|
||||
if (ticket != null &&
|
||||
ticket.Identity != null &&
|
||||
ticket.Identity.IsAuthenticated)
|
||||
{
|
||||
// bearer token with identity starts validated
|
||||
context.Validated();
|
||||
}
|
||||
|
||||
await Options.Notifications.ValidateIdentity(context);
|
||||
if (!context.IsValidated)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// resulting identity values go back to caller
|
||||
return context.Ticket;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.WriteError("Authentication failed", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyResponseChallenge()
|
||||
{
|
||||
if (Response.StatusCode != 401)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ChallengeContext != null)
|
||||
{
|
||||
OAuthChallengeContext challengeContext = new OAuthChallengeContext(Context, _challenge);
|
||||
Options.Notifications.ApplyChallenge(challengeContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyResponseGrant()
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Security.DataHandler;
|
||||
using Microsoft.AspNet.Security.DataProtection;
|
||||
using Microsoft.AspNet.Security.Infrastructure;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Bearer authentication middleware component which is added to an HTTP pipeline. This class is not
|
||||
/// created by application code directly, instead it is added by calling the the IAppBuilder UseOAuthBearerAuthentication
|
||||
/// extension method.
|
||||
/// </summary>
|
||||
public class OAuthBearerAuthenticationMiddleware : AuthenticationMiddleware<OAuthBearerAuthenticationOptions>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly string _challenge;
|
||||
|
||||
/// <summary>
|
||||
/// Bearer authentication component which is added to an HTTP pipeline. This constructor is not
|
||||
/// called by application code directly, instead it is added by calling the the IAppBuilder UseOAuthBearerAuthentication
|
||||
/// extension method.
|
||||
/// </summary>
|
||||
public OAuthBearerAuthenticationMiddleware(
|
||||
RequestDelegate next,
|
||||
IDataProtectionProvider dataProtectionProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptionsAccessor<OAuthBearerAuthenticationOptions> options,
|
||||
IOptionsAction<OAuthBearerAuthenticationOptions> configureOptions)
|
||||
: base(next, options, configureOptions)
|
||||
{
|
||||
_logger = loggerFactory.Create<OAuthBearerAuthenticationMiddleware>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Options.Challenge))
|
||||
{
|
||||
_challenge = Options.Challenge;
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(Options.Realm))
|
||||
{
|
||||
_challenge = "Bearer";
|
||||
}
|
||||
else
|
||||
{
|
||||
_challenge = "Bearer realm=\"" + Options.Realm + "\"";
|
||||
}
|
||||
|
||||
if (Options.Notifications == null)
|
||||
{
|
||||
Options.Notifications = new OAuthBearerAuthenticationNotifications();
|
||||
}
|
||||
|
||||
if (Options.AccessTokenFormat == null)
|
||||
{
|
||||
var dataProtector = DataProtectionHelpers.CreateDataProtector(dataProtectionProvider,
|
||||
this.GetType().FullName, Options.AuthenticationType, "v1");
|
||||
Options.AccessTokenFormat = new TicketDataFormat(dataProtector);
|
||||
}
|
||||
|
||||
if (Options.AccessTokenProvider == null)
|
||||
{
|
||||
Options.AccessTokenProvider = new AuthenticationTokenProvider();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the AuthenticationMiddleware base class to create a per-request handler.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the request handler</returns>
|
||||
protected override AuthenticationHandler<OAuthBearerAuthenticationOptions> CreateHandler()
|
||||
{
|
||||
return new OAuthBearerAuthenticationHandler(_logger, _challenge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Security.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.Security.OAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// Options class provides information needed to control Bearer Authentication middleware behavior
|
||||
/// </summary>
|
||||
public class OAuthBearerAuthenticationOptions : AuthenticationOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of bearer authentication options with default values.
|
||||
/// </summary>
|
||||
public OAuthBearerAuthenticationOptions() : base()
|
||||
{
|
||||
SystemClock = new SystemClock();
|
||||
AuthenticationType = OAuthBearerAuthenticationDefaults.AuthenticationType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines what realm value is included when the bearer middleware adds a response header to an unauthorized request.
|
||||
/// If not assigned, the response header does not have a realm.
|
||||
/// </summary>
|
||||
public string Realm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the full challenge to send to the client, and should start with "Bearer". If a challenge is provided then the
|
||||
/// Realm property is ignored. If no challenge is specified then one is created using "Bearer" and the value of the Realm
|
||||
/// property.
|
||||
/// </summary>
|
||||
public string Challenge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The object provided by the application to process events raised by the bearer authentication middleware.
|
||||
/// The application may implement the interface fully, or it may create an instance of OAuthBearerAuthenticationProvider
|
||||
/// and assign delegates only to the events it wants to process.
|
||||
/// </summary>
|
||||
public IOAuthBearerAuthenticationNotifications Notifications { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The data format used to un-protect the information contained in the access token.
|
||||
/// If not provided by the application the default data protection provider depends on the host server.
|
||||
/// The SystemWeb host on IIS will use ASP.NET machine key data protection, and HttpListener and other self-hosted
|
||||
/// servers will use DPAPI data protection. If a different access token
|
||||
/// provider or format is assigned, a compatible instance must be assigned to the OAuthAuthorizationServerOptions.AccessTokenProvider
|
||||
/// and OAuthAuthorizationServerOptions.AccessTokenFormat of the authorization server.
|
||||
/// </summary>
|
||||
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Receives the bearer token the client application will be providing to web application. If not provided the token
|
||||
/// produced on the server's default data protection by using the AccessTokenFormat. If a different access token
|
||||
/// provider or format is assigned, a compatible instance must be assigned to the OAuthAuthorizationServerOptions.AccessTokenProvider
|
||||
/// and OAuthAuthorizationServerOptions.AccessTokenFormat of the authorization server.
|
||||
/// </summary>
|
||||
public IAuthenticationTokenProvider AccessTokenProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to know what the current clock time is when calculating or validating token expiration. When not assigned default is based on
|
||||
/// DateTimeOffset.UtcNow. This is typically needed only for unit testing.
|
||||
/// </summary>
|
||||
public ISystemClock SystemClock { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue