Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/modules/Elsa.Studio.Login/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Elsa.Studio.Login.Extensions;

/// <summary>
/// Provides a set of extension methods for <see cref="string"/>.
/// </summary>
internal static class StringExtensions
{
/// <summary>
/// Ensures the string starts with the specified character when non-empty.
/// </summary>
public static string EnsureStartsWith(this string? value, string prefix)
{
if (string.IsNullOrEmpty(value))
return string.Empty;

return value.StartsWith(prefix) ? value : prefix + value;
}

/// <summary>
/// Ensures the string ends with the specified string when non-empty.
/// </summary>
public static string EnsureEndsWith(this string? value, string suffix)
{
if (string.IsNullOrEmpty(value))
return string.Empty;

return value.EndsWith(suffix) ? value : value + suffix;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ public class OpenIdConnectConfiguration
/// </summary>
public required string EndSessionEndpoint { get; set; }

/// <summary>
/// A prefix to insert before <c>/signin-oidc</c> when constructing the redirect_uri for the authorization request.
/// Useful for sub-path deployments behind a reverse proxy, e.g. setting this to <c>/workflow</c> produces
/// <c>https://myapp.com/workflow/signin-oidc</c>. The value must start with <c>/</c>. When not set the redirect_uri
/// defaults to <c>{origin}/signin-oidc</c>.
/// </summary>
Comment thread
IbrahimMNada marked this conversation as resolved.
public string? RedirectUriPrefix { get; set; }

/// <summary>
/// The client_id as which this application is registered with the authorization server
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Elsa.Studio.Login.Contracts;
using Elsa.Studio.Login.Contracts;
using Elsa.Studio.Login.Extensions;
using Elsa.Studio.Login.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.WebUtilities;
Expand All @@ -21,7 +22,7 @@ public class OpenIdConnectAuthorizationService(IJwtAccessor jwtAccessor, IOption
public async Task RedirectToAuthorizationServer()
{
var config = configuration.Value;
var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + "/signin-oidc";
var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + config.RedirectUriPrefix.EnsureStartsWith("/") + "/signin-oidc";
string url = config.AuthEndpoint + $"?client_id={WebUtility.UrlEncode(config.ClientId)}&redirect_uri={WebUtility.UrlEncode(redirectUri)}&response_type=code&scope={WebUtility.UrlEncode(String.Join(' ', config.Scopes))}";
if (config.UsePkce)
{
Expand All @@ -40,7 +41,7 @@ public async Task RedirectToAuthorizationServer()
public async Task ReceiveAuthorizationCode(string code, string? state, CancellationToken cancellationToken)
{
var config = configuration.Value;
var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + "/signin-oidc";
var redirectUri = new Uri(navigationManager.Uri).GetLeftPart(UriPartial.Authority) + config.RedirectUriPrefix.EnsureStartsWith("/") + "/signin-oidc";

var formValues = new List<KeyValuePair<string, string>>
{
Expand All @@ -50,7 +51,7 @@ public async Task ReceiveAuthorizationCode(string code, string? state, Cancellat
new("redirect_uri", redirectUri)
};

if(!string.IsNullOrWhiteSpace(config.ClientSecret))
if (!string.IsNullOrWhiteSpace(config.ClientSecret))
{
formValues.Add(new KeyValuePair<string, string>("client_secret", config.ClientSecret));
}
Expand Down Expand Up @@ -132,7 +133,7 @@ private static async Task<string> ReadErrorSummaryAsync(HttpContent content, Can
if (summary.Length > MaxLoggedErrorLength)
summary = summary[..MaxLoggedErrorLength];

return truncated ? $"{summary}" : summary;
return truncated ? $"{summary}" : summary;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Corrupted ellipsis character

The original file (which had a UTF-8 BOM) contained the HORIZONTAL ELLIPSIS (U+2026) on this line. When the BOM was stripped in this PR, the multi-byte sequence for that character was corrupted to U+FFFD (the Unicode Replacement Character). At runtime, truncated error summaries logged by ReadErrorSummaryAsync will end with the replacement character <?> instead of , producing garbled log output. Replace the character literal on this line with the correct (U+2026), or use the escape \u2026.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/modules/Elsa.Studio.Login/Services/OpenIdConnectAuthorizationService.cs
Line: 136

Comment:
**Corrupted ellipsis character**

The original file (which had a UTF-8 BOM) contained the HORIZONTAL ELLIPSIS `` (U+2026) on this line. When the BOM was stripped in this PR, the multi-byte sequence for that character was corrupted to U+FFFD (the Unicode Replacement Character). At runtime, truncated error summaries logged by `ReadErrorSummaryAsync` will end with the replacement character `<?>` instead of ``, producing garbled log output. Replace the character literal on this line with the correct `` (U+2026), or use the escape `\u2026`.

How can I resolve this? If you propose a fix, please make it concise.

}

private static async Task<(string Content, bool Truncated)> ReadContentSnippetAsync(HttpContent content, CancellationToken cancellationToken)
Expand Down Expand Up @@ -178,4 +179,5 @@ private static async Task<string> ReadErrorSummaryAsync(HttpContent content, Can

return null;
}

}