GH-208: Allow setting of SMB min/max versions

Fixes https://github.com/spring-projects/spring-integration-extensions/issues/208

* Updated to be able to use min/max SMB version property settings

* cleanup of formatting of file

* Updated based on review comments

* Updated readme for new functionality

* Some polishing of readme and follow current naming conventions

* Updated, missed naming convention on Javadoc

* Updated per review comments
This commit is contained in:
Gregory Bragg
2019-04-15 11:11:11 -04:00
committed by Artem Bilan
parent e91cb382e7
commit d4f42cb6b8
5 changed files with 199 additions and 20 deletions

View File

@@ -3,7 +3,7 @@ Spring Integration SMB Support
## Introduction
This module add Spring Integration support for [Server Message Block][] (SMB).
This module adds Spring Integration support for [Server Message Block][] (SMB).
[Server Message Block]: https://en.wikipedia.org/wiki/Server_Message_Block
@@ -23,9 +23,13 @@ Put the following block into pom.xml if using Maven:
## Changes
##### Version 1.1
* Updated to use the latest version of the [JCIFS](https://github.com/codelibs/jcifs) library
* SMB2 (2.02 protocol level) support, some SMB3 support
##### Version 1.2
* Ability to set the SMB min/max versions in the `SmbSessionFactory` via configuration in the JCIFS library
## Overview
The Java CIFS Client Library has been chosen as a Java implementation for the CIFS/SMB networking protocol.
@@ -46,15 +50,37 @@ For XML configuration the `<int-smb:inbound-channel-adapter>` component is provi
There is no (yet) some SMB specific requirements for files transferring to SMB, so for XML `<int-smb:outbound-channel-adapter>` 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<SmbFile> 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;
}
````java
@ServiceActivator(inputChannel = "storeToSmb")
@Bean
public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) {
FileTransferringMessageHandler<SmbFile> 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;
}
````
### Setting SMB Protocol Min/Max Versions
Example: To set a minimum version of SMB 2.1 and a maximum version of SMB 3.1.1
````java
@Bean
public SmbSessionFactory smbSessionFactory() {
SmbSessionFactory smbSession = new SmbSessionFactory();
smbSession.setHost("myHost");
smbSession.setPort(445);
smbSession.setDomain("myDomain");
smbSession.setUsername("myUser");
smbSession.setPassword("myPassword");
smbSession.setShareAndDir("myShareAndDir");
smbSession.setSmbMinVersion(DialectVersion.SMB210);
smbSession.setSmbMaxVersion(DialectVersion.SMB311);
return smbSession;
}
````

View File

@@ -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.
@@ -22,6 +22,8 @@ import java.net.URISyntaxException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import jcifs.DialectVersion;
/**
* Data holder class for a SMB share configuration.
*
@@ -31,8 +33,7 @@ import org.springframework.util.StringUtils;
* @author Markus Spann
* @author Prafull Kumar Soni
* @author Artem Bilan
*
* @since 1.0
* @author Gregory Bragg
*/
public class SmbConfig {
@@ -52,6 +53,18 @@ public class SmbConfig {
private boolean useTempFile = false;
/**
* Defaults to and follows the jCIFS library default of 'SMB1'
* @since 1.2
*/
private DialectVersion smbMinVersion = DialectVersion.SMB1;
/**
* Defaults to and follows the jCIFS library default of 'SMB210'
* @since 1.2
*/
private DialectVersion smbMaxVersion = DialectVersion.SMB210;
public SmbConfig() {
}
@@ -134,6 +147,46 @@ public class SmbConfig {
return this.useTempFile;
}
/**
* Gets the desired minimum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @return one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
* @since 1.2
*/
public DialectVersion getSmbMinVersion() {
return this.smbMinVersion;
}
/**
* Sets the desired minimum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @param _smbMinVersion one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
* @since 1.2
*/
public void setSmbMinVersion(DialectVersion _smbMinVersion) {
this.smbMinVersion = _smbMinVersion;
}
/**
* Gets the desired maximum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @return one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
* @since 1.2
*/
public DialectVersion getSmbMaxVersion() {
return this.smbMaxVersion;
}
/**
* Sets the desired maximum SMB version value for what the Windows server will allow
* during protocol transport negotiation.
* @param _smbMaxVersion one of SMB1, SMB202, SMB210, SMB300, SMB302 or SMB311
* @since 1.2
*/
public void setSmbMaxVersion(DialectVersion _smbMaxVersion) {
this.smbMaxVersion = _smbMaxVersion;
}
String getDomainUserPass(boolean _includePassword) {
String domainUserPass;
if (StringUtils.hasText(this.domain)) {

View File

@@ -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.
@@ -17,6 +17,7 @@
package org.springframework.integration.smb.session;
import java.io.IOException;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -29,7 +30,7 @@ import jcifs.smb.SmbFile;
* The SMB session factory.
*
* @author Markus Spann
* @since 1.0
* @author Gregory Bragg
*/
public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFile> {
@@ -39,6 +40,7 @@ public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFi
logger.debug("New " + getClass().getName() + " created.");
}
@Override
public final SmbSession getSession() {
try {
return createSession();
@@ -49,7 +51,11 @@ public class SmbSessionFactory extends SmbConfig implements SessionFactory<SmbFi
}
protected SmbSession createSession() throws IOException {
SmbShare smbShare = new SmbShare(this);
Properties props = new Properties();
props.setProperty("jcifs.smb.client.minVersion", this.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", this.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(this, props);
smbShare.setReplaceFile(isReplaceFile());
smbShare.setUseTempFile(isUseTempFile());

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.smb.session;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
@@ -26,6 +27,8 @@ import org.springframework.core.NestedIOException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import jcifs.config.PropertyConfiguration;
import jcifs.context.BaseContext;
import jcifs.context.SingletonContext;
import jcifs.smb.NtlmPasswordAuthenticator;
import jcifs.smb.SmbException;
@@ -55,12 +58,36 @@ public class SmbShare extends SmbFile {
super(StringUtils.cleanPath(url));
}
/**
* Initializes the jCIFS library with default properties.
* @param _smbConfig the SMB share configuration
* @throws IOException if an invalid SMB URL was constructed by jCIFS
* @since 1.1
*/
public SmbShare(SmbConfig _smbConfig) throws IOException {
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
SingletonContext.getInstance().withCredentials(new NtlmPasswordAuthenticator(
SingletonContext.getInstance().withCredentials(
new NtlmPasswordAuthenticator(
_smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword())));
}
/**
* Initializes the jCIFS library with custom properties such as
* 'jcifs.smb.client.minVersion' and 'jcifs.smb.client.maxVersion'
* for setting the minimum/maximum SMB supported versions.
* @param _smbConfig the SMB share configuration
* @param _props the custom property set for jCIFS to initialize
* @throws IOException if an invalid property was set or an invalid SMB URL was constructed by jCIFS
* @since 1.2
*/
public SmbShare(SmbConfig _smbConfig, Properties _props) throws IOException {
super(StringUtils.cleanPath(_smbConfig.validate().getUrl()),
new BaseContext(
new PropertyConfiguration(_props)).withCredentials(
new NtlmPasswordAuthenticator(
_smbConfig.getDomain(), _smbConfig.getUsername(), _smbConfig.getPassword())));
}
public void init() throws NestedIOException {
boolean canRead = false;
try {

View File

@@ -19,9 +19,11 @@ package org.springframework.integration.smb.session;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.junit.Test;
import jcifs.DialectVersion;
import jcifs.smb.SmbFile;
/**
@@ -134,4 +136,69 @@ public class SmbSessionTests {
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithSmb3Versions1() throws IOException {
Properties props = new Properties();
SmbConfig config = new SmbConfig();
config.setHost("myshare");
config.setPort(445);
config.setShareAndDir("shared/");
config.setSmbMinVersion(DialectVersion.SMB300);
config.setSmbMaxVersion(DialectVersion.SMB311);
props.setProperty("jcifs.smb.client.minVersion", config.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", config.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(config, props);
SmbSession smbSession = new SmbSession(smbShare);
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
assertEquals("smb://myshare/blubba", smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithSmb3Versions2() throws IOException {
Properties props = new Properties();
SmbConfig config = new SmbConfig();
config.setHost("myshare");
config.setPort(445);
config.setShareAndDir("shared/");
config.setSmbMinVersion(DialectVersion.SMB302);
config.setSmbMaxVersion(DialectVersion.SMB311);
props.setProperty("jcifs.smb.client.minVersion", config.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", config.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(config, props);
SmbSession smbSession = new SmbSession(smbShare);
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
assertEquals("smb://myshare/blubba", smbFile.getPath());
smbSession.close();
}
@Test
public void testCreateSmbFileObjectWithSmb3Versions3() throws IOException {
Properties props = new Properties();
SmbConfig config = new SmbConfig();
config.setHost("myshare");
config.setPort(445);
config.setShareAndDir("shared/");
config.setSmbMinVersion(DialectVersion.SMB311);
config.setSmbMaxVersion(DialectVersion.SMB311);
props.setProperty("jcifs.smb.client.minVersion", config.getSmbMinVersion().name());
props.setProperty("jcifs.smb.client.maxVersion", config.getSmbMaxVersion().name());
SmbShare smbShare = new SmbShare(config, props);
SmbSession smbSession = new SmbSession(smbShare);
SmbFile smbFile = smbSession.createSmbFileObject("smb://myshare\\blubba");
assertEquals("smb://myshare/blubba", smbFile.getPath());
smbSession.close();
}
}