Skip to content

Commit 624e3fb

Browse files
committed
spring-projectsGH-9794: Allow usage of '@' in SMB domain, username and password
Fixes: spring-projects#9794 The `SmbConfig.rawUrl()` method doesn't apply any URL encoding, resulting in parts of the `domainUserPass` that may contain a `@` character to break the URL logic in regard to determining the hostname. * Modify `SmbConfig.getDomainUserPass(_includePassword)` to conditionally encode the variables. Makes sure to encode the individual parts to not undesirably encode the `;` and `:` characters, breaking other logic. * Modify `SmbConfig.rawUrl(_includePassword)` and `SmbConfig.createUri(_includePassword)` to call the modified method with the correct `_urlEncode` variable Signed-off-by: Jelle Smits <[email protected]>
1 parent 69aaa1d commit 624e3fb

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbConfig.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
1818

1919
import java.net.URI;
2020
import java.net.URISyntaxException;
21+
import java.net.URLEncoder;
22+
import java.nio.charset.StandardCharsets;
2123

2224
import jcifs.DialectVersion;
2325

@@ -163,16 +165,19 @@ public void setSmbMaxVersion(DialectVersion _smbMaxVersion) {
163165
this.smbMaxVersion = _smbMaxVersion;
164166
}
165167

166-
String getDomainUserPass(boolean _includePassword) {
168+
String getDomainUserPass(boolean _includePassword, boolean _urlEncode) {
167169
String domainUserPass;
170+
String username = _urlEncode ? URLEncoder.encode(this.username, StandardCharsets.UTF_8) : this.username;
171+
String password = _urlEncode ? URLEncoder.encode(this.password, StandardCharsets.UTF_8) : this.password;
168172
if (StringUtils.hasText(this.domain)) {
169-
domainUserPass = String.format("%s;%s", this.domain, this.username);
173+
String domain = _urlEncode ? URLEncoder.encode(this.domain, StandardCharsets.UTF_8) : this.domain;
174+
domainUserPass = String.format("%s;%s", domain, username);
170175
}
171176
else {
172-
domainUserPass = this.username;
177+
domainUserPass = username;
173178
}
174-
if (StringUtils.hasText(this.password)) {
175-
domainUserPass += ":" + (_includePassword ? this.password : "********");
179+
if (StringUtils.hasText(password)) {
180+
domainUserPass += ":" + (_includePassword ? password : "********");
176181
}
177182
return domainUserPass;
178183
}
@@ -211,20 +216,24 @@ public final String rawUrl() {
211216
}
212217

213218
/**
214-
* Return the url string for the share connection without encoding.
219+
* Return the url string for the share connection without encoding
220+
* the host and path. The {@code domainUserPass} is encoded, as
221+
* {@link java.net.URL} identifies the host part by looking
222+
* for the first {@code @} character, which fails if the
223+
* domain, username or password contains that character.
215224
* Used in the {@link SmbShare} constructor delegation.
216225
* @param _includePassword whether password has to be masked in credentials of URL.
217226
* @return the url string for the share connection without encoding.
218227
* @since 6.3.8
219228
*/
220229
public final String rawUrl(boolean _includePassword) {
221-
String domainUserPass = getDomainUserPass(_includePassword);
230+
String domainUserPass = getDomainUserPass(_includePassword, true);
222231
String path = cleanPath();
223232
return "smb://%s@%s%s".formatted(domainUserPass, getHostPort(), path);
224233
}
225234

226235
private URI createUri(boolean _includePassword) {
227-
String domainUserPass = getDomainUserPass(_includePassword);
236+
String domainUserPass = getDomainUserPass(_includePassword, false);
228237
String path = cleanPath();
229238
try {
230239
return new URI("smb", domainUserPass, this.host, this.port, path, null, null);

spring-integration-smb/src/test/java/org/springframework/integration/smb/SmbMessageHistoryTests.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,16 @@
1616

1717
package org.springframework.integration.smb;
1818

19+
import java.net.MalformedURLException;
1920
import java.net.URI;
2021
import java.net.URISyntaxException;
22+
import java.net.URL;
23+
import java.util.Properties;
2124

25+
import jcifs.CIFSContext;
26+
import jcifs.CIFSException;
27+
import jcifs.config.PropertyConfiguration;
28+
import jcifs.context.BaseContext;
2229
import org.junit.jupiter.api.Test;
2330

2431
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -36,7 +43,7 @@
3643
public class SmbMessageHistoryTests extends AbstractBaseTests {
3744

3845
@Test
39-
public void testMessageHistory() throws URISyntaxException {
46+
public void testMessageHistory() throws URISyntaxException, MalformedURLException, CIFSException {
4047
try (ClassPathXmlApplicationContext applicationContext = getApplicationContext()) {
4148
SourcePollingChannelAdapter adapter = applicationContext
4249
.getBean("smbInboundChannelAdapter", SourcePollingChannelAdapter.class);
@@ -51,6 +58,12 @@ public void testMessageHistory() throws URISyntaxException {
5158
assertThat(uri.getUserInfo()).isEqualTo("sambagu@est:sambag%uest");
5259
assertThat(uri.getPath()).isEqualTo("/smb share/");
5360
assertThat(uri.getRawPath()).isEqualTo("/smb%20share/");
61+
62+
CIFSContext context = new BaseContext(new PropertyConfiguration(new Properties()));
63+
URL rawUrl = new URL(null, smbSessionFactory.rawUrl(true), context.getUrlHandler());
64+
assertThat(rawUrl.getHost()).isEqualTo("localhost");
65+
assertThat(rawUrl.getUserInfo()).isEqualTo("sambagu%40est:sambag%25uest");
66+
assertThat(rawUrl.getPath()).isEqualTo("/smb share/");
5467
}
5568
}
5669

0 commit comments

Comments
 (0)