Browse Source
Apply SsrfProtectionValidator.validateUri() to AI providers with user-supplied URLs (OpenAI baseUrl, Azure OpenAI endpoint, Ollama baseUrl). Validation at two layers: - execution time in Langchain4jChatModelConfigurerImpl - save time in AiModelDataValidator Controlled by the existing SSRF_PROTECTION_ENABLED flag.pull/15412/head
4 changed files with 170 additions and 0 deletions
@ -0,0 +1,103 @@ |
|||
/** |
|||
* Copyright © 2016-2026 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.ai; |
|||
|
|||
import org.junit.jupiter.api.AfterEach; |
|||
import org.junit.jupiter.api.BeforeEach; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.junit.jupiter.api.parallel.ResourceLock; |
|||
import org.thingsboard.common.util.SsrfProtectionValidator; |
|||
import org.thingsboard.server.common.data.ai.model.chat.AzureOpenAiChatModelConfig; |
|||
import org.thingsboard.server.common.data.ai.model.chat.OllamaChatModelConfig; |
|||
import org.thingsboard.server.common.data.ai.model.chat.OpenAiChatModelConfig; |
|||
import org.thingsboard.server.common.data.ai.provider.AzureOpenAiProviderConfig; |
|||
import org.thingsboard.server.common.data.ai.provider.OllamaProviderConfig; |
|||
import org.thingsboard.server.common.data.ai.provider.OpenAiProviderConfig; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
|||
|
|||
@ResourceLock("SsrfProtectionValidator") |
|||
class Langchain4jChatModelConfigurerImplTest { |
|||
|
|||
private final Langchain4jChatModelConfigurerImpl configurer = new Langchain4jChatModelConfigurerImpl(); |
|||
|
|||
@BeforeEach |
|||
void enableSsrfProtection() { |
|||
SsrfProtectionValidator.setEnabled(true); |
|||
} |
|||
|
|||
@AfterEach |
|||
void disableSsrfProtection() { |
|||
SsrfProtectionValidator.setEnabled(false); |
|||
} |
|||
|
|||
@Test |
|||
void configureChatModel_openAi_withPrivateIp_shouldThrow() { |
|||
var config = OpenAiChatModelConfig.builder() |
|||
.providerConfig(OpenAiProviderConfig.builder() |
|||
.baseUrl("http://172.17.0.1:8080/") |
|||
.apiKey("test") |
|||
.build()) |
|||
.modelId("gpt-4o") |
|||
.build(); |
|||
|
|||
assertThatThrownBy(() -> configurer.configureChatModel(config)) |
|||
.isInstanceOf(RuntimeException.class) |
|||
.hasMessageContaining("URI is invalid"); |
|||
} |
|||
|
|||
@Test |
|||
void configureChatModel_openAi_withLocalhostUrl_shouldThrow() { |
|||
var config = OpenAiChatModelConfig.builder() |
|||
.providerConfig(OpenAiProviderConfig.builder() |
|||
.baseUrl("http://localhost:22/") |
|||
.apiKey("test") |
|||
.build()) |
|||
.modelId("gpt-4o") |
|||
.build(); |
|||
|
|||
assertThatThrownBy(() -> configurer.configureChatModel(config)) |
|||
.isInstanceOf(RuntimeException.class) |
|||
.hasMessageContaining("URI is invalid"); |
|||
} |
|||
|
|||
@Test |
|||
void configureChatModel_azureOpenAi_withPrivateIp_shouldThrow() { |
|||
var config = AzureOpenAiChatModelConfig.builder() |
|||
.providerConfig(new AzureOpenAiProviderConfig( |
|||
"http://10.0.0.1:8080/", null, "test-key")) |
|||
.modelId("gpt-4o") |
|||
.build(); |
|||
|
|||
assertThatThrownBy(() -> configurer.configureChatModel(config)) |
|||
.isInstanceOf(RuntimeException.class) |
|||
.hasMessageContaining("URI is invalid"); |
|||
} |
|||
|
|||
@Test |
|||
void configureChatModel_ollama_withPrivateIp_shouldThrow() { |
|||
var config = OllamaChatModelConfig.builder() |
|||
.providerConfig(new OllamaProviderConfig( |
|||
"http://192.168.1.100:11434/", new OllamaProviderConfig.OllamaAuth.None())) |
|||
.modelId("llama3") |
|||
.build(); |
|||
|
|||
assertThatThrownBy(() -> configurer.configureChatModel(config)) |
|||
.isInstanceOf(RuntimeException.class) |
|||
.hasMessageContaining("URI is invalid"); |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue