public async Task <EndpointResult> ProcessRedirection( AuthorizationParameter authorizationParameter, string?code, string subject, Claim[] claims, string?issuerName, CancellationToken cancellationToken) { var client = authorizationParameter.ClientId == null ? null : await _clientRepository.GetById(authorizationParameter.ClientId, cancellationToken) .ConfigureAwait(false); if (client == null) { throw new InvalidOperationException(SharedStrings.TheClientDoesntExist); } // Redirect to the consent page if the prompt parameter contains "consent" EndpointResult result; var prompts = authorizationParameter.Prompt.ParsePrompts(); if (prompts.Contains(PromptParameters.Consent) && code != null) { return(EndpointResult.CreateAnEmptyActionResultWithRedirection( SimpleAuthEndPoints.ConsentIndex, new Parameter("code", code))); } var assignedConsent = await _consentRepository .GetConfirmedConsents(subject, authorizationParameter, cancellationToken) .ConfigureAwait(false); // If there's already one consent then redirect to the callback if (assignedConsent != null) { var claimsIdentity = new ClaimsIdentity(claims, "SimpleAuth"); var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); result = await _generateAuthorizationResponse.Generate( EndpointResult.CreateAnEmptyActionResultWithRedirectionToCallBackUrl(), authorizationParameter, claimsPrincipal, client, issuerName, cancellationToken) .ConfigureAwait(false); var responseMode = authorizationParameter.ResponseMode; if (responseMode != ResponseModes.None) { return(result with { RedirectInstruction = result.RedirectInstruction !with { ResponseMode = responseMode } }); } var responseTypes = authorizationParameter.ResponseType.ParseResponseTypes(); var authorizationFlow = GetAuthorizationFlow(authorizationParameter.State, responseTypes); switch (authorizationFlow) { case Option <AuthorizationFlow> .Error e: return(EndpointResult.CreateBadRequestResult(e.Details)); case Option <AuthorizationFlow> .Result r: responseMode = GetResponseMode(r.Item); break; } return(result with { RedirectInstruction = result.RedirectInstruction !with { ResponseMode = responseMode } }); } // If there's no consent & there's no consent prompt then redirect to the consent screen. return(EndpointResult.CreateAnEmptyActionResultWithRedirection( SimpleAuthEndPoints.ConsentIndex, new Parameter("code", code ?? ""))); }
/// <summary> /// Fetch the scopes and client name from the ClientRepository and the parameter /// Those information are used to create the consent screen. /// </summary> /// <param name="authorizationParameter">Authorization code grant type parameter.</param> /// <param name="claimsPrincipal"></param> /// <param name="issuerName"></param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param> /// <returns>Action resultKind.</returns> public async Task <DisplayContentResult> Execute( AuthorizationParameter authorizationParameter, ClaimsPrincipal claimsPrincipal, string issuerName, CancellationToken cancellationToken) { var client = authorizationParameter.ClientId == null ? null : await _clientRepository.GetById(authorizationParameter.ClientId, cancellationToken) .ConfigureAwait(false); if (client == null) { return(new DisplayContentResult( EndpointResult.CreateBadRequestResult( new ErrorDetails { Title = ErrorCodes.InvalidRequest, Detail = string.Format(Strings.ClientIsNotValid, authorizationParameter.ClientId), Status = HttpStatusCode.BadRequest }))); } EndpointResult endpointResult; var subject = claimsPrincipal.GetSubject() !; var assignedConsent = await _consentRepository .GetConfirmedConsents(subject, authorizationParameter, cancellationToken) .ConfigureAwait(false); // If there's already a consent then redirect to the callback if (assignedConsent != null) { endpointResult = await _generateAuthorizationResponse.Generate( EndpointResult.CreateAnEmptyActionResultWithRedirectionToCallBackUrl(), authorizationParameter, claimsPrincipal, client, issuerName, cancellationToken) .ConfigureAwait(false); var responseMode = authorizationParameter.ResponseMode; if (responseMode == ResponseModes.None) { var responseTypes = authorizationParameter.ResponseType.ParseResponseTypes(); var authorizationFlow = GetAuthorizationFlow(responseTypes, authorizationParameter.State); switch (authorizationFlow) { case Option <AuthorizationFlow> .Error e: return(new DisplayContentResult(EndpointResult.CreateBadRequestResult(e.Details))); case Option <AuthorizationFlow> .Result r: responseMode = GetResponseMode(r.Item); break; } } endpointResult = endpointResult with { RedirectInstruction = endpointResult.RedirectInstruction !with { ResponseMode = responseMode } }; return(new DisplayContentResult(endpointResult)); } ICollection <string> allowedClaims = Array.Empty <string>(); ICollection <Scope> allowedScopes = Array.Empty <Scope>(); var claimsParameter = authorizationParameter.Claims; if (claimsParameter.IsAnyIdentityTokenClaimParameter() || claimsParameter.IsAnyUserInfoClaimParameter()) { allowedClaims = claimsParameter.GetClaimNames(); } else { allowedScopes = (await GetScopes(authorizationParameter.Scope !, cancellationToken).ConfigureAwait(false)) .Where(s => s.IsDisplayedInConsent) .ToList(); } endpointResult = EndpointResult.CreateAnEmptyActionResultWithOutput(); return(new DisplayContentResult(client, allowedScopes, allowedClaims, endpointResult)); }
/// <summary> /// This method is executed when the user confirm the consent /// 1). If there's already consent confirmed in the past by the resource owner /// 1).* then we generate an authorization code and redirects to the callback. /// 2). If there's no consent then we insert it and the authorization code is returned /// 2°.* to the callback url. /// </summary> /// <param name="authorizationParameter">Authorization code grant-type</param> /// <param name="claimsPrincipal">Resource owner's claims</param> /// <param name="issuerName"></param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param> /// <returns>Redirects the authorization code to the callback.</returns> public async Task <EndpointResult> Execute( AuthorizationParameter authorizationParameter, ClaimsPrincipal claimsPrincipal, string issuerName, CancellationToken cancellationToken) { var client = authorizationParameter.ClientId == null ? null : await _clientRepository.GetById(authorizationParameter.ClientId, cancellationToken) .ConfigureAwait(false); if (client == null) { throw new InvalidOperationException( string.Format( Strings.TheClientIdDoesntExist, authorizationParameter.ClientId)); } var subject = claimsPrincipal.GetSubject() !; var assignedConsent = await _consentRepository .GetConfirmedConsents(subject, authorizationParameter, cancellationToken) .ConfigureAwait(false); // Insert a new consent. if (assignedConsent == null) { var claimsParameter = authorizationParameter.Claims; if (claimsParameter.IsAnyIdentityTokenClaimParameter() || claimsParameter.IsAnyUserInfoClaimParameter()) { // A consent can be given to a set of claims assignedConsent = new Consent { Id = Id.Create(), ClientId = client.ClientId, ClientName = client.ClientName, Subject = subject, Claims = claimsParameter.GetClaimNames() }; } else { // A consent can be given to a set of scopes assignedConsent = new Consent { Id = Id.Create(), ClientId = client.ClientId, ClientName = client.ClientName, GrantedScopes = authorizationParameter.Scope == null ? Array.Empty <string>() : (await GetScopes(authorizationParameter.Scope, cancellationToken) .ConfigureAwait(false)).ToArray(), Subject = subject, }; } // A consent can be given to a set of claims await _consentRepository.Insert(assignedConsent, cancellationToken).ConfigureAwait(false); await _eventPublisher.Publish( new ConsentAccepted( Id.Create(), subject, client.ClientId, assignedConsent.GrantedScopes, DateTimeOffset.UtcNow)) .ConfigureAwait(false); } var result = await _generateAuthorizationResponse.Generate( EndpointResult.CreateAnEmptyActionResultWithRedirectionToCallBackUrl(), authorizationParameter, claimsPrincipal, client, issuerName, cancellationToken) .ConfigureAwait(false); // If redirect to the callback and the response mode has not been set. if (result.Type != ActionResultType.RedirectToCallBackUrl) { return(result); } var responseMode = authorizationParameter.ResponseMode; if (responseMode == ResponseModes.None) { var responseTypes = authorizationParameter.ResponseType.ParseResponseTypes(); var authorizationFlow = GetAuthorizationFlow(responseTypes, authorizationParameter.State); switch (authorizationFlow) { case Option <AuthorizationFlow> .Error e: return(EndpointResult.CreateBadRequestResult(e.Details)); case Option <AuthorizationFlow> .Result r: responseMode = GetResponseMode(r.Item); break; } } result = result with { RedirectInstruction = result.RedirectInstruction !with { ResponseMode = responseMode } }; return(result); }