diff --git a/src/Api/Models/Request/TwoFactorRequestModels.cs b/src/Api/Models/Request/TwoFactorRequestModels.cs index 846a76c89..0642d62ea 100644 --- a/src/Api/Models/Request/TwoFactorRequestModels.cs +++ b/src/Api/Models/Request/TwoFactorRequestModels.cs @@ -105,7 +105,7 @@ namespace Bit.Api.Models.Request public IEnumerable Validate(ValidationContext validationContext) { - if (!Host.StartsWith("api-") || (!Host.EndsWith(".duosecurity.com") && !Host.EndsWith(".duofederal.com"))) + if (!Core.Utilities.Duo.DuoApi.ValidHost(Host)) { yield return new ValidationResult("Host is invalid.", new string[] { nameof(Host) }); } diff --git a/src/Core/Utilities/DuoApi.cs b/src/Core/Utilities/DuoApi.cs index 0aa906f8b..8c35578c6 100644 --- a/src/Core/Utilities/DuoApi.cs +++ b/src/Core/Utilities/DuoApi.cs @@ -35,6 +35,21 @@ namespace Bit.Core.Utilities.Duo _ikey = ikey; _skey = skey; _host = host; + + if (!ValidHost(host)) + { + throw new DuoException("Invalid Duo host configured.", new ArgumentException(nameof(host))); + } + } + + public static bool ValidHost(string host) + { + if (Uri.TryCreate($"https://{host}", UriKind.Absolute, out var uri)) + { + return uri.Host.StartsWith("api-") && + (uri.Host.EndsWith(".duosecurity.com") || uri.Host.EndsWith(".duofederal.com")); + } + return false; } public static string CanonicalizeParams(Dictionary parameters) @@ -246,6 +261,10 @@ namespace Bit.Core.Utilities.Duo { public int HttpStatus { get; private set; } + public DuoException(string message, Exception inner) + : base(message, inner) + { } + public DuoException(int httpStatus, string message, Exception inner) : base(message, inner) {