Skip to content

Commit ef3ee8f

Browse files
artembilanspring-builds
authored andcommitted
GH-9711: Avoid double URL encoding in SmbShare
Fixes: #9711 Issue link: #9711 The `SmbConfig.getUrl(_includePassword)` uses `URI.toASCIIString()` which has all the parts of the URI encoded. Then this string is used by the `SmbShare` for its super constructor, which, in turn, calls `new URL()` leading, essentially, to a second encoding round. * Add `SmbConfig.rawUrl()` methods to return an `smb://` url as a plain string. * Use this new API in the `SmbShare` for a delegation constructor * Modify some tests to reflect and cover new behavior (cherry picked from commit 5e3d8d8)
1 parent 04845b0 commit ef3ee8f

File tree

7 files changed

+92
-65
lines changed

7 files changed

+92
-65
lines changed

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

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -25,7 +25,7 @@
2525
import org.springframework.util.StringUtils;
2626

2727
/**
28-
* Data holder class for a SMB share configuration.
28+
* Data holder class for an SMB share configuration.
2929
*<p>
3030
* SmbFile URLs syntax:
3131
* smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]]
@@ -197,22 +197,50 @@ public final String getUrl() {
197197
}
198198

199199
public final String getUrl(boolean _includePassword) {
200-
String domainUserPass = getDomainUserPass(_includePassword);
200+
return createUri(_includePassword).toASCIIString();
201+
}
201202

202-
String path = StringUtils.cleanPath(this.shareAndDir);
203+
/**
204+
* Return the url string for the share connection without encoding.
205+
* Used in the {@link SmbShare} constructor delegation.
206+
* @return the url string for the share connection without encoding.
207+
* @since 6.3.8
208+
*/
209+
public final String rawUrl() {
210+
return rawUrl(true);
211+
}
203212

204-
if (!path.startsWith("/")) {
205-
path = "/" + path;
206-
}
213+
/**
214+
* Return the url string for the share connection without encoding.
215+
* Used in the {@link SmbShare} constructor delegation.
216+
* @param _includePassword whether password has to be masked in credentials of URL.
217+
* @return the url string for the share connection without encoding.
218+
* @since 6.3.8
219+
*/
220+
public final String rawUrl(boolean _includePassword) {
221+
String domainUserPass = getDomainUserPass(_includePassword);
222+
String path = cleanPath();
223+
return "smb://%s@%s%s".formatted(domainUserPass, getHostPort(), path);
224+
}
207225

226+
private URI createUri(boolean _includePassword) {
227+
String domainUserPass = getDomainUserPass(_includePassword);
228+
String path = cleanPath();
208229
try {
209-
return new URI("smb", domainUserPass, this.host, this.port, path, null, null)
210-
.toASCIIString();
230+
return new URI("smb", domainUserPass, this.host, this.port, path, null, null);
211231
}
212232
catch (URISyntaxException e) {
213233
throw new IllegalArgumentException(e);
214234
}
235+
}
215236

237+
private String cleanPath() {
238+
String path = StringUtils.cleanPath(this.shareAndDir);
239+
240+
if (!path.startsWith("/")) {
241+
path = "/" + path;
242+
}
243+
return path;
216244
}
217245

218246
@Override

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class SmbShare extends SmbFile {
6363
* @throws IOException if an invalid SMB URL was constructed by jCIFS
6464
*/
6565
public SmbShare(SmbConfig _smbConfig) throws IOException {
66-
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
66+
super(StringUtils.cleanPath(_smbConfig.validate().rawUrl()),
6767
SingletonContext.getInstance().withCredentials(
6868
new NtlmPasswordAuthenticator(
6969
_smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword())));
@@ -76,7 +76,7 @@ public SmbShare(SmbConfig _smbConfig) throws IOException {
7676
* @throws IOException if an invalid SMB URL was constructed by jCIFS
7777
*/
7878
public SmbShare(SmbConfig _smbConfig, CIFSContext _context) throws IOException {
79-
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()), _context);
79+
super(StringUtils.cleanPath(_smbConfig.validate().rawUrl()), _context);
8080
}
8181

8282
/**
@@ -88,7 +88,7 @@ public SmbShare(SmbConfig _smbConfig, CIFSContext _context) throws IOException {
8888
* @throws IOException if an invalid property was set or an invalid SMB URL was constructed by jCIFS
8989
*/
9090
public SmbShare(SmbConfig _smbConfig, Properties _props) throws IOException {
91-
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
91+
super(StringUtils.cleanPath(_smbConfig.validate().rawUrl()),
9292
new BaseContext(
9393
new PropertyConfiguration(_props)).withCredentials(
9494
new NtlmPasswordAuthenticator(

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

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xmlns:int="http://www.springframework.org/schema/integration"
5-
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
6-
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:int="http://www.springframework.org/schema/integration"
5+
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
6+
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
77
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
88
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
99

1010
<int:message-history/>
1111

1212
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
13-
<property name="host" value="localhost"/>
14-
<property name="port" value="0"/>
15-
<property name="domain" value=""/>
16-
<property name="username" value="sambagu@est"/>
17-
<property name="password" value="sambag%uest"/>
18-
<property name="shareAndDir" value="smb-share/"/>
13+
<property name="host" value="localhost"/>
14+
<property name="port" value="0"/>
15+
<property name="domain" value=""/>
16+
<property name="username" value="sambagu@est"/>
17+
<property name="password" value="sambag%uest"/>
18+
<property name="shareAndDir" value="smb share/"/>
1919
</bean>
2020

2121
<int-smb:inbound-channel-adapter id="smbInboundChannelAdapter"
22-
session-factory="smbSessionFactory"
23-
channel="smbInboundChannel"
24-
auto-create-local-directory="true"
25-
local-directory="file:test-temp/local-5"
26-
remote-directory="test-temp/remote-9"
27-
delete-remote-files="false">
22+
session-factory="smbSessionFactory"
23+
channel="smbInboundChannel"
24+
auto-create-local-directory="true"
25+
local-directory="file:test-temp/local-5"
26+
remote-directory="test-temp/remote-9"
27+
auto-startup="false"
28+
delete-remote-files="false">
2829
<int:poller fixed-rate="1000"/>
2930
</int-smb:inbound-channel-adapter>
3031

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -47,8 +47,10 @@ public void testMessageHistory() throws URISyntaxException {
4747

4848
String url = smbSessionFactory.getUrl();
4949
URI uri = new URI(url);
50-
assertThat("sambagu%40est:sambag%25uest").isEqualTo(uri.getRawUserInfo());
51-
assertThat("sambagu@est:sambag%uest").isEqualTo(uri.getUserInfo());
50+
assertThat(uri.getRawUserInfo()).isEqualTo("sambagu%40est:sambag%25uest");
51+
assertThat(uri.getUserInfo()).isEqualTo("sambagu@est:sambag%uest");
52+
assertThat(uri.getPath()).isEqualTo("/smb share/");
53+
assertThat(uri.getRawPath()).isEqualTo("/smb%20share/");
5254
}
5355
}
5456

spring-integration-smb/src/test/java/org/springframework/integration/smb/SmbParserInboundTests-context.xml

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,49 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xmlns:int="http://www.springframework.org/schema/integration"
5-
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
6-
xmlns:context="http://www.springframework.org/schema/context"
7-
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:int="http://www.springframework.org/schema/integration"
5+
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
6+
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
87
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
98
http://www.springframework.org/schema/integration/smb https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd">
109

1110
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
12-
<property name="host" value="localhost"/>
13-
<property name="domain" value=""/>
14-
<property name="username" value="sambaguest"/>
15-
<property name="password" value="sambaguest"/>
11+
<property name="host" value="localhost"/>
12+
<property name="domain" value=""/>
13+
<property name="username" value="sambaguest"/>
14+
<property name="password" value="sambaguest"/>
1615
<property name="shareAndDir" value="smb-share/"/>
1716
</bean>
1817

1918
<int-smb:inbound-channel-adapter id="adapterSmb"
20-
session-factory="smbSessionFactory"
21-
channel="smbIn"
22-
filename-pattern="foo"
23-
local-directory="test-temp/local-10"
24-
remote-directory="test-temp/remote-10"
25-
auto-create-local-directory="true"
26-
delete-remote-files="false">
27-
<int:poller ref="smbPoller" />
19+
session-factory="smbSessionFactory"
20+
channel="smbIn"
21+
filename-pattern="foo"
22+
local-directory="test-temp/local-10"
23+
remote-directory="test-temp/remote-10"
24+
auto-create-local-directory="true"
25+
auto-startup="false"
26+
delete-remote-files="false">
27+
<int:poller ref="smbPoller"/>
2828
</int-smb:inbound-channel-adapter>
2929

3030
<int-smb:inbound-channel-adapter id="adapterSmb2"
31-
session-factory="smbSessionFactory"
32-
channel="smbIn"
33-
filter="filter"
34-
local-directory="test-temp"
35-
remote-directory="test-temp/remote-11"
36-
auto-create-local-directory="true"
37-
delete-remote-files="false">
38-
<int:poller ref="smbPoller" />
31+
session-factory="smbSessionFactory"
32+
channel="smbIn"
33+
filter="filter"
34+
local-directory="test-temp"
35+
remote-directory="test-temp/remote-11"
36+
auto-create-local-directory="true"
37+
auto-startup="false"
38+
delete-remote-files="false">
39+
<int:poller ref="smbPoller"/>
3940
</int-smb:inbound-channel-adapter>
4041

4142
<bean id="filter" class="org.mockito.Mockito" factory-method="mock">
42-
<constructor-arg value="org.springframework.integration.file.filters.FileListFilter" type="java.lang.Class"/>
43+
<constructor-arg value="org.springframework.integration.file.filters.FileListFilter" type="java.lang.Class"/>
4344
</bean>
4445

45-
<int:poller fixed-rate="3000" id="smbPoller" />
46+
<int:poller fixed-rate="3000" id="smbPoller"/>
4647

4748
<int:channel id="smbIn">
4849
<int:queue/>

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,4 @@ public void cleanUp() {
6060
delete("test-temp/local-10", "test-temp/local-6");
6161
}
6262

63-
public static void main(String[] _args) throws Exception {
64-
new SmbParserInboundTests().cleanUp();
65-
runTests(SmbParserInboundTests.class, "testLocalFilesAutoCreationTrue", "testLocalFilesAutoCreationFalse");
66-
}
67-
6863
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public class SmbTestSupport extends RemoteFileTestSupport {
6868

6969
public static final String HOST = "127.0.0.1";
7070

71-
public static final String SHARE_AND_DIR = "smb-share";
71+
public static final String SHARE_AND_DIR = "smb share";
7272

7373
public static final String USERNAME = "sambaguest";
7474

@@ -110,7 +110,7 @@ public static void connectToSMBServer() throws IOException {
110110
}
111111

112112
public static String smbServerUrl() {
113-
return smbSessionFactory.getUrl().replaceFirst('/' + SHARE_AND_DIR + '/', "");
113+
return smbSessionFactory.rawUrl().replaceFirst('/' + SHARE_AND_DIR + '/', "");
114114
}
115115

116116
public static SessionFactory<SmbFile> sessionFactory() {

0 commit comments

Comments
 (0)