Skip to content

Commit 6c3dca7

Browse files
Shubhamgreenrobot
authored andcommitted
sync: allow adding multiple credentials for auth objectbox-java#252
add new CredentialsType for JWT tokens add addLoginCredentials to SyncClientImpl.java
1 parent 621c6a9 commit 6c3dca7

File tree

10 files changed

+308
-20
lines changed

10 files changed

+308
-20
lines changed

objectbox-java/src/main/java/io/objectbox/sync/CredentialsType.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,21 @@ private CredentialsType() { }
5454
* Generic credential type suitable for ObjectBox admin (and possibly others in the future)
5555
*/
5656
public static final int UserPassword = 6;
57+
/**
58+
* JSON Web Token (JWT): an ID token that typically provides identity information about the authenticated user.
59+
*/
60+
public static final int JwtId = 7;
61+
/**
62+
* JSON Web Token (JWT): an access token that is used to access resources.
63+
*/
64+
public static final int JwtAccess = 8;
65+
/**
66+
* JSON Web Token (JWT): a refresh token that is used to obtain a new access token.
67+
*/
68+
public static final int JwtRefresh = 9;
69+
/**
70+
* JSON Web Token (JWT): a token that is neither an ID, access, nor refresh token.
71+
*/
72+
public static final int JwtCustom = 10;
5773
}
5874

objectbox-java/src/main/java/io/objectbox/sync/Sync.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ public static SyncBuilder client(BoxStore boxStore, String url, SyncCredentials
6363
return new SyncBuilder(boxStore, url, credentials);
6464
}
6565

66+
/**
67+
* Starts building a {@link SyncClient}. Once done, complete with {@link SyncBuilder#build() build()}.
68+
*
69+
* @param boxStore The {@link BoxStore} the client should use.
70+
* @param url The URL of the Sync server on which the Sync protocol is exposed. This is typically a WebSockets URL
71+
* starting with {@code ws://} or {@code wss://} (for encrypted connections), for example
72+
* {@code ws://127.0.0.1:9999}.
73+
* @param multipleCredentials An array of {@link SyncCredentials} to be used to authenticate the user.
74+
*/
75+
public static SyncBuilder client(BoxStore boxStore, String url, SyncCredentials[] multipleCredentials) {
76+
return new SyncBuilder(boxStore, url, multipleCredentials);
77+
}
78+
6679
/**
6780
* Starts building a {@link SyncServer}. Once done, complete with {@link SyncServerBuilder#build() build()}.
6881
* <p>

objectbox-java/src/main/java/io/objectbox/sync/SyncBuilder.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package io.objectbox.sync;
1818

1919
import java.util.Arrays;
20+
import java.util.Collections;
21+
import java.util.List;
2022

2123
import javax.annotation.Nullable;
2224

@@ -40,7 +42,7 @@ public final class SyncBuilder {
4042
final Platform platform;
4143
final BoxStore boxStore;
4244
String url;
43-
final SyncCredentials credentials;
45+
final List<SyncCredentials> credentials;
4446

4547
@Nullable SyncLoginListener loginListener;
4648
@Nullable SyncCompletedListener completedListener;
@@ -94,7 +96,23 @@ public SyncBuilder(BoxStore boxStore, SyncCredentials credentials) {
9496
}
9597
this.platform = Platform.findPlatform();
9698
this.boxStore = boxStore;
97-
this.credentials = credentials;
99+
this.credentials = Collections.singletonList(credentials);
100+
}
101+
102+
@Internal
103+
public SyncBuilder(BoxStore boxStore, SyncCredentials[] multipleCredentials) {
104+
checkNotNull(boxStore, "BoxStore is required.");
105+
if (multipleCredentials.length == 0) {
106+
throw new IllegalArgumentException("At least one Sync credential is required.");
107+
}
108+
if (!BoxStore.isSyncAvailable()) {
109+
throw new IllegalStateException(
110+
"This library does not include ObjectBox Sync. " +
111+
"Please visit https://objectbox.io/sync/ for options.");
112+
}
113+
this.platform = Platform.findPlatform();
114+
this.boxStore = boxStore;
115+
this.credentials = Arrays.asList(multipleCredentials);
98116
}
99117

100118
@Internal
@@ -104,6 +122,13 @@ public SyncBuilder(BoxStore boxStore, String url, SyncCredentials credentials) {
104122
this.url = url;
105123
}
106124

125+
@Internal
126+
public SyncBuilder(BoxStore boxStore, String url, SyncCredentials[] multipleCredentials) {
127+
this(boxStore, multipleCredentials);
128+
checkNotNull(url, "Sync server URL is required.");
129+
this.url = url;
130+
}
131+
107132
/**
108133
* Allows internal code to set the Sync server URL after creating this builder.
109134
*/

objectbox-java/src/main/java/io/objectbox/sync/SyncClient.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ public interface SyncClient extends Closeable {
133133
*/
134134
void setLoginCredentials(SyncCredentials credentials);
135135

136+
void setLoginCredentials(SyncCredentials[] multipleCredentials);
137+
136138
/**
137139
* Waits until the sync client receives a response to its first (connection and) login attempt
138140
* or until the given time has expired.

objectbox-java/src/main/java/io/objectbox/sync/SyncClientImpl.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,13 @@ public final class SyncClientImpl implements SyncClient {
9696
this.internalListener = new InternalSyncClientListener();
9797
nativeSetListener(handle, internalListener);
9898

99-
setLoginCredentials(builder.credentials);
99+
if (builder.credentials.size() == 1) {
100+
setLoginCredentials(builder.credentials.get(0));
101+
} else if (builder.credentials.size() > 1) {
102+
setLoginCredentials(builder.credentials.toArray(new SyncCredentials[0]));
103+
} else {
104+
throw new IllegalArgumentException("No credentials provided");
105+
}
100106

101107
// If created successfully, let store keep a reference so the caller does not have to.
102108
InternalAccess.setSyncClient(builder.boxStore, this);
@@ -196,6 +202,26 @@ public void setLoginCredentials(SyncCredentials credentials) {
196202
}
197203
}
198204

205+
@Override
206+
public void setLoginCredentials(SyncCredentials[] multipleCredentials) {
207+
for (int i = 0; i < multipleCredentials.length; i++) {
208+
SyncCredentials credentials = multipleCredentials[i];
209+
boolean isLast = i == multipleCredentials.length - 1;
210+
if (credentials instanceof SyncCredentialsToken) {
211+
SyncCredentialsToken credToken = (SyncCredentialsToken) credentials;
212+
nativeAddLoginCredentials(getHandle(), credToken.getTypeId(), credToken.getTokenBytes(), isLast);
213+
credToken.clear(); // Clear immediately, not needed anymore.
214+
} else if (credentials instanceof SyncCredentialsUserPassword) {
215+
SyncCredentialsUserPassword credUserPassword = (SyncCredentialsUserPassword) credentials;
216+
nativeAddLoginCredentialsUserPassword(getHandle(), credUserPassword.getTypeId(), credUserPassword.getUsername(),
217+
credUserPassword.getPassword(), isLast);
218+
} else {
219+
throw new IllegalArgumentException("credentials is not a supported type");
220+
}
221+
}
222+
}
223+
224+
199225
@Override
200226
public boolean awaitFirstLogin(long millisToWait) {
201227
if (!started) {
@@ -322,6 +348,10 @@ public ObjectsMessageBuilder startObjectsMessage(long flags, @Nullable String to
322348

323349
private native void nativeSetLoginInfoUserPassword(long handle, long credentialsType, String username, String password);
324350

351+
private native void nativeAddLoginCredentials(long handle, long credentialsType, @Nullable byte[] credentials, boolean complete);
352+
353+
private native void nativeAddLoginCredentialsUserPassword(long handle, long credentialsType, String username, String password, boolean complete);
354+
325355
private native void nativeSetListener(long handle, @Nullable InternalSyncClientListener listener);
326356

327357
private native void nativeSetSyncChangesListener(long handle, @Nullable SyncChangeListener advancedListener);

objectbox-java/src/main/java/io/objectbox/sync/SyncCredentials.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ public static SyncCredentials userAndPassword(String user, String password) {
5252
return new SyncCredentialsUserPassword(user, password);
5353
}
5454

55+
public static SyncCredentials jwtIdToken(String jwtIdToken) {
56+
return new SyncCredentialsToken(CredentialsType.JWT_ID_TOKEN, jwtIdToken);
57+
}
58+
59+
public static SyncCredentials jwtAccessToken(String jwtAccessToken) {
60+
return new SyncCredentialsToken(CredentialsType.JWT_ACCESS_TOKEN, jwtAccessToken);
61+
}
62+
63+
public static SyncCredentials jwtRefreshToken(String jwtRefreshToken) {
64+
return new SyncCredentialsToken(CredentialsType.JWT_REFRESH_TOKEN, jwtRefreshToken);
65+
}
66+
67+
public static SyncCredentials jwtCustomToken(String jwtCustomToken) {
68+
return new SyncCredentialsToken(CredentialsType.JWT_CUSTOM_TOKEN, jwtCustomToken);
69+
}
70+
5571
/**
5672
* No authentication, unsecured. Use only for development and testing purposes.
5773
*/
@@ -65,7 +81,11 @@ public enum CredentialsType {
6581
GOOGLE(io.objectbox.sync.CredentialsType.GoogleAuth),
6682
SHARED_SECRET_SIPPED(io.objectbox.sync.CredentialsType.SharedSecretSipped),
6783
OBX_ADMIN_USER(io.objectbox.sync.CredentialsType.ObxAdminUser),
68-
USER_PASSWORD(io.objectbox.sync.CredentialsType.UserPassword);
84+
USER_PASSWORD(io.objectbox.sync.CredentialsType.UserPassword),
85+
JWT_ID_TOKEN(io.objectbox.sync.CredentialsType.JwtId),
86+
JWT_ACCESS_TOKEN(io.objectbox.sync.CredentialsType.JwtAccess),
87+
JWT_REFRESH_TOKEN(io.objectbox.sync.CredentialsType.JwtRefresh),
88+
JWT_CUSTOM_TOKEN(io.objectbox.sync.CredentialsType.JwtCustom);
6989

7090
public final long id;
7191

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// automatically generated by the FlatBuffers compiler, do not modify
2+
3+
package io.objectbox.sync.server;
4+
5+
import io.objectbox.flatbuffers.BaseVector;
6+
import io.objectbox.flatbuffers.BooleanVector;
7+
import io.objectbox.flatbuffers.ByteVector;
8+
import io.objectbox.flatbuffers.Constants;
9+
import io.objectbox.flatbuffers.DoubleVector;
10+
import io.objectbox.flatbuffers.FlatBufferBuilder;
11+
import io.objectbox.flatbuffers.FloatVector;
12+
import io.objectbox.flatbuffers.IntVector;
13+
import io.objectbox.flatbuffers.LongVector;
14+
import io.objectbox.flatbuffers.ShortVector;
15+
import io.objectbox.flatbuffers.StringVector;
16+
import io.objectbox.flatbuffers.Struct;
17+
import io.objectbox.flatbuffers.Table;
18+
import io.objectbox.flatbuffers.UnionVector;
19+
import java.nio.ByteBuffer;
20+
import java.nio.ByteOrder;
21+
22+
@SuppressWarnings("unused")
23+
public final class JwtConfig extends Table {
24+
public static void ValidateVersion() { Constants.FLATBUFFERS_23_5_26(); }
25+
public static JwtConfig getRootAsJwtConfig(ByteBuffer _bb) { return getRootAsJwtConfig(_bb, new JwtConfig()); }
26+
public static JwtConfig getRootAsJwtConfig(ByteBuffer _bb, JwtConfig obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
27+
public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
28+
public JwtConfig __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
29+
30+
/**
31+
* URL to fetch the current public key used to verify JWT signatures.
32+
*/
33+
public String publicKeyUrl() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
34+
public ByteBuffer publicKeyUrlAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
35+
public ByteBuffer publicKeyUrlInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 4, 1); }
36+
/**
37+
* Fixed public key used to sign JWT tokens; e.g. for development purposes.
38+
* Supply either publicKey or publicKeyUrl, but not both.
39+
*/
40+
public String publicKey() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; }
41+
public ByteBuffer publicKeyAsByteBuffer() { return __vector_as_bytebuffer(6, 1); }
42+
public ByteBuffer publicKeyInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 6, 1); }
43+
/**
44+
* Cache expiration time in seconds for the public key(s) fetched from publicKeyUrl.
45+
* If absent or zero, the default is used.
46+
*/
47+
public long publicKeyCacheExpirationSeconds() { int o = __offset(8); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
48+
/**
49+
* JWT claim "aud" (audience) used to verify JWT tokens.
50+
*/
51+
public String claimAud() { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; }
52+
public ByteBuffer claimAudAsByteBuffer() { return __vector_as_bytebuffer(10, 1); }
53+
public ByteBuffer claimAudInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 10, 1); }
54+
/**
55+
* JWT claim "iss" (issuer) used to verify JWT tokens.
56+
*/
57+
public String claimIss() { int o = __offset(12); return o != 0 ? __string(o + bb_pos) : null; }
58+
public ByteBuffer claimIssAsByteBuffer() { return __vector_as_bytebuffer(12, 1); }
59+
public ByteBuffer claimIssInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 12, 1); }
60+
61+
public static int createJwtConfig(FlatBufferBuilder builder,
62+
int publicKeyUrlOffset,
63+
int publicKeyOffset,
64+
long publicKeyCacheExpirationSeconds,
65+
int claimAudOffset,
66+
int claimIssOffset) {
67+
builder.startTable(5);
68+
JwtConfig.addClaimIss(builder, claimIssOffset);
69+
JwtConfig.addClaimAud(builder, claimAudOffset);
70+
JwtConfig.addPublicKeyCacheExpirationSeconds(builder, publicKeyCacheExpirationSeconds);
71+
JwtConfig.addPublicKey(builder, publicKeyOffset);
72+
JwtConfig.addPublicKeyUrl(builder, publicKeyUrlOffset);
73+
return JwtConfig.endJwtConfig(builder);
74+
}
75+
76+
public static void startJwtConfig(FlatBufferBuilder builder) { builder.startTable(5); }
77+
public static void addPublicKeyUrl(FlatBufferBuilder builder, int publicKeyUrlOffset) { builder.addOffset(0, publicKeyUrlOffset, 0); }
78+
public static void addPublicKey(FlatBufferBuilder builder, int publicKeyOffset) { builder.addOffset(1, publicKeyOffset, 0); }
79+
public static void addPublicKeyCacheExpirationSeconds(FlatBufferBuilder builder, long publicKeyCacheExpirationSeconds) { builder.addInt(2, (int) publicKeyCacheExpirationSeconds, (int) 0L); }
80+
public static void addClaimAud(FlatBufferBuilder builder, int claimAudOffset) { builder.addOffset(3, claimAudOffset, 0); }
81+
public static void addClaimIss(FlatBufferBuilder builder, int claimIssOffset) { builder.addOffset(4, claimIssOffset, 0); }
82+
public static int endJwtConfig(FlatBufferBuilder builder) {
83+
int o = builder.endTable();
84+
return o;
85+
}
86+
87+
public static final class Vector extends BaseVector {
88+
public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; }
89+
90+
public JwtConfig get(int j) { return get(new JwtConfig(), j); }
91+
public JwtConfig get(JwtConfig obj, int j) { return obj.__assign(__indirect(__element(j), bb), bb); }
92+
}
93+
}

0 commit comments

Comments
 (0)