Skip to content

Commit fe04cec

Browse files
committed
Auth
1 parent c7b1987 commit fe04cec

File tree

127 files changed

+3550
-358
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+3550
-358
lines changed

driver/clirr-ignored-differences.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,4 +433,16 @@
433433
<method>org.neo4j.driver.BookmarkManager queryTaskBookmarkManager()</method>
434434
</difference>
435435

436+
<difference>
437+
<className>org/neo4j/driver/Driver</className>
438+
<differenceType>7012</differenceType>
439+
<method>org.neo4j.driver.BaseSession session(java.lang.Class, org.neo4j.driver.AuthToken)</method>
440+
</difference>
441+
442+
<difference>
443+
<className>org/neo4j/driver/Driver</className>
444+
<differenceType>7012</differenceType>
445+
<method>org.neo4j.driver.BaseSession session(java.lang.Class, org.neo4j.driver.SessionConfig, org.neo4j.driver.AuthToken)</method>
446+
</difference>
447+
436448
</differences>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver;
20+
21+
import java.util.concurrent.CompletionStage;
22+
23+
/**
24+
* An {@link AuthToken} manager used by the driver.
25+
* <p>
26+
* Implementations should supply the same token unless it needs to be updated as a change of token might result in extra
27+
* processing by the driver.
28+
* <p>
29+
* Driver initializes new connections with a token supplied by the manager. If token changes, driver action depends on
30+
* connection Bolt protocol version:
31+
* <ul>
32+
* <li>Bolt 5.1 or above - {@code LOGOFF} and {@code LOGON} messages are dispatched to update the token</li>
33+
* <li>Bolt 5.0 or below - connection is closed an a new one is initialized with the new token</li>
34+
* </ul>
35+
* <p>
36+
* All implementations of this interface must be non-blocking for caller threads.
37+
* @since 5.6
38+
*/
39+
public interface AuthTokenManager {
40+
/**
41+
* Returns a {@link CompletionStage} for a valid {@link AuthToken}.
42+
* <p>
43+
* Driver invokes this method often to check if token changed.
44+
* @return a stage for a valid token
45+
*/
46+
CompletionStage<AuthToken> getToken();
47+
48+
/**
49+
* Handles an error notification emitted by the server of the token is expired.
50+
* <p>
51+
* This will be called when driver throws {@link org.neo4j.driver.exceptions.TokenExpiredException}.
52+
*
53+
* @param authToken the token
54+
*/
55+
void onExpired(AuthToken authToken);
56+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver;
20+
21+
import java.time.Clock;
22+
import java.util.concurrent.CompletableFuture;
23+
import java.util.concurrent.CompletionStage;
24+
import java.util.concurrent.Flow;
25+
import java.util.concurrent.ForkJoinPool;
26+
import java.util.function.Supplier;
27+
import org.neo4j.driver.internal.reactive.TemporalAuthDataSupplier;
28+
import org.neo4j.driver.internal.security.TemporalAuthTokenManager;
29+
import org.reactivestreams.FlowAdapters;
30+
import org.reactivestreams.Publisher;
31+
32+
/**
33+
* Implementations of {@link AuthTokenManager}.
34+
* @since 5.6
35+
*/
36+
public final class AuthTokenManagers {
37+
private AuthTokenManagers() {}
38+
39+
/**
40+
* Returns a temporal {@link AuthTokenManager} implementation that manages {@link AuthToken} instances with UTC
41+
* expiration timestamp.
42+
* <p>
43+
* The implementation will only use the token supplier when it needs a new token instance in the following
44+
* situations:
45+
* <ol>
46+
* <li>token's UTC timestamp is expired</li>
47+
* <li>server rejects the token (see {@link AuthTokenManager#onExpired(AuthToken)})</li>
48+
* </ol>
49+
* <p>
50+
* The supplier will be called by a task running in the {@link ForkJoinPool#commonPool()} as documented in the
51+
* {@link CompletableFuture#supplyAsync(Supplier)}.
52+
*
53+
* @param freshTokenSupplier a new token supplier
54+
* @return a new token manager
55+
*/
56+
public static AuthTokenManager temporal(Supplier<TemporalAuthData> freshTokenSupplier) {
57+
return new TemporalAuthTokenManager(() -> CompletableFuture.supplyAsync(freshTokenSupplier), Clock.systemUTC());
58+
}
59+
60+
/**
61+
* Returns a temporal {@link AuthTokenManager} implementation that manages {@link AuthToken} instances with UTC
62+
* expiration timestamp.
63+
* <p>
64+
* The implementation will only use the token supplier when it needs a new token instance in the following
65+
* situations:
66+
* <ol>
67+
* <li>token's UTC timestamp is expired</li>
68+
* <li>server rejects the token (see {@link AuthTokenManager#onExpired(AuthToken)})</li>
69+
* </ol>
70+
* <p>
71+
* The provided supplier and its completion stages must be non-blocking as documented in the {@link AuthTokenManager}.
72+
*
73+
* @param freshTokenSupplier a new token supplier
74+
* @return a new token manager
75+
*/
76+
public static AuthTokenManager temporalAsync(Supplier<CompletionStage<TemporalAuthData>> freshTokenSupplier) {
77+
return new TemporalAuthTokenManager(freshTokenSupplier, Clock.systemUTC());
78+
}
79+
80+
/**
81+
* Returns a temporal {@link AuthTokenManager} implementation that manages {@link AuthToken} instances with UTC
82+
* expiration timestamp.
83+
* <p>
84+
* The implementation will only use the token publisher when it needs a new token instance in the following
85+
* situations:
86+
* <ol>
87+
* <li>token's UTC timestamp is expired</li>
88+
* <li>server rejects the token (see {@link AuthTokenManager#onExpired(AuthToken)})</li>
89+
* </ol>
90+
* @param freshTokenPublisher a new token publisher
91+
* @return a new token manager
92+
*/
93+
public static AuthTokenManager temporalFlow(Flow.Publisher<TemporalAuthData> freshTokenPublisher) {
94+
return new TemporalAuthTokenManager(
95+
new TemporalAuthDataSupplier(FlowAdapters.toPublisher(freshTokenPublisher)), Clock.systemUTC());
96+
}
97+
98+
/**
99+
* Returns a temporal {@link AuthTokenManager} implementation that manages {@link AuthToken} instances with UTC
100+
* expiration timestamp.
101+
* <p>
102+
* The implementation will only use the token publisher when it needs a new token instance in the following
103+
* situations:
104+
* <ol>
105+
* <li>token's UTC timestamp is expired</li>
106+
* <li>server rejects the token (see {@link AuthTokenManager#onExpired(AuthToken)})</li>
107+
* </ol>
108+
* @param freshTokenPublisher a new token publisher
109+
* @return a new token manager
110+
*/
111+
public static AuthTokenManager temporalReactiveStreams(Publisher<TemporalAuthData> freshTokenPublisher) {
112+
return new TemporalAuthTokenManager(new TemporalAuthDataSupplier(freshTokenPublisher), Clock.systemUTC());
113+
}
114+
115+
/**
116+
* A container used by the temporal {@link AuthTokenManager} implementation provided by the driver, it contains an
117+
* {@link AuthToken} and expiration timestamp.
118+
*/
119+
public interface TemporalAuthData {
120+
/**
121+
* Returns an instance with provided token and {@link Long#MAX_VALUE} expiration timestamp.
122+
* @param authToken token
123+
* @return a new instance
124+
*/
125+
static TemporalAuthData of(AuthToken authToken) {
126+
return of(authToken, Long.MAX_VALUE);
127+
}
128+
129+
/**
130+
* Returns an instance with provided token and expiration timestamp.
131+
* @param authToken token
132+
* @param expirationTimestamp expiration timestamp
133+
* @return a new instance
134+
*/
135+
static TemporalAuthData of(AuthToken authToken, long expirationTimestamp) {
136+
return new TemporalAuthTokenManager.InternalTemporalAuthData(authToken, expirationTimestamp);
137+
}
138+
139+
/**
140+
* Returns an {@link AuthToken}.
141+
*
142+
* @return token
143+
*/
144+
AuthToken authToken();
145+
146+
/**
147+
* Returns token's UTC expiration timestamp.
148+
*
149+
* @return token's UTC expiration timestamp
150+
*/
151+
long expirationTimestamp();
152+
}
153+
}

driver/src/main/java/org/neo4j/driver/Driver.java

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,38 @@ default <T extends BaseSession> T session(Class<T> sessionClass) {
144144
return session(sessionClass, SessionConfig.defaultConfig());
145145
}
146146

147+
/**
148+
* Instantiate a new session of supported type with default {@link SessionConfig session configuration} and provided {@link AuthToken}.
149+
* <p>
150+
* Supported types are:
151+
* <ul>
152+
* <li>{@link org.neo4j.driver.Session} - synchronous session</li>
153+
* <li>{@link org.neo4j.driver.async.AsyncSession} - asynchronous session</li>
154+
* <li>{@link org.neo4j.driver.reactive.ReactiveSession} - reactive session using Flow API</li>
155+
* <li>{@link org.neo4j.driver.reactivestreams.ReactiveSession} - reactive session using Reactive Streams
156+
* API</li>
157+
* <li>{@link org.neo4j.driver.reactive.RxSession} - deprecated reactive session using Reactive Streams
158+
* API, superseded by {@link org.neo4j.driver.reactivestreams.ReactiveSession}</li>
159+
* </ul>
160+
* <p>
161+
* Sample usage:
162+
* <pre>
163+
* {@code
164+
* var session = driver.session(AsyncSession.class);
165+
* }
166+
* </pre>
167+
*
168+
* @param sessionClass session type class, must not be null
169+
* @param authToken a token, null will result in driver-level configuration being used
170+
* @return session instance
171+
* @param <T> session type
172+
* @throws IllegalArgumentException for unsupported session types
173+
* @since 5.6
174+
*/
175+
default <T extends BaseSession> T session(Class<T> sessionClass, AuthToken authToken) {
176+
return session(sessionClass, SessionConfig.defaultConfig(), authToken);
177+
}
178+
147179
/**
148180
* Create a new session of supported type with a specified {@link SessionConfig session configuration}.
149181
* <p>
@@ -172,7 +204,40 @@ default <T extends BaseSession> T session(Class<T> sessionClass) {
172204
* @throws IllegalArgumentException for unsupported session types
173205
* @since 5.2
174206
*/
175-
<T extends BaseSession> T session(Class<T> sessionClass, SessionConfig sessionConfig);
207+
default <T extends BaseSession> T session(Class<T> sessionClass, SessionConfig sessionConfig) {
208+
return session(sessionClass, sessionConfig, null);
209+
}
210+
211+
/**
212+
* Instantiate a new session of supported type with a specified {@link SessionConfig session configuration} and provided {@link AuthToken}.
213+
* <p>
214+
* Supported types are:
215+
* <ul>
216+
* <li>{@link org.neo4j.driver.Session} - synchronous session</li>
217+
* <li>{@link org.neo4j.driver.async.AsyncSession} - asynchronous session</li>
218+
* <li>{@link org.neo4j.driver.reactive.ReactiveSession} - reactive session using Flow API</li>
219+
* <li>{@link org.neo4j.driver.reactivestreams.ReactiveSession} - reactive session using Reactive Streams
220+
* API</li>
221+
* <li>{@link org.neo4j.driver.reactive.RxSession} - deprecated reactive session using Reactive Streams
222+
* API, superseded by {@link org.neo4j.driver.reactivestreams.ReactiveSession}</li>
223+
* </ul>
224+
* <p>
225+
* Sample usage:
226+
* <pre>
227+
* {@code
228+
* var session = driver.session(AsyncSession.class);
229+
* }
230+
* </pre>
231+
*
232+
* @param sessionClass session type class, must not be null
233+
* @param sessionConfig session config, must not be null
234+
* @param authToken a token, null will result in driver-level configuration being used
235+
* @return session instance
236+
* @param <T> session type
237+
* @throws IllegalArgumentException for unsupported session types
238+
* @since 5.6
239+
*/
240+
<T extends BaseSession> T session(Class<T> sessionClass, SessionConfig sessionConfig, AuthToken authToken);
176241

177242
/**
178243
* Create a new general purpose {@link RxSession} with default {@link SessionConfig session configuration}. The {@link RxSession} provides a reactive way to

driver/src/main/java/org/neo4j/driver/GraphDatabase.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
*/
1919
package org.neo4j.driver;
2020

21+
import static java.util.Objects.requireNonNull;
22+
import static org.neo4j.driver.internal.security.AuthTokenUtil.requireValidAuthToken;
23+
2124
import java.net.URI;
2225
import org.neo4j.driver.internal.DriverFactory;
26+
import org.neo4j.driver.internal.security.StaticAuthTokenManager;
27+
import org.neo4j.driver.internal.security.VerifyingAuthTokenManager;
2328

2429
/**
2530
* Creates {@link Driver drivers}, optionally letting you {@link #driver(URI, Config)} to configure them.
@@ -114,12 +119,56 @@ public static Driver driver(String uri, AuthToken authToken, Config config) {
114119
* @return a new driver to the database instance specified by the URL
115120
*/
116121
public static Driver driver(URI uri, AuthToken authToken, Config config) {
117-
return driver(uri, authToken, config, new DriverFactory());
122+
if (authToken == null) {
123+
authToken = AuthTokens.none();
124+
}
125+
requireValidAuthToken(authToken);
126+
return driver(uri, new StaticAuthTokenManager(authToken), config, new DriverFactory());
127+
}
128+
129+
/**
130+
* Return a driver for a Neo4j instance with the default configuration settings
131+
*
132+
* @param uri the URL to a Neo4j instance
133+
* @param authTokenManager manager to use
134+
* @return a new driver to the database instance specified by the URL
135+
* @since 5.6
136+
*/
137+
public static Driver driver(URI uri, AuthTokenManager authTokenManager) {
138+
return driver(uri, authTokenManager, Config.defaultConfig());
139+
}
140+
141+
/**
142+
* Return a driver for a Neo4j instance with custom configuration.
143+
*
144+
* @param uri the URL to a Neo4j instance
145+
* @param authTokenManager manager to use
146+
* @param config user defined configuration
147+
* @return a new driver to the database instance specified by the URL
148+
* @since 5.6
149+
*/
150+
public static Driver driver(String uri, AuthTokenManager authTokenManager, Config config) {
151+
return driver(URI.create(uri), authTokenManager, config);
152+
}
153+
154+
/**
155+
* Return a driver for a Neo4j instance with custom configuration.
156+
*
157+
* @param uri the URL to a Neo4j instance
158+
* @param authTokenManager manager to use
159+
* @param config user defined configuration
160+
* @return a new driver to the database instance specified by the URL
161+
* @since 5.6
162+
*/
163+
public static Driver driver(URI uri, AuthTokenManager authTokenManager, Config config) {
164+
return driver(uri, authTokenManager, config, new DriverFactory());
118165
}
119166

120-
static Driver driver(URI uri, AuthToken authToken, Config config, DriverFactory driverFactory) {
167+
private static Driver driver(
168+
URI uri, AuthTokenManager authTokenManager, Config config, DriverFactory driverFactory) {
169+
requireNonNull(authTokenManager, "authTokenManager must not be null");
121170
config = getOrDefault(config);
122-
return driverFactory.newInstance(uri, authToken, config);
171+
return driverFactory.newInstance(uri, new VerifyingAuthTokenManager(authTokenManager), config);
123172
}
124173

125174
private static Config getOrDefault(Config config) {

0 commit comments

Comments
 (0)