Skip to content

Commit 1ac0038

Browse files
authored
Merge pull request #216 from zhenlineo/1.0-permission-to-known-host-file
Added permission check to the known_host file
2 parents 42f7248 + 757ae3e commit 1ac0038

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

driver/src/main/java/org/neo4j/driver/internal/connector/socket/TrustOnFirstUseTrustManager.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
import java.security.cert.X509Certificate;
3131
import javax.net.ssl.X509TrustManager;
3232

33-
import org.neo4j.driver.v1.Logger;
3433
import org.neo4j.driver.internal.util.BytePrinter;
34+
import org.neo4j.driver.v1.Logger;
3535

36+
import static java.lang.String.format;
3637
import static org.neo4j.driver.internal.util.CertificateTool.X509CertToString;
3738

3839
/**
@@ -77,6 +78,8 @@ private void load() throws IOException
7778
return;
7879
}
7980

81+
assertKnownHostFileReadable();
82+
8083
BufferedReader reader = new BufferedReader( new FileReader( knownHosts ) );
8184
String line;
8285
while ( (line = reader.readLine()) != null )
@@ -107,12 +110,38 @@ private void saveTrustedHost( String fingerprint ) throws IOException
107110
logger.warn( "Adding %s as known and trusted certificate for %s.", fingerprint, serverId );
108111
createKnownCertFileIfNotExists();
109112

113+
assertKnownHostFileWritable();
110114
BufferedWriter writer = new BufferedWriter( new FileWriter( knownHosts, true ) );
111115
writer.write( serverId + " " + this.fingerprint );
112116
writer.newLine();
113117
writer.close();
114118
}
115119

120+
121+
private void assertKnownHostFileReadable() throws IOException
122+
{
123+
if( !knownHosts.canRead() )
124+
{
125+
throw new IOException( format(
126+
"Failed to load certificates from file %s as you have no read permissions to it.\n" +
127+
"Try configuring the Neo4j driver to use a file system location you do have read permissions to.",
128+
knownHosts.getAbsolutePath()
129+
) );
130+
}
131+
}
132+
133+
private void assertKnownHostFileWritable() throws IOException
134+
{
135+
if( !knownHosts.canWrite() )
136+
{
137+
throw new IOException( format(
138+
"Failed to write certificates to file %s as you have no write permissions to it.\n" +
139+
"Try configuring the Neo4j driver to use a file system location you do have write permissions to.",
140+
knownHosts.getAbsolutePath()
141+
) );
142+
}
143+
}
144+
116145
/*
117146
* Disallow all client connection to this client
118147
*/
@@ -140,7 +169,7 @@ public void checkServerTrusted( X509Certificate[] chain, String authType )
140169
}
141170
catch ( IOException e )
142171
{
143-
throw new CertificateException( String.format(
172+
throw new CertificateException( format(
144173
"Failed to save the server ID and the certificate received from the server to file %s.\n" +
145174
"Server ID: %s\nReceived cert:\n%s",
146175
knownHosts.getAbsolutePath(), serverId, X509CertToString( cert ) ), e );
@@ -150,7 +179,7 @@ public void checkServerTrusted( X509Certificate[] chain, String authType )
150179
{
151180
if ( !this.fingerprint.equals( cert ) )
152181
{
153-
throw new CertificateException( String.format(
182+
throw new CertificateException( format(
154183
"Unable to connect to neo4j at `%s`, because the certificate the server uses has changed. " +
155184
"This is a security feature to protect against man-in-the-middle attacks.\n" +
156185
"If you trust the certificate the server uses now, simply remove the line that starts with " +

driver/src/test/java/org/neo4j/driver/internal/connector/socket/TrustOnFirstUseTrustManagerTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,17 @@
2525
import org.junit.rules.TemporaryFolder;
2626

2727
import java.io.File;
28+
import java.io.IOException;
2829
import java.io.PrintWriter;
2930
import java.security.cert.CertificateException;
3031
import java.security.cert.X509Certificate;
3132
import java.util.Scanner;
3233

3334
import org.neo4j.driver.v1.Logger;
3435

36+
import static org.hamcrest.CoreMatchers.containsString;
3537
import static org.junit.Assert.assertEquals;
38+
import static org.junit.Assert.assertThat;
3639
import static org.junit.Assert.assertTrue;
3740
import static org.junit.Assert.fail;
3841
import static org.mockito.Mockito.mock;
@@ -141,4 +144,54 @@ private String nextLine( Scanner reader )
141144
while ( line.trim().startsWith( "#" ) );
142145
return line;
143146
}
147+
148+
@Test
149+
public void shouldThrowMeaningfulExceptionIfHasNoReadPermissionToKnownHostFile() throws Throwable
150+
{
151+
// Given
152+
File knownHostFile = mock( File.class );
153+
when( knownHostFile.canRead() ).thenReturn( false );
154+
when( knownHostFile.exists() ).thenReturn( true );
155+
156+
// When & Then
157+
try
158+
{
159+
new TrustOnFirstUseTrustManager( null, -1, knownHostFile, null );
160+
fail( "Should have failed in load certs" );
161+
}
162+
catch( IOException e )
163+
{
164+
assertThat( e.getMessage(), containsString( "you have no read permissions to it" ) );
165+
}
166+
catch( Exception e )
167+
{
168+
fail( "Should not get any other error besides no permission to read" );
169+
}
170+
}
171+
172+
@Test
173+
public void shouldThrowMeaningfulExceptionIfHasNoWritePermissionToKnownHostFile() throws Throwable
174+
{
175+
// Given
176+
File knownHostFile = mock( File.class );
177+
when( knownHostFile.exists() ).thenReturn( false /*skip reading*/, true );
178+
when( knownHostFile.canWrite() ).thenReturn( false );
179+
180+
// When & Then
181+
try
182+
{
183+
TrustOnFirstUseTrustManager manager =
184+
new TrustOnFirstUseTrustManager( null, -1, knownHostFile, mock( Logger.class ) );
185+
manager.checkServerTrusted( new X509Certificate[]{ knownCertificate}, null );
186+
fail( "Should have failed in write to certs" );
187+
}
188+
catch( CertificateException e )
189+
{
190+
assertThat( e.getCause().getMessage(), containsString( "you have no write permissions to it" ) );
191+
}
192+
catch( Exception e )
193+
{
194+
fail( "Should not get any other error besides no permission to write" );
195+
}
196+
}
144197
}

0 commit comments

Comments
 (0)