public async Task <IActionResult> Consent([FromForm] InputModel input) { var request = await _interaction.GetLoginRequestByInternalIdAsync(input.Id); var viewModel = BuildViewModelAsync(request, input.Id, input); CompleteBackchannelLoginRequest result = null; // user clicked 'no' - send back the standard 'access_denied' response if (input.Button == "no") { result = new CompleteBackchannelLoginRequest(input.Id); // emit event await _events.RaiseAsync(new ConsentDeniedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues)) .ConfigureAwait(false); } // user clicked 'yes' - validate the data else if (input.Button == "yes") { // if the user consented to some scope, build the response model if (input.ScopesConsented != null && input.ScopesConsented.Any()) { var scopes = input.ScopesConsented; if (ConsentOptions.EnableOfflineAccess == false) { scopes = scopes.Where(x => x != StandardScopes.OfflineAccess); } result = new CompleteBackchannelLoginRequest(input.Id) { ScopesValuesConsented = scopes.ToArray(), Description = input.Description }; // emit event await _events.RaiseAsync(new ConsentGrantedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues, result.ScopesValuesConsented, false)) .ConfigureAwait(false);; } else { ModelState.AddModelError(string.Empty, ConsentOptions.MustChooseOneErrorMessage); } } else { ModelState.AddModelError(string.Empty, ConsentOptions.InvalidSelectionErrorMessage); } if (result != null) { // communicate outcome of consent back to identityserver await _interaction.CompleteLoginRequestAsync(result); return(RedirectToPage("/Account/Manage/Ciba", new { area = "Identity" })); } return(View(viewModel)); }
public async Task <IActionResult> OnPost() { // validate return url is still valid var request = await _interaction.GetLoginRequestByInternalIdAsync(Input.Id); if (request == null || request.Subject.GetSubjectId() != User.GetSubjectId()) { _logger.LogError("Invalid id {id}", Input.Id); return(RedirectToPage("/Home/Error/Index")); } CompleteBackchannelLoginRequest result = null; // user clicked 'no' - send back the standard 'access_denied' response if (Input?.Button == "no") { result = new CompleteBackchannelLoginRequest(Input.Id); // emit event await _events.RaiseAsync(new ConsentDeniedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues)); } // user clicked 'yes' - validate the data else if (Input?.Button == "yes") { // if the user consented to some scope, build the response model if (Input.ScopesConsented != null && Input.ScopesConsented.Any()) { var scopes = Input.ScopesConsented; if (ConsentOptions.EnableOfflineAccess == false) { scopes = scopes.Where(x => x != Duende.IdentityServer.IdentityServerConstants.StandardScopes.OfflineAccess); } result = new CompleteBackchannelLoginRequest(Input.Id) { ScopesValuesConsented = scopes.ToArray(), Description = Input.Description }; // emit event await _events.RaiseAsync(new ConsentGrantedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues, result.ScopesValuesConsented, false)); } else { ModelState.AddModelError("", ConsentOptions.MustChooseOneErrorMessage); } } else { ModelState.AddModelError("", ConsentOptions.InvalidSelectionErrorMessage); } if (result != null) { // communicate outcome of consent back to identityserver await _interaction.CompleteLoginRequestAsync(result); return(RedirectToPage("/Ciba/All")); } // we need to redisplay the consent UI View = await BuildViewModelAsync(Input.Id, Input); return(Page()); }
/// <inheritdoc/> public async Task CompleteLoginRequestAsync(CompleteBackchannelLoginRequest competionRequest) { using var activity = Tracing.ServiceActivitySource.StartActivity("DefaultBackchannelAuthenticationInteractionService.CompleteLoginRequest"); if (competionRequest == null) { throw new ArgumentNullException(nameof(competionRequest)); } var request = await _requestStore.GetByInternalIdAsync(competionRequest.InternalId); if (request == null) { throw new InvalidOperationException("Invalid backchannel authentication request id."); } var subject = competionRequest.Subject ?? await _session.GetUserAsync(); if (subject == null) { throw new InvalidOperationException("Invalid subject."); } if (subject.GetSubjectId() != request.Subject.GetSubjectId()) { throw new InvalidOperationException($"User's subject id: '{subject.GetSubjectId()}' does not match subject id for backchannel authentication request: '{request.Subject.GetSubjectId()}'."); } var sid = (competionRequest.Subject == null) ? await _session.GetSessionIdAsync() : competionRequest.SessionId; if (competionRequest.ScopesValuesConsented != null) { var extra = competionRequest.ScopesValuesConsented.Except(request.RequestedScopes); if (extra.Any()) { throw new InvalidOperationException("More scopes consented than originally requested."); } } var subjectClone = subject.Clone(); if (!subject.HasClaim(x => x.Type == JwtClaimTypes.AuthenticationTime)) { subjectClone.Identities.First().AddClaim(new Claim(JwtClaimTypes.AuthenticationTime, _systemClock.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer)); } if (!subject.HasClaim(x => x.Type == JwtClaimTypes.IdentityProvider)) { subjectClone.Identities.First().AddClaim(new Claim(JwtClaimTypes.IdentityProvider, IdentityServerConstants.LocalIdentityProvider)); } request.IsComplete = true; request.Subject = subjectClone; request.SessionId = sid; request.AuthorizedScopes = competionRequest.ScopesValuesConsented; request.Description = competionRequest.Description; await _requestStore.UpdateByInternalIdAsync(competionRequest.InternalId, request); _logger.LogDebug("Successful update for backchannel authentication request id {id}", competionRequest.InternalId); }