Skip to content

Commit

Permalink
add more response generators
Browse files Browse the repository at this point in the history
  • Loading branch information
brockallen committed Jul 19, 2023
1 parent d311222 commit 0b74cb0
Show file tree
Hide file tree
Showing 23 changed files with 307 additions and 203 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,23 @@ public static IIdentityServerBuilder AddDefaultEndpoints(this IIdentityServerBui
builder.AddEndpoint<TokenEndpoint>(EndpointNames.Token, ProtocolRoutePaths.Token.EnsureLeadingSlash());
builder.AddEndpoint<UserInfoEndpoint>(EndpointNames.UserInfo, ProtocolRoutePaths.UserInfo.EnsureLeadingSlash());

builder.AddEndpointResultGenerator<DiscoveryDocumentResult, DiscoveryDocumentResultGenerator>();
builder.AddEndpointResultGenerator<AuthorizeResult, AuthorizeResultGenerator>();
builder.AddEndpointResultGenerator<AuthorizeInteractionPageResult, AuthorizeInteractionPageResultGenerator>();
builder.AddEndpointResultGenerator<AuthorizeResult, AuthorizeResultGenerator>();
builder.AddEndpointResultGenerator<BackchannelAuthenticationResult, BackchannelAuthenticationResultGenerator>();
builder.AddEndpointResultGenerator<BadRequestResult, BadRequestResultGenerator>();
builder.AddEndpointResultGenerator<CheckSessionResult, CheckSessionResultGenerator>();
builder.AddEndpointResultGenerator<DeviceAuthorizationResult, DeviceAuthorizationResultGenerator>();
builder.AddEndpointResultGenerator<DiscoveryDocumentResult, DiscoveryDocumentResultGenerator>();
builder.AddEndpointResultGenerator<EndSessionCallbackResult, EndSessionCallbackResultGenerator>();
builder.AddEndpointResultGenerator<EndSessionResult, EndSessionResultGenerator>();
builder.AddEndpointResultGenerator<IntrospectionResult, IntrospectionResultGenerator>();
builder.AddEndpointResultGenerator<JsonWebKeysResult, JsonWebKeysResultGenerator>();
builder.AddEndpointResultGenerator<ProtectedResourceErrorResult, ProtectedResourceErrorResultGenerator>();
builder.AddEndpointResultGenerator<StatusCodeResult, StatusCodeResultGenerator>();
builder.AddEndpointResultGenerator<TokenErrorResult, TokenErrorResultGenerator>();
builder.AddEndpointResultGenerator<TokenResult, TokenResultGenerator>();
builder.AddEndpointResultGenerator<TokenRevocationErrorResult, TokenRevocationErrorResultGenerator>();
builder.AddEndpointResultGenerator<UserInfoResult, UserInfoResultGenerator>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ public AuthorizeInteractionPageResult(ValidatedAuthorizeRequest request, string
public string ReturnUrlParameterName { get; }
}

/// <summary>
/// Result generator for AuthorizeInteractionPageResult
/// </summary>
public class AuthorizeInteractionPageResultGenerator : IEndpointResultGenerator<AuthorizeInteractionPageResult>
class AuthorizeInteractionPageResultGenerator : IEndpointResultGenerator<AuthorizeInteractionPageResult>
{
private readonly IServerUrls _urls;
private readonly IAuthorizationParametersMessageStore _authorizationParametersMessageStore;
Expand Down
13 changes: 12 additions & 1 deletion src/IdentityServer/Endpoints/Results/AuthorizeResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,21 @@

namespace Duende.IdentityServer.Endpoints.Results;

internal class AuthorizeResult : EndpointResult<AuthorizeResult>
/// <summary>
/// Models the result from the authorize endpoint
/// </summary>
public class AuthorizeResult : EndpointResult<AuthorizeResult>
{
/// <summary>
/// The authorize response
/// </summary>
public AuthorizeResponse Response { get; }

/// <summary>
/// Ctor
/// </summary>
/// <param name="response"></param>
/// <exception cref="ArgumentNullException"></exception>
public AuthorizeResult(AuthorizeResponse response)
{
Response = response ?? throw new ArgumentNullException(nameof(response));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,21 @@

namespace Duende.IdentityServer.Endpoints.Results;

internal class BackchannelAuthenticationResult : EndpointResult<BackchannelAuthenticationResult>
/// <summary>
/// Models the result of backchannel authentication
/// </summary>
public class BackchannelAuthenticationResult : EndpointResult<BackchannelAuthenticationResult>
{
public BackchannelAuthenticationResponse Response { get; set; }
/// <summary>
/// The response
/// </summary>
public BackchannelAuthenticationResponse Response { get; }

/// <summary>
/// Ctor
/// </summary>
/// <param name="response"></param>
/// <exception cref="ArgumentNullException"></exception>
public BackchannelAuthenticationResult(BackchannelAuthenticationResponse response)
{
Response = response ?? throw new ArgumentNullException(nameof(response));
Expand Down
37 changes: 27 additions & 10 deletions src/IdentityServer/Endpoints/Results/BadRequestResult.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Duende Software. All rights reserved.
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.


Expand All @@ -9,28 +9,45 @@

namespace Duende.IdentityServer.Endpoints.Results;

internal class BadRequestResult : IEndpointResult
/// <summary>
/// The result of a bad request
/// </summary>
public class BadRequestResult : EndpointResult<BadRequestResult>
{
public string Error { get; set; }
public string ErrorDescription { get; set; }

/// <summary>
/// The error
/// </summary>
public string Error { get; }
/// <summary>
/// The error description
/// </summary>
public string ErrorDescription { get; }

/// <summary>
/// Ctor
/// </summary>
/// <param name="error"></param>
/// <param name="errorDescription"></param>
public BadRequestResult(string error = null, string errorDescription = null)
{
Error = error;
ErrorDescription = errorDescription;
}
}

public async Task ExecuteAsync(HttpContext context)
internal class BadRequestResultGenerator : IEndpointResultGenerator<BadRequestResult>
{
public async Task ExecuteAsync(BadRequestResult result, HttpContext context)
{
context.Response.StatusCode = 400;
context.Response.SetNoCache();

if (Error.IsPresent())
if (result.Error.IsPresent())
{
var dto = new ResultDto
{
error = Error,
error_description = ErrorDescription
error = result.Error,
error_description = result.ErrorDescription
};

await context.Response.WriteJsonAsync(dto);
Expand All @@ -41,5 +58,5 @@ internal class ResultDto
{
public string error { get; set; }
public string error_description { get; set; }
}
}
}
24 changes: 10 additions & 14 deletions src/IdentityServer/Endpoints/Results/CheckSessionResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Duende.IdentityServer.Extensions;

namespace Duende.IdentityServer.Endpoints.Results;

internal class CheckSessionResult : IEndpointResult
/// <summary>
/// The resukt of the check session endpoint
/// </summary>
public class CheckSessionResult : EndpointResult<CheckSessionResult>
{
public CheckSessionResult()
{
}
}

internal CheckSessionResult(IdentityServerOptions options)

internal class CheckSessionResultGenerator : IEndpointResultGenerator<CheckSessionResult>
{
public CheckSessionResultGenerator(IdentityServerOptions options)
{
_options = options;
}
Expand All @@ -27,15 +30,8 @@ internal CheckSessionResult(IdentityServerOptions options)
private static readonly object Lock = new object();
private static volatile string LastCheckSessionCookieName;

private void Init(HttpContext context)
public async Task ExecuteAsync(CheckSessionResult result, HttpContext context)
{
_options = _options ?? context.RequestServices.GetRequiredService<IdentityServerOptions>();
}

public async Task ExecuteAsync(HttpContext context)
{
Init(context);

AddCspHeaders(context);

var html = GetHtml(_options.Authentication.CheckSessionCookieName);
Expand Down
30 changes: 22 additions & 8 deletions src/IdentityServer/Endpoints/Results/DeviceAuthorizationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,41 @@

namespace Duende.IdentityServer.Endpoints.Results;

internal class DeviceAuthorizationResult : IEndpointResult
/// <summary>
/// The result of device authorization
/// </summary>
public class DeviceAuthorizationResult : EndpointResult<DeviceAuthorizationResult>
{
/// <summary>
/// The response
/// </summary>
public DeviceAuthorizationResponse Response { get; }

/// <summary>
/// Ctor
/// </summary>
/// <param name="response"></param>
/// <exception cref="ArgumentNullException"></exception>
public DeviceAuthorizationResult(DeviceAuthorizationResponse response)
{
Response = response ?? throw new ArgumentNullException(nameof(response));
}
}

public async Task ExecuteAsync(HttpContext context)
internal class DeviceAuthorizationResultGenerator : IEndpointResultGenerator<DeviceAuthorizationResult>
{
public async Task ExecuteAsync(DeviceAuthorizationResult result, HttpContext context)
{
context.Response.SetNoCache();

var dto = new ResultDto
{
device_code = Response.DeviceCode,
user_code = Response.UserCode,
verification_uri = Response.VerificationUri,
verification_uri_complete = Response.VerificationUriComplete,
expires_in = Response.DeviceCodeLifetime,
interval = Response.Interval
device_code = result.Response.DeviceCode,
user_code = result.Response.UserCode,
verification_uri = result.Response.VerificationUri,
verification_uri_complete = result.Response.VerificationUriComplete,
expires_in = result.Response.DeviceCodeLifetime,
interval = result.Response.Interval
};

await context.Response.WriteJsonAsync(dto);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,14 @@ public class DiscoveryDocumentResult : EndpointResult<DiscoveryDocumentResult>
/// <param name="entries">The entries.</param>
/// <param name="maxAge">The maximum age.</param>
/// <exception cref="System.ArgumentNullException">entries</exception>
public DiscoveryDocumentResult(Dictionary<string, object> entries, int? maxAge)
public DiscoveryDocumentResult(Dictionary<string, object> entries, int? maxAge = null)
{
Entries = entries ?? throw new ArgumentNullException(nameof(entries));
MaxAge = maxAge;
}
}

/// <summary>
/// The result generator for DiscoveryDocumentResult.
/// </summary>
public class DiscoveryDocumentResultGenerator : Hosting.IEndpointResultGenerator<DiscoveryDocumentResult>
class DiscoveryDocumentResultGenerator : IEndpointResultGenerator<DiscoveryDocumentResult>
{
/// <inheritdoc/>
public Task ExecuteAsync(DiscoveryDocumentResult result, HttpContext context)
Expand Down
2 changes: 1 addition & 1 deletion src/IdentityServer/Endpoints/Results/EndPointResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace Duende.IdentityServer.Endpoints.Results;

/// <summary>
/// Provides the base implementation of IEndpointResult.
/// Provides the base implementation of IEndpointResult that invokes the corresponding IEndpointResultGenerator<typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class EndpointResult<T> : IEndpointResult
Expand Down
57 changes: 30 additions & 27 deletions src/IdentityServer/Endpoints/Results/EndSessionCallbackResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,69 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System;
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Hosting;
using Duende.IdentityServer.Validation;
using Duende.IdentityServer.Extensions;
using System.Text.Encodings.Web;
using System.Text;
using Duende.IdentityServer.Hosting;

namespace Duende.IdentityServer.Endpoints.Results;

internal class EndSessionCallbackResult : IEndpointResult
/// <summary>
/// Models the result of end session callback
/// </summary>
public class EndSessionCallbackResult : EndpointResult<EndSessionCallbackResult>
{
private readonly EndSessionCallbackValidationResult _result;

/// <summary>
/// The result
/// </summary>
public EndSessionCallbackValidationResult Result { get; }

/// <summary>
/// Ctor
/// </summary>
/// <param name="result"></param>
/// <exception cref="ArgumentNullException"></exception>
public EndSessionCallbackResult(EndSessionCallbackValidationResult result)
{
_result = result ?? throw new ArgumentNullException(nameof(result));
Result = result ?? throw new ArgumentNullException(nameof(result));
}
}

internal EndSessionCallbackResult(
EndSessionCallbackValidationResult result,
IdentityServerOptions options)
: this(result)
class EndSessionCallbackResultGenerator : IEndpointResultGenerator<EndSessionCallbackResult>
{
public EndSessionCallbackResultGenerator(IdentityServerOptions options)
{
_options = options;
}

private IdentityServerOptions _options;

private void Init(HttpContext context)
public async Task ExecuteAsync(EndSessionCallbackResult result, HttpContext context)
{
_options = _options ?? context.RequestServices.GetRequiredService<IdentityServerOptions>();
}

public async Task ExecuteAsync(HttpContext context)
{
Init(context);

if (_result.IsError)
if (result.Result.IsError)
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
}
else
{
context.Response.SetNoCache();
AddCspHeaders(context);
AddCspHeaders(result, context);

var html = GetHtml();
var html = GetHtml(result);
await context.Response.WriteHtmlAsync(html);
}
}

private void AddCspHeaders(HttpContext context)
private void AddCspHeaders(EndSessionCallbackResult result, HttpContext context)
{
if (_options.Authentication.RequireCspFrameSrcForSignout)
{
var sb = new StringBuilder();
var origins = _result.FrontChannelLogoutUrls?.Select(x => x.GetOrigin());
var origins = result.Result.FrontChannelLogoutUrls?.Select(x => x.GetOrigin());
if (origins != null)
{
foreach (var origin in origins.Distinct())
Expand All @@ -79,14 +82,14 @@ private void AddCspHeaders(HttpContext context)
}
}

private string GetHtml()
private string GetHtml(EndSessionCallbackResult result)
{
var sb = new StringBuilder();
sb.Append("<!DOCTYPE html><html><style>iframe{{display:none;width:0;height:0;}}</style><body>");

if (_result.FrontChannelLogoutUrls != null)
if (result.Result.FrontChannelLogoutUrls != null)
{
foreach (var url in _result.FrontChannelLogoutUrls)
foreach (var url in result.Result.FrontChannelLogoutUrls)
{
sb.AppendFormat("<iframe loading='eager' allow='' src='{0}'></iframe>", HtmlEncoder.Default.Encode(url));
sb.AppendLine();
Expand Down
Loading

0 comments on commit 0b74cb0

Please sign in to comment.