diff --git a/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/CertificateTrustIT.cs b/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/CertificateTrustIT.cs index ca04bb958..fb1923467 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/CertificateTrustIT.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/CertificateTrustIT.cs @@ -148,7 +148,7 @@ private async Task TestConnectivity(Uri target, Config config) private IDriver SetupWithCustomResolver(Uri overridenUri, Config config) { - var connectionSettings = new ConnectionSettings(Server.AuthToken, config); + var connectionSettings = new ConnectionSettings(overridenUri, Server.AuthToken, config); connectionSettings.SocketSettings.HostResolver = new CustomHostResolver(Server.BoltUri, connectionSettings.SocketSettings.HostResolver); var bufferSettings = new BufferSettings(config); diff --git a/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/EncryptionIT.cs b/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/EncryptionIT.cs new file mode 100644 index 000000000..4639f1c43 --- /dev/null +++ b/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Direct/EncryptionIT.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2002-2020 "Neo4j," +// Neo4j Sweden AB [http://neo4j.com] +// +// This file is part of Neo4j. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using FluentAssertions; +using Neo4j.Driver.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Neo4j.Driver.IntegrationTests.Direct +{ + public class EncryptionIT : DirectDriverTestBase + { + public EncryptionIT(ITestOutputHelper output, StandAloneIntegrationTestFixture fixture) + : base(output, fixture) + { + } + + [RequireServerFact] + public async Task ShouldBeAbleToConnectWithInsecureConfig() + { + using (var driver = GraphDatabase.Driver(ServerEndPoint, AuthToken, + o => o + .WithEncryptionLevel(EncryptionLevel.Encrypted) + .WithTrustManager(TrustManager.CreateInsecure()))) + { + await VerifyConnectivity(driver); + } + } + + [RequireServerFact] + public async Task ShouldBeAbleToConnectUsingInsecureUri() + { + var builder = new UriBuilder("bolt+ssc", ServerEndPoint.Host, ServerEndPoint.Port); + using (var driver = GraphDatabase.Driver(builder.Uri, AuthToken)) + { + await VerifyConnectivity(driver); + } + } + + private static async Task VerifyConnectivity(IDriver driver) + { + var session = driver.AsyncSession(); + + try + { + var cursor = await session.RunAsync("RETURN 2 as Number"); + var records = await cursor.ToListAsync(r => r["Number"].As()); + + records.Should().BeEquivalentTo(2); + } + finally + { + await session.CloseAsync(); + } + } + } +} \ No newline at end of file diff --git a/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Stress/StressTest.cs b/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Stress/StressTest.cs index ce8d8965b..8b94afacc 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Stress/StressTest.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests.Integration/Stress/StressTest.cs @@ -593,7 +593,7 @@ private static Task[] LaunchPoolWorkers(IDriver driver, CancellationToken token, Logger = new StressTestLogger(_output, LoggingEnabled) }; - var connectionSettings = new ConnectionSettings(_authToken, config); + var connectionSettings = new ConnectionSettings(_databaseUri, _authToken, config); var bufferSettings = new BufferSettings(config); var connectionFactory = new MonitoredPooledConnectionFactory( new PooledConnectionFactory(connectionSettings, bufferSettings, config.Logger)); diff --git a/Neo4j.Driver/Neo4j.Driver.Tests/ConfigTests.cs b/Neo4j.Driver/Neo4j.Driver.Tests/ConfigTests.cs index 2373d573f..fab63ff62 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests/ConfigTests.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests/ConfigTests.cs @@ -55,6 +55,28 @@ public void ShouldSetMaxIdleValueWhenSetSeparately() config.MaxConnectionPoolSize.Should().Be(50); config.MaxIdleConnectionPoolSize.Should().Be(20); } + + [Fact] + public void ShouldDefaultToNoEncryptionAndNoTrust() + { + var config = Config.Default; + config.NullableEncryptionLevel.Should().BeNull(); + config.EncryptionLevel.Should().Be(EncryptionLevel.None); + config.TrustManager.Should().BeNull(); + } + + [Fact] + public void ShouldSetEncryptionAndTrust() + { + var config = new Config + { + EncryptionLevel = EncryptionLevel.None, + TrustManager = null + }; + config.NullableEncryptionLevel.Should().Be(EncryptionLevel.None); + config.EncryptionLevel.Should().Be(EncryptionLevel.None); + config.TrustManager.Should().BeNull(); + } } public class ConfigBuilderTests @@ -107,10 +129,11 @@ public void WithPoolSizeShouldModifyTheSingleValue() } [Fact] - public void WithEncryptionLevelShouldModifyTheSingleValue() + public void WithEncryptionLevelShouldModifyTheNullableValue() { var config = Config.Builder.WithEncryptionLevel(EncryptionLevel.None).Build(); config.EncryptionLevel.Should().Be(EncryptionLevel.None); + config.NullableEncryptionLevel.Should().Be(EncryptionLevel.None); config.TrustManager.Should().BeNull(); config.Logger.Should().BeOfType(); config.MaxIdleConnectionPoolSize.Should().Be(500); diff --git a/Neo4j.Driver/Neo4j.Driver.Tests/Connector/EncryptionManagerTests.cs b/Neo4j.Driver/Neo4j.Driver.Tests/Connector/EncryptionManagerTests.cs index 6b4b5d29d..5599d6d20 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests/Connector/EncryptionManagerTests.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests/Connector/EncryptionManagerTests.cs @@ -30,31 +30,135 @@ namespace Neo4j.Driver.Tests.Connector { public class EncryptionManagerTests { - [Fact] - public void ShouldNotCreateTrustManagerIfEncryptionDisabled() + public class CreateFromConfigMethod { - var encryption = - new EncryptionManager(EncryptionLevel.None, null, null); + [Fact] + public void ShouldNotCreateTrustManagerIfNotEncrypted() + { + var encryption = + EncryptionManager.CreateFromConfig(EncryptionLevel.None, null, null); - encryption.TrustManager.Should().BeNull(); - } + encryption.UseTls.Should().BeFalse(); + encryption.TrustManager.Should().BeNull(); + } - [Fact] - public void ShouldCreateDefaulTrustManagerIfEncrypted() - { - var encryption = - new EncryptionManager(EncryptionLevel.Encrypted, null, null); + [Fact] + public void ShouldNotCreateTrustManagerIfEncryptedIsNull() + { + var encryption = + EncryptionManager.CreateFromConfig(null, null, null); + + encryption.UseTls.Should().BeFalse(); + encryption.TrustManager.Should().BeNull(); + } + + [Fact] + public void ShouldCreateDefaultTrustManagerIfEncrypted() + { + var encryption = + EncryptionManager.CreateFromConfig(EncryptionLevel.Encrypted, null, null); + + encryption.UseTls.Should().BeTrue(); + encryption.TrustManager.Should().NotBeNull().And.BeOfType(); + } + + [Fact] + public void ShouldUseProvidedTrustManager() + { + var encryption = + EncryptionManager.CreateFromConfig(null, new CustomTrustManager(), null); + + encryption.UseTls.Should().BeFalse(); + encryption.TrustManager.Should().NotBeNull().And.BeOfType(); + } - encryption.TrustManager.Should().NotBeNull().And.BeOfType(); } - [Fact] - public void ShouldUseProvidedTrustManager() + public class CreateMethod { - var encryption = - new EncryptionManager(EncryptionLevel.Encrypted, new CustomTrustManager(), null); + [Theory] + [InlineData("bolt")] + [InlineData("neo4j")] + public void ShouldCreateDefaultWithoutConfig(string scheme) + { + var uri = new Uri($"{scheme}://localhost/?"); + var encryption = + EncryptionManager.Create(uri, null, null, null); + + encryption.UseTls.Should().BeFalse(); + encryption.TrustManager.Should().BeNull(); + } - encryption.TrustManager.Should().NotBeNull().And.BeOfType(); + [Theory] + [InlineData("bolt")] + [InlineData("neo4j")] + public void ShouldCreateFromConfig(string scheme) + { + var uri = new Uri($"{scheme}://localhost/?"); + var encryption = + EncryptionManager.Create(uri, EncryptionLevel.Encrypted, null, null); + + encryption.UseTls.Should().BeTrue(); + encryption.TrustManager.Should().BeOfType(); + } + + [Theory] + [InlineData("bolt+s")] + [InlineData("neo4j+s")] + public void ShouldCreateChainTrustFromUri(string scheme) + { + var uri = new Uri($"{scheme}://localhost/?"); + var encryption = + EncryptionManager.Create(uri, null, null, null); + + encryption.UseTls.Should().BeTrue(); + encryption.TrustManager.Should().BeOfType(); + } + + [Theory] + [InlineData("bolt+ssc")] + [InlineData("neo4j+ssc")] + public void ShouldCreateInsecureTrustFromUri(string scheme) + { + var uri = new Uri($"{scheme}://localhost/?"); + var encryption = + EncryptionManager.Create(uri, null, null, null); + + encryption.UseTls.Should().BeTrue(); + encryption.TrustManager.Should().BeOfType(); + } + + [Theory] + [InlineData("bolt+s", EncryptionLevel.None)] + [InlineData("neo4j+s", EncryptionLevel.None)] + [InlineData("bolt+ssc", EncryptionLevel.None)] + [InlineData("neo4j+ssc", EncryptionLevel.None)] + [InlineData("bolt+s", EncryptionLevel.Encrypted)] + [InlineData("neo4j+s", EncryptionLevel.Encrypted)] + [InlineData("bolt+ssc", EncryptionLevel.Encrypted)] + [InlineData("neo4j+ssc", EncryptionLevel.Encrypted)] + public void ShouldErrorIfEncryptionLevelNotNull(string scheme, EncryptionLevel level) + { + var uri = new Uri($"{scheme}://localhost/?"); + var ex = Record.Exception(() => EncryptionManager.Create(uri, level, null, null)); + + ex.Should().BeOfType(); + ex.Message.Should().Contain("cannot both be set via uri scheme and driver configuration"); + } + + [Theory] + [InlineData("bolt+s")] + [InlineData("neo4j+s")] + [InlineData("bolt+ssc")] + [InlineData("neo4j+ssc")] + public void ShouldErrorIfTrustManagerNotNull(string scheme) + { + var uri = new Uri($"{scheme}://localhost/?"); + var ex = Record.Exception(() => EncryptionManager.Create(uri, null, new CustomTrustManager(), null)); + + ex.Should().BeOfType(); + ex.Message.Should().Contain("cannot both be set via uri scheme and driver configuration"); + } } private class CustomTrustManager : TrustManager diff --git a/Neo4j.Driver/Neo4j.Driver.Tests/Connector/TcpSocketClientTests.cs b/Neo4j.Driver/Neo4j.Driver.Tests/Connector/TcpSocketClientTests.cs index c01093c01..231b1f3e4 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests/Connector/TcpSocketClientTests.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests/Connector/TcpSocketClientTests.cs @@ -57,7 +57,7 @@ public async Task ShouldThrowExceptionIfConnectionTimedOut() ConnectionTimeout = TimeSpan.FromSeconds(1), HostResolver = new SystemHostResolver(), EncryptionManager = - new EncryptionManager(EncryptionLevel.None, null, null) + new EncryptionManager(false, null) }); // ReSharper disable once PossibleNullReferenceException @@ -79,7 +79,7 @@ public async Task ShouldBeAbleToConnectAgainIfFirstFailed() ConnectionTimeout = TimeSpan.FromSeconds(10), HostResolver = new SystemHostResolver(), EncryptionManager = - new EncryptionManager(EncryptionLevel.None, null, null) + new EncryptionManager(false, null) }; var client = new TcpSocketClient(socketSettings); @@ -113,7 +113,7 @@ public async Task ShouldThrowExceptionIfConnectionTimedOut() { ConnectionTimeout = TimeSpan.FromSeconds(1), HostResolver = new SystemHostResolver(), - EncryptionManager = new EncryptionManager(EncryptionLevel.None, null, null) + EncryptionManager = new EncryptionManager(false, null) }); // ReSharper disable once PossibleNullReferenceException diff --git a/Neo4j.Driver/Neo4j.Driver.Tests/TestUtil/NetworkExtensionsTests.cs b/Neo4j.Driver/Neo4j.Driver.Tests/TestUtil/NetworkExtensionsTests.cs index 03bcc1819..28bc28841 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests/TestUtil/NetworkExtensionsTests.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests/TestUtil/NetworkExtensionsTests.cs @@ -21,7 +21,9 @@ using System.Net.Sockets; using System.Threading.Tasks; using FluentAssertions; +using Moq; using Neo4j.Driver.Internal; +using Neo4j.Driver.Internal.Connector.Trust; using Xunit; using static Neo4j.Driver.Internal.NetworkExtensions; @@ -88,5 +90,138 @@ public void ShouldErrorIfDuplicateKey(string scheme) exception.Message.Should().Contain("Duplicated query parameters with key 'name'"); } } + + public class IsSimpleUriSchemeMethod + { + [Theory] + [InlineData("bolt")] + [InlineData("neo4j")] + public void ShouldBeSimpleUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var isSimple = raw.IsSimpleUriScheme(); + + isSimple.Should().BeTrue(); + } + + [Theory] + [InlineData("bolt+s")] + [InlineData("bolt+ssc")] + [InlineData("neo4j+s")] + [InlineData("neo4j+ssc")] + public void ShouldNotBeSimpleUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var isSimple = raw.IsSimpleUriScheme(); + + isSimple.Should().BeFalse(); + } + + [Theory] + [InlineData("bolt+ss")] + [InlineData("bolts")] + [InlineData("neo4js")] + [InlineData("neo4j-ssc")] + public void ShouldErrorForUnknownBoltUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var ex = Record.Exception(() => raw.IsSimpleUriScheme()); + ex.Should().BeOfType(); + } + } + + public class IsRoutingUriMethod + { + [Theory] + [InlineData("neo4j")] + [InlineData("neo4j+s")] + [InlineData("neo4j+ssc")] + public void ShouldBeRoutingUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var isRoutingUri = raw.IsRoutingUri(); + + isRoutingUri.Should().BeTrue(); + } + + [Theory] + [InlineData("bolt")] + [InlineData("bolt+s")] + [InlineData("bolt+ssc")] + public void ShouldNotBeRoutingUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var isRoutingUri = raw.IsRoutingUri(); + + isRoutingUri.Should().BeFalse(); + } + + [Theory] + [InlineData("bolt+ss")] + [InlineData("bolts")] + [InlineData("neo4js")] + [InlineData("neo4j-ssc")] + public void ShouldErrorForUnknownBoltUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var ex = Record.Exception(() => raw.IsRoutingUri()); + ex.Should().BeOfType(); + } + } + + public class ParseUriSchemeToEncryptionManagerMethod + { + [Theory] + [InlineData("bolt")] + [InlineData("neo4j")] + public void ShouldBeNoEncryptionNoTrust(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var manager = raw.ParseUriSchemeToEncryptionManager(null); + + manager.UseTls.Should().BeFalse(); + manager.TrustManager.Should().BeNull(); + } + + [Theory] + [InlineData("bolt+s")] + [InlineData("neo4j+s")] + public void ShouldBeEncryptionWithChainTrust(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var log = new Mock().Object; + var manager = raw.ParseUriSchemeToEncryptionManager(log); + + manager.UseTls.Should().BeTrue(); + manager.TrustManager.Should().BeOfType(); + manager.TrustManager.Logger.Should().Be(log); + } + + [Theory] + [InlineData("bolt+ssc")] + [InlineData("neo4j+ssc")] + public void ShouldBeEncryptionWithInsecureTrust(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var log = new Mock().Object; + var manager = raw.ParseUriSchemeToEncryptionManager(log); + + manager.UseTls.Should().BeTrue(); + manager.TrustManager.Should().BeOfType(); + manager.TrustManager.Logger.Should().Be(log); + } + + [Theory] + [InlineData("bolt+ss")] + [InlineData("bolts")] + [InlineData("neo4js")] + [InlineData("neo4j-ssc")] + public void ShouldErrorForUnknownBoltUri(string scheme) + { + var raw = new Uri($"{scheme}://localhost/?"); + var ex = Record.Exception(() => raw.ParseUriSchemeToEncryptionManager(null)); + ex.Should().BeOfType(); + } + } } } diff --git a/Neo4j.Driver/Neo4j.Driver/Config.cs b/Neo4j.Driver/Neo4j.Driver/Config.cs index c1085cdd2..26a24b2b8 100644 --- a/Neo4j.Driver/Neo4j.Driver/Config.cs +++ b/Neo4j.Driver/Neo4j.Driver/Config.cs @@ -74,7 +74,13 @@ public class Config /// /// The use of encryption for all the connections created by the . /// - public EncryptionLevel EncryptionLevel { get; internal set; } = EncryptionLevel.None; + public EncryptionLevel EncryptionLevel + { + get => NullableEncryptionLevel.GetValueOrDefault(EncryptionLevel.None); + internal set => NullableEncryptionLevel = value; + } + + internal EncryptionLevel? NullableEncryptionLevel { get; set; } /// /// Specifies which implementation should be used while establishing trust via TLS. @@ -147,7 +153,7 @@ public int MaxIdleConnectionPoolSize public TimeSpan ConnectionIdleTimeout { get; internal set; } = InfiniteInterval; /// - /// The maximum connection lifetime on pooled connecitons. + /// The maximum connection lifetime on pooled connections. /// A connection that has been created for longer than the given time will be closed once it is seen. /// Use to disable connection lifetime checking. /// diff --git a/Neo4j.Driver/Neo4j.Driver/ConfigBuilder.cs b/Neo4j.Driver/Neo4j.Driver/ConfigBuilder.cs index 552801987..552be6461 100644 --- a/Neo4j.Driver/Neo4j.Driver/ConfigBuilder.cs +++ b/Neo4j.Driver/Neo4j.Driver/ConfigBuilder.cs @@ -50,7 +50,7 @@ internal Config Build() /// An instance for further configuration options. public ConfigBuilder WithEncryptionLevel(EncryptionLevel level) { - _config.EncryptionLevel = level; + _config.NullableEncryptionLevel = level; return this; } diff --git a/Neo4j.Driver/Neo4j.Driver/GraphDatabase.cs b/Neo4j.Driver/Neo4j.Driver/GraphDatabase.cs index e02c700df..83970a800 100644 --- a/Neo4j.Driver/Neo4j.Driver/GraphDatabase.cs +++ b/Neo4j.Driver/Neo4j.Driver/GraphDatabase.cs @@ -208,7 +208,7 @@ public static IDriver Driver(Uri uri, IAuthToken authToken, Action internal class EncryptionManager { - private readonly EncryptionLevel _encryptionLevel; - public EncryptionManager() { } // for test - public EncryptionManager(EncryptionLevel level, TrustManager trustManager, ILogger logger) + public EncryptionManager(bool useTls, TrustManager trustManager) { - _encryptionLevel = level; + UseTls = useTls; + TrustManager = trustManager; + } - if (_encryptionLevel == EncryptionLevel.Encrypted) + public static EncryptionManager Create(Uri uri, EncryptionLevel? level, TrustManager trustManager, + ILogger logger) + { + var configured = level.HasValue || trustManager != null; + if (configured) { - if (trustManager == null) - { - trustManager = TrustManager.CreateChainTrust(); - } + AssertSimpleUriScheme(uri, level, trustManager); + return CreateFromConfig(level, trustManager, logger); + } + return CreateFromUriScheme(uri, logger); - trustManager.Logger = logger; + } - TrustManager = trustManager; + private static EncryptionManager CreateFromUriScheme(Uri uri, ILogger logger) + { + // let the uri scheme to decide + return uri.ParseUriSchemeToEncryptionManager(logger); + } + + private static void AssertSimpleUriScheme(Uri uri, EncryptionLevel? encryptionLevel, TrustManager trustManager) + { + if (!uri.IsSimpleUriScheme()) + { + throw new ArgumentException( + "The encryption and trust settings cannot both be set via uri scheme and driver configuration. " + + $"uri scheme = {uri.Scheme}, encryption = {encryptionLevel}, trust = {trustManager}"); } } - public bool UseTls + public static EncryptionManager CreateFromConfig(EncryptionLevel? nullableLevel, TrustManager trustManager, + ILogger logger) { - get + var encrypted = ParseEncrypted(nullableLevel); + if (encrypted && trustManager == null) { - switch (_encryptionLevel) - { - case EncryptionLevel.Encrypted: - return true; - case EncryptionLevel.None: - return false; - default: - throw new NotSupportedException($"Unknown encryption level: {_encryptionLevel}"); - } + return new EncryptionManager(true, CreateSecureTrustManager(logger)); } + return new EncryptionManager(encrypted, trustManager); + } + + private static bool ParseEncrypted(EncryptionLevel? nullableLevel) + { + var level = nullableLevel.GetValueOrDefault(EncryptionLevel.None); + switch (level) + { + case EncryptionLevel.Encrypted: + return true; + case EncryptionLevel.None: + return false; + default: + throw new NotSupportedException($"Unknown encryption level: {level}"); + } + } + + public static TrustManager CreateSecureTrustManager(ILogger logger) + { + var trustManager = TrustManager.CreateChainTrust(); + trustManager.Logger = logger; + return trustManager; + } + + public static TrustManager CreateInsecureTrustManager(ILogger logger) + { + var trustManager = TrustManager.CreateInsecure(); + trustManager.Logger = logger; + return trustManager; } + public bool UseTls { get; } public TrustManager TrustManager { get; } } diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Extensions/NetworkExtensions.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Extensions/NetworkExtensions.cs index d99fccd3d..d1546f4bf 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/Extensions/NetworkExtensions.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Extensions/NetworkExtensions.cs @@ -27,7 +27,62 @@ namespace Neo4j.Driver.Internal { internal static class NetworkExtensions { - + public static bool IsSimpleUriScheme(this Uri uri) + { + var scheme = uri.Scheme.ToLower(); + switch (scheme) + { + case "bolt+s": + case "bolt+ssc": + case "neo4j+s": + case "neo4j+ssc": + return false; + case "bolt": + case "neo4j": + return true; + default: + throw new NotSupportedException($"Unsupported URI scheme: {scheme}"); + } + } + public static bool IsRoutingUri(this Uri uri) + { + var scheme = uri.Scheme.ToLower(); + switch (scheme) + { + case "bolt": + case "bolt+s": + case "bolt+ssc": + return false; + case "neo4j": + case "neo4j+s": + case "neo4j+ssc": + return true; + default: + throw new NotSupportedException($"Unsupported URI scheme: {scheme}"); + } + } + + public static EncryptionManager ParseUriSchemeToEncryptionManager(this Uri uri, ILogger logger) + { + var scheme = uri.Scheme.ToLower(); + switch (scheme) + { + case "bolt": + case "neo4j": + // no encryption, no trust + return new EncryptionManager(false, null); + case "bolt+s": + case "neo4j+s": + // encryption with chain trust + return new EncryptionManager(true, EncryptionManager.CreateSecureTrustManager(logger)); + case "bolt+ssc": + case "neo4j+ssc": + return new EncryptionManager(true, EncryptionManager.CreateInsecureTrustManager(logger)); + default: + throw new NotSupportedException($"Unsupported URI scheme: {scheme}"); + } + } + public static Uri ParseBoltUri(this Uri uri, int defaultPort) { var port = defaultPort;