Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
19 changes: 13 additions & 6 deletions core/src/main/java/io/ably/lib/rest/AblyBase.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.ably.lib.rest;

import io.ably.annotation.Experimental;
import io.ably.lib.debug.DebugOptions;
import io.ably.lib.http.AsyncHttpScheduler;
import io.ably.lib.http.Http;
import io.ably.lib.http.HttpCore;
Expand Down Expand Up @@ -33,6 +34,7 @@
import io.ably.lib.util.Crypto;
import io.ably.lib.util.InternalMap;
import io.ably.lib.util.Log;
import io.ably.lib.util.ObjectCopyUtil;
import io.ably.lib.util.PlatformAgentProvider;
import io.ably.lib.util.Serialisation;

Expand Down Expand Up @@ -83,17 +85,22 @@ public AblyBase(ClientOptions options, PlatformAgentProvider platformAgentProvid
Log.e(getClass().getName(), msg);
throw AblyException.fromErrorInfo(new ErrorInfo(msg, 400, 40000));
}
this.options = options;

if (options instanceof DebugOptions) {
this.options = options;
} else {
this.options = ObjectCopyUtil.copy(options);
}
Comment thread
KacperKluka marked this conversation as resolved.

/* process options */
Log.setLevel(options.logLevel);
Log.setHandler(options.logHandler);
Log.setLevel(this.options.logLevel);
Log.setHandler(this.options.logHandler);
Log.i(getClass().getName(), "started");

this.platformAgentProvider = platformAgentProvider;
auth = new Auth(this, options);
httpCore = new HttpCore(options, auth, this.platformAgentProvider);
http = new Http(new AsyncHttpScheduler(httpCore, options), new SyncHttpScheduler(httpCore));
auth = new Auth(this, this.options);
httpCore = new HttpCore(this.options, auth, this.platformAgentProvider);
http = new Http(new AsyncHttpScheduler(httpCore, this.options), new SyncHttpScheduler(httpCore));

channels = (Channels<ChannelType>) new InternalChannels();

Expand Down
6 changes: 5 additions & 1 deletion core/src/main/java/io/ably/lib/rest/Auth.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ public String asJson() {
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TokenDetails)) {
return false;
}
Comment thread
KacperKluka marked this conversation as resolved.

TokenDetails details = (TokenDetails)obj;
return equalNullableStrings(this.token, details.token) &
equalNullableStrings(this.capability, details.capability) &
Expand Down Expand Up @@ -360,7 +364,7 @@ private TokenParams storedValues() {
*
* @return copied object
*/
private TokenParams copy() {
public TokenParams copy() {
Comment thread
KacperKluka marked this conversation as resolved.
TokenParams result = new TokenParams();
result.ttl = this.ttl;
result.capability = this.capability;
Expand Down
98 changes: 98 additions & 0 deletions core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package io.ably.lib.util;

import java.util.Arrays;
import java.util.HashMap;

import io.ably.lib.rest.Auth;
import io.ably.lib.types.ClientOptions;
import io.ably.lib.types.ProxyOptions;

public class ObjectCopyUtil {
Comment thread
KacperKluka marked this conversation as resolved.
Outdated
Comment thread
qsdigor marked this conversation as resolved.
Outdated
Comment thread
qsdigor marked this conversation as resolved.
Outdated

public static ClientOptions copy(ClientOptions options) {
ClientOptions copyOptions = new ClientOptions();
Comment thread
qsdigor marked this conversation as resolved.
Outdated
copyOptions.clientId = options.clientId;
copyOptions.logLevel = options.logLevel;
copyOptions.logHandler = options.logHandler;
copyOptions.tls = options.tls;
copyOptions.restHost = options.restHost;
copyOptions.realtimeHost = options.realtimeHost;
copyOptions.port = options.port;
copyOptions.tlsPort = options.tlsPort;
copyOptions.autoConnect = options.autoConnect;
copyOptions.useBinaryProtocol = options.useBinaryProtocol;
copyOptions.queueMessages = options.queueMessages;
copyOptions.echoMessages = options.echoMessages;
copyOptions.recover = options.recover;
copyOptions.idempotentRestPublishing = options.idempotentRestPublishing;
copyOptions.httpOpenTimeout = options.httpOpenTimeout;
copyOptions.httpRequestTimeout = options.httpRequestTimeout;
copyOptions.httpMaxRetryCount = options.httpMaxRetryCount;
copyOptions.realtimeRequestTimeout = options.realtimeRequestTimeout;
copyOptions.fallbackHostsUseDefault = options.fallbackHostsUseDefault;
copyOptions.fallbackRetryTimeout = options.fallbackRetryTimeout;
copyOptions.defaultTokenParams = options.defaultTokenParams.copy();
copyOptions.channelRetryTimeout = options.channelRetryTimeout;
copyOptions.asyncHttpThreadpoolSize = options.asyncHttpThreadpoolSize;
copyOptions.pushFullWait = options.pushFullWait;
copyOptions.localStorage = options.localStorage;
copyOptions.addRequestIds = options.addRequestIds;
copyOptions.environment = options.environment;

//params from AuthOptions
copyOptions.authCallback = options.authCallback;
copyOptions.authUrl = options.authUrl;
copyOptions.authMethod = options.authMethod;
copyOptions.key = options.key;
copyOptions.token = options.token;
copyOptions.queryTime = options.queryTime;
copyOptions.useTokenAuth = options.useTokenAuth;

if (options.headers != null) {
copyOptions.headers = new HashMap<>(options.headers);
}

if (options.agents != null) {
copyOptions.agents = new HashMap<>(options.agents);
}

if (options.authParams != null) {
copyOptions.authParams = Arrays.copyOf(options.authParams, options.authParams.length);
}

if (options.authHeaders != null) {
copyOptions.authHeaders = Arrays.copyOf(options.authHeaders, options.authHeaders.length);
}

if (options.transportParams != null) {
copyOptions.transportParams = Arrays.copyOf(options.transportParams, options.transportParams.length);
}

if (options.fallbackHosts != null) {
copyOptions.fallbackHosts = Arrays.copyOf(options.fallbackHosts, options.fallbackHosts.length);
}

if (options.proxy != null) {
ProxyOptions po = new ProxyOptions();
po.host = options.proxy.host;
po.port = options.proxy.port;
po.username = options.proxy.username;
po.password = options.proxy.password;
po.nonProxyHosts = options.proxy.nonProxyHosts;
po.prefAuthType = options.proxy.prefAuthType;
copyOptions.proxy = po;
}

if (options.tokenDetails != null) {
Auth.TokenDetails tokenDetails = new Auth.TokenDetails();
tokenDetails.token = options.tokenDetails.token;
tokenDetails.expires = options.tokenDetails.expires;
tokenDetails.issued = options.tokenDetails.issued;
tokenDetails.capability = options.tokenDetails.capability;
tokenDetails.clientId = options.tokenDetails.clientId;
copyOptions.tokenDetails = tokenDetails;
}

return copyOptions;
}
}
95 changes: 95 additions & 0 deletions core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,24 @@
import io.ably.lib.types.Message;
import io.ably.lib.types.Param;
import io.ably.lib.types.ProtocolMessage;
import io.ably.lib.types.ProxyOptions;
import io.ably.lib.util.Log;

import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.HashMap;

public abstract class RealtimeAuthTest extends ParameterizedTest {

@Rule
Expand Down Expand Up @@ -956,4 +963,92 @@ public Object getTokenRequest(Auth.TokenParams params) throws AblyException {
}
}

/**
* Verify that instance of ClientOptions cannot change AblyRealtime options once it is provided to constructor
*/
@Test
public void auth_client_options_immutable() {
try {
/* create token with clientId */
ClientOptions optsForToken = createOptions(testVars.keys[0].keyStr);
optsForToken.clientId = "token_clientId";
AblyBase<PushBase, Platform, RestChannelBase> ablyForToken = createAblyRest(optsForToken);
TokenDetails tokenDetails = ablyForToken.auth.requestToken(null, null);

/* create ably realtime */
ClientOptions opts = new ClientOptions();
opts.clientId = null;
opts.token = tokenDetails.token;
opts.autoConnect = false;
opts.headers = new HashMap<>();
opts.headers.put("old_key", "old_value");
opts.tokenDetails = new TokenDetails("my_old_details_token");
opts.logHandler = new Log.DefaultHandler();
opts.authCallback = new Auth.TokenCallback() {
@Override
public Object getTokenRequest(Auth.TokenParams params) {
return null;
}
};
opts.authHeaders = new Param[1];
opts.authHeaders[0] = new Param("old_key", "old_key");
opts.proxy = new ProxyOptions();
opts.proxy.host = "https://ably.com";
opts.proxy.port = 8080;
AblyRealtimeBase<PushBase, Platform, RealtimeChannelBase> ablyRealtime = createAblyRealtime(opts);

assertEquals("clientId should be equal before change", opts.clientId, ablyRealtime.options.clientId);
Comment thread
qsdigor marked this conversation as resolved.
Outdated
opts.clientId = "my_new_clientId";
assertNotEquals("clientId should not be equal after change", opts.clientId, ablyRealtime.options.clientId);
Comment thread
ikbalkaya marked this conversation as resolved.
Outdated

assertEquals("logLevel should be equal before change", opts.logLevel, ablyRealtime.options.logLevel);
opts.logLevel = 33;
assertNotEquals("logLevel should not be equal after change", opts.logLevel, ablyRealtime.options.logLevel);

assertEquals("autoConnect should be equal before change", opts.autoConnect, ablyRealtime.options.autoConnect);
opts.autoConnect = true;
assertNotEquals("autoConnect should not be equal after change", opts.autoConnect, ablyRealtime.options.autoConnect);

assertEquals("logHandler should be equal before change", opts.logHandler, ablyRealtime.options.logHandler);
opts.logHandler = new Log.DefaultHandler();
assertNotEquals("logHandler should not be equal after change", opts.logHandler, ablyRealtime.options.logHandler);
Comment thread
ikbalkaya marked this conversation as resolved.
Outdated

assertEquals("authCallback should be equal before change", opts.authCallback, ablyRealtime.options.authCallback);
opts.authCallback = new Auth.TokenCallback() {
@Override
public Object getTokenRequest(Auth.TokenParams params) {
return null;
}
};
assertNotEquals("authCallback should not be equal after change", opts.authCallback, ablyRealtime.options.authCallback);

assertEquals("token should be equal before change", opts.token, ablyRealtime.options.token);
opts.token = "my_new_token";
assertNotEquals("token should not be equal after change", opts.token, ablyRealtime.options.token);

assertEquals("tokenDetails should be equal before change", opts.tokenDetails, ablyRealtime.options.tokenDetails);
opts.tokenDetails = new TokenDetails("my_new_details_token");
assertNotEquals("tokenDetails should not be equal after change", opts.tokenDetails, ablyRealtime.options.tokenDetails);

assertEquals("headers should be equal before change", opts.headers, ablyRealtime.options.headers);
opts.headers = new HashMap<>();
opts.headers.put("new_key", "new_value");
assertNotEquals("headers should not be equal after change", opts.headers, ablyRealtime.options.headers);

assertArrayEquals("authHeaders should be equal before change", opts.authHeaders, ablyRealtime.options.authHeaders);
opts.authHeaders = new Param[1];
opts.authHeaders[0] = new Param("new_key", "new_key");
assertNotEquals("authHeaders should not be equal after change", opts.authHeaders, ablyRealtime.options.authHeaders);

assertEquals("proxy.port should be equal before change", opts.proxy.port, ablyRealtime.options.proxy.port);
opts.proxy.port = 9090;
assertNotEquals("proxy.port should not be equal after change", opts.proxy.port, ablyRealtime.options.proxy.port);

ablyRealtime.close();
} catch (AblyException e) {
e.printStackTrace();
fail();
}
}

}