Skip to content

Introducing protocol 4.4 and User Impersonation #784

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

Merged
merged 41 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bed090c
Introducing protocol 4.4 and User Impersonation
bigmontz Oct 7, 2021
2e1279b
Add protocol to the handshake
bigmontz Oct 7, 2021
376bcb5
Add new route message to the bolt protocol
bigmontz Oct 8, 2021
bfa4721
Implementing RUN and BEGIN messages with imp_user
bigmontz Oct 8, 2021
e0747d7
Add impersonatedUser o the driver surface
bigmontz Oct 8, 2021
d5bf0cc
adjusting routing message serialization
bigmontz Oct 8, 2021
14bd749
Resolve default dabase name
bigmontz Oct 8, 2021
0f5ac76
Add tests to the RoutingTableRaw implementation
bigmontz Oct 11, 2021
bf800dd
Enable tests for impersonation and v4.4
bigmontz Oct 11, 2021
7c316d3
Resolving home db during fetching the routing table
bigmontz Oct 11, 2021
643ee6f
Addapting connection-provider-routing tests to use impersonated user …
bigmontz Oct 12, 2021
7342a92
Expecting routing table for a given user
bigmontz Oct 12, 2021
ed6cf7b
Test home db name resolution
bigmontz Oct 12, 2021
6b7c9df
Fix a test which was not behaving well
bigmontz Oct 12, 2021
0b9fdc6
Fix strange identation
bigmontz Oct 12, 2021
9799ecf
Update packages/neo4j-driver/src/driver.js
bigmontz Oct 12, 2021
809e318
Update packages/neo4j-driver/test/internal/node/direct.driver.boltkit…
bigmontz Oct 12, 2021
48f8e7e
Update packages/core/src/transaction.ts
bigmontz Oct 12, 2021
4468716
Update packages/bolt-connection/src/bolt/request-message.js
bigmontz Oct 12, 2021
1cebdba
Update packages/bolt-connection/src/bolt/request-message.js
bigmontz Oct 12, 2021
ae5a8bf
Update packages/bolt-connection/src/bolt/request-message.js
bigmontz Oct 12, 2021
ec0afe7
Remove duplicated test
bigmontz Oct 12, 2021
ea50882
Update packages/bolt-connection/src/connection-provider/connection-pr…
bigmontz Oct 12, 2021
02ebea3
Update packages/bolt-connection/test/connection-provider/connection-p…
bigmontz Oct 12, 2021
f42def7
format
bigmontz Oct 12, 2021
838e452
format:
bigmontz Oct 12, 2021
ba60902
Update packages/bolt-connection/src/connection-provider/connection-pr…
bigmontz Oct 12, 2021
4cae8a9
Update packages/bolt-connection/test/connection-provider/connection-p…
bigmontz Oct 12, 2021
68e5576
Update packages/bolt-connection/src/bolt/create.js
bigmontz Oct 12, 2021
b1bccbb
Add test for the case the db name is not the default
bigmontz Oct 12, 2021
e034f9c
removing todo
bigmontz Oct 12, 2021
02008c4
Keep the resolved db name per session
bigmontz Oct 13, 2021
acf8584
Fix tests
bigmontz Oct 13, 2021
407452c
Fix lite driver test
bigmontz Oct 13, 2021
de13b02
Add test to cover the database name resolution
bigmontz Oct 13, 2021
a2c1c71
Throw error if the impersonated user is passed to the wrong protocol …
bigmontz Oct 14, 2021
df65fc0
fix imp user error message
bigmontz Oct 14, 2021
b9ba4f3
Addressing reviews comments
bigmontz Oct 14, 2021
15704e4
Update packages/bolt-connection/test/connection-provider/connection-p…
bigmontz Oct 14, 2021
fafc540
Update packages/bolt-connection/test/connection-provider/connection-p…
bigmontz Oct 14, 2021
3d95ca8
Update packages/bolt-connection/test/connection-provider/connection-p…
bigmontz Oct 14, 2021
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
23 changes: 22 additions & 1 deletion packages/bolt-connection/src/bolt/bolt-protocol-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,25 @@ function assertDatabaseIsEmpty (database, onProtocolError = () => {}, observer)
}
}

export { assertDatabaseIsEmpty, assertTxConfigIsEmpty }
/**
* Asserts that the passed-in impersonated user is empty
* @param {string} impersonatedUser
* @param {function (err:Error)} onProtocolError Called when it does have impersonated user set
* @param {any} observer
*/
function assertImpersonatedUserIsEmpty (impersonatedUser, onProtocolError = () => {}, observer) {
if (impersonatedUser) {
const error = newError(
'Driver is connected to the database that does not support user impersonation. ' +
'Please upgrade to neo4j 4.4.0 or later in order to use this functionality. ' +
`Trying to impersonate ${impersonatedUser}.`
)

// unsupported API was used, consider this a fatal error for the current connection
onProtocolError(error.message)
observer.onError(error)
throw error
}
}

export { assertDatabaseIsEmpty, assertTxConfigIsEmpty, assertImpersonatedUserIsEmpty }
10 changes: 9 additions & 1 deletion packages/bolt-connection/src/bolt/bolt-protocol-v1.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
*/
import {
assertDatabaseIsEmpty,
assertTxConfigIsEmpty
assertTxConfigIsEmpty,
assertImpersonatedUserIsEmpty
} from './bolt-protocol-util'
import { Chunker } from '../chunking'
import { v1 } from '../packstream'
Expand Down Expand Up @@ -143,6 +144,7 @@ export default class BoltProtocol {
* @param {TxConfig} param.txConfig the configuration.
* @param {string} param.database the target database name.
* @param {string} param.mode the access mode.
* @param {string} param.impersonatedUser the impersonated user
* @param {function(err: Error)} param.beforeError the callback to invoke before handling the error.
* @param {function(err: Error)} param.afterError the callback to invoke after handling the error.
* @param {function()} param.beforeComplete the callback to invoke before handling the completion.
Expand All @@ -154,6 +156,7 @@ export default class BoltProtocol {
txConfig,
database,
mode,
impersonatedUser,
beforeError,
afterError,
beforeComplete,
Expand All @@ -167,6 +170,7 @@ export default class BoltProtocol {
txConfig: txConfig,
database,
mode,
impersonatedUser,
beforeError,
afterError,
beforeComplete,
Expand Down Expand Up @@ -248,6 +252,7 @@ export default class BoltProtocol {
* @param {Bookmark} param.bookmark the bookmark.
* @param {TxConfig} param.txConfig the transaction configuration.
* @param {string} param.database the target database name.
* @param {string} param.impersonatedUser the impersonated user
* @param {string} param.mode the access mode.
* @param {function(keys: string[])} param.beforeKeys the callback to invoke before handling the keys.
* @param {function(keys: string[])} param.afterKeys the callback to invoke after handling the keys.
Expand All @@ -266,6 +271,7 @@ export default class BoltProtocol {
txConfig,
database,
mode,
impersonatedUser,
beforeKeys,
afterKeys,
beforeError,
Expand All @@ -289,6 +295,8 @@ export default class BoltProtocol {
assertTxConfigIsEmpty(txConfig, this._onProtocolError, observer)
// passing in a database name on this protocol version throws an error
assertDatabaseIsEmpty(database, this._onProtocolError, observer)
// passing impersonated user on this protocol version throws an error
assertImpersonatedUserIsEmpty(impersonatedUser, this._onProtocolError, observer)

this.write(RequestMessage.run(query, parameters), observer, false)
this.write(RequestMessage.pullAll(), observer, flush)
Expand Down
8 changes: 7 additions & 1 deletion packages/bolt-connection/src/bolt/bolt-protocol-v3.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
import BoltProtocolV2 from './bolt-protocol-v2'
import RequestMessage from './request-message'
import { assertDatabaseIsEmpty } from './bolt-protocol-util'
import { assertDatabaseIsEmpty, assertImpersonatedUserIsEmpty } from './bolt-protocol-util'
import {
StreamObserver,
LoginObserver,
Expand Down Expand Up @@ -78,6 +78,7 @@ export default class BoltProtocol extends BoltProtocolV2 {
bookmark,
txConfig,
database,
impersonatedUser,
mode,
beforeError,
afterError,
Expand All @@ -95,6 +96,8 @@ export default class BoltProtocol extends BoltProtocolV2 {

// passing in a database name on this protocol version throws an error
assertDatabaseIsEmpty(database, this._onProtocolError, observer)
// passing impersonated user on this protocol version throws an error
assertImpersonatedUserIsEmpty(impersonatedUser, this._onProtocolError, observer)

this.write(
RequestMessage.begin({ bookmark, txConfig, mode }),
Expand Down Expand Up @@ -152,6 +155,7 @@ export default class BoltProtocol extends BoltProtocolV2 {
bookmark,
txConfig,
database,
impersonatedUser,
mode,
beforeKeys,
afterKeys,
Expand All @@ -174,6 +178,8 @@ export default class BoltProtocol extends BoltProtocolV2 {

// passing in a database name on this protocol version throws an error
assertDatabaseIsEmpty(database, this._onProtocolError, observer)
// passing impersonated user on this protocol version throws an error
assertImpersonatedUserIsEmpty(impersonatedUser, this._onProtocolError, observer)

this.write(
RequestMessage.runWithMetadata(query, parameters, {
Expand Down
9 changes: 9 additions & 0 deletions packages/bolt-connection/src/bolt/bolt-protocol-v4x0.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
import BoltProtocolV3 from './bolt-protocol-v3'
import RequestMessage, { ALL } from './request-message'
import { assertImpersonatedUserIsEmpty } from './bolt-protocol-util'
import {
ResultStreamObserver,
ProcedureRouteObserver
Expand All @@ -44,6 +45,7 @@ export default class BoltProtocol extends BoltProtocolV3 {
bookmark,
txConfig,
database,
impersonatedUser,
mode,
beforeError,
afterError,
Expand All @@ -59,6 +61,9 @@ export default class BoltProtocol extends BoltProtocolV3 {
})
observer.prepareToHandleSingleResponse()

// passing impersonated user on this protocol version throws an error
assertImpersonatedUserIsEmpty(impersonatedUser, this._onProtocolError, observer)

this.write(
RequestMessage.begin({ bookmark, txConfig, database, mode }),
observer,
Expand All @@ -75,6 +80,7 @@ export default class BoltProtocol extends BoltProtocolV3 {
bookmark,
txConfig,
database,
impersonatedUser,
mode,
beforeKeys,
afterKeys,
Expand All @@ -101,6 +107,9 @@ export default class BoltProtocol extends BoltProtocolV3 {
afterComplete
})

// passing impersonated user on this protocol version throws an error
assertImpersonatedUserIsEmpty(impersonatedUser, this._onProtocolError, observer)

const flushRun = reactive
this.write(
RequestMessage.runWithMetadata(query, parameters, {
Expand Down
153 changes: 153 additions & 0 deletions packages/bolt-connection/src/bolt/bolt-protocol-v4x4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* Copyright (c) "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.
*/
import BoltProtocolV43 from './bolt-protocol-v4x3'

import { internal } from 'neo4j-driver-core'
import RequestMessage, { ALL } from './request-message'
import { RouteObserver, ResultStreamObserver } from './stream-observers'

const {
constants: { BOLT_PROTOCOL_V4_4 },
bookmark: { Bookmark },
} = internal

export default class BoltProtocol extends BoltProtocolV43 {
get version() {
return BOLT_PROTOCOL_V4_4
}

/**
* Request routing information
*
* @param {Object} param -
* @param {object} param.routingContext The routing context used to define the routing table.
* Multi-datacenter deployments is one of its use cases
* @param {string} param.databaseName The database name
* @param {Bookmark} params.sessionContext.bookmark The bookmark used for request the routing table
* @param {function(err: Error)} param.onError
* @param {function(RawRoutingTable)} param.onCompleted
* @returns {RouteObserver} the route observer
*/
requestRoutingInformation ({
routingContext = {},
databaseName = null,
impersonatedUser = null,
sessionContext = {},
onError,
onCompleted
}) {
const observer = new RouteObserver({
onProtocolError: this._onProtocolError,
onError,
onCompleted
})
const bookmark = sessionContext.bookmark || Bookmark.empty()
this.write(
RequestMessage.routeV4x4(routingContext, bookmark.values(), { databaseName, impersonatedUser }),
observer,
true
)

return observer
}

run (
query,
parameters,
{
bookmark,
txConfig,
database,
mode,
impersonatedUser,
beforeKeys,
afterKeys,
beforeError,
afterError,
beforeComplete,
afterComplete,
flush = true,
reactive = false,
fetchSize = ALL
} = {}
) {
const observer = new ResultStreamObserver({
server: this._server,
reactive: reactive,
fetchSize: fetchSize,
moreFunction: this._requestMore.bind(this),
discardFunction: this._requestDiscard.bind(this),
beforeKeys,
afterKeys,
beforeError,
afterError,
beforeComplete,
afterComplete
})

const flushRun = reactive
this.write(
RequestMessage.runWithMetadata(query, parameters, {
bookmark,
txConfig,
database,
mode,
impersonatedUser
}),
observer,
flushRun && flush
)

if (!reactive) {
this.write(RequestMessage.pull({ n: fetchSize }), observer, flush)
}

return observer
}

beginTransaction ({
bookmark,
txConfig,
database,
mode,
impersonatedUser,
beforeError,
afterError,
beforeComplete,
afterComplete
} = {}) {
const observer = new ResultStreamObserver({
server: this._server,
beforeError,
afterError,
beforeComplete,
afterComplete
})
observer.prepareToHandleSingleResponse()

this.write(
RequestMessage.begin({ bookmark, txConfig, database, mode, impersonatedUser }),
observer,
true
)

return observer
}

}
11 changes: 11 additions & 0 deletions packages/bolt-connection/src/bolt/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import BoltProtocolV4x0 from './bolt-protocol-v4x0'
import BoltProtocolV4x1 from './bolt-protocol-v4x1'
import BoltProtocolV4x2 from './bolt-protocol-v4x2'
import BoltProtocolV4x3 from './bolt-protocol-v4x3'
import BoltProtocolV4x4 from './bolt-protocol-v4x4'
import { Chunker, Dechunker } from '../channel'
import ResponseHandler from './response-handler'

Expand Down Expand Up @@ -164,6 +165,16 @@ function createProtocol (
onProtocolError,
serversideRouting
)
case 4.4:
return new BoltProtocolV4x4(
server,
chunker,
packingConfig,
createResponseHandler,
log,
onProtocolError,
serversideRouting
)
default:
throw newError('Unknown Bolt protocol version: ' + version)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/bolt-connection/src/bolt/handshake.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function parseNegotiatedResponse (buffer) {
*/
function newHandshakeBuffer () {
return createHandshakeMessage([
[version(4, 3), version(4, 2)],
[version(4, 4), version(4, 2)],
version(4, 1),
version(4, 0),
version(3, 0)
Expand Down
Loading