From 376a34c03128c013ae063a0b1a3eae51fa3e176d Mon Sep 17 00:00:00 2001 From: Gregory Bragg Date: Mon, 8 Apr 2019 09:15:56 -0400 Subject: [PATCH] GH-206: jCIFS to the latest version for SMB2/3 Fixes https://github.com/spring-projects/spring-integration-extensions/issues/206 Updated test to better reflect reality, getCanonicalPath() -> getPath() Updated readme doc with more information, guidance Updated to address deprecated constructor in jCIFS library * Polishing code, versions, checkstyle, Copyrights year * Add `@author` to affected classes --- spring-integration-smb/README.md | 53 ++++++++++- spring-integration-smb/build.gradle | 12 +-- spring-integration-smb/gradle.properties | 2 +- .../checkstyle/checkstyle-suppressions.xml | 5 +- .../src/checkstyle/checkstyle.xml | 5 +- .../integration/smb/session/SmbSession.java | 35 +------- .../integration/smb/session/SmbShare.java | 16 +++- .../smb/session/SmbSessionTests.java | 88 +++++++++++++------ 8 files changed, 140 insertions(+), 76 deletions(-) diff --git a/spring-integration-smb/README.md b/spring-integration-smb/README.md index b3586a3..a72568c 100644 --- a/spring-integration-smb/README.md +++ b/spring-integration-smb/README.md @@ -1,4 +1,4 @@ -Spring Integration Smb Support +Spring Integration SMB Support ============================== ## Introduction @@ -7,3 +7,54 @@ This module add Spring Integration support for [Server Message Block][] (SMB). [Server Message Block]: https://en.wikipedia.org/wiki/Server_Message_Block +## Version + +[Versions in Maven Repository](http://central.maven.org/maven2/org/springframework/integration/spring-integration-smb/) + +## Using Maven + +Put the following block into pom.xml if using Maven: + + + org.springframework.integration + spring-integration-smb + 1.0.0.RELEASE + + +## Changes + + * Updated to use the latest version of the [JCIFS](https://github.com/codelibs/jcifs) library + * SMB2 (2.02 protocol level) support, some SMB3 support + +## Overview + +The Java CIFS Client Library has been chosen as a Java implementation for the CIFS/SMB networking protocol. +Its `SmbFile` abstraction is simply wrapped to the Spring Integration "Remote File" foundations like `SmbSession`, `SmbRemoteFileTemplate`, etc. + +The SMB Channel Adapters and support classes implementations are fully similar to existing components for (S)FTP or AWS S3 protocols. +So, if you familiar with those components, it is pretty straightforward to use this extension. But any way here are several words about existing components: + +### SMB Inbound Channel Adapter + +To download SMB files locally the `SmbInboundFileSynchronizingMessageSource` is provided. +It is simple extension of the `AbstractInboundFileSynchronizingMessageSource` which requires `SmbInboundFileSynchronizer` injection. +For filtering remote files you still can use any existing `FileListFilter` implementations, but particular `SmbRegexPatternFileListFilter` and `SmbSimplePatternFileListFilter` are provided. +For XML configuration the `` component is provided. + +### SMB Outbound Channel Adapter + +There is no (yet) some SMB specific requirements for files transferring to SMB, so for XML `` component we simply reuse an existing `FileTransferringMessageHandler`. +In case of Java configuration that `FileTransferringMessageHandler` should be supplied with the `SmbSessionFactory` (or `SmbRemoteFileTemplate`). + + @ServiceActivator(inputChannel = "storeToSmb") + @Bean + public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) { + FileTransferringMessageHandler handler = + new FileTransferringMessageHandler<>(smbSessionFactory); + handler.setRemoteDirectoryExpression( + new LiteralExpression("remote-target-dir")); + handler.setFileNameGenerator(m -> + m.getHeaders().get(FileHeaders.FILENAME, String.class) + ".test"); + handler.setAutoCreateDirectory(true); + return handler; + } diff --git a/spring-integration-smb/build.gradle b/spring-integration-smb/build.gradle index 8a75f78..76df3a1 100644 --- a/spring-integration-smb/build.gradle +++ b/spring-integration-smb/build.gradle @@ -15,7 +15,7 @@ plugins { id 'idea' id 'jacoco' id 'checkstyle' - id 'org.sonarqube' version '2.6.2' + id 'org.sonarqube' version '2.7' } description = 'Spring Integration SMB Support' @@ -56,9 +56,9 @@ compileTestJava { ext { idPrefix = 'smb' - jcifsVersion = '1.3.18.3' - log4jVersion = '2.11.0' - springIntegrationVersion = '5.0.13.BUILD-SNAPSHOT' + jcifsVersion = '2.1.7' + log4jVersion = '2.11.2' + springIntegrationVersion = '5.0.13.RELEASE' linkHomepage = 'https://github.com/SpringSource/spring-integration-extensions' @@ -81,12 +81,12 @@ sourceSets { } jacoco { - toolVersion = "0.7.8" + toolVersion = "0.8.2" } checkstyle { configFile = file("$rootDir/src/checkstyle/checkstyle.xml") - toolVersion = "8.9" + toolVersion = "8.19" } dependencies { diff --git a/spring-integration-smb/gradle.properties b/spring-integration-smb/gradle.properties index 1c7ff0f..673d96e 100644 --- a/spring-integration-smb/gradle.properties +++ b/spring-integration-smb/gradle.properties @@ -1 +1 @@ -version=1.0.1.BUILD-SNAPSHOT +version=1.1.0.BUILD-SNAPSHOT diff --git a/spring-integration-smb/src/checkstyle/checkstyle-suppressions.xml b/spring-integration-smb/src/checkstyle/checkstyle-suppressions.xml index 4bcc130..8621bfc 100644 --- a/spring-integration-smb/src/checkstyle/checkstyle-suppressions.xml +++ b/spring-integration-smb/src/checkstyle/checkstyle-suppressions.xml @@ -1,13 +1,12 @@ + "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" + "https://checkstyle.org/dtds/suppressions_1_2.dtd"> - diff --git a/spring-integration-smb/src/checkstyle/checkstyle.xml b/spring-integration-smb/src/checkstyle/checkstyle.xml index 988861e..533e068 100644 --- a/spring-integration-smb/src/checkstyle/checkstyle.xml +++ b/spring-integration-smb/src/checkstyle/checkstyle.xml @@ -1,5 +1,8 @@ - + + diff --git a/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java b/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java index e46a74c..90d1be8 100644 --- a/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java +++ b/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,6 +53,7 @@ import jcifs.smb.SmbFileOutputStream; * @author Oleg Zhurakousky * @author Artem Bilan * @author Prafull Kumar Soni + * @author Gregory Bragg * */ public class SmbSession implements Session { @@ -63,10 +64,6 @@ public class SmbSession implements Session { private static final String SMB_FILE_SEPARATOR = "/"; - static { - configureJcifs(); - } - private final SmbShare smbShare; /** @@ -458,7 +455,7 @@ public class SmbSession implements Session { return this.smbShare; } - SmbFile smbFile = new SmbFile(this.smbShare, cleanedPath, SmbFile.FILE_SHARE_READ); + SmbFile smbFile = new SmbFile(this.smbShare, cleanedPath); boolean appendFileSeparator = !cleanedPath.endsWith(SMB_FILE_SEPARATOR); if (appendFileSeparator) { @@ -498,32 +495,6 @@ public class SmbSession implements Session { return createSmbFileObject(_path, true); } - /** - * Static configuration of the JCIFS library. - * The log level of this class is mapped to a suitable jcifs.util.loglevel - */ - static void configureJcifs() { - // TODO jcifs.Config.setProperty("jcifs.smb.client.useExtendedSecurity", "false"); - // TODO jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords", "false"); - - // set JCIFS SMB client library' log level unless already configured by system property - final String sysPropLogLevel = "jcifs.util.loglevel"; - - if (jcifs.Config.getProperty(sysPropLogLevel) == null) { - // set log level according to this class' logger's log level. - Log log = LogFactory.getLog(SmbSession.class); - if (log.isTraceEnabled()) { - jcifs.Config.setProperty(sysPropLogLevel, "N"); - } - else if (log.isDebugEnabled()) { - jcifs.Config.setProperty(sysPropLogLevel, "3"); - } - else { - jcifs.Config.setProperty(sysPropLogLevel, "1"); - } - } - } - @Override public String[] listNames(String path) { throw new UnsupportedOperationException("Not implemented yet"); diff --git a/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbShare.java b/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbShare.java index bbcb193..5f015fd 100644 --- a/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbShare.java +++ b/spring-integration-smb/src/main/java/org/springframework/integration/smb/session/SmbShare.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,12 +26,14 @@ import org.springframework.core.NestedIOException; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import jcifs.context.SingletonContext; +import jcifs.smb.NtlmPasswordAuthenticator; import jcifs.smb.SmbException; import jcifs.smb.SmbFile; /** * @author Markus Spann - * @since 1.0 + * @author Gregory Bragg */ public class SmbShare extends SmbFile { @@ -43,12 +45,20 @@ public class SmbShare extends SmbFile { private final AtomicBoolean useTempFile = new AtomicBoolean(false); + /** + * @deprecated as of release 1.1.0, use {@link #SmbShare(SmbConfig)} instead. + * @param url do not use + * @throws IOException do not use + */ + @Deprecated public SmbShare(String url) throws IOException { super(StringUtils.cleanPath(url)); } public SmbShare(SmbConfig _smbConfig) throws IOException { - this(_smbConfig.validate().getUrl()); + super(StringUtils.cleanPath(_smbConfig.validate().getUrl()), + SingletonContext.getInstance().withCredentials(new NtlmPasswordAuthenticator( + _smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword()))); } public void init() throws NestedIOException { diff --git a/spring-integration-smb/src/test/java/org/springframework/integration/smb/session/SmbSessionTests.java b/spring-integration-smb/src/test/java/org/springframework/integration/smb/session/SmbSessionTests.java index 2eaad4e..335332b 100644 --- a/spring-integration-smb/src/test/java/org/springframework/integration/smb/session/SmbSessionTests.java +++ b/spring-integration-smb/src/test/java/org/springframework/integration/smb/session/SmbSessionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,81 +27,111 @@ import jcifs.smb.SmbFile; /** * * @author Gunnar Hillert + * @author Gregory Bragg * */ public class SmbSessionTests { @Test public void testCreateSmbFileObjectWithBackSlash1() throws IOException { - System.setProperty("file.separator", "\\"); - SmbShare smbShare = new SmbShare("smb://myshare/shared/"); + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared/"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); + SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba\\"); - assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath()); + assertEquals("smb://myshare/blubba/", smbFile.getPath()); + smbSession.close(); } @Test public void testCreateSmbFileObjectWithBackSlash2() throws IOException { - System.setProperty("file.separator", "\\"); - SmbShare smbShare = new SmbShare("smb://myshare\\shared\\"); + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared\\"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); + SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba\\"); - assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath()); + assertEquals("smb://myshare/blubba/", smbFile.getPath()); + smbSession.close(); } @Test public void testCreateSmbFileObjectWithBackSlash3() throws IOException { - System.setProperty("file.separator", "\\"); - SmbShare smbShare = new SmbShare("smb://myshare\\shared\\"); + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared\\"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); + SmbFile smbFile = smbSession.createSmbFileObject("..\\another"); - assertEquals("smb://myshare/another/", smbFile.getCanonicalPath()); + assertEquals("smb://myshare:445/another", smbFile.getPath()); + smbSession.close(); } @Test public void testCreateSmbFileObjectWithBackSlash4() throws IOException { - System.setProperty("file.separator", "/"); - SmbShare smbShare = new SmbShare("smb://myshare/shared/"); + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared/"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); + SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba\\"); - assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath()); + assertEquals("smb://myshare/blubba/", smbFile.getPath()); + smbSession.close(); } - @Test - public void testCreateSmbFileObjectwithMissingTrailingSlash1() throws IOException { - - SmbShare smbShare = new SmbShare("smb://myshare/shared"); + public void testCreateSmbFileObjectWithMissingTrailingSlash1() throws IOException { + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba"); - assertEquals("smb://myshare/blubba/", smbFile.getCanonicalPath()); - + assertEquals("smb://myshare/blubba", smbFile.getPath()); + smbSession.close(); } @Test - public void testCreateSmbFileObjectwithMissingTrailingSlash2() throws IOException { - - SmbShare smbShare = new SmbShare("smb://myshare/shared/"); + public void testCreateSmbFileObjectWithMissingTrailingSlash2() throws IOException { + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared/"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); SmbFile smbFile = smbSession.createSmbFileObject("."); - assertEquals("smb://myshare/shared/", smbFile.getCanonicalPath()); - + assertEquals("smb://myshare:445/shared/", smbFile.getPath()); + smbSession.close(); } @Test - public void testCreateSmbFileObjectwithMissingTrailingSlash3() throws IOException { - - SmbShare smbShare = new SmbShare("smb://myshare/shared/"); + public void testCreateSmbFileObjectWithMissingTrailingSlash3() throws IOException { + SmbConfig config = new SmbConfig(); + config.setHost("myshare"); + config.setPort(445); + config.setShareAndDir("shared/"); + SmbShare smbShare = new SmbShare(config); SmbSession smbSession = new SmbSession(smbShare); SmbFile smbFile = smbSession.createSmbFileObject("../anotherShare"); - assertEquals("smb://myshare/anotherShare/", smbFile.getCanonicalPath()); - + assertEquals("smb://myshare:445/anotherShare", smbFile.getPath()); + smbSession.close(); } + }