Skip to content

Commit

Permalink
Merge pull request #20 from bcgov/bugfix/sso-issue
Browse files Browse the repository at this point in the history
Fix for SSO Login Issue
  • Loading branch information
WadeBarnes authored Sep 11, 2024
2 parents 5bbe0b4 + 041ace9 commit 7b567d6
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 10 deletions.
7 changes: 6 additions & 1 deletion api/Controllers/AuthController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@ await Db.RequestFileAccess.AddAsync(new RequestFileAccess

return Ok(new
{
Url = $"{XForwardedForHelper.BuildUrlString(forwardedHost, forwardedPort, baseUrl)}civil-file/{request.FileId}?fromA2A=true"
Url = XForwardedForHelper.BuildUrlString(
forwardedHost,
forwardedPort,
baseUrl,
$"civil-file/{request.FileId}",
"fromA2A=true")
});
}

Expand Down
35 changes: 31 additions & 4 deletions api/Helpers/XForwardedForHelper.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
namespace Scv.Api.Helpers
using System;

namespace Scv.Api.Helpers
{
public static class XForwardedForHelper
{
public static string BuildUrlString(string forwardedHost, string forwardedPort, string baseUrl)
public static string BuildUrlString(string forwardedHost, string forwardedPort, string baseUrl, string remainingPath = "", string query = "")
{
var portComponent = string.IsNullOrEmpty(forwardedPort) || forwardedPort == "80" || forwardedPort == "443" ? "" : $":{forwardedPort}";
return $"https://{forwardedHost}{portComponent}{baseUrl}";
var sanitizedPath = baseUrl;
if (!string.IsNullOrEmpty(remainingPath))
{
sanitizedPath = string.Format("{0}/{1}", baseUrl.TrimEnd('/'), remainingPath.TrimStart('/'));
}

var uriBuilder = new UriBuilder
{
Scheme = "https",
Host = forwardedHost,
Path = sanitizedPath,
Query = query
};

var portComponent =
string.IsNullOrEmpty(forwardedPort) || forwardedPort == "80" || forwardedPort == "443"
? ""
: $":{forwardedPort}";

if (!string.IsNullOrEmpty(portComponent))
{
int port;
int.TryParse(forwardedPort, out port);
uriBuilder.Port = port;
}

return uriBuilder.Uri.AbsoluteUri;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ await cookieCtx.HttpContext.SignOutAsync(CookieAuthenticationDefaults

var loggerFactory = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("OnTokenValidated");
logger.LogInformation($"OpenIdConnect UserId - { context.Principal.UserId() } - logged in.");
logger.LogInformation($"OpenIdConnect UserId - {context.Principal.UserId()} - logged in.");

//Cleanup keycloak claims, that are unused.
foreach (var claim in identity.Claims.WhereToList(c =>
Expand All @@ -152,13 +152,13 @@ await cookieCtx.HttpContext.SignOutAsync(CookieAuthenticationDefaults

if (fileAccess != null && !string.IsNullOrEmpty(fileAccess.PartId) && !string.IsNullOrEmpty(fileAccess.AgencyId))
{
logger.LogInformation($"UserId - { context.Principal.UserId() } - Using credentials passed in from A2A.");
logger.LogInformation($"UserId - {context.Principal.UserId()} - Using credentials passed in from A2A.");
var aesGcmEncryption = context.HttpContext.RequestServices.GetRequiredService<AesGcmEncryption>();
partId = aesGcmEncryption.Decrypt(fileAccess.PartId);
agencyId = aesGcmEncryption.Decrypt(fileAccess.AgencyId);
applicationCode = "A2A";
}
}
}
else if (context.Principal.IsIdirUser() && context.Principal.Groups().Contains("court-viewer-supreme"))
{
isSupremeUser = true;
Expand Down Expand Up @@ -197,8 +197,11 @@ await cookieCtx.HttpContext.SignOutAsync(CookieAuthenticationDefaults
var forwardedHost = context.HttpContext.Request.Headers["X-Forwarded-Host"];
var forwardedPort = context.HttpContext.Request.Headers["X-Forwarded-Port"];
var baseUrl = context.HttpContext.Request.Headers["X-Base-Href"];
context.ProtocolMessage.RedirectUri =
$"{XForwardedForHelper.BuildUrlString(forwardedHost, forwardedPort, baseUrl)}{options.CallbackPath}";
context.ProtocolMessage.RedirectUri = XForwardedForHelper.BuildUrlString(
forwardedHost,
forwardedPort,
baseUrl,
options.CallbackPath);
}
return Task.CompletedTask;
}
Expand Down
133 changes: 133 additions & 0 deletions tests/api/Helpers/XForwardedForHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System.Net;
using System.Collections.Generic;
using System;
using Bogus;
using Scv.Api.Helpers;
using Xunit;

namespace tests.api.Helpers
{
public class XForwardedForHelperTests
{
[Fact]
public void BuildUrlString_ShouldRemoveDoubleSlashesInUrlPath()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var path1 = WebUtility.UrlEncode(faker.Random.Word());
var path2 = WebUtility.UrlEncode(faker.Random.Word());
var port = 8080;
var expected = $"https://{host}:{port}/{path1}/{path2}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", $"{path1}///", $"//{path2}");

Assert.Equal(expected, result);
}

[Fact]
public void BuildUrlString_ShouldRemoveDoubleSlashesInUrlPathWithManyForwardSlash()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var path1 = WebUtility.UrlEncode(faker.Random.Word());
var path2 = WebUtility.UrlEncode(faker.Random.Word());
var port = 80;
var expected = $"https://{host}/{path1}/{path2}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", $"{path1}//////////////", $"///////////////{path2}");

Assert.Equal(expected, result);
}

[Fact]
public void BuildUrlString_ShouldExcludeWhenPortIs443()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var path1 = WebUtility.UrlEncode(faker.Random.Word());
var path2 = WebUtility.UrlEncode(faker.Random.Word());
var port = 443;
var expected = $"https://{host}/{path1}/{path2}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", path1, path2);

Assert.Equal(expected, result);
}

[Fact]
public void BuildUrlString_ShouldExcludeWhenPortIs80()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var path1 = WebUtility.UrlEncode(faker.Random.Word());
var path2 = WebUtility.UrlEncode(faker.Random.Word());
var port = 80;
var expected = $"https://{host}/{path1}/{path2}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", path1, path2);

Assert.Equal(expected, result);
}

[Fact]
public void BuildUrlString_ShouldReturnCorrectURLWhenNoOtherUrlPath()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var path1 = WebUtility.UrlEncode(faker.Random.Word());
var port = 80;
var expected = $"https://{host}/{path1}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", path1);

Assert.Equal(expected, result);
}

[Fact]
public void BuildUrlString_ShouldReturnCorrectURLWithQueryParams()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var path1 = WebUtility.UrlEncode(faker.Random.Word());
var path2 = WebUtility.UrlEncode(faker.Random.Word());
var port = 80;
string param1 = WebUtility.UrlEncode($"{faker.Lorem.Word()}={faker.Random.Number(1, 100)}");
string param2 = WebUtility.UrlEncode($"{faker.Lorem.Word()}={faker.Internet.UserName()}");
string param3 = WebUtility.UrlEncode($"{faker.Lorem.Word()}={faker.Random.Bool()}");

var expected = $"https://{host}/{path1}/{path2}?{param1}&{param2}&{param3}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", path1, path2, $"{param1}&{param2}&{param3}");

Assert.Equal(expected, result);
}

[Fact]
public void BuildUrlString_ShouldReturnCorrectURLRandomPaths()
{
var faker = new Faker();
var host = faker.Internet.DomainName();
var basePath = WebUtility.UrlEncode(faker.Random.Word());
var remainingPathCount = faker.Random.Number(1, 5);
var paths = new List<string>();
var port = 80;

string param1 = WebUtility.UrlEncode($"{faker.Lorem.Word()}={faker.Random.Number(1, 100)}");
string param2 = WebUtility.UrlEncode($"{faker.Lorem.Word()}={faker.Internet.UserName()}");
string param3 = WebUtility.UrlEncode($"{faker.Lorem.Word()}={faker.Random.Bool()}");

for (int i = 0; i < remainingPathCount; i++)
{
paths.Add(WebUtility.UrlEncode(faker.Random.Word()));
}

var expected = $"https://{host}/{basePath}/{string.Join("/", paths)}?{param1}&{param2}&{param3}";

var result = XForwardedForHelper.BuildUrlString(host, $"{port}", basePath, string.Join("/", paths), $"{param1}&{param2}&{param3}");

Console.WriteLine(expected);

Assert.Equal(expected, result);
}
}
}
1 change: 1 addition & 0 deletions tests/tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Bogus" Version="35.6.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="Moq" Version="4.14.1" />
<PackageReference Include="xunit" Version="2.4.1" />
Expand Down

0 comments on commit 7b567d6

Please sign in to comment.