diff --git a/src/shared/Core.Tests/Interop/Windows/WindowsCredentialManagerTests.cs b/src/shared/Core.Tests/Interop/Windows/WindowsCredentialManagerTests.cs index 78295276e..b7b5cef62 100644 --- a/src/shared/Core.Tests/Interop/Windows/WindowsCredentialManagerTests.cs +++ b/src/shared/Core.Tests/Interop/Windows/WindowsCredentialManagerTests.cs @@ -270,6 +270,70 @@ public void WindowsCredentialManager_IsMatch( Assert.Equal(expected, actual); } + [PlatformFact(Platforms.Windows)] + public void WindowsCredentialManager_IsMatch_NoNamespace_NotMatched() + { + var win32Cred = new Win32Credential + { + UserName = "test", + TargetName = $"{WindowsCredentialManager.TargetNameLegacyGenericPrefix}https://example.com" + }; + + var credManager = new WindowsCredentialManager(TestNamespace); + + bool result = credManager.IsMatch("https://example.com", null, win32Cred); + + Assert.False(result); + } + + [PlatformFact(Platforms.Windows)] + public void WindowsCredentialManager_IsMatch_DifferentNamespace_NotMatched() + { + var win32Cred = new Win32Credential + { + UserName = "test", + TargetName = $"{WindowsCredentialManager.TargetNameLegacyGenericPrefix}:random-namespace:https://example.com" + }; + + var credManager = new WindowsCredentialManager(TestNamespace); + + bool result = credManager.IsMatch("https://example.com", null, win32Cred); + + Assert.False(result); + } + + [PlatformFact(Platforms.Windows)] + public void WindowsCredentialManager_IsMatch_CaseSensitiveNamespace_NotMatched() + { + var win32Cred = new Win32Credential + { + UserName = "test", + TargetName = $"{WindowsCredentialManager.TargetNameLegacyGenericPrefix}:nAmEsPaCe:https://example.com" + }; + + var credManager = new WindowsCredentialManager("namespace"); + + bool result = credManager.IsMatch("https://example.com", null, win32Cred); + + Assert.False(result); + } + + [PlatformFact(Platforms.Windows)] + public void WindowsCredentialManager_IsMatch_NoNamespaceInQuery_IsMatched() + { + var win32Cred = new Win32Credential + { + UserName = "test", + TargetName = $"{WindowsCredentialManager.TargetNameLegacyGenericPrefix}https://example.com" + }; + + var credManager = new WindowsCredentialManager(); + + bool result = credManager.IsMatch("https://example.com", null, win32Cred); + + Assert.True(result); + } + [PlatformTheory(Platforms.Windows)] [InlineData("https://example.com", null, "https://example.com")] [InlineData("https://example.com", "bob", "https://bob@example.com")] diff --git a/src/shared/Core/Interop/Windows/WindowsCredentialManager.cs b/src/shared/Core/Interop/Windows/WindowsCredentialManager.cs index 5fa366e8a..63e9c9560 100644 --- a/src/shared/Core/Interop/Windows/WindowsCredentialManager.cs +++ b/src/shared/Core/Interop/Windows/WindowsCredentialManager.cs @@ -274,11 +274,19 @@ private WindowsCredential CreateCredentialFromStructure(Win32Credential credenti return false; } - // Trim the "LegacyGeneric" prefix Windows adds and any namespace we have been filtered with + // Trim the "LegacyGeneric" prefix Windows adds string targetName = credential.TargetName.TrimUntilIndexOf(TargetNameLegacyGenericPrefix); + + // Only match credentials with the namespace we have been configured with (if any) if (!string.IsNullOrWhiteSpace(_namespace)) { - targetName = targetName.TrimUntilIndexOf($"{_namespace}:"); + string nsPrefix = $"{_namespace}:"; + if (!targetName.StartsWith(nsPrefix, StringComparison.Ordinal)) + { + return false; + } + + targetName = targetName.Substring(nsPrefix.Length); } // If the target name matches the service name exactly then return 'match'