Add websocket-resources as a module

This commit is contained in:
Moxie Marlinspike
2019-04-30 23:58:27 -07:00
parent 66917cd2c0
commit 9220f4d829
38 changed files with 9206 additions and 26 deletions

View File

@@ -0,0 +1,64 @@
package org.whispersystems.websocket;
import org.eclipse.jetty.server.AbstractNCSARequestLog;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.junit.Test;
import org.whispersystems.websocket.messages.WebSocketMessageFactory;
import org.whispersystems.websocket.messages.WebSocketRequestMessage;
import org.whispersystems.websocket.servlet.LoggableRequest;
import org.whispersystems.websocket.servlet.LoggableResponse;
import org.whispersystems.websocket.servlet.WebSocketServletRequest;
import org.whispersystems.websocket.servlet.WebSocketServletResponse;
import org.whispersystems.websocket.session.WebSocketSessionContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Optional;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class LoggableRequestResponseTest {
@Test
public void testLogging() {
NCSARequestLog requestLog = new EnabledNCSARequestLog();
WebSocketClient webSocketClient = mock(WebSocketClient.class );
WebSocketRequestMessage requestMessage = mock(WebSocketRequestMessage.class);
ServletContext servletContext = mock(ServletContext.class );
RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class );
WebSocketMessageFactory messageFactory = mock(WebSocketMessageFactory.class);
when(requestMessage.getVerb()).thenReturn("GET");
when(requestMessage.getBody()).thenReturn(Optional.empty());
when(requestMessage.getHeaders()).thenReturn(new HashMap<>());
when(requestMessage.getPath()).thenReturn("/api/v1/test");
when(requestMessage.getRequestId()).thenReturn(1L);
when(requestMessage.hasRequestId()).thenReturn(true);
WebSocketSessionContext sessionContext = new WebSocketSessionContext (webSocketClient );
HttpServletRequest servletRequest = new WebSocketServletRequest (sessionContext, requestMessage, servletContext);
HttpServletResponse servletResponse = new WebSocketServletResponse(remoteEndpoint, 1, messageFactory );
LoggableRequest loggableRequest = new LoggableRequest (servletRequest );
LoggableResponse loggableResponse = new LoggableResponse(servletResponse);
requestLog.log(loggableRequest, loggableResponse);
}
private class EnabledNCSARequestLog extends NCSARequestLog {
@Override
public boolean isEnabled() {
return true;
}
}
}

View File

@@ -0,0 +1,73 @@
package org.whispersystems.websocket;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.junit.Test;
import org.whispersystems.websocket.auth.AuthenticationException;
import org.whispersystems.websocket.auth.WebSocketAuthenticator;
import org.whispersystems.websocket.setup.WebSocketEnvironment;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Optional;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import static org.junit.Assert.*;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
public class WebSocketResourceProviderFactoryTest {
@Test
public void testUnauthorized() throws ServletException, AuthenticationException, IOException {
JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class );
WebSocketEnvironment environment = mock(WebSocketEnvironment.class );
WebSocketAuthenticator authenticator = mock(WebSocketAuthenticator.class);
ServletUpgradeRequest request = mock(ServletUpgradeRequest.class );
ServletUpgradeResponse response = mock(ServletUpgradeResponse.class);
when(environment.getAuthenticator()).thenReturn(authenticator);
when(authenticator.authenticate(eq(request))).thenReturn(new WebSocketAuthenticator.AuthenticationResult<>(Optional.empty(), true));
when(environment.jersey()).thenReturn(jerseyEnvironment);
WebSocketResourceProviderFactory factory = new WebSocketResourceProviderFactory(environment);
Object connection = factory.createWebSocket(request, response);
assertNull(connection);
verify(response).sendForbidden(eq("Unauthorized"));
verify(authenticator).authenticate(eq(request));
}
@Test
public void testValidAuthorization() throws AuthenticationException, ServletException {
JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class );
WebSocketEnvironment environment = mock(WebSocketEnvironment.class );
WebSocketAuthenticator authenticator = mock(WebSocketAuthenticator.class);
ServletUpgradeRequest request = mock(ServletUpgradeRequest.class );
ServletUpgradeResponse response = mock(ServletUpgradeResponse.class);
Session session = mock(Session.class );
Account account = new Account();
when(environment.getAuthenticator()).thenReturn(authenticator);
when(authenticator.authenticate(eq(request))).thenReturn(new WebSocketAuthenticator.AuthenticationResult<>(Optional.of(account), true));
when(environment.jersey()).thenReturn(jerseyEnvironment);
WebSocketResourceProviderFactory factory = new WebSocketResourceProviderFactory(environment);
Object connection = factory.createWebSocket(request, response);
assertNotNull(connection);
verifyNoMoreInteractions(response);
verify(authenticator).authenticate(eq(request));
((WebSocketResourceProvider)connection).onWebSocketConnect(session);
assertNotNull(((WebSocketResourceProvider) connection).getContext().getAuthenticated());
assertEquals(((WebSocketResourceProvider)connection).getContext().getAuthenticated(), account);
}
private static class Account {}
}

View File

@@ -0,0 +1,90 @@
package org.whispersystems.websocket;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.websocket.api.CloseStatus;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.whispersystems.websocket.WebSocketResourceProvider;
import org.whispersystems.websocket.auth.AuthenticationException;
import org.whispersystems.websocket.auth.WebSocketAuthenticator;
import org.whispersystems.websocket.messages.protobuf.ProtobufWebSocketMessageFactory;
import org.whispersystems.websocket.setup.WebSocketConnectListener;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
public class WebSocketResourceProviderTest {
@Test
public void testOnConnect() throws AuthenticationException, IOException {
HttpServlet contextHandler = mock(HttpServlet.class);
WebSocketAuthenticator<String> authenticator = mock(WebSocketAuthenticator.class);
RequestLog requestLog = mock(RequestLog.class);
WebSocketResourceProvider provider = new WebSocketResourceProvider(contextHandler, requestLog,
null,
new ProtobufWebSocketMessageFactory(),
Optional.empty(),
30000);
Session session = mock(Session.class );
UpgradeRequest request = mock(UpgradeRequest.class);
when(session.getUpgradeRequest()).thenReturn(request);
when(authenticator.authenticate(request)).thenReturn(new WebSocketAuthenticator.AuthenticationResult<>(Optional.of("fooz"), true));
provider.onWebSocketConnect(session);
verify(session, never()).close(anyInt(), anyString());
verify(session, never()).close();
verify(session, never()).close(any(CloseStatus.class));
}
@Test
public void testRouteMessage() throws Exception {
HttpServlet servlet = mock(HttpServlet.class );
WebSocketAuthenticator<String> authenticator = mock(WebSocketAuthenticator.class);
RequestLog requestLog = mock(RequestLog.class );
WebSocketResourceProvider provider = new WebSocketResourceProvider(servlet, requestLog, Optional.of((WebSocketAuthenticator)authenticator), new ProtobufWebSocketMessageFactory(), Optional.empty(), 30000);
Session session = mock(Session.class );
RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
UpgradeRequest request = mock(UpgradeRequest.class);
when(session.getUpgradeRequest()).thenReturn(request);
when(session.getRemote()).thenReturn(remoteEndpoint);
when(authenticator.authenticate(request)).thenReturn(new WebSocketAuthenticator.AuthenticationResult<>(Optional.of("foo"), true));
provider.onWebSocketConnect(session);
verify(session, never()).close(anyInt(), anyString());
verify(session, never()).close();
verify(session, never()).close(any(CloseStatus.class));
byte[] message = new ProtobufWebSocketMessageFactory().createRequest(Optional.of(111L), "GET", "/bar", new LinkedList<String>(), Optional.of("hello world!".getBytes())).toByteArray();
provider.onWebSocketBinary(message, 0, message.length);
ArgumentCaptor<HttpServletRequest> requestCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
verify(servlet).service(requestCaptor.capture(), any(HttpServletResponse.class));
HttpServletRequest bundledRequest = requestCaptor.getValue();
byte[] expected = new byte[bundledRequest.getInputStream().available()];
int read = bundledRequest.getInputStream().read(expected);
assertThat(read).isEqualTo(expected.length);
assertThat(new String(expected)).isEqualTo("hello world!");
}
}