Skip to content

Commit 5af032c

Browse files
author
Peter Wilhelmsson
committed
Extend URI configuration with schemes for encryption/trust
Added support for: - bolt+s - bolt+ssc - neo4j+s - neo4j+ssc
1 parent f11494c commit 5af032c

File tree

4 files changed

+153
-6
lines changed

4 files changed

+153
-6
lines changed

src/driver.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
import Session from './session'
3232
import RxSession from './session-rx'
3333
import { ALL } from './internal/request-message'
34+
import { ENCRYPTION_ON, ENCRYPTION_OFF } from './internal/util'
3435

3536
const DEFAULT_MAX_CONNECTION_LIFETIME = 60 * 60 * 1000 // 1 hour
3637

@@ -136,6 +137,34 @@ class Driver {
136137
return connectionProvider.supportsTransactionConfig()
137138
}
138139

140+
/**
141+
* @protected
142+
* @returns {boolean}
143+
*/
144+
_supportsRouting () {
145+
return false
146+
}
147+
148+
/**
149+
* Returns boolean to indicate if driver has been configured with encryption enabled.
150+
*
151+
* @protected
152+
* @returns {boolean}
153+
*/
154+
_isEncrypted () {
155+
return this._config.encrypted === ENCRYPTION_ON
156+
}
157+
158+
/**
159+
* Returns the configured trust strategy that the driver has been configured with.
160+
*
161+
* @protected
162+
* @returns {TrustStrategy}
163+
*/
164+
_getTrust () {
165+
return this._config.trust
166+
}
167+
139168
/**
140169
* Acquire a session to communicate with the database. The session will
141170
* borrow connections from the underlying connection pool as required and

src/index.js

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ import Record from './record'
3737
import { Driver, READ, WRITE } from './driver'
3838
import RoutingDriver from './routing-driver'
3939
import VERSION from './version'
40-
import { assertString, isEmptyObjectOrNull } from './internal/util'
40+
import {
41+
ENCRYPTION_ON,
42+
ENCRYPTION_OFF,
43+
assertString,
44+
isEmptyObjectOrNull
45+
} from './internal/util'
4146
import urlUtil from './internal/url-util'
4247
import { isPoint, Point } from './spatial-types'
4348
import {
@@ -178,18 +183,63 @@ import ServerAddress from './internal/server-address'
178183
function driver (url, authToken, config = {}) {
179184
assertString(url, 'Bolt URL')
180185
const parsedUrl = urlUtil.parseDatabaseUrl(url)
181-
if (parsedUrl.scheme === 'neo4j') {
186+
187+
// Determine entryption/trust options from the URL.
188+
let routing = false
189+
let encrypted = false
190+
let trust = ''
191+
switch (parsedUrl.scheme) {
192+
case 'bolt':
193+
break
194+
case 'bolt+s':
195+
encrypted = true
196+
trust = 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
197+
break
198+
case 'bolt+ssc':
199+
encrypted = true
200+
trust = 'TRUST_ALL_CERTIFICATES'
201+
break
202+
case 'neo4j':
203+
routing = true
204+
break
205+
case 'neo4j+s':
206+
encrypted = true
207+
trust = 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
208+
routing = true
209+
break
210+
case 'neo4j+ssc':
211+
encrypted = true
212+
trust = 'TRUST_ALL_CERTIFICATES'
213+
routing = true
214+
break
215+
default:
216+
throw new Error(`Unknown scheme: ${parsedUrl.scheme}`)
217+
}
218+
219+
// Encryption enabled on URL, propagate trust to the config.
220+
if (encrypted) {
221+
// Check for configuration conflict between URL and config.
222+
if ('encrypted' in config || 'trust' in config) {
223+
throw new Error(
224+
'Encryption/trust can only be configured either through URL or config, not both'
225+
)
226+
}
227+
config.encrypted = ENCRYPTION_ON
228+
config.trust = trust
229+
}
230+
231+
if (routing) {
182232
return new RoutingDriver(
183233
ServerAddress.fromUrl(parsedUrl.hostAndPort),
184234
parsedUrl.query,
185235
USER_AGENT,
186236
authToken,
187237
config
188238
)
189-
} else if (parsedUrl.scheme === 'bolt') {
239+
} else {
190240
if (!isEmptyObjectOrNull(parsedUrl.query)) {
191241
throw new Error(
192-
`Parameters are not supported with scheme 'bolt'. Given URL: '${url}'`
242+
`Parameters are not supported with none routed scheme. Given URL: '${url}'`
193243
)
194244
}
195245
return new Driver(
@@ -198,8 +248,6 @@ function driver (url, authToken, config = {}) {
198248
authToken,
199249
config
200250
)
201-
} else {
202-
throw new Error(`Unknown scheme: ${parsedUrl.scheme}`)
203251
}
204252
}
205253

src/routing-driver.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ class RoutingDriver extends Driver {
5252
authToken: authToken
5353
})
5454
}
55+
56+
_supportsRouting () {
57+
return true
58+
}
5559
}
5660

5761
/**

test/driver.test.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,72 @@ import {
2727
import { ServerVersion, VERSION_4_0_0 } from '../src/internal/server-version'
2828
import testUtils from './internal/test-utils'
2929

30+
// As long as driver creation doesn't touch the network it's fine to run
31+
// this as a unit test.
32+
describe('#unit driver', () => {
33+
let driver
34+
35+
afterEach(async () => {
36+
if (driver) {
37+
await driver.close()
38+
}
39+
})
40+
41+
it('should create an unencrypted, non-routed driver for scheme: bolt', () => {
42+
driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken)
43+
expect(driver._isEncrypted()).toBeFalsy()
44+
expect(driver._supportsRouting()).toBeFalsy()
45+
})
46+
47+
it('should create an encrypted, system CAs trusting, non-routed driver for scheme: bolt+s', () => {
48+
driver = neo4j.driver('bolt+s://localhost', sharedNeo4j.authToken)
49+
expect(driver._isEncrypted()).toBeTruthy()
50+
expect(driver._getTrust()).toEqual('TRUST_SYSTEM_CA_SIGNED_CERTIFICATES')
51+
expect(driver._supportsRouting()).toBeFalsy()
52+
})
53+
54+
it('should create an encrypted, all trusting, non-routed driver for scheme: bolt+ssc', () => {
55+
driver = neo4j.driver('bolt+ssc://localhost', sharedNeo4j.authToken)
56+
expect(driver._isEncrypted()).toBeTruthy()
57+
expect(driver._getTrust()).toEqual('TRUST_ALL_CERTIFICATES')
58+
expect(driver._supportsRouting()).toBeFalsy()
59+
})
60+
61+
it('should create an unencrypted, routed driver for scheme: neo4j', () => {
62+
driver = neo4j.driver('neo4j://localhost', sharedNeo4j.authToken)
63+
expect(driver._isEncrypted()).toBeFalsy()
64+
expect(driver._supportsRouting()).toBeTruthy()
65+
})
66+
67+
it('should create an encrypted, system CAs trusting, routed driver for scheme: neo4j+s', () => {
68+
driver = neo4j.driver('neo4j+s://localhost', sharedNeo4j.authToken)
69+
expect(driver._isEncrypted()).toBeTruthy()
70+
expect(driver._getTrust()).toEqual('TRUST_SYSTEM_CA_SIGNED_CERTIFICATES')
71+
expect(driver._supportsRouting()).toBeTruthy()
72+
})
73+
74+
it('should create an encrypted, all trusting, routed driver for scheme: neo4j+ssc', () => {
75+
driver = neo4j.driver('neo4j+ssc://localhost', sharedNeo4j.authToken)
76+
expect(driver._isEncrypted()).toBeTruthy()
77+
expect(driver._getTrust()).toEqual('TRUST_ALL_CERTIFICATES')
78+
expect(driver._supportsRouting()).toBeTruthy()
79+
})
80+
81+
it('should throw when encryption in url AND in config', () => {
82+
expect(() =>
83+
neo4j.driver('neo4j+ssc://localhost', sharedNeo4j.authToken, {
84+
encrypted: 'ENCRYPTION_OFF'
85+
})
86+
).toThrow()
87+
// Throw even in case where there is no conflict
88+
expect(() =>
89+
neo4j.driver('neo4j+s://localhost', sharedNeo4j.authToken, {
90+
encrypted: 'ENCRYPTION_ON'
91+
})
92+
).toThrow()
93+
})
94+
})
95+
3096
describe('#integration driver', () => {
3197
let driver
3298
let serverVersion

0 commit comments

Comments
 (0)