Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added EncryptionLevel.REQUIRED_NON_LOCAL #191

Merged
merged 8 commits into from
Jul 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
import org.neo4j.driver.v1.exceptions.ClientException;
import org.neo4j.driver.v1.exceptions.Neo4jException;

import static org.neo4j.driver.internal.util.AddressUtil.isLocalHost;
import static org.neo4j.driver.v1.Config.EncryptionLevel.REQUIRED;
import static org.neo4j.driver.v1.Config.EncryptionLevel.REQUIRED_NON_LOCAL;

public class InternalDriver implements Driver
{
private final ConnectionPool connections;
Expand All @@ -42,6 +46,15 @@ public InternalDriver( URI url, AuthToken authToken, Config config )
this.config = config;
}

@Override
public boolean isEncrypted()
{

Config.EncryptionLevel encryptionLevel = config.encryptionLevel();
return encryptionLevel.equals( REQUIRED ) ||
( encryptionLevel.equals( REQUIRED_NON_LOCAL ) && !isLocalHost( url.getHost() ) );
}

/**
* Establish a session
* @return a session that could be used to run {@link Session#run(String) a statement} or
Expand All @@ -63,7 +76,7 @@ public void close() throws Neo4jException
{
connections.close();
}
catch( Exception e )
catch ( Exception e )
{
throw new ClientException( "Failed to close driver.", e );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import static java.nio.ByteOrder.BIG_ENDIAN;
import static org.neo4j.driver.internal.connector.socket.SocketUtils.blockingRead;
import static org.neo4j.driver.internal.connector.socket.SocketUtils.blockingWrite;
import static org.neo4j.driver.internal.util.AddressUtil.isLocalHost;

public class SocketClient
{
Expand Down Expand Up @@ -235,6 +236,18 @@ public static ByteChannel create( String host, int port, Config config, Logger l
channel = new TLSSocketChannel( host, port, soChannel, logger, config.trustStrategy() );
break;
}
case REQUIRED_NON_LOCAL:
{
if ( isLocalHost( host ) )
{
channel = soChannel;
}
else
{
channel = new TLSSocketChannel( host, port, soChannel, logger, config.trustStrategy() );
}
break;
}
case NONE:
{
channel = soChannel;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.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.
*/

package org.neo4j.driver.internal.util;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class AddressUtil
{
/**
* Return true if the host provided matches "localhost" or "127.x.x.x".
*
* @param host the host name to test
* @return true if localhost, false otherwise
*/
public static boolean isLocalHost( String host )
{
try
{
// confirmed to work as desired with both "localhost" and "127.x.x.x"
return InetAddress.getByName( host ).isLoopbackAddress();
}
catch ( UnknownHostException e )
{
// if it's unknown, it's not local so we can safely return false
return false;
}
}

}
10 changes: 7 additions & 3 deletions driver/src/main/java/org/neo4j/driver/v1/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private Config( ConfigBuilder builder )
this.connectionPoolSize = builder.connectionPoolSize;
this.idleTimeBeforeConnectionTest = builder.idleTimeBeforeConnectionTest;

this.encryptionLevel = builder.encruptionLevel;
this.encryptionLevel = builder.encryptionLevel;
this.trustStrategy = builder.trustStrategy;
}

Expand Down Expand Up @@ -140,7 +140,7 @@ public static class ConfigBuilder
private Logging logging = new JULogging( Level.INFO );
private int connectionPoolSize = 50;
private long idleTimeBeforeConnectionTest = 200;
private EncryptionLevel encruptionLevel = EncryptionLevel.REQUIRED;
private EncryptionLevel encryptionLevel = EncryptionLevel.REQUIRED_NON_LOCAL;
private TrustStrategy trustStrategy = trustOnFirstUse(
new File( getProperty( "user.home" ), ".neo4j" + File.separator + "known_hosts" ) );

Expand Down Expand Up @@ -208,7 +208,7 @@ public ConfigBuilder withSessionLivenessCheckTimeout( long timeout )
*/
public ConfigBuilder withEncryptionLevel( EncryptionLevel level )
{
this.encruptionLevel = level;
this.encryptionLevel = level;
return this;
}

Expand Down Expand Up @@ -250,6 +250,10 @@ public enum EncryptionLevel
/** With this level, the driver will only connect to the server if it can do it without encryption. */
NONE,

/** With this level, the driver will only connect to the server without encryption if local but with
* encryption otherwise. */
REQUIRED_NON_LOCAL,

/** With this level, the driver will only connect to the server it if can do it with encryption. */
REQUIRED
}
Expand Down
6 changes: 6 additions & 0 deletions driver/src/main/java/org/neo4j/driver/v1/Driver.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.net.URI;

import org.neo4j.driver.v1.Config.EncryptionLevel;
import org.neo4j.driver.v1.exceptions.Neo4jException;

/**
Expand Down Expand Up @@ -71,6 +72,11 @@
*/
public interface Driver extends AutoCloseable
{
/**
* Return a flag to indicate whether or not encryption is used for this driver.
*/
boolean isEncrypted();

/**
* Establish a session
* @return a session that could be used to run {@link Session#run(String) a statement} or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.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.
*/
package org.neo4j.driver.internal.util;

import org.junit.Test;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
import static org.neo4j.driver.internal.util.AddressUtil.isLocalHost;

public class AddressUtilTest
{
@Test
public void shouldWorkForVariantsOfLocalHost() throws Exception
{
assertThat( isLocalHost( "localhost" ), equalTo( true ) );
assertThat( isLocalHost( "LocalHost" ), equalTo( true ) );
assertThat( isLocalHost( "LOCALHOST" ), equalTo( true ) );
assertThat( isLocalHost( "127.0.0.1" ), equalTo( true ) );
assertThat( isLocalHost( "127.5.6.7" ), equalTo( true ) );
assertThat( isLocalHost( "x" ), equalTo( false ) );
}

}
107 changes: 107 additions & 0 deletions driver/src/test/java/org/neo4j/driver/v1/integration/EncryptionIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.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.
*/
package org.neo4j.driver.v1.integration;

import org.junit.Rule;
import org.junit.Test;
import org.neo4j.driver.v1.*;
import org.neo4j.driver.v1.util.TestNeo4j;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.neo4j.driver.internal.util.AddressUtil.isLocalHost;
import static org.neo4j.driver.v1.Config.EncryptionLevel.NONE;
import static org.neo4j.driver.v1.Config.EncryptionLevel.REQUIRED;
import static org.neo4j.driver.v1.Config.EncryptionLevel.REQUIRED_NON_LOCAL;

public class EncryptionIT
{
@Rule
public TestNeo4j neo4j = new TestNeo4j();

@Test
public void shouldOperateWithNoEncryption() throws Exception
{
// Given
Driver driver = GraphDatabase.driver( neo4j.address(), Config.build().withEncryptionLevel( NONE ).toConfig() );

// Then
assertThat( driver.isEncrypted(), equalTo( false ) );

// When
Session session = driver.session();
StatementResult result = session.run( "RETURN 1" );

// Then
Record record = result.next();
int value = record.get( 0 ).asInt();
assertThat( value, equalTo( 1 ) );

// Finally
session.close();
driver.close();
}

@Test
public void shouldOperateWithRequiredNonLocalEncryption() throws Exception
{
// Given
Driver driver = GraphDatabase.driver( neo4j.address(), Config.build().withEncryptionLevel( REQUIRED_NON_LOCAL ).toConfig() );

// Then
assertThat( driver.isEncrypted(), equalTo( !isLocalHost( neo4j.host() ) ) );

// When
Session session = driver.session();
StatementResult result = session.run( "RETURN 1" );

// Then
Record record = result.next();
int value = record.get( 0 ).asInt();
assertThat( value, equalTo( 1 ) );

// Finally
session.close();
driver.close();
}

@Test
public void shouldOperateWithRequiredEncryption() throws Exception
{
// Given
Driver driver = GraphDatabase.driver( neo4j.address(), Config.build().withEncryptionLevel( REQUIRED ).toConfig() );

// Then
assertThat( driver.isEncrypted(), equalTo( true ) );

// When
Session session = driver.session();
StatementResult result = session.run( "RETURN 1" );

// Then
Record record = result.next();
int value = record.get( 0 ).asInt();
assertThat( value, equalTo( 1 ) );

// Finally
session.close();
driver.close();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public class Neo4jRunner

public static final String NEORUN_START_ARGS = System.getProperty( "neorun.start.args" );
public static final String DEFAULT_URL = "bolt://localhost:7687";
private static final Config TEST_CONFIG = Config.build().withEncryptionLevel( Config.EncryptionLevel.NONE ).toConfig();
private Driver driver;
private Neo4jSettings currentSettings = Neo4jSettings.DEFAULT_SETTINGS;

Expand Down Expand Up @@ -106,7 +105,7 @@ private void startNeo4j() throws IOException
{
throw new IOException( "Failed to start neo4j server." );
}
driver = GraphDatabase.driver( DEFAULT_URL, TEST_CONFIG );
driver = GraphDatabase.driver( DEFAULT_URL /* default encryption REQUIRED_NON_LOCAL */ );
}

public synchronized void stopNeo4j() throws IOException
Expand Down
6 changes: 6 additions & 0 deletions driver/src/test/java/org/neo4j/driver/v1/util/TestNeo4j.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URL;

import org.neo4j.driver.v1.Driver;
Expand Down Expand Up @@ -95,6 +96,11 @@ public String address()
return Neo4jRunner.DEFAULT_URL;
}

public String host()
{
return URI.create( Neo4jRunner.DEFAULT_URL ).getHost();
}

static void clearDatabaseContents( Session session, String reason )
{
Neo4jRunner.debug( "Clearing database contents for: %s", reason );
Expand Down