using System; using System.Threading.Tasks; using AspNet.Security.OpenIdConnect.Primitives; using JetBrains.Annotations; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using Microsoft.Extensions.DependencyInjection; namespace OpenIddict.Mvc { /// /// Represents an ASP.NET Core MVC model binder that is able to bind /// and /// instances. /// public class OpenIddictModelBinder : IModelBinder, IModelBinderProvider { /// /// Tries to bind a model from the request. /// /// The model binding context. /// A representing the asynchronous operation. public Task BindModelAsync([NotNull] ModelBindingContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.ModelType == typeof(OpenIdConnectRequest)) { var request = context.HttpContext.GetOpenIdConnectRequest(); if (request == null) { throw new InvalidOperationException("The OpenID Connect request cannot be retrieved from the ASP.NET context. " + "Make sure that 'app.UseOpenIddict()' is called before 'app.UseMvc()' and " + "that the action route corresponds to the endpoint path registered via " + "'services.AddOpenIddict().Enable[...]Endpoint(...)'."); } // Add a new validation state entry to prevent the built-in // model validators from validating the OpenID Connect request. context.ValidationState.Add(request, new ValidationStateEntry { SuppressValidation = true }); context.Result = ModelBindingResult.Success(request); return Task.FromResult(0); } else if (context.ModelType == typeof(OpenIdConnectResponse)) { var response = context.HttpContext.GetOpenIdConnectResponse(); if (response != null) { // Add a new validation state entry to prevent the built-in // model validators from validating the OpenID Connect response. context.ValidationState.Add(response, new ValidationStateEntry { SuppressValidation = true }); } context.Result = ModelBindingResult.Success(response); return Task.FromResult(0); } throw new InvalidOperationException("The specified model type is not supported by this binder."); } /// /// Tries to resolve the model binder corresponding to the given model. /// /// The model binding context. /// The current instance or null if the model is not supported. public IModelBinder GetBinder([NotNull] ModelBinderProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.Metadata.ModelType == typeof(OpenIdConnectRequest) || context.Metadata.ModelType == typeof(OpenIdConnectResponse)) { return this; } return null; } } }