diff --git a/build.gradle b/build.gradle index b7fe3f63..29087fc3 100644 --- a/build.gradle +++ b/build.gradle @@ -133,6 +133,9 @@ testing { } sources { + java { + srcDirs = ['src/it/java'] + } groovy { srcDirs = ['src/it/groovy'] } diff --git a/src/it/java/com/hierynomus/smbj/AnonymousIntegrationTest.java b/src/it/java/com/hierynomus/smbj/AnonymousIntegrationTest.java new file mode 100644 index 00000000..25c989a4 --- /dev/null +++ b/src/it/java/com/hierynomus/smbj/AnonymousIntegrationTest.java @@ -0,0 +1,51 @@ +package com.hierynomus.smbj; + +import org.junit.jupiter.api.Test; + +import com.hierynomus.mssmb2.SMB2Dialect; +import com.hierynomus.security.bc.BCSecurityProvider; +import com.hierynomus.smbj.auth.AuthenticationContext; +import com.hierynomus.smbj.session.SMB2GuestSigningRequiredException; +import com.hierynomus.smbj.session.Session; +import com.hierynomus.smbj.share.DiskShare; +import com.hierynomus.smbj.share.Share; + +import static org.junit.jupiter.api.Assertions.*; +import static com.hierynomus.smbj.testing.TestingUtils.*; + +public class AnonymousIntegrationTest { + + private SmbConfig base = SmbConfig.builder().withDialects(SMB2Dialect.SMB_3_1_1).withEncryptData(true).withSigningRequired(false).withMultiProtocolNegotiate(true).withDfsEnabled(true).withSecurityProvider(new BCSecurityProvider()).build(); + + @Test + public void shouldAuthenticateAnonymous() throws Exception { + withConnectedClient(base, (connection) -> { + try (Session session = connection.authenticate(AuthenticationContext.anonymous())) { + assertNotNull(session.getSessionId()); + } + }); + } + + @Test + public void shouldFailConnectingAnonymousWhenSigningRequired() throws Exception { + SmbConfig config = SmbConfig.builder(base).withSigningRequired(true).build(); + assertThrows(SMB2GuestSigningRequiredException.class, () -> withConnectedClient(config, (connection) -> { + try (Session session = connection.authenticate(AuthenticationContext.anonymous())) { + fail("Should not be able to connect"); + } + })); + } + + @Test + public void shouldConnectToPublicShare() throws Exception { + withConnectedClient(base, (connection) -> { + try (Session session = connection.authenticate(AuthenticationContext.anonymous())) { + try (Share share = session.connectShare("public")) { + assertInstanceOf(DiskShare.class, share); + assertTrue(share.isConnected()); + assertNotNull(share.getTreeConnect().getTreeId()); + } + } + }); + } +} diff --git a/src/it/java/com/hierynomus/smbj/testing/TestingUtils.java b/src/it/java/com/hierynomus/smbj/testing/TestingUtils.java new file mode 100644 index 00000000..bc9c7a1e --- /dev/null +++ b/src/it/java/com/hierynomus/smbj/testing/TestingUtils.java @@ -0,0 +1,21 @@ +package com.hierynomus.smbj.testing; + +import java.util.function.Consumer; + +import com.hierynomus.smbj.SMBClient; +import com.hierynomus.smbj.SmbConfig; +import com.hierynomus.smbj.connection.Connection; + +public class TestingUtils { + public static void withConnectedClient(SmbConfig config, ConsumerWithError f) throws Exception { + try (SMBClient client = new SMBClient(config)) { + try (Connection connection = client.connect("127.0.0.1")) { + f.accept(connection); + } + } + } + + public interface ConsumerWithError { + void accept(T val) throws Exception; + } +} diff --git a/src/main/java/com/hierynomus/ntlm/NtlmConfig.java b/src/main/java/com/hierynomus/ntlm/NtlmConfig.java index 3f26a40b..c605d341 100644 --- a/src/main/java/com/hierynomus/ntlm/NtlmConfig.java +++ b/src/main/java/com/hierynomus/ntlm/NtlmConfig.java @@ -38,6 +38,10 @@ public static Builder builder(Random r) { return new Builder(r); } + public static Builder builder(NtlmConfig baseConfig) { + return new Builder(baseConfig); + } + private NtlmConfig() { } @@ -74,13 +78,18 @@ public static class Builder { public Builder(Random r) { config = new NtlmConfig(); - config.windowsVersion = new WindowsVersion(ProductMajorVersion.WINDOWS_MAJOR_VERSION_6, ProductMinorVersion.WINDOWS_MINOR_VERSION_1, 7600, NtlmRevisionCurrent.NTLMSSP_REVISION_W2K3); + config.windowsVersion = new WindowsVersion(ProductMajorVersion.WINDOWS_MAJOR_VERSION_6, + ProductMinorVersion.WINDOWS_MINOR_VERSION_1, 7600, NtlmRevisionCurrent.NTLMSSP_REVISION_W2K3); config.integrity = true; config.omitVersion = false; config.machineID = new byte[32]; r.nextBytes(config.machineID); } + public Builder(NtlmConfig baseConfig) { + config = new NtlmConfig(baseConfig); + } + public Builder withWindowsVersion(WindowsVersion windowsVersion) { config.windowsVersion = windowsVersion; return this; diff --git a/src/main/java/com/hierynomus/smbj/SmbConfig.java b/src/main/java/com/hierynomus/smbj/SmbConfig.java index 1d4f85a3..2347ae29 100644 --- a/src/main/java/com/hierynomus/smbj/SmbConfig.java +++ b/src/main/java/com/hierynomus/smbj/SmbConfig.java @@ -98,26 +98,30 @@ public static SmbConfig createDefaultConfig() { } public static Builder builder() { - Builder b = new Builder() - .withClientGuid(UUID.randomUUID()) - .withSecurityProvider(getDefaultSecurityProvider()) - .withSocketFactory(new ProxySocketFactory()) - .withSigningRequired(false) - .withDfsEnabled(false) - .withMultiProtocolNegotiate(false) - .withBufferSize(DEFAULT_BUFFER_SIZE) - .withTransportLayerFactory(DEFAULT_TRANSPORT_LAYER_FACTORY) - .withSoTimeout(DEFAULT_SO_TIMEOUT, DEFAULT_SO_TIMEOUT_UNIT) - .withDialects(SMB_3_1_1, SMB_3_0_2, SMB_3_0, SMB_2_1, SMB_2_0_2) - // order is important. The authenticators listed first will be selected - .withAuthenticators(getDefaultAuthenticators()) - .withTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT) - .withClientGSSContextConfig(GSSContextConfig.createDefaultConfig()) - .withEncryptData(false); + Builder b = new Builder() + .withClientGuid(UUID.randomUUID()) + .withSecurityProvider(getDefaultSecurityProvider()) + .withSocketFactory(new ProxySocketFactory()) + .withSigningRequired(false) + .withDfsEnabled(false) + .withMultiProtocolNegotiate(false) + .withBufferSize(DEFAULT_BUFFER_SIZE) + .withTransportLayerFactory(DEFAULT_TRANSPORT_LAYER_FACTORY) + .withSoTimeout(DEFAULT_SO_TIMEOUT, DEFAULT_SO_TIMEOUT_UNIT) + .withDialects(SMB_3_1_1, SMB_3_0_2, SMB_3_0, SMB_2_1, SMB_2_0_2) + // order is important. The authenticators listed first will be selected + .withAuthenticators(getDefaultAuthenticators()) + .withTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT) + .withClientGSSContextConfig(GSSContextConfig.createDefaultConfig()) + .withEncryptData(false); return b; } + public static Builder builder(SmbConfig baseConfig) { + return new Builder(baseConfig); + } + private static SecurityProvider getDefaultSecurityProvider() { return new BCSecurityProvider(); } @@ -284,6 +288,11 @@ public static class Builder { ntlmConfigBuilder = NtlmConfig.builder(config.random); } + Builder(SmbConfig baseConfig) { + config = new SmbConfig(baseConfig); + ntlmConfigBuilder = NtlmConfig.builder(config.ntlmConfig); + } + public Builder withRandomProvider(Random random) { if (random == null) { throw new IllegalArgumentException("Random provider may not be null"); diff --git a/src/main/java/com/hierynomus/smbj/connection/SMBSessionBuilder.java b/src/main/java/com/hierynomus/smbj/connection/SMBSessionBuilder.java index 130af485..65b6eb74 100644 --- a/src/main/java/com/hierynomus/smbj/connection/SMBSessionBuilder.java +++ b/src/main/java/com/hierynomus/smbj/connection/SMBSessionBuilder.java @@ -107,7 +107,7 @@ public SMBSessionBuilder(Connection connection, SmbConfig config, SessionFactory public Session establish(AuthenticationContext authContext) { try { Authenticator authenticator = getAuthenticator(authContext); - if (authenticator instanceof NtlmAuthenticator && config.getNtlmConfig().isIntegrityEnabled()) { + if (authenticator instanceof NtlmAuthenticator && config.getNtlmConfig().isIntegrityEnabled() && !(authContext.isAnonymous() && !(authContext.isGuest()))) { authenticator = new NtlmSealer((NtlmAuthenticator) authenticator); } @@ -163,7 +163,9 @@ private Session setupSession(BuilderContext ctx) throws IOException { SessionContext context = session.getSessionContext(); processAuthenticationToken(ctx, response.getSecurityBuffer()); - context.setSessionKey(new SecretKeySpec(ctx.sessionKey, HMAC_SHA256_ALGORITHM)); + if (!ctx.authContext.isAnonymous() && !ctx.authContext.isGuest()) { + context.setSessionKey(new SecretKeySpec(ctx.sessionKey, HMAC_SHA256_ALGORITHM)); + } if (dialect == SMB2Dialect.SMB_3_1_1) { updatePreauthIntegrityValue(ctx, context, ctx.request); }