// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using IdentityServer4.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using IdentityServer4.Quickstart.UI.Models;
using Identity.API.Models.AccountViewModels;
using Identity.API.Services;
namespace IdentityServer4.Quickstart.UI.Controllers
{
///
/// This controller implements the consent logic
///
public class ConsentController : Controller
{
private readonly ILogger _logger;
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
private readonly IIdentityServerInteractionService _interaction;
public ConsentController(
ILogger logger,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IResourceStore resourceStore)
{
_logger = logger;
_interaction = interaction;
_clientStore = clientStore;
_resourceStore = resourceStore;
}
///
/// Shows the consent screen
///
///
///
[HttpGet]
public async Task Index(string returnUrl)
{
var vm = await BuildViewModelAsync(returnUrl);
ViewData["ReturnUrl"] = returnUrl;
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
///
/// Handles the consent screen postback
///
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Index(ConsentInputModel model)
{
// parse the return URL back to an AuthorizeRequest object
var request = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
ConsentResponse response = null;
// user clicked 'no' - send back the standard 'access_denied' response
if (model.Button == "no")
{
response = ConsentResponse.Denied;
}
// user clicked 'yes' - validate the data
else if (model.Button == "yes" && model != null)
{
// if the user consented to some scope, build the response model
if (model.ScopesConsented != null && model.ScopesConsented.Any())
{
response = new ConsentResponse
{
RememberConsent = model.RememberConsent,
ScopesConsented = model.ScopesConsented
};
}
else
{
ModelState.AddModelError("", "You must pick at least one permission.");
}
}
else
{
ModelState.AddModelError("", "Invalid Selection");
}
if (response != null)
{
// communicate outcome of consent back to identityserver
await _interaction.GrantConsentAsync(request, response);
// redirect back to authorization endpoint
return Redirect(model.ReturnUrl);
}
var vm = await BuildViewModelAsync(model.ReturnUrl, model);
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
async Task BuildViewModelAsync(string returnUrl, ConsentInputModel model = null)
{
var request = await _interaction.GetAuthorizationContextAsync(returnUrl);
if (request != null)
{
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
if (client != null)
{
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
if (resources != null && (resources.IdentityResources.Any() || resources.ApiResources.Any()))
{
return new ConsentViewModel(model, returnUrl, request, client, resources);
}
else
{
_logger.LogError("No scopes matching: {0}", request.ScopesRequested.Aggregate((x, y) => x + ", " + y));
}
}
else
{
_logger.LogError("Invalid client id: {0}", request.ClientId);
}
}
else
{
_logger.LogError("No consent request matching request: {0}", returnUrl);
}
return null;
}
}
}