From 2e41a7063b8731676cdc180277a4e137ddb2394b Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Wed, 3 Oct 2018 14:14:14 -0700 Subject: [PATCH] [Java] Add accessTokenProvider (#3046) --- .../aspnet/signalr/HttpConnectionOptions.java | 37 ++-- .../aspnet/signalr/HubConnection.java | 57 +++--- .../aspnet/signalr/HubConnectionBuilder.java | 32 ++-- .../signalr/HttpConnectionOptionsTest.java | 3 +- .../aspnet/signalr/HubConnectionTest.java | 167 ++++++++++++------ .../microsoft/aspnet/signalr/TestUtils.java | 24 +++ 6 files changed, 217 insertions(+), 103 deletions(-) create mode 100644 clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/TestUtils.java diff --git a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HttpConnectionOptions.java b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HttpConnectionOptions.java index 70d7895bee..659f519f78 100644 --- a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HttpConnectionOptions.java +++ b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HttpConnectionOptions.java @@ -3,32 +3,30 @@ package com.microsoft.aspnet.signalr; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + public class HttpConnectionOptions { - private String url; private Transport transport; private LogLevel loglevel; - private Logger logger; private boolean skipNegotiate; + private Supplier> accessTokenProvider; + private HttpClient client; public HttpConnectionOptions() {} - public HttpConnectionOptions(String url, Transport transport, LogLevel logLevel, boolean skipNegotiate) { - this.url = url; + public HttpConnectionOptions(Transport transport, LogLevel logLevel, boolean skipNegotiate) { this.transport = transport; this.skipNegotiate = skipNegotiate; this.loglevel = logLevel; } - public HttpConnectionOptions(String url, Transport transport, Logger logger, boolean skipNegotiate) { - this.url = url; + public HttpConnectionOptions(Transport transport, Logger logger, boolean skipNegotiate) { this.transport = transport; this.skipNegotiate = skipNegotiate; this.logger = logger; } - public void setUrl(String url) { - this.url = url; - } public void setTransport(Transport transport) { this.transport = transport; @@ -42,10 +40,6 @@ public class HttpConnectionOptions { this.skipNegotiate = skipNegotiate; } - public String getUrl() { - return url; - } - public Transport getTransport() { return transport; } @@ -65,4 +59,21 @@ public class HttpConnectionOptions { public void setLogger(Logger logger) { this.logger = logger; } + + public void setAccessTokenProvider(Supplier> accessTokenProvider) { + this.accessTokenProvider = accessTokenProvider; + } + + public Supplier> getAccessTokenProvider() { + return accessTokenProvider; + } + + // For testing purposes only + void setHttpClient(HttpClient client) { + this.client = client; + } + + HttpClient getHttpClient() { + return client; + } } diff --git a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java index c1db6c5b85..9c6f72fae4 100644 --- a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java +++ b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnection.java @@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; +import java.util.function.Supplier; public class HubConnection { private String baseUrl; @@ -28,7 +29,7 @@ public class HubConnection { private Logger logger; private List> onClosedCallbackList; private boolean skipNegotiate = false; - private String accessToken; + private Supplier> accessTokenProvider; private Map headers = new HashMap<>(); private ConnectionState connectionState = null; private HttpClient httpClient; @@ -36,7 +37,7 @@ public class HubConnection { private static ArrayList> emptyArray = new ArrayList<>(); private static int MAX_NEGOTIATE_ATTEMPTS = 100; - public HubConnection(String url, Transport transport, Logger logger, boolean skipNegotiate, HttpClient client) { + public HubConnection(String url, HttpConnectionOptions options) { if (url == null || url.isEmpty()) { throw new IllegalArgumentException("A valid url is required."); } @@ -44,26 +45,31 @@ public class HubConnection { this.baseUrl = url; this.protocol = new JsonHubProtocol(); - if (logger != null) { - this.logger = logger; + if (options.getAccessTokenProvider() != null) { + this.accessTokenProvider = options.getAccessTokenProvider(); + } else { + this.accessTokenProvider = () -> CompletableFuture.completedFuture(null); + } + + if (options.getLogger() != null) { + this.logger = options.getLogger(); } else { this.logger = new NullLogger(); } - if (client != null) { - this.httpClient = client; + if (options.getHttpClient() != null) { + this.httpClient = options.getHttpClient(); } else { this.httpClient = new DefaultHttpClient(this.logger); } - if (transport != null) { - this.transport = transport; + if (options.getTransport() != null) { + this.transport = options.getTransport(); } - this.skipNegotiate = skipNegotiate; + this.skipNegotiate = options.getSkipNegotiate(); this.callback = (payload) -> { - if (!handshakeReceived) { int handshakeLength = payload.indexOf(RECORD_SEPARATOR) + 1; String handshakeResponseString = payload.substring(0, handshakeLength - 1); @@ -126,7 +132,7 @@ public class HubConnection { }; } - private CompletableFuture handleNegotiate(String url) throws IOException, InterruptedException, ExecutionException { + private CompletableFuture handleNegotiate(String url) { HttpRequest request = new HttpRequest(); request.setHeaders(this.headers); @@ -143,7 +149,15 @@ public class HubConnection { } if (negotiateResponse.getAccessToken() != null) { - this.headers.put("Authorization", "Bearer " + negotiateResponse.getAccessToken()); + this.accessTokenProvider = () -> CompletableFuture.completedFuture(negotiateResponse.getAccessToken()); + String token = ""; + try { + // We know the future is already completed in this case + // It's fine to call get() on it. + token = this.accessTokenProvider.get().get(); + } catch (InterruptedException | ExecutionException e) { + } + this.headers.put("Authorization", "Bearer " + token); } return CompletableFuture.completedFuture(negotiateResponse); @@ -169,11 +183,18 @@ public class HubConnection { return CompletableFuture.completedFuture(null); } + CompletableFuture tokenFuture = accessTokenProvider.get() + .thenAccept((token) -> { + if (token != null) { + this.headers.put("Authorization", "Bearer " + token); + } + }); + CompletableFuture negotiate = null; if (!skipNegotiate) { - negotiate = startNegotiate(baseUrl, 0); + negotiate = tokenFuture.thenCompose((v) -> startNegotiate(baseUrl, 0)); } else { - negotiate = CompletableFuture.completedFuture(baseUrl); + negotiate = tokenFuture.thenCompose((v) -> CompletableFuture.completedFuture(baseUrl)); } return negotiate.thenCompose((url) -> { @@ -207,7 +228,7 @@ public class HubConnection { }); } - private CompletableFuture startNegotiate(String url, int negotiateAttempts) throws IOException, InterruptedException, ExecutionException { + private CompletableFuture startNegotiate(String url, int negotiateAttempts) { if (hubConnectionState != HubConnectionState.DISCONNECTED) { return CompletableFuture.completedFuture(null); } @@ -238,11 +259,7 @@ public class HubConnection { return CompletableFuture.completedFuture(finalUrl); } - try { - return startNegotiate(response.getRedirectUrl(), negotiateAttempts + 1); - } catch (IOException | InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } + return startNegotiate(response.getRedirectUrl(), negotiateAttempts + 1); }); } diff --git a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnectionBuilder.java b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnectionBuilder.java index e9c4dc94ef..bdae13b1fe 100644 --- a/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnectionBuilder.java +++ b/clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HubConnectionBuilder.java @@ -7,8 +7,7 @@ public class HubConnectionBuilder { private String url; private Transport transport; private Logger logger; - private boolean skipNegotiate; - private HttpClient client; + private HttpConnectionOptions options = null; public HubConnectionBuilder withUrl(String url) { if (url == null || url.isEmpty()) { @@ -30,13 +29,7 @@ public class HubConnectionBuilder { public HubConnectionBuilder withUrl(String url, HttpConnectionOptions options) { this.url = url; - this.transport = options.getTransport(); - if (options.getLogger() != null) { - this.logger = options.getLogger(); - } else if (options.getLoglevel() != null) { - this.logger = new ConsoleLogger(options.getLoglevel()); - } - this.skipNegotiate = options.getSkipNegotiate(); + this.options = options; return this; } @@ -50,16 +43,23 @@ public class HubConnectionBuilder { return this; } - // For testing purposes only - HubConnectionBuilder configureHttpClient(HttpClient client) { - this.client = client; - return this; - } - public HubConnection build() { if (this.url == null) { throw new RuntimeException("The 'HubConnectionBuilder.withUrl' method must be called before building the connection."); } - return new HubConnection(url, transport, logger, skipNegotiate, client); + if (options == null) { + options = new HttpConnectionOptions(); + } + if (options.getTransport() == null && this.transport != null) { + options.setTransport(this.transport); + } + if (options.getLogger() == null && options.getLoglevel() != null) { + options.setLogger(new ConsoleLogger(options.getLoglevel())); + } + if (options.getLogger() == null && this.logger != null) { + options.setLogger(this.logger); + } + + return new HubConnection(url, options); } } \ No newline at end of file diff --git a/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HttpConnectionOptionsTest.java b/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HttpConnectionOptionsTest.java index b70d3a3c42..4b17d4f0a3 100644 --- a/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HttpConnectionOptionsTest.java +++ b/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HttpConnectionOptionsTest.java @@ -13,8 +13,7 @@ class HttpConnectionOptionsTest { @Test public void CheckHttpConnectionOptionsFields() { Transport mockTransport = new MockTransport(); - HttpConnectionOptions options = new HttpConnectionOptions("http://example.com", mockTransport, LogLevel.Information, true); - assertEquals("http://example.com",options.getUrl()); + HttpConnectionOptions options = new HttpConnectionOptions(mockTransport, LogLevel.Information, true); assertEquals(LogLevel.Information, options.getLoglevel()); assertTrue(options.getSkipNegotiate()); assertNotNull(options.getTransport()); diff --git a/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HubConnectionTest.java b/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HubConnectionTest.java index 9db3fca0a2..0813066e46 100644 --- a/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HubConnectionTest.java +++ b/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/HubConnectionTest.java @@ -21,8 +21,7 @@ class HubConnectionTest { @Test public void checkHubConnectionState() throws Exception { - Transport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com"); hubConnection.start(); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); @@ -48,7 +47,7 @@ class HubConnectionTest { @Test public void hubConnectionClosesAfterCloseMessage() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); @@ -63,7 +62,7 @@ class HubConnectionTest { @Test public void hubConnectionReceiveHandshakeResponseWithError() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); Throwable exception = assertThrows(HubException.class, () -> mockTransport.receiveMessage("{\"error\":\"Requested protocol 'messagepack' is not available.\"}" + RECORD_SEPARATOR)); @@ -74,7 +73,7 @@ class HubConnectionTest { public void registeringMultipleHandlersAndBothGetTriggered() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); hubConnection.on("inc", action); @@ -100,7 +99,7 @@ class HubConnectionTest { public void removeHandlerByName() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); hubConnection.on("inc", action); @@ -127,7 +126,7 @@ class HubConnectionTest { public void addAndRemoveHandlerImmediately() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); hubConnection.on("inc", action); @@ -152,7 +151,7 @@ class HubConnectionTest { public void removingMultipleHandlersWithOneCallToRemove() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Action secondAction = () -> value.getAndUpdate((val) -> val + 2); @@ -184,7 +183,7 @@ class HubConnectionTest { public void removeHandlerWithUnsubscribe() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Subscription subscription = hubConnection.on("inc", action); @@ -217,7 +216,7 @@ class HubConnectionTest { public void unsubscribeTwice() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(),true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Subscription subscription = hubConnection.on("inc", action); @@ -251,7 +250,7 @@ class HubConnectionTest { public void removeSingleHandlerWithUnsubscribe() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Action secondAction = () -> value.getAndUpdate((val) -> val + 2); @@ -281,7 +280,7 @@ class HubConnectionTest { public void addAndRemoveHandlerImmediatelyWithSubscribe() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Subscription sub = hubConnection.on("inc", action); @@ -306,7 +305,7 @@ class HubConnectionTest { public void registeringMultipleHandlersThatTakeParamsAndBothGetTriggered() throws Exception { AtomicReference value = new AtomicReference<>(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); Action1 action = (number) -> value.getAndUpdate((val) -> val + number); @@ -325,7 +324,7 @@ class HubConnectionTest { @Test public void invokeWaitsForCompletionMessage() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); @@ -342,7 +341,7 @@ class HubConnectionTest { @Test public void multipleInvokesWaitForOwnCompletionMessage() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); @@ -365,7 +364,7 @@ class HubConnectionTest { @Test public void invokeWorksForPrimitiveTypes() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); @@ -383,7 +382,7 @@ class HubConnectionTest { @Test public void completionMessageCanHaveError() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); @@ -407,7 +406,7 @@ class HubConnectionTest { @Test public void stopCancelsActiveInvokes() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.start(); mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); @@ -432,7 +431,7 @@ class HubConnectionTest { public void sendWithNoParamsTriggersOnHandler() throws Exception { AtomicReference value = new AtomicReference<>(0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", () ->{ assertEquals(Integer.valueOf(0), value.get()); @@ -451,7 +450,7 @@ class HubConnectionTest { public void sendWithParamTriggersOnHandler() throws Exception { AtomicReference value = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param) ->{ assertNull(value.get()); @@ -473,7 +472,7 @@ class HubConnectionTest { AtomicReference value2 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2) ->{ assertNull(value1.get()); @@ -500,7 +499,7 @@ class HubConnectionTest { AtomicReference value3 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3) ->{ assertNull(value1.get()); @@ -531,7 +530,7 @@ class HubConnectionTest { AtomicReference value4 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4) ->{ assertNull(value1.get()); @@ -565,7 +564,7 @@ class HubConnectionTest { AtomicReference value5 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4, param5) ->{ assertNull(value1.get()); @@ -603,7 +602,7 @@ class HubConnectionTest { AtomicReference value6 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4, param5, param6) -> { assertNull(value1.get()); @@ -645,7 +644,7 @@ class HubConnectionTest { AtomicReference value7 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4, param5, param6, param7) -> { assertNull(value1.get()); @@ -691,7 +690,7 @@ class HubConnectionTest { AtomicReference value8 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4, param5, param6, param7, param8) -> { assertNull(value1.get()); @@ -738,7 +737,7 @@ class HubConnectionTest { AtomicReference value1 = new AtomicReference<>(); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1) -> { assertNull(value1.get()); @@ -763,7 +762,7 @@ class HubConnectionTest { public void receiveHandshakeResponseAndMessage() throws Exception { AtomicReference value = new AtomicReference(0.0); MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("inc", () ->{ assertEquals(Double.valueOf(0), value.get()); @@ -784,8 +783,7 @@ class HubConnectionTest { @Test public void onClosedCallbackRunsWhenStopIsCalled() throws Exception { AtomicReference value1 = new AtomicReference<>(); - Transport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com"); hubConnection.start(); hubConnection.onClosed((ex) -> { assertNull(value1.get()); @@ -801,8 +799,7 @@ class HubConnectionTest { public void multipleOnClosedCallbacksRunWhenStopIsCalled() throws Exception { AtomicReference value1 = new AtomicReference<>(); AtomicReference value2 = new AtomicReference<>(); - Transport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com"); hubConnection.start(); hubConnection.onClosed((ex) -> { @@ -827,7 +824,7 @@ class HubConnectionTest { @Test public void hubConnectionClosesAndRunsOnClosedCallbackAfterCloseMessageWithError() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.onClosed((ex) -> { assertEquals(ex.getMessage(), "There was an error"); }); @@ -843,8 +840,7 @@ class HubConnectionTest { @Test public void callingStartOnStartedHubConnectionNoOps() throws Exception { - Transport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com"); hubConnection.start(); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); @@ -857,8 +853,7 @@ class HubConnectionTest { @Test public void cannotSendBeforeStart() throws Exception { - Transport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com"); assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState()); Throwable exception = assertThrows(HubException.class, () -> hubConnection.send("inc")); @@ -868,7 +863,7 @@ class HubConnectionTest { @Test public void errorWhenReceivingInvokeWithIncorrectArgumentLength() throws Exception { MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport); hubConnection.on("Send", (s) -> { assertTrue(false); }, String.class); @@ -886,9 +881,10 @@ class HubConnectionTest { TestHttpClient client = new TestHttpClient() .on("POST", (req) -> CompletableFuture.completedFuture(new HttpResponse(404, "", ""))); + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setHttpClient(client); HubConnection hubConnection = new HubConnectionBuilder() - .withUrl("http://example.com") - .configureHttpClient(client) + .withUrl("http://example.com", options) .build(); try { @@ -905,8 +901,11 @@ class HubConnectionTest { TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate", (req) -> CompletableFuture.completedFuture(new HttpResponse(200, "", "{\"url\":\"http://example.com\"}"))); - HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com") - .configureHttpClient(client).build(); + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setHttpClient(client); + HubConnection hubConnection = new HubConnectionBuilder() + .withUrl("http://example.com", options) + .build(); ExecutionException exception = assertThrows(ExecutionException.class, () -> hubConnection.start().get(1000, TimeUnit.MILLISECONDS)); assertEquals("Negotiate redirection limit exceeded.", exception.getCause().getMessage()); @@ -922,8 +921,10 @@ class HubConnectionTest { MockTransport transport = new MockTransport(); HttpConnectionOptions options = new HttpConnectionOptions(); options.setTransport(transport); - HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options) - .configureHttpClient(client).build(); + options.setHttpClient(client); + HubConnection hubConnection = new HubConnectionBuilder() + .withUrl("http://example.com", options) + .build(); hubConnection.start().get(1000, TimeUnit.MILLISECONDS); @@ -940,8 +941,10 @@ class HubConnectionTest { MockTransport transport = new MockTransport(); HttpConnectionOptions options = new HttpConnectionOptions(); options.setTransport(transport); - HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options) - .configureHttpClient(client).build(); + options.setHttpClient(client); + HubConnection hubConnection = new HubConnectionBuilder() + .withUrl("http://example.com", options) + .build(); ExecutionException exception = assertThrows(ExecutionException.class, () -> hubConnection.start().get(1000, TimeUnit.MILLISECONDS)); assertEquals("Test error.", exception.getCause().getMessage()); @@ -958,18 +961,75 @@ class HubConnectionTest { MockTransport transport = new MockTransport(); HttpConnectionOptions options = new HttpConnectionOptions(); options.setTransport(transport); - HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options) - .configureHttpClient(client).build(); + options.setHttpClient(client); + HubConnection hubConnection = new HubConnectionBuilder() + .withUrl("http://example.com", options) + .build(); hubConnection.start().get(1000, TimeUnit.MILLISECONDS); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); hubConnection.stop(); } + @Test + public void accessTokenProviderIsUsedForNegotiate() + throws InterruptedException, ExecutionException, TimeoutException, Exception { + AtomicReference token = new AtomicReference<>(); + TestHttpClient client = new TestHttpClient() + .on("POST", "http://example.com/negotiate", + (req) -> { + token.set(req.getHeaders().get("Authorization")); + return CompletableFuture + .completedFuture(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + }); + + MockTransport transport = new MockTransport(); + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setTransport(transport); + options.setHttpClient(client); + options.setAccessTokenProvider(() -> CompletableFuture.completedFuture("secretToken")); + HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build(); + + hubConnection.start().get(1000, TimeUnit.MILLISECONDS); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + hubConnection.stop(); + assertEquals("Bearer secretToken", token.get()); + } + + @Test + public void accessTokenProviderIsOverriddenFromRedirectNegotiate() + throws InterruptedException, ExecutionException, TimeoutException, Exception { + AtomicReference token = new AtomicReference<>(); + TestHttpClient client = new TestHttpClient() + .on("POST", "http://example.com/negotiate", (req) -> CompletableFuture.completedFuture(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"newToken\"}"))) + .on("POST", "http://testexample.com/negotiate", (req) -> { + token.set(req.getHeaders().get("Authorization")); + return CompletableFuture + .completedFuture(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")); + }); + + MockTransport transport = new MockTransport(); + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setTransport(transport); + options.setHttpClient(client); + options.setAccessTokenProvider(() -> CompletableFuture.completedFuture("secretToken")); + HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build(); + + hubConnection.start().get(1000, TimeUnit.MILLISECONDS); + assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); + hubConnection.stop(); + assertEquals("Bearer newToken", token.get()); + } + @Test public void hubConnectionCanBeStartedAfterBeingStopped() throws Exception { - MockTransport mockTransport = new MockTransport(); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient()); + MockTransport transport = new MockTransport(); + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setTransport(transport); + options.setSkipNegotiate(true); + HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build(); hubConnection.start().get(1000, TimeUnit.MILLISECONDS); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); @@ -990,7 +1050,10 @@ class HubConnectionTest { .on("POST", "http://testexample.com/negotiate", (req) -> CompletableFuture .completedFuture(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\"" + "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"))); - HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), false, client); + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setTransport(mockTransport); + options.setHttpClient(client); + HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build(); hubConnection.start().get(1000, TimeUnit.MILLISECONDS); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); diff --git a/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/TestUtils.java b/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/TestUtils.java new file mode 100644 index 0000000000..bc5cbd0a8e --- /dev/null +++ b/clients/java/signalr/src/test/java/com/microsoft/aspnet/signalr/TestUtils.java @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +package com.microsoft.aspnet.signalr; + +class TestUtils { + static HubConnection createHubConnection(String url) { + return createHubConnection(url, new MockTransport(), new NullLogger(), true, new TestHttpClient()); + } + + static HubConnection createHubConnection(String url, Transport transport) { + return createHubConnection(url, transport, new NullLogger(), true, new TestHttpClient()); + } + + static HubConnection createHubConnection(String url, Transport transport, Logger logger, boolean skipNegotiate, HttpClient client) { + HttpConnectionOptions options = new HttpConnectionOptions(); + options.setTransport(transport); + options.setLogger(logger); + options.setSkipNegotiate(skipNegotiate); + options.setHttpClient(client); + HubConnectionBuilder builder = new HubConnectionBuilder(); + return builder.withUrl(url, options).build(); + } +} \ No newline at end of file