// 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 System;
using System.Globalization;
using System.Net.Http;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.OAuth
{
///
/// An ASP.NET Core middleware for authenticating users using OAuth services.
///
public class OAuthMiddleware : AuthenticationMiddleware where TOptions : OAuthOptions, new()
{
///
/// Initializes a new .
///
/// The next middleware in the HTTP pipeline to invoke.
///
///
/// The .
/// The configuration options for this middleware.
/// Configuration options for the middleware.
public OAuthMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IOptions sharedOptions,
IOptions options)
: base(next, options, loggerFactory, encoder)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (sharedOptions == null)
{
throw new ArgumentNullException(nameof(sharedOptions));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
// todo: review error handling
if (string.IsNullOrEmpty(Options.AuthenticationScheme))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AuthenticationScheme)));
}
if (string.IsNullOrEmpty(Options.ClientId))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ClientId)));
}
if (string.IsNullOrEmpty(Options.ClientSecret))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ClientSecret)));
}
if (string.IsNullOrEmpty(Options.AuthorizationEndpoint))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AuthorizationEndpoint)));
}
if (string.IsNullOrEmpty(Options.TokenEndpoint))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.TokenEndpoint)));
}
if (!Options.CallbackPath.HasValue)
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.CallbackPath)));
}
if (Options.Events == null)
{
Options.Events = new OAuthEvents();
}
if (Options.StateDataFormat == null)
{
var dataProtector = dataProtectionProvider.CreateProtector(
GetType().FullName, Options.AuthenticationScheme, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth middleware");
Backchannel.Timeout = Options.BackchannelTimeout;
Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
if (string.IsNullOrEmpty(Options.SignInScheme))
{
Options.SignInScheme = sharedOptions.Value.SignInScheme;
}
if (string.IsNullOrEmpty(Options.SignInScheme))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.SignInScheme)));
}
}
protected HttpClient Backchannel { get; private set; }
///
/// Provides the object for processing authentication-related requests.
///
/// An configured with the supplied to the constructor.
protected override AuthenticationHandler CreateHandler()
{
return new OAuthHandler(Backchannel);
}
}
}