Browse Source

Merge pull request #20628 from abpframework/UriHelpers

Support wildcard domain in `AppUrlProvider `.
pull/20648/head
Engincan VESKE 2 years ago
committed by GitHub
parent
commit
3f020e8d69
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 28
      framework/src/Volo.Abp.Core/Volo/Abp/Http/UrlHelpers.cs
  2. 4
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs
  3. 43
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/Http/UrlHelpers_Tests.cs
  4. 11
      framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AppUrlProvider_Tests.cs

28
framework/src/Volo.Abp.Core/Volo/Abp/Http/UrlHelpers.cs

@ -0,0 +1,28 @@
using System;
namespace Volo.Abp.Http;
public static class UrlHelpers
{
private const string WildcardSubdomain = "*.";
public static bool IsSubdomainOf(string subdomain, string domain)
{
if (Uri.TryCreate(subdomain, UriKind.Absolute, out var subdomainUri) &&
Uri.TryCreate(domain.Replace(WildcardSubdomain, string.Empty), UriKind.Absolute, out var domainUri))
{
return domainUri == subdomainUri || IsSubdomainOf(subdomainUri, domainUri);
}
return false;
}
public static bool IsSubdomainOf(Uri subdomain, Uri domain)
{
return subdomain.IsAbsoluteUri
&& domain.IsAbsoluteUri
&& subdomain.Scheme == domain.Scheme
&& subdomain.Port == domain.Port
&& subdomain.Host.EndsWith($".{domain.Host}", StringComparison.Ordinal);
}
}

4
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs

@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.UI.Navigation.Urls;
@ -43,7 +44,8 @@ public class AppUrlProvider : IAppUrlProvider, ITransientDependency
{
redirectAllowedUrls.Add((await NormalizeUrlAsync(redirectAllowedUrl))!);
}
var allow = redirectAllowedUrls.Any(x => url.StartsWith(x, StringComparison.CurrentCultureIgnoreCase));
var allow = redirectAllowedUrls.Any(x => url.StartsWith(x, StringComparison.CurrentCultureIgnoreCase) ||
UrlHelpers.IsSubdomainOf(url, x));
if (!allow)
{
Logger.LogError($"Invalid RedirectUrl: {url}, Use {nameof(AppUrlProvider)} to configure it!");

43
framework/test/Volo.Abp.Core.Tests/Volo/Abp/Http/UrlHelpers_Tests.cs

@ -0,0 +1,43 @@
using Shouldly;
using Xunit;
namespace Volo.Abp.Http;
public class UrlHelpers_Tests
{
[Theory]
[InlineData(null)]
[InlineData("null")]
[InlineData("http://")]
[InlineData("http://*")]
[InlineData("http://.domain")]
[InlineData("http://.domain/hello")]
public void IsSubdomainOf_ReturnsFalseIfDomainIsMalformedUri(string domain)
{
var actual = UrlHelpers.IsSubdomainOf("http://*.domain", domain);
actual.ShouldBeFalse();
}
[Theory]
[InlineData("http://sub.domain", "http://domain")]
[InlineData("http://sub.domain", "http://*.domain")]
[InlineData("http://sub.sub.domain", "http://*.domain")]
[InlineData("http://sub.sub.domain", "http://*.sub.domain")]
[InlineData("http://sub.domain:4567", "http://*.domain:4567")]
public void IsSubdomainOf_ReturnsTrue_WhenASubdomain(string subdomain, string domain)
{
var actual = UrlHelpers.IsSubdomainOf(subdomain, domain);
actual.ShouldBeTrue();
}
[Theory]
[InlineData("http://sub.domain:1234", "http://*.domain:5678")]
[InlineData("http://sub.domain", "http://domain.*")]
[InlineData("http://sub.domain.hacker", "http://*.domain")]
[InlineData("https://sub.domain", "http://*.domain")]
public void IsSubdomainOf_ReturnsFalse_WhenNotASubdomain(string subdomain, string domain)
{
var actual = UrlHelpers.IsSubdomainOf(subdomain, domain);
actual.ShouldBeFalse();
}
}

11
framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AppUrlProvider_Tests.cs

@ -40,7 +40,8 @@ public class AppUrlProvider_Tests : AbpIntegratedTest<AbpUiNavigationTestModule>
"https://wwww.volosoft.com",
"https://wwww.aspnetzero.com",
"https://{{tenantName}}.abp.io",
"https://{{tenantId}}.abp.io"
"https://{{tenantId}}.abp.io",
"https://*.demo.myabp.io"
});
options.Applications["BLAZOR"].RootUrl = "https://{{tenantId}}.abp.io";
@ -101,12 +102,16 @@ public class AppUrlProvider_Tests : AbpIntegratedTest<AbpUiNavigationTestModule>
[Fact]
public async Task IsRedirectAllowedUrlAsync()
{
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://community.abp.io")).ShouldBeFalse();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://wwww.volosoft.com")).ShouldBeTrue();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://wwww.demo.myabp.io")).ShouldBeTrue();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://demo.myabp.io")).ShouldBeTrue();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://api.demo.myabp.io")).ShouldBeTrue();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://test.api.demo.myabp.io")).ShouldBeTrue();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://volosoft.com/demo.myabp.io")).ShouldBeFalse();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://wwww.myabp.io")).ShouldBeFalse();
using (_currentTenant.Change(null))
{
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://www.abp.io")).ShouldBeFalse();
(await _appUrlProvider.IsRedirectAllowedUrlAsync("https://abp.io")).ShouldBeTrue();
}

Loading…
Cancel
Save