@@ -72,17 +72,18 @@ private static void checkFeatureSyncServerAvailable() {
72
72
* Use {@link Sync#server(BoxStore, String, SyncCredentials)} instead.
73
73
*/
74
74
@ Internal
75
- public SyncServerBuilder (BoxStore boxStore , String url , @ Nullable SyncCredentials authenticatorCredentials ) {
75
+ public SyncServerBuilder (BoxStore boxStore , String url , SyncCredentials authenticatorCredentials ) {
76
76
checkNotNull (boxStore , "BoxStore is required." );
77
77
checkNotNull (url , "Sync server URL is required." );
78
+ checkNotNull (authenticatorCredentials , "Authenticator credentials are required." );
78
79
checkFeatureSyncServerAvailable ();
79
80
this .boxStore = boxStore ;
80
81
try {
81
82
this .url = new URI (url );
82
83
} catch (URISyntaxException e ) {
83
84
throw new IllegalArgumentException ("Sync server URL is invalid: " + url , e );
84
85
}
85
- authenticatorCredentialsOrNull (authenticatorCredentials );
86
+ authenticatorCredentials (authenticatorCredentials );
86
87
}
87
88
88
89
/**
@@ -100,7 +101,9 @@ public SyncServerBuilder(BoxStore boxStore, String url, SyncCredentials[] multip
100
101
} catch (URISyntaxException e ) {
101
102
throw new IllegalArgumentException ("Sync server URL is invalid: " + url , e );
102
103
}
103
- authenticatorCredentials (multipleAuthenticatorCredentials );
104
+ for (SyncCredentials credentials : multipleAuthenticatorCredentials ) {
105
+ authenticatorCredentials (credentials );
106
+ }
104
107
}
105
108
106
109
/**
@@ -115,48 +118,39 @@ public SyncServerBuilder certificatePath(String certificatePath) {
115
118
return this ;
116
119
}
117
120
118
- private SyncServerBuilder authenticatorCredentialsOrNull (@ Nullable SyncCredentials authenticatorCredentials ) {
119
- if (authenticatorCredentials == null ) {
120
- return this ; // Do nothing
121
- }
122
- if (!(authenticatorCredentials instanceof SyncCredentialsToken )) {
123
- throw new IllegalArgumentException ("Sync credentials of type " + authenticatorCredentials .getType ()
124
- + " are not supported" );
125
- }
126
- credentials .add ((SyncCredentialsToken ) authenticatorCredentials );
127
- return this ;
128
- }
129
-
130
121
/**
131
122
* Adds additional authenticator credentials to authenticate clients or peers with.
132
123
* <p>
133
- * For the embedded server, currently only {@link SyncCredentials#sharedSecret} and {@link SyncCredentials#none}
134
- * are supported.
124
+ * For the embedded server, currently only {@link SyncCredentials#sharedSecret}, any JWT method like
125
+ * {@link SyncCredentials#jwtIdTokenServer()} as well as {@link SyncCredentials#none} are supported.
135
126
*/
136
127
public SyncServerBuilder authenticatorCredentials (SyncCredentials authenticatorCredentials ) {
137
128
checkNotNull (authenticatorCredentials , "Authenticator credentials must not be null." );
138
- return authenticatorCredentialsOrNull (authenticatorCredentials );
139
- }
140
-
141
- /**
142
- * Adds additional authenticator credentials to authenticate clients or peers with.
143
- * <p>
144
- * For the embedded server, currently only {@link SyncCredentials#sharedSecret} and {@link SyncCredentials#none}
145
- * are supported.
146
- */
147
- public SyncServerBuilder authenticatorCredentials (SyncCredentials [] multipleAuthenticatorCredentials ) {
148
- checkNotNull (multipleAuthenticatorCredentials , "Authenticator credentials must not be null." );
149
- for (SyncCredentials credentials : multipleAuthenticatorCredentials ) {
150
- authenticatorCredentials (credentials );
129
+ if (!(authenticatorCredentials instanceof SyncCredentialsToken )) {
130
+ throw new IllegalArgumentException ("Sync credentials of type " + authenticatorCredentials .getType ()
131
+ + " are not supported" );
151
132
}
133
+ SyncCredentialsToken tokenCredential = (SyncCredentialsToken ) authenticatorCredentials ;
134
+ SyncCredentials .CredentialsType type = tokenCredential .getType ();
135
+ switch (type ) {
136
+ case JWT_ID_TOKEN :
137
+ case JWT_ACCESS_TOKEN :
138
+ case JWT_REFRESH_TOKEN :
139
+ case JWT_CUSTOM_TOKEN :
140
+ if (tokenCredential .hasToken ()) {
141
+ throw new IllegalArgumentException ("Must not supply a token for a credential of type "
142
+ + authenticatorCredentials .getType ());
143
+ }
144
+ }
145
+ credentials .add (tokenCredential );
152
146
return this ;
153
147
}
154
148
155
149
/**
156
150
* Sets a listener to observe fine granular changes happening during sync.
157
151
* <p>
158
- * This listener can also be {@link SyncServer#setSyncChangeListener(SyncChangeListener) set or removed}
159
- * on the Sync server directly.
152
+ * This listener can also be {@link SyncServer#setSyncChangeListener(SyncChangeListener) set or removed} on the Sync
153
+ * server directly.
160
154
*/
161
155
public SyncServerBuilder changeListener (SyncChangeListener changeListener ) {
162
156
this .changeListener = changeListener ;
@@ -282,6 +276,10 @@ public SyncServerBuilder workerThreads(int workerThreads) {
282
276
* Sets the public key used to verify JWT tokens.
283
277
* <p>
284
278
* The public key should be in the PEM format.
279
+ * <p>
280
+ * However, typically the key is supplied using a JWKS file served from a {@link #jwtPublicKeyUrl(String)}.
281
+ * <p>
282
+ * See {@link #jwtPublicKeyUrl(String)} for a common configuration to enable JWT auth.
285
283
*/
286
284
public SyncServerBuilder jwtPublicKey (String publicKey ) {
287
285
this .jwtPublicKey = publicKey ;
@@ -290,6 +288,19 @@ public SyncServerBuilder jwtPublicKey(String publicKey) {
290
288
291
289
/**
292
290
* Sets the JWKS (Json Web Key Sets) URL to fetch the current public key used to verify JWT tokens.
291
+ * <p>
292
+ * A working JWT configuration can look like this:
293
+ * <pre>{@code
294
+ * SyncCredentials auth = SyncCredentials.jwtIdTokenServer();
295
+ * SyncServer server = Sync.server(store, url, auth)
296
+ * .jwtPublicKeyUrl("https://example.com/public-key")
297
+ * .jwtClaimAud("<audience>")
298
+ * .jwtClaimIss("<issuer>")
299
+ * .build();
300
+ * }</pre>
301
+ *
302
+ * See the <a href="https://sync.objectbox.io/sync-server-configuration/jwt-authentication">JWT authentication documentation</a>
303
+ * for details.
293
304
*/
294
305
public SyncServerBuilder jwtPublicKeyUrl (String publicKeyUrl ) {
295
306
this .jwtPublicKeyUrl = publicKeyUrl ;
@@ -298,6 +309,8 @@ public SyncServerBuilder jwtPublicKeyUrl(String publicKeyUrl) {
298
309
299
310
/**
300
311
* Sets the JWT claim "iss" (issuer) used to verify JWT tokens.
312
+ *
313
+ * @see #jwtPublicKeyUrl(String)
301
314
*/
302
315
public SyncServerBuilder jwtClaimIss (String claimIss ) {
303
316
this .jwtClaimIss = claimIss ;
@@ -306,6 +319,8 @@ public SyncServerBuilder jwtClaimIss(String claimIss) {
306
319
307
320
/**
308
321
* Sets the JWT claim "aud" (audience) used to verify JWT tokens.
322
+ *
323
+ * @see #jwtPublicKeyUrl(String)
309
324
*/
310
325
public SyncServerBuilder jwtClaimAud (String claimAud ) {
311
326
this .jwtClaimAud = claimAud ;
@@ -322,7 +337,8 @@ private boolean hasJwtConfig() {
322
337
* Note: this clears all previously set authenticator credentials.
323
338
*/
324
339
public SyncServer build () {
325
- if (!hasJwtConfig () && credentials .isEmpty ()) {
340
+ // Note: even when only using JWT auth, must supply one of the credentials of JWT type
341
+ if (credentials .isEmpty ()) {
326
342
throw new IllegalStateException ("At least one authenticator is required." );
327
343
}
328
344
if (hasJwtConfig ()) {
@@ -374,10 +390,7 @@ byte[] buildSyncServerOptions() {
374
390
if (clusterId != null ) {
375
391
clusterIdOffset = fbb .createString (clusterId );
376
392
}
377
- int authenticationMethodsOffset = 0 ;
378
- if (!credentials .isEmpty ()) {
379
- authenticationMethodsOffset = buildAuthenticationMethods (fbb );
380
- }
393
+ int authenticationMethodsOffset = buildAuthenticationMethods (fbb );
381
394
int clusterPeersVectorOffset = buildClusterPeers (fbb );
382
395
int jwtConfigOffset = 0 ;
383
396
if (hasJwtConfig ()) {
@@ -396,9 +409,7 @@ byte[] buildSyncServerOptions() {
396
409
// After collecting all offsets, create options
397
410
SyncServerOptions .startSyncServerOptions (fbb );
398
411
SyncServerOptions .addUrl (fbb , urlOffset );
399
- if (authenticationMethodsOffset != 0 ) {
400
- SyncServerOptions .addAuthenticationMethods (fbb , authenticationMethodsOffset );
401
- }
412
+ SyncServerOptions .addAuthenticationMethods (fbb , authenticationMethodsOffset );
402
413
if (syncFlags != 0 ) {
403
414
SyncServerOptions .addSyncFlags (fbb , syncFlags );
404
415
}
0 commit comments