diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 69c6cfc1..26264199 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -8005,8 +8005,8 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::ITOOLIMPLEMENTATION::T35170 -- Tool description UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::ITOOLIMPLEMENTATION::T4056470505"] = "Tool description" --- Load a single web page, extract its main HTML content, and return structured working material for the model. Use the result to synthesize a natural-language answer instead of exposing the raw payload to the user. -UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T1823236891"] = "Load a single web page, extract its main HTML content, and return structured working material for the model. Use the result to synthesize a natural-language answer instead of exposing the raw payload to the user." +-- Load a single web page and extract its main HTML content. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T204256540"] = "Load a single web page and extract its main HTML content." -- Optional global truncation limit for extracted Markdown returned to the model. UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2066580916"] = "Optional global truncation limit for extracted Markdown returned to the model." @@ -8014,12 +8014,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS: -- Allowed private hosts must be host names only, without scheme or path. UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2196457612"] = "Allowed private hosts must be host names only, without scheme or path." --- Optional host allowlist for private or VPN web pages. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a High-confidence provider. -UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T237631450"] = "Optional host allowlist for private or VPN web pages. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a High-confidence provider." - -- Maximum Content Characters UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2801581200"] = "Maximum Content Characters" +-- Optional host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, example.com. Allowed private hosts require a high-confidence provider. For allowed internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2866833707"] = "Optional host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, example.com. Allowed private hosts require a high-confidence provider. For allowed internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication." + -- Optional HTTP timeout for loading a web page in seconds. UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2941521561"] = "Optional HTTP timeout for loading a web page in seconds." diff --git a/app/MindWork AI Studio/Plugins/configuration/plugin.lua b/app/MindWork AI Studio/Plugins/configuration/plugin.lua index 18b23fc0..042d4d3d 100644 --- a/app/MindWork AI Studio/Plugins/configuration/plugin.lua +++ b/app/MindWork AI Studio/Plugins/configuration/plugin.lua @@ -272,6 +272,9 @@ CONFIG["SETTINGS"] = {} -- Configure private or VPN hosts that the Read Web Page tool may access. -- Public web pages do not need to be listed here. -- Private hosts listed here still require a provider with HIGH confidence before any page content is sent to the model. +-- For hosts on this allowlist, AI Studio also tries the current user's operating-system sign-in +-- automatically when the server requests integrated authentication (for example Kerberos or NTLM). +-- This does not reuse Firefox cookies or an existing browser session. -- Separate host patterns with commas. Wildcards only match subdomains, so add the root domain separately if needed. -- Examples: -- CONFIG["SETTINGS"]["DataTools.ReadWebPageAllowedPrivateHosts"] = "dlr.de, *.dlr.de" diff --git a/app/MindWork AI Studio/Tools/HTMLParser.cs b/app/MindWork AI Studio/Tools/HTMLParser.cs index c2463750..d7b144de 100644 --- a/app/MindWork AI Studio/Tools/HTMLParser.cs +++ b/app/MindWork AI Studio/Tools/HTMLParser.cs @@ -44,13 +44,22 @@ public sealed class HTMLParser return innerHtml; } - public async Task LoadWebPageAsync(Uri url, CancellationToken token = default, int timeoutSeconds = 30, Func>>? resolveUrlAddressesAsync = null, int maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES) + public async Task LoadWebPageAsync( + Uri url, + CancellationToken token = default, + int timeoutSeconds = 30, + Func>>? resolveUrlAddressesAsync = null, + int maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES, + ExternalWebAuthenticationMode authenticationMode = ExternalWebAuthenticationMode.NONE) { using var handler = new SocketsHttpHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli, AllowAutoRedirect = false, }; + if (authenticationMode is ExternalWebAuthenticationMode.OS_DEFAULT_CREDENTIALS) + handler.Credentials = CreateDefaultCredentialCache(url); + if (resolveUrlAddressesAsync is not null) { // The callback binds the request to a vetted target IP; a proxy would change the endpoint being connected to. @@ -107,6 +116,16 @@ public sealed class HTMLParser throw new HttpRequestException($"The server returned more than {MAX_REDIRECTS} redirects for '{url}'."); } + private static CredentialCache CreateDefaultCredentialCache(Uri url) + { + var credentialCache = new CredentialCache(); + var uriPrefix = new UriBuilder(url.Scheme, url.Host, url.Port).Uri; + credentialCache.Add(uriPrefix, "Negotiate", CredentialCache.DefaultNetworkCredentials); + credentialCache.Add(uriPrefix, "NTLM", CredentialCache.DefaultNetworkCredentials); + credentialCache.Add(uriPrefix, "Kerberos", CredentialCache.DefaultNetworkCredentials); + return credentialCache; + } + private static void ValidateHttpOrHttpsUrl(Uri url) { if (url.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) || @@ -248,3 +267,9 @@ public sealed class HTMLParserWebPage public required HtmlDocument Document { get; init; } } + +public enum ExternalWebAuthenticationMode +{ + NONE, + OS_DEFAULT_CREDENTIALS +} diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs index dde886bf..590fecee 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/ReadWebPageTool.cs @@ -57,7 +57,7 @@ public sealed class ReadWebPageTool(HTMLParser htmlParser, ILogger TB("Optional HTTP timeout for loading a web page in seconds."), "maxContentCharacters" => TB("Optional global truncation limit for extracted Markdown returned to the model."), - ALLOWED_PRIVATE_HOSTS_SETTING => TB("Optional host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, example.com. Allowed private hosts require a high-confidence provider."), + ALLOWED_PRIVATE_HOSTS_SETTING => TB("Optional host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a high-confidence provider. For allowed internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication."), _ => TB(fieldDefinition.Description), }; @@ -113,6 +113,7 @@ public sealed class ReadWebPageTool(HTMLParser htmlParser, ILogger await this.ResolveValidatedUrlAddressesAsync(candidateUrl, allowedPrivateHosts, context.ProviderConfidence, validationToken), - MAX_RESPONSE_BYTES); + MAX_RESPONSE_BYTES, + shouldTryOsSso ? ExternalWebAuthenticationMode.OS_DEFAULT_CREDENTIALS : ExternalWebAuthenticationMode.NONE); } catch (OperationCanceledException) when (!token.IsCancellationRequested) { @@ -133,6 +135,13 @@ public sealed class ReadWebPageTool(HTMLParser htmlParser, ILogger pattern.IsMatch(normalizedHost)); } + private static bool ShouldTryOsSso( + Uri url, + IReadOnlyList allowedPrivateHosts, + ConfidenceLevel providerConfidence) => + providerConfidence >= ConfidenceLevel.HIGH && + !IsBlockedHostName(url.Host) && + IsAllowedPrivateHost(url.Host, allowedPrivateHosts); + private static string NormalizeHost(string host) => host.Trim().TrimEnd('.').ToLowerInvariant(); private static bool IsNeverAllowedAddress(IPAddress address)