Dropwizard 9 compatibility!

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-07-23 23:32:26 -07:00
parent 39e3366b3b
commit 3885ae6337
27 changed files with 540 additions and 496 deletions

93
pom.xml
View File

@ -9,12 +9,10 @@
<groupId>org.whispersystems.textsecure</groupId> <groupId>org.whispersystems.textsecure</groupId>
<artifactId>TextSecureServer</artifactId> <artifactId>TextSecureServer</artifactId>
<version>0.54</version> <version>0.60-RC3</version>
<properties> <properties>
<dropwizard.version>0.7.1</dropwizard.version> <dropwizard.version>0.9.0-rc3</dropwizard.version>
<jackson.api.version>2.3.3</jackson.api.version>
<commons-codec.version>1.6</commons-codec.version>
</properties> </properties>
<dependencies> <dependencies>
@ -58,78 +56,67 @@
<artifactId>dropwizard-papertrail</artifactId> <artifactId>dropwizard-papertrail</artifactId>
<version>1.1</version> <version>1.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>jersey-json</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.codahale.metrics</groupId>
<artifactId>metrics-graphite</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>9.0.7.v20131107</version>
</dependency>
<dependency>
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId> <artifactId>bcprov-jdk16</artifactId>
<version>140</version> <version>1.46</version>
</dependency>
<dependency>
<groupId>com.google.android.gcm</groupId>
<artifactId>gcm-server</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.notnoop.apns</groupId>
<artifactId>apns</artifactId>
<version>0.2.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.amazonaws</groupId> <groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId> <artifactId>aws-java-sdk-s3</artifactId>
<version>1.4.1</version> <version>1.10.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.protobuf</groupId> <groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId> <artifactId>protobuf-java</artifactId>
<version>2.5.0</version> <version>2.6.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>redis.clients</groupId> <groupId>redis.clients</groupId>
<artifactId>jedis</artifactId> <artifactId>jedis</artifactId>
<version>2.6.2</version> <version>2.7.3</version>
<type>jar</type> <type>jar</type>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.twilio.sdk</groupId> <groupId>com.twilio.sdk</groupId>
<artifactId>twilio-java-sdk</artifactId> <artifactId>twilio-java-sdk</artifactId>
<version>3.4.5</version> <version>4.4.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version> <version>9.4-1201-jdbc41</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-tcp</artifactId>
<version>4.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.whispersystems</groupId> <groupId>org.whispersystems</groupId>
<artifactId>websocket-resources</artifactId> <artifactId>websocket-resources</artifactId>
<version>0.2.3</version> <version>0.3.1</version>
</dependency>
<dependency>
<groupId>org.whispersystems</groupId>
<artifactId>dropwizard-simpleauth</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.19</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>
@ -137,14 +124,14 @@
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>httpclient</artifactId>
<version>${jackson.api.version}</version> <version>4.4.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>commons-codec</artifactId> <artifactId>httpcore</artifactId>
<version>${commons-codec.version}</version> <version>4.4.1</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

@ -20,15 +20,16 @@ import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.graphite.GraphiteReporter; import com.codahale.metrics.graphite.GraphiteReporter;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.Client;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.eclipse.jetty.servlets.CrossOriginFilter; import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.skife.jdbi.v2.DBI; import org.skife.jdbi.v2.DBI;
import org.whispersystems.dispatch.DispatchChannel; import org.whispersystems.dispatch.DispatchChannel;
import org.whispersystems.dispatch.DispatchManager; import org.whispersystems.dispatch.DispatchManager;
import org.whispersystems.dropwizard.simpleauth.AuthDynamicFeature;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.dropwizard.simpleauth.BasicCredentialAuthFilter;
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator; import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator; import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator;
import org.whispersystems.textsecuregcm.auth.MultiBasicAuthProvider;
import org.whispersystems.textsecuregcm.configuration.NexmoConfiguration; import org.whispersystems.textsecuregcm.configuration.NexmoConfiguration;
import org.whispersystems.textsecuregcm.controllers.AccountController; import org.whispersystems.textsecuregcm.controllers.AccountController;
import org.whispersystems.textsecuregcm.controllers.AttachmentController; import org.whispersystems.textsecuregcm.controllers.AttachmentController;
@ -66,9 +67,9 @@ import org.whispersystems.textsecuregcm.push.WebsocketSender;
import org.whispersystems.textsecuregcm.sms.NexmoSmsSender; import org.whispersystems.textsecuregcm.sms.NexmoSmsSender;
import org.whispersystems.textsecuregcm.sms.SmsSender; import org.whispersystems.textsecuregcm.sms.SmsSender;
import org.whispersystems.textsecuregcm.sms.TwilioSmsSender; import org.whispersystems.textsecuregcm.sms.TwilioSmsSender;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Accounts; import org.whispersystems.textsecuregcm.storage.Accounts;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.DirectoryManager; import org.whispersystems.textsecuregcm.storage.DirectoryManager;
import org.whispersystems.textsecuregcm.storage.Keys; import org.whispersystems.textsecuregcm.storage.Keys;
import org.whispersystems.textsecuregcm.storage.Messages; import org.whispersystems.textsecuregcm.storage.Messages;
@ -92,6 +93,7 @@ import org.whispersystems.websocket.setup.WebSocketEnvironment;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration; import javax.servlet.FilterRegistration;
import javax.servlet.ServletRegistration; import javax.servlet.ServletRegistration;
import javax.ws.rs.client.Client;
import java.security.Security; import java.security.Security;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -163,7 +165,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
PendingAccountsManager pendingAccountsManager = new PendingAccountsManager(pendingAccounts, cacheClient); PendingAccountsManager pendingAccountsManager = new PendingAccountsManager(pendingAccounts, cacheClient);
PendingDevicesManager pendingDevicesManager = new PendingDevicesManager (pendingDevices, cacheClient ); PendingDevicesManager pendingDevicesManager = new PendingDevicesManager (pendingDevices, cacheClient );
AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient); AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient);
FederatedClientManager federatedClientManager = new FederatedClientManager(config.getFederationConfiguration()); FederatedClientManager federatedClientManager = new FederatedClientManager(environment, config.getJerseyClientConfiguration(), config.getFederationConfiguration());
MessagesManager messagesManager = new MessagesManager(messages); MessagesManager messagesManager = new MessagesManager(messages);
DeadLetterHandler deadLetterHandler = new DeadLetterHandler(messagesManager); DeadLetterHandler deadLetterHandler = new DeadLetterHandler(messagesManager);
DispatchManager dispatchManager = new DispatchManager(cacheClientFactory, Optional.<DispatchChannel>of(deadLetterHandler)); DispatchManager dispatchManager = new DispatchManager(cacheClientFactory, Optional.<DispatchChannel>of(deadLetterHandler));
@ -171,6 +173,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
PushServiceClient pushServiceClient = new PushServiceClient(httpClient, config.getPushConfiguration()); PushServiceClient pushServiceClient = new PushServiceClient(httpClient, config.getPushConfiguration());
WebsocketSender websocketSender = new WebsocketSender(messagesManager, pubSubManager); WebsocketSender websocketSender = new WebsocketSender(messagesManager, pubSubManager);
AccountAuthenticator deviceAuthenticator = new AccountAuthenticator(accountsManager ); AccountAuthenticator deviceAuthenticator = new AccountAuthenticator(accountsManager );
FederatedPeerAuthenticator federatedPeerAuthenticator = new FederatedPeerAuthenticator(config.getFederationConfiguration());
RateLimiters rateLimiters = new RateLimiters(config.getLimitsConfiguration(), cacheClient); RateLimiters rateLimiters = new RateLimiters(config.getLimitsConfiguration(), cacheClient);
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient); ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushServiceClient);
@ -192,10 +195,15 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
KeysControllerV2 keysControllerV2 = new KeysControllerV2(rateLimiters, keys, accountsManager, federatedClientManager); KeysControllerV2 keysControllerV2 = new KeysControllerV2(rateLimiters, keys, accountsManager, federatedClientManager);
MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, federatedClientManager); MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, federatedClientManager);
environment.jersey().register(new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(config.getFederationConfiguration()), environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Account>()
FederatedPeer.class, .setAuthenticator(deviceAuthenticator)
deviceAuthenticator, .setPrincipal(Account.class)
Device.class, "WhisperServer")); .buildAuthFilter(),
new BasicCredentialAuthFilter.Builder<FederatedPeer>()
.setAuthenticator(federatedPeerAuthenticator)
.setPrincipal(FederatedPeer.class)
.buildAuthFilter()));
environment.jersey().register(new AuthValueFactoryProvider.Binder());
environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, rateLimiters, smsSender, messagesManager, new TimeProvider(), authorizationKey, config.getTestDevices())); environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, rateLimiters, smsSender, messagesManager, new TimeProvider(), authorizationKey, config.getTestDevices()));
environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, rateLimiters)); environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, rateLimiters));

View File

@ -22,6 +22,7 @@ import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.dropwizard.simpleauth.Authenticator;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
@ -29,7 +30,6 @@ import org.whispersystems.textsecuregcm.util.Constants;
import static com.codahale.metrics.MetricRegistry.name; import static com.codahale.metrics.MetricRegistry.name;
import io.dropwizard.auth.AuthenticationException; import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials; import io.dropwizard.auth.basic.BasicCredentials;
public class AccountAuthenticator implements Authenticator<BasicCredentials, Account> { public class AccountAuthenticator implements Authenticator<BasicCredentials, Account> {

View File

@ -22,6 +22,7 @@ import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.dropwizard.simpleauth.Authenticator;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration; import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.federation.FederatedPeer; import org.whispersystems.textsecuregcm.federation.FederatedPeer;
import org.whispersystems.textsecuregcm.util.Constants; import org.whispersystems.textsecuregcm.util.Constants;
@ -30,7 +31,6 @@ import java.util.List;
import static com.codahale.metrics.MetricRegistry.name; import static com.codahale.metrics.MetricRegistry.name;
import io.dropwizard.auth.AuthenticationException; import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials; import io.dropwizard.auth.basic.BasicCredentials;

View File

@ -1,66 +0,0 @@
/**
* Copyright (C) 2013 Open WhisperSystems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.auth;
import com.sun.jersey.api.model.Parameter;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import io.dropwizard.auth.Auth;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicAuthProvider;
import io.dropwizard.auth.basic.BasicCredentials;
public class MultiBasicAuthProvider<T1,T2> implements InjectableProvider<Auth, Parameter> {
private final BasicAuthProvider<T1> provider1;
private final BasicAuthProvider<T2> provider2;
private final Class<?> clazz1;
private final Class<?> clazz2;
public MultiBasicAuthProvider(Authenticator<BasicCredentials, T1> authenticator1,
Class<?> clazz1,
Authenticator<BasicCredentials, T2> authenticator2,
Class<?> clazz2,
String realm)
{
this.provider1 = new BasicAuthProvider<>(authenticator1, realm);
this.provider2 = new BasicAuthProvider<>(authenticator2, realm);
this.clazz1 = clazz1;
this.clazz2 = clazz2;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
@Override
public Injectable<?> getInjectable(ComponentContext componentContext,
Auth auth, Parameter parameter)
{
if (parameter.getParameterClass().equals(clazz1)) {
return this.provider1.getInjectable(componentContext, auth, parameter);
} else {
return this.provider2.getInjectable(componentContext, auth, parameter);
}
}
}

View File

@ -29,7 +29,7 @@ public class KeepAliveController {
@Timed @Timed
@GET @GET
public Response getKeepAlive(@Auth(required = false) Account account, public Response getKeepAlive(@Auth Account account,
@WebSocketSession WebSocketSessionContext context) @WebSocketSession WebSocketSessionContext context)
{ {
if (account != null) { if (account != null) {

View File

@ -52,7 +52,6 @@ public class KeysController {
this.federatedClientManager = federatedClientManager; this.federatedClientManager = federatedClientManager;
} }
@Timed
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public PreKeyCount getStatus(@Auth Account account) { public PreKeyCount getStatus(@Auth Account account) {

View File

@ -17,20 +17,17 @@
package org.whispersystems.textsecuregcm.federation; package org.whispersystems.textsecuregcm.federation;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.Client; import org.apache.http.client.CredentialsProvider;
import com.sun.jersey.api.client.ClientHandlerException; import org.apache.http.config.Registry;
import com.sun.jersey.api.client.ClientResponse; import org.apache.http.config.RegistryBuilder;
import com.sun.jersey.api.client.UniformInterfaceException; import org.apache.http.conn.socket.ConnectionSocketFactory;
import com.sun.jersey.api.client.WebResource; import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import com.sun.jersey.api.client.config.ClientConfig; import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import org.apache.http.conn.ssl.StrictHostnameVerifier; import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.bouncycastle.openssl.PEMReader; import org.bouncycastle.openssl.PEMReader;
import org.glassfish.jersey.SslConfigurator;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.entities.AccountCount; import org.whispersystems.textsecuregcm.entities.AccountCount;
@ -40,11 +37,16 @@ import org.whispersystems.textsecuregcm.entities.ClientContacts;
import org.whispersystems.textsecuregcm.entities.IncomingMessageList; import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
import org.whispersystems.textsecuregcm.entities.PreKeyResponseV1; import org.whispersystems.textsecuregcm.entities.PreKeyResponseV1;
import org.whispersystems.textsecuregcm.entities.PreKeyResponseV2; import org.whispersystems.textsecuregcm.entities.PreKeyResponseV2;
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.providers.JacksonConfigurator;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -59,7 +61,10 @@ import java.security.SecureRandom;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.List; import java.util.List;
import java.util.Map;
import io.dropwizard.client.JerseyClientBuilder;
import io.dropwizard.client.JerseyClientConfiguration;
import io.dropwizard.setup.Environment;
public class FederatedClient { public class FederatedClient {
@ -75,15 +80,14 @@ public class FederatedClient {
private final FederatedPeer peer; private final FederatedPeer peer;
private final Client client; private final Client client;
private final String authorizationHeader;
public FederatedClient(String federationName, FederatedPeer peer) public FederatedClient(Environment environment, JerseyClientConfiguration configuration,
String federationName, FederatedPeer peer)
throws IOException throws IOException
{ {
try { try {
this.client = Client.create(getClientConfig(peer)); this.client = createClient(environment, configuration, federationName, peer);
this.peer = peer; this.peer = peer;
this.authorizationHeader = getAuthorizationHeader(federationName, peer);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new AssertionError(e); throw new AssertionError(e);
} catch (KeyStoreException | KeyManagementException | CertificateException e) { } catch (KeyStoreException | KeyManagementException | CertificateException e) {
@ -93,20 +97,14 @@ public class FederatedClient {
public URL getSignedAttachmentUri(long attachmentId) throws IOException { public URL getSignedAttachmentUri(long attachmentId) throws IOException {
try { try {
WebResource resource = client.resource(peer.getUrl()) AttachmentUri response = client.target(peer.getUrl())
.path(String.format(ATTACHMENT_URI_PATH, attachmentId)); .path(String.format(ATTACHMENT_URI_PATH, attachmentId))
.request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(AttachmentUri.class);
ClientResponse response = resource.accept(MediaType.APPLICATION_JSON) return response.getLocation();
.header("Authorization", authorizationHeader) } catch (ProcessingException e) {
.get(ClientResponse.class);
if (response.getStatus() < 200 || response.getStatus() >= 300) {
throw new WebApplicationException(clientResponseToResponse(response));
}
return response.getEntity(AttachmentUri.class).getLocation();
} catch (UniformInterfaceException | ClientHandlerException e) {
logger.warn("Bad URI", e); logger.warn("Bad URI", e);
throw new IOException(e); throw new IOException(e);
} }
@ -114,19 +112,14 @@ public class FederatedClient {
public Optional<PreKeyResponseV1> getKeysV1(String destination, String device) { public Optional<PreKeyResponseV1> getKeysV1(String destination, String device) {
try { try {
WebResource resource = client.resource(peer.getUrl()).path(String.format(PREKEY_PATH_DEVICE_V1, destination, device)); PreKeyResponseV1 response = client.target(peer.getUrl())
.path(String.format(PREKEY_PATH_DEVICE_V1, destination, device))
.request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(PreKeyResponseV1.class);
ClientResponse response = resource.accept(MediaType.APPLICATION_JSON) return Optional.of(response);
.header("Authorization", authorizationHeader) } catch (ProcessingException e) {
.get(ClientResponse.class);
if (response.getStatus() < 200 || response.getStatus() >= 300) {
throw new WebApplicationException(clientResponseToResponse(response));
}
return Optional.of(response.getEntity(PreKeyResponseV1.class));
} catch (UniformInterfaceException | ClientHandlerException e) {
logger.warn("PreKey", e); logger.warn("PreKey", e);
return Optional.absent(); return Optional.absent();
} }
@ -134,34 +127,29 @@ public class FederatedClient {
public Optional<PreKeyResponseV2> getKeysV2(String destination, String device) { public Optional<PreKeyResponseV2> getKeysV2(String destination, String device) {
try { try {
WebResource resource = client.resource(peer.getUrl()).path(String.format(PREKEY_PATH_DEVICE_V2, destination, device)); PreKeyResponseV2 response = client.target(peer.getUrl())
.path(String.format(PREKEY_PATH_DEVICE_V2, destination, device))
.request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(PreKeyResponseV2.class);
ClientResponse response = resource.accept(MediaType.APPLICATION_JSON) return Optional.of(response);
.header("Authorization", authorizationHeader) } catch (ProcessingException e) {
.get(ClientResponse.class);
if (response.getStatus() < 200 || response.getStatus() >= 300) {
throw new WebApplicationException(clientResponseToResponse(response));
}
return Optional.of(response.getEntity(PreKeyResponseV2.class));
} catch (UniformInterfaceException | ClientHandlerException e) {
logger.warn("PreKey", e); logger.warn("PreKey", e);
return Optional.absent(); return Optional.absent();
} }
} }
public int getUserCount() { public int getUserCount() {
try { try {
WebResource resource = client.resource(peer.getUrl()).path(USER_COUNT_PATH); AccountCount count = client.target(peer.getUrl())
AccountCount count = resource.accept(MediaType.APPLICATION_JSON) .path(USER_COUNT_PATH)
.header("Authorization", authorizationHeader) .request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(AccountCount.class); .get(AccountCount.class);
return count.getCount(); return count.getCount();
} catch (UniformInterfaceException | ClientHandlerException e) { } catch (ProcessingException e) {
logger.warn("User Count", e); logger.warn("User Count", e);
return 0; return 0;
} }
@ -169,13 +157,14 @@ public class FederatedClient {
public List<ClientContact> getUserTokens(int offset) { public List<ClientContact> getUserTokens(int offset) {
try { try {
WebResource resource = client.resource(peer.getUrl()).path(String.format(USER_TOKENS_PATH, offset)); ClientContacts contacts = client.target(peer.getUrl())
ClientContacts contacts = resource.accept(MediaType.APPLICATION_JSON) .path(String.format(USER_TOKENS_PATH, offset))
.header("Authorization", authorizationHeader) .request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(ClientContacts.class); .get(ClientContacts.class);
return contacts.getContacts(); return contacts.getContacts();
} catch (UniformInterfaceException | ClientHandlerException e) { } catch (ProcessingException e) {
logger.warn("User Tokens", e); logger.warn("User Tokens", e);
return null; return null;
} }
@ -185,16 +174,16 @@ public class FederatedClient {
throws IOException throws IOException
{ {
try { try {
WebResource resource = client.resource(peer.getUrl()).path(String.format(RELAY_MESSAGE_PATH, source, sourceDeviceId, destination)); Response response = client.target(peer.getUrl())
ClientResponse response = resource.type(MediaType.APPLICATION_JSON) .path(String.format(RELAY_MESSAGE_PATH, source, sourceDeviceId, destination))
.header("Authorization", authorizationHeader) .request()
.entity(messages) .put(Entity.entity(messages, MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
if (response.getStatus() != 200 && response.getStatus() != 204) { if (response.getStatus() != 200 && response.getStatus() != 204) {
throw new WebApplicationException(clientResponseToResponse(response)); throw new WebApplicationException(response);
} }
} catch (UniformInterfaceException | ClientHandlerException e) {
} catch (ProcessingException e) {
logger.warn("sendMessage", e); logger.warn("sendMessage", e);
throw new IOException(e); throw new IOException(e);
} }
@ -204,26 +193,22 @@ public class FederatedClient {
throws IOException throws IOException
{ {
try { try {
String path = String.format(RECEIPT_PATH, source, sourceDeviceId, destination, messageId); Response response = client.target(peer.getUrl())
WebResource resource = client.resource(peer.getUrl()).path(path); .path(String.format(RECEIPT_PATH, source, sourceDeviceId, destination, messageId))
ClientResponse response = resource.type(MediaType.APPLICATION_JSON) .request()
.header("Authorization", authorizationHeader) .put(Entity.json(null));
.put(ClientResponse.class);
if (response.getStatus() != 200 && response.getStatus() != 204) { if (response.getStatus() != 200 && response.getStatus() != 204) {
throw new WebApplicationException(clientResponseToResponse(response)); throw new WebApplicationException(response);
} }
} catch (UniformInterfaceException | ClientHandlerException e) { } catch (ProcessingException e) {
logger.warn("sendMessage", e); logger.warn("sendMessage", e);
throw new IOException(e); throw new IOException(e);
} }
} }
private String getAuthorizationHeader(String federationName, FederatedPeer peer) { private Client createClient(Environment environment, JerseyClientConfiguration configuration,
return "Basic " + Base64.encodeBytes((federationName + ":" + peer.getAuthenticationToken()).getBytes()); String federationName, FederatedPeer peer)
}
private ClientConfig getClientConfig(FederatedPeer peer)
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException
{ {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
@ -232,13 +217,16 @@ public class FederatedClient {
SSLContext sslContext = SSLContext.getInstance("TLS"); SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), SecureRandom.getInstance("SHA1PRNG")); sslContext.init(null, trustManagerFactory.getTrustManagers(), SecureRandom.getInstance("SHA1PRNG"));
ClientConfig config = new DefaultClientConfig(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier());
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build();
new HTTPSProperties(new StrictHostnameVerifier(), sslContext));
config.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
config.getSingletons().add(new JacksonJsonProvider().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return config; Client client = new JerseyClientBuilder(environment).using(configuration)
.using(registry)
.build("FederatedClient");
client.register(HttpAuthenticationFeature.basic(federationName, peer.getAuthenticationToken()));
return client;
} }
private KeyStore initializeTrustStore(String name, String pemCertificate) private KeyStore initializeTrustStore(String name, String pemCertificate)
@ -264,19 +252,6 @@ public class FederatedClient {
} }
} }
private Response clientResponseToResponse(ClientResponse r) {
Response.ResponseBuilder rb = Response.status(r.getStatus());
for (Map.Entry<String, List<String>> entry : r.getHeaders().entrySet()) {
for (String value : entry.getValue()) {
rb.header(entry.getKey(), value);
}
}
rb.entity(r.getEntityInputStream());
return rb.build();
}
public String getPeerName() { public String getPeerName() {
return peer.getName(); return peer.getName();
} }

View File

@ -25,13 +25,18 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import io.dropwizard.client.JerseyClientConfiguration;
import io.dropwizard.setup.Environment;
public class FederatedClientManager { public class FederatedClientManager {
private final Logger logger = LoggerFactory.getLogger(FederatedClientManager.class); private final Logger logger = LoggerFactory.getLogger(FederatedClientManager.class);
private final HashMap<String, FederatedClient> clients = new HashMap<>(); private final HashMap<String, FederatedClient> clients = new HashMap<>();
public FederatedClientManager(FederationConfiguration federationConfig) public FederatedClientManager(Environment environment,
JerseyClientConfiguration clientConfig,
FederationConfiguration federationConfig)
throws IOException throws IOException
{ {
List<FederatedPeer> peers = federationConfig.getPeers(); List<FederatedPeer> peers = federationConfig.getPeers();
@ -40,7 +45,7 @@ public class FederatedClientManager {
if (peers != null) { if (peers != null) {
for (FederatedPeer peer : peers) { for (FederatedPeer peer : peers) {
logger.info("Adding peer: " + peer.getName()); logger.info("Adding peer: " + peer.getName());
clients.put(peer.getName(), new FederatedClient(identity, peer)); clients.put(peer.getName(), new FederatedClient(environment, clientConfig, identity, peer));
} }
} }
} }

View File

@ -7,9 +7,9 @@ import java.sql.SQLException;
import io.dropwizard.Configuration; import io.dropwizard.Configuration;
import io.dropwizard.cli.ConfiguredCommand; import io.dropwizard.cli.ConfiguredCommand;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.db.DatabaseConfiguration; import io.dropwizard.db.DatabaseConfiguration;
import io.dropwizard.db.ManagedDataSource; import io.dropwizard.db.ManagedDataSource;
import io.dropwizard.db.PooledDataSourceFactory;
import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Bootstrap;
import liquibase.Liquibase; import liquibase.Liquibase;
import liquibase.exception.LiquibaseException; import liquibase.exception.LiquibaseException;
@ -40,10 +40,8 @@ public abstract class AbstractLiquibaseCommand<T extends Configuration> extends
@Override @Override
@SuppressWarnings("UseOfSystemOutOrSystemErr") @SuppressWarnings("UseOfSystemOutOrSystemErr")
protected void run(Bootstrap<T> bootstrap, Namespace namespace, T configuration) throws Exception { protected void run(Bootstrap<T> bootstrap, Namespace namespace, T configuration) throws Exception {
final DataSourceFactory dbConfig = strategy.getDataSourceFactory(configuration); final PooledDataSourceFactory dbConfig = strategy.getDataSourceFactory(configuration);
dbConfig.setMaxSize(1); dbConfig.asSingleConnectionPool();
dbConfig.setMinSize(1);
dbConfig.setInitialSize(1);
try (final CloseableLiquibase liquibase = openLiquibase(dbConfig, namespace)) { try (final CloseableLiquibase liquibase = openLiquibase(dbConfig, namespace)) {
run(namespace, liquibase); run(namespace, liquibase);
@ -53,7 +51,7 @@ public abstract class AbstractLiquibaseCommand<T extends Configuration> extends
} }
} }
private CloseableLiquibase openLiquibase(final DataSourceFactory dataSourceFactory, final Namespace namespace) private CloseableLiquibase openLiquibase(final PooledDataSourceFactory dataSourceFactory, final Namespace namespace)
throws ClassNotFoundException, SQLException, LiquibaseException throws ClassNotFoundException, SQLException, LiquibaseException
{ {
final ManagedDataSource dataSource = dataSourceFactory.build(new MetricRegistry(), "liquibase"); final ManagedDataSource dataSource = dataSourceFactory.build(new MetricRegistry(), "liquibase");

View File

@ -0,0 +1,24 @@
package org.whispersystems.textsecuregcm.providers;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
@Provider
public class JacksonConfigurator implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public JacksonConfigurator() {
mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}

View File

@ -1,9 +1,5 @@
package org.whispersystems.textsecuregcm.push; package org.whispersystems.textsecuregcm.push;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.PushConfiguration; import org.whispersystems.textsecuregcm.configuration.PushConfiguration;
@ -13,7 +9,11 @@ import org.whispersystems.textsecuregcm.entities.UnregisteredEvent;
import org.whispersystems.textsecuregcm.entities.UnregisteredEventList; import org.whispersystems.textsecuregcm.entities.UnregisteredEventList;
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.util.Base64;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -57,16 +57,17 @@ public class PushServiceClient {
private void sendPush(String path, Object entity) throws TransientPushFailureException { private void sendPush(String path, Object entity) throws TransientPushFailureException {
try { try {
ClientResponse response = client.resource("http://" + host + ":" + port + path) Response response = client.target("http://" + host + ":" + port)
.path(path)
.request()
.header("Authorization", authorization) .header("Authorization", authorization)
.entity(entity, MediaType.APPLICATION_JSON) .put(Entity.entity(entity, MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
if (response.getStatus() != 204 && response.getStatus() != 200) { if (response.getStatus() != 204 && response.getStatus() != 200) {
logger.warn("PushServer response: " + response.getStatus() + " " + response.getStatusInfo().getReasonPhrase()); logger.warn("PushServer response: " + response.getStatus() + " " + response.getStatusInfo().getReasonPhrase());
throw new TransientPushFailureException("Bad response: " + response.getStatus()); throw new TransientPushFailureException("Bad response: " + response.getStatus());
} }
} catch (UniformInterfaceException | ClientHandlerException e) { } catch (ProcessingException e) {
logger.warn("Push error: ", e); logger.warn("Push error: ", e);
throw new TransientPushFailureException(e); throw new TransientPushFailureException(e);
} }
@ -74,12 +75,14 @@ public class PushServiceClient {
private List<UnregisteredEvent> getFeedback(String path) throws IOException { private List<UnregisteredEvent> getFeedback(String path) throws IOException {
try { try {
UnregisteredEventList unregisteredEvents = client.resource("http://" + host + ":" + port + path) UnregisteredEventList unregisteredEvents = client.target("http://" + host + ":" + port)
.path(path)
.request()
.header("Authorization", authorization) .header("Authorization", authorization)
.get(UnregisteredEventList.class); .get(UnregisteredEventList.class);
return unregisteredEvents.getDevices(); return unregisteredEvents.getDevices();
} catch (UniformInterfaceException | ClientHandlerException e) { } catch (ProcessingException e) {
logger.warn("Request error:", e); logger.warn("Request error:", e);
throw new IOException(e); throw new IOException(e);
} }

View File

@ -47,7 +47,7 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener {
@Override @Override
public void onWebSocketConnect(WebSocketSessionContext context) { public void onWebSocketConnect(WebSocketSessionContext context) {
final Account account = context.getAuthenticated(Account.class).get(); final Account account = context.getAuthenticated(Account.class);
final Device device = account.getAuthenticatedDevice().get(); final Device device = account.getAuthenticatedDevice().get();
final long connectTime = System.currentTimeMillis(); final long connectTime = System.currentTimeMillis();
final WebsocketAddress address = new WebsocketAddress(account.getNumber(), device.getId()); final WebsocketAddress address = new WebsocketAddress(account.getNumber(), device.getId());

View File

@ -8,6 +8,7 @@ import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.websocket.auth.AuthenticationException; import org.whispersystems.websocket.auth.AuthenticationException;
import org.whispersystems.websocket.auth.WebSocketAuthenticator; import org.whispersystems.websocket.auth.WebSocketAuthenticator;
import java.util.List;
import java.util.Map; import java.util.Map;
import io.dropwizard.auth.basic.BasicCredentials; import io.dropwizard.auth.basic.BasicCredentials;
@ -24,18 +25,18 @@ public class WebSocketAccountAuthenticator implements WebSocketAuthenticator<Acc
@Override @Override
public Optional<Account> authenticate(UpgradeRequest request) throws AuthenticationException { public Optional<Account> authenticate(UpgradeRequest request) throws AuthenticationException {
try { try {
Map<String, String[]> parameters = request.getParameterMap(); Map<String, List<String>> parameters = request.getParameterMap();
String[] usernames = parameters.get("login"); List<String> usernames = parameters.get("login");
String[] passwords = parameters.get("password"); List<String> passwords = parameters.get("password");
if (usernames == null || usernames.length == 0 || if (usernames == null || usernames.size() == 0 ||
passwords == null || passwords.length == 0) passwords == null || passwords.size() == 0)
{ {
return Optional.absent(); return Optional.absent();
} }
BasicCredentials credentials = new BasicCredentials(usernames[0].replace(" ", "+"), BasicCredentials credentials = new BasicCredentials(usernames.get(0).replace(" ", "+"),
passwords[0].replace(" ", "+")); passwords.get(0).replace(" ", "+"));
return accountAuthenticator.authenticate(credentials); return accountAuthenticator.authenticate(credentials);
} catch (io.dropwizard.auth.AuthenticationException e) { } catch (io.dropwizard.auth.AuthenticationException e) {

View File

@ -27,31 +27,40 @@ import org.whispersystems.textsecuregcm.storage.Accounts;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.DirectoryManager; import org.whispersystems.textsecuregcm.storage.DirectoryManager;
import io.dropwizard.Application;
import io.dropwizard.cli.ConfiguredCommand; import io.dropwizard.cli.ConfiguredCommand;
import io.dropwizard.cli.EnvironmentCommand;
import io.dropwizard.db.DataSourceFactory; import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.jdbi.ImmutableListContainerFactory; import io.dropwizard.jdbi.ImmutableListContainerFactory;
import io.dropwizard.jdbi.ImmutableSetContainerFactory; import io.dropwizard.jdbi.ImmutableSetContainerFactory;
import io.dropwizard.jdbi.OptionalContainerFactory; import io.dropwizard.jdbi.OptionalContainerFactory;
import io.dropwizard.jdbi.args.OptionalArgumentFactory; import io.dropwizard.jdbi.args.OptionalArgumentFactory;
import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
public class DirectoryCommand extends ConfiguredCommand<WhisperServerConfiguration> { public class DirectoryCommand extends EnvironmentCommand<WhisperServerConfiguration> {
private final Logger logger = LoggerFactory.getLogger(DirectoryCommand.class); private final Logger logger = LoggerFactory.getLogger(DirectoryCommand.class);
public DirectoryCommand() { public DirectoryCommand() {
super("directory", "Update directory from DB and peers."); super(new Application<WhisperServerConfiguration>() {
@Override
public void run(WhisperServerConfiguration configuration, Environment environment)
throws Exception
{
}
}, "directory", "Update directory from DB and peers.");
} }
@Override @Override
protected void run(Bootstrap<WhisperServerConfiguration> bootstrap, protected void run(Environment environment, Namespace namespace,
Namespace namespace, WhisperServerConfiguration configuration)
WhisperServerConfiguration config)
throws Exception throws Exception
{ {
try { try {
DataSourceFactory dbConfig = config.getDataSourceFactory(); DataSourceFactory dbConfig = configuration.getDataSourceFactory();
DBI dbi = new DBI(dbConfig.getUrl(), dbConfig.getUser(), dbConfig.getPassword()); DBI dbi = new DBI(dbConfig.getUrl(), dbConfig.getUser(), dbConfig.getPassword());
dbi.registerArgumentFactory(new OptionalArgumentFactory(dbConfig.getDriverClass())); dbi.registerArgumentFactory(new OptionalArgumentFactory(dbConfig.getDriverClass()));
@ -60,11 +69,13 @@ public class DirectoryCommand extends ConfiguredCommand<WhisperServerConfigurati
dbi.registerContainerFactory(new OptionalContainerFactory()); dbi.registerContainerFactory(new OptionalContainerFactory());
Accounts accounts = dbi.onDemand(Accounts.class); Accounts accounts = dbi.onDemand(Accounts.class);
JedisPool cacheClient = new RedisClientFactory(config.getCacheConfiguration().getUrl()).getRedisClientPool(); JedisPool cacheClient = new RedisClientFactory(configuration.getCacheConfiguration().getUrl()).getRedisClientPool();
JedisPool redisClient = new RedisClientFactory(config.getDirectoryConfiguration().getUrl()).getRedisClientPool(); JedisPool redisClient = new RedisClientFactory(configuration.getDirectoryConfiguration().getUrl()).getRedisClientPool();
DirectoryManager directory = new DirectoryManager(redisClient); DirectoryManager directory = new DirectoryManager(redisClient);
AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient); AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient);
FederatedClientManager federatedClientManager = new FederatedClientManager(config.getFederationConfiguration()); FederatedClientManager federatedClientManager = new FederatedClientManager(environment,
configuration.getJerseyClientConfiguration(),
configuration.getFederationConfiguration());
DirectoryUpdater update = new DirectoryUpdater(accountsManager, federatedClientManager, directory); DirectoryUpdater update = new DirectoryUpdater(accountsManager, federatedClientManager, directory);

View File

@ -1,12 +1,13 @@
package org.whispersystems.textsecuregcm.tests.controllers; package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.AccountController; import org.whispersystems.textsecuregcm.controllers.AccountController;
import org.whispersystems.textsecuregcm.entities.AccountAttributes; import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.limits.RateLimiter; import org.whispersystems.textsecuregcm.limits.RateLimiter;
@ -17,15 +18,15 @@ import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.PendingAccountsManager; import org.whispersystems.textsecuregcm.storage.PendingAccountsManager;
//import org.whispersystems.textsecuregcm.storage.StoredMessages;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap; import java.util.HashMap;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -44,7 +45,9 @@ public class AccountControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new AccountController(pendingAccountsManager, .addResource(new AccountController(pendingAccountsManager,
accountsManager, accountsManager,
rateLimiters, rateLimiters,
@ -69,9 +72,11 @@ public class AccountControllerTest {
@Test @Test
public void testSendCode() throws Exception { public void testSendCode() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/sms/code/%s", SENDER)) resources.getJerseyTest()
.get(ClientResponse.class); .target(String.format("/v1/accounts/sms/code/%s", SENDER))
.request()
.get();
assertThat(response.getStatus()).isEqualTo(200); assertThat(response.getStatus()).isEqualTo(200);
@ -80,12 +85,13 @@ public class AccountControllerTest {
@Test @Test
public void testVerifyCode() throws Exception { public void testVerifyCode() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/code/%s", "1234")) resources.getJerseyTest()
.target(String.format("/v1/accounts/code/%s", "1234"))
.request()
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new AccountAttributes("keykeykeykey", false, 2222)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 2222),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(204); assertThat(response.getStatus()).isEqualTo(204);
@ -94,12 +100,13 @@ public class AccountControllerTest {
@Test @Test
public void testVerifyBadCode() throws Exception { public void testVerifyBadCode() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/code/%s", "1111")) resources.getJerseyTest()
.target(String.format("/v1/accounts/code/%s", "1111"))
.request()
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new AccountAttributes("keykeykeykey", false, 3333)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 3333),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(403); assertThat(response.getStatus()).isEqualTo(403);
@ -112,12 +119,13 @@ public class AccountControllerTest {
String token = SENDER + ":1415906573:af4f046107c21721224a"; String token = SENDER + ":1415906573:af4f046107c21721224a";
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/token/%s", token)) resources.getJerseyTest()
.target(String.format("/v1/accounts/token/%s", token))
.request()
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new AccountAttributes("keykeykeykey", false, 4444)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 4444),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(204); assertThat(response.getStatus()).isEqualTo(204);
@ -130,12 +138,13 @@ public class AccountControllerTest {
String token = SENDER + ":1415906574:af4f046107c21721224a"; String token = SENDER + ":1415906574:af4f046107c21721224a";
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/token/%s", token)) resources.getJerseyTest()
.target(String.format("/v1/accounts/token/%s", token))
.request()
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new AccountAttributes("keykeykeykey", false, 4444)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 4444),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(403); assertThat(response.getStatus()).isEqualTo(403);
@ -148,12 +157,13 @@ public class AccountControllerTest {
String token = SENDER + ":1415906573:af4f046107c21721224a"; String token = SENDER + ":1415906573:af4f046107c21721224a";
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/token/%s", token)) resources.getJerseyTest()
.target(String.format("/v1/accounts/token/%s", token))
.request()
.header("Authorization", AuthHelper.getAuthHeader("+14151111111", "bar")) .header("Authorization", AuthHelper.getAuthHeader("+14151111111", "bar"))
.entity(new AccountAttributes("keykeykeykey", false, 4444)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 4444),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(403); assertThat(response.getStatus()).isEqualTo(403);
@ -166,12 +176,13 @@ public class AccountControllerTest {
String token = SENDER + ":1415906573:af4f046107c21721224a"; String token = SENDER + ":1415906573:af4f046107c21721224a";
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/accounts/token/%s", token)) resources.getJerseyTest()
.target(String.format("/v1/accounts/token/%s", token))
.request()
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new AccountAttributes("keykeykeykey", false, 4444)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 4444),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(403); assertThat(response.getStatus()).isEqualTo(403);

View File

@ -17,10 +17,11 @@
package org.whispersystems.textsecuregcm.tests.controllers; package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.DeviceController; import org.whispersystems.textsecuregcm.controllers.DeviceController;
import org.whispersystems.textsecuregcm.entities.AccountAttributes; import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.DeviceResponse; import org.whispersystems.textsecuregcm.entities.DeviceResponse;
@ -34,11 +35,13 @@ import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.VerificationCode; import org.whispersystems.textsecuregcm.util.VerificationCode;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import io.dropwizard.jersey.validation.ConstraintViolationExceptionMapper; import io.dropwizard.jersey.validation.ConstraintViolationExceptionMapper;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -64,7 +67,9 @@ public class DeviceControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addProvider(new DeviceLimitExceededExceptionMapper()) .addProvider(new DeviceLimitExceededExceptionMapper())
.addProvider(new ConstraintViolationExceptionMapper()) .addProvider(new ConstraintViolationExceptionMapper())
.addResource(new DumbVerificationDeviceController(pendingDevicesManager, .addResource(new DumbVerificationDeviceController(pendingDevicesManager,
@ -92,17 +97,21 @@ public class DeviceControllerTest {
@Test @Test
public void validDeviceRegisterTest() throws Exception { public void validDeviceRegisterTest() throws Exception {
VerificationCode deviceCode = resources.client().resource("/v1/devices/provisioning/code") VerificationCode deviceCode = resources.getJerseyTest()
.target("/v1/devices/provisioning/code")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(VerificationCode.class); .get(VerificationCode.class);
assertThat(deviceCode).isEqualTo(new VerificationCode(5678901)); assertThat(deviceCode).isEqualTo(new VerificationCode(5678901));
DeviceResponse response = resources.client().resource("/v1/devices/5678901") DeviceResponse response = resources.getJerseyTest()
.target("/v1/devices/5678901")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
.entity(new AccountAttributes("keykeykeykey", false, 1234)) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 1234),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE),
.put(DeviceResponse.class); DeviceResponse.class);
assertThat(response.getDeviceId()).isEqualTo(42L); assertThat(response.getDeviceId()).isEqualTo(42L);
@ -111,20 +120,23 @@ public class DeviceControllerTest {
@Test @Test
public void maxDevicesTest() throws Exception { public void maxDevicesTest() throws Exception {
ClientResponse response = resources.client().resource("/v1/devices/provisioning/code") Response response = resources.getJerseyTest()
.target("/v1/devices/provisioning/code")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO))
.get(ClientResponse.class); .get();
assertEquals(response.getStatus(), 411); assertEquals(response.getStatus(), 411);
} }
@Test @Test
public void longNameTest() throws Exception { public void longNameTest() throws Exception {
ClientResponse response = resources.client().resource("/v1/devices/5678901") Response response = resources.getJerseyTest()
.target("/v1/devices/5678901")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
.entity(new AccountAttributes("keykeykeykey", false, 1234, "this is a really long name that is longer than 80 characters")) .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 1234, "this is a really long name that is longer than 80 characters"),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertEquals(response.getStatus(), 422); assertEquals(response.getStatus(), 422);
} }

View File

@ -1,12 +1,12 @@
package org.whispersystems.textsecuregcm.tests.controllers; package org.whispersystems.textsecuregcm.tests.controllers;
import com.sun.jersey.api.client.ClientResponse; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.DirectoryController; import org.whispersystems.textsecuregcm.controllers.DirectoryController;
import org.whispersystems.textsecuregcm.entities.ClientContactTokens; import org.whispersystems.textsecuregcm.entities.ClientContactTokens;
import org.whispersystems.textsecuregcm.limits.RateLimiter; import org.whispersystems.textsecuregcm.limits.RateLimiter;
@ -15,12 +15,14 @@ import org.whispersystems.textsecuregcm.storage.DirectoryManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.util.Base64;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyList; import static org.mockito.Matchers.anyList;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -33,7 +35,9 @@ public class DirectoryControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new DirectoryController(rateLimiters, .addResource(new DirectoryController(rateLimiters,
directoryManager)) directoryManager))
.build(); .build();
@ -64,17 +68,17 @@ public class DirectoryControllerTest {
List<String> expectedResponse = new LinkedList<>(tokens); List<String> expectedResponse = new LinkedList<>(tokens);
expectedResponse.remove(0); expectedResponse.remove(0);
ClientResponse response = Response response =
resources.client().resource("/v1/directory/tokens/") resources.getJerseyTest()
.entity(new ClientContactTokens(tokens)) .target("/v1/directory/tokens/")
.type(MediaType.APPLICATION_JSON_TYPE) .request()
.header("Authorization", .header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER,
AuthHelper.VALID_PASSWORD)) AuthHelper.VALID_PASSWORD))
.put(ClientResponse.class); .put(Entity.entity(new ClientContactTokens(tokens), MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(200); assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getEntity(ClientContactTokens.class).getContacts()).isEqualTo(expectedResponse); assertThat(response.readEntity(ClientContactTokens.class).getContacts()).isEqualTo(expectedResponse);
} }
} }

View File

@ -3,10 +3,11 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.FederationControllerV1; import org.whispersystems.textsecuregcm.controllers.FederationControllerV1;
import org.whispersystems.textsecuregcm.controllers.FederationControllerV2; import org.whispersystems.textsecuregcm.controllers.FederationControllerV2;
import org.whispersystems.textsecuregcm.controllers.KeysControllerV2; import org.whispersystems.textsecuregcm.controllers.KeysControllerV2;
@ -27,7 +28,9 @@ import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Set; import java.util.Set;
@ -64,7 +67,9 @@ public class FederatedControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new FederationControllerV1(accountsManager, null, messageController, null)) .addResource(new FederationControllerV1(accountsManager, null, messageController, null))
.addResource(new FederationControllerV2(accountsManager, null, messageController, keysControllerV2)) .addResource(new FederationControllerV2(accountsManager, null, messageController, keysControllerV2))
.build(); .build();
@ -97,12 +102,13 @@ public class FederatedControllerTest {
@Test @Test
public void testSingleDeviceCurrent() throws Exception { public void testSingleDeviceCurrent() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/federation/messages/+14152223333/1/%s", SINGLE_DEVICE_RECIPIENT)) resources.getJerseyTest()
.target(String.format("/v1/federation/messages/+14152223333/1/%s", SINGLE_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo")) .header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo"))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat("Good Response", response.getStatus(), is(equalTo(204))); assertThat("Good Response", response.getStatus(), is(equalTo(204)));
@ -112,7 +118,9 @@ public class FederatedControllerTest {
@Test @Test
public void testSignedPreKeyV2() throws Exception { public void testSignedPreKeyV2() throws Exception {
PreKeyResponseV2 response = PreKeyResponseV2 response =
resources.client().resource("/v2/federation/key/+14152223333/1") resources.getJerseyTest()
.target("/v2/federation/key/+14152223333/1")
.request()
.header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo")) .header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo"))
.get(PreKeyResponseV2.class); .get(PreKeyResponseV2.class);

View File

@ -1,14 +1,14 @@
package org.whispersystems.textsecuregcm.tests.controllers; package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.KeysControllerV1; import org.whispersystems.textsecuregcm.controllers.KeysControllerV1;
import org.whispersystems.textsecuregcm.controllers.KeysControllerV2; import org.whispersystems.textsecuregcm.controllers.KeysControllerV2;
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.entities.PreKeyCount; import org.whispersystems.textsecuregcm.entities.PreKeyCount;
import org.whispersystems.textsecuregcm.entities.PreKeyResponseV1; import org.whispersystems.textsecuregcm.entities.PreKeyResponseV1;
import org.whispersystems.textsecuregcm.entities.PreKeyResponseV2; import org.whispersystems.textsecuregcm.entities.PreKeyResponseV2;
@ -16,6 +16,7 @@ import org.whispersystems.textsecuregcm.entities.PreKeyStateV1;
import org.whispersystems.textsecuregcm.entities.PreKeyStateV2; import org.whispersystems.textsecuregcm.entities.PreKeyStateV2;
import org.whispersystems.textsecuregcm.entities.PreKeyV1; import org.whispersystems.textsecuregcm.entities.PreKeyV1;
import org.whispersystems.textsecuregcm.entities.PreKeyV2; import org.whispersystems.textsecuregcm.entities.PreKeyV2;
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.limits.RateLimiter; import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
@ -25,14 +26,16 @@ import org.whispersystems.textsecuregcm.storage.KeyRecord;
import org.whispersystems.textsecuregcm.storage.Keys; import org.whispersystems.textsecuregcm.storage.Keys;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
public class KeyControllerTest { public class KeyControllerTest {
@ -63,7 +66,9 @@ public class KeyControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new KeysControllerV1(rateLimiters, keys, accounts, null)) .addResource(new KeysControllerV1(rateLimiters, keys, accounts, null))
.addResource(new KeysControllerV2(rateLimiters, keys, accounts, null)) .addResource(new KeysControllerV2(rateLimiters, keys, accounts, null))
.build(); .build();
@ -134,7 +139,9 @@ public class KeyControllerTest {
@Test @Test
public void validKeyStatusTestV1() throws Exception { public void validKeyStatusTestV1() throws Exception {
PreKeyCount result = resources.client().resource("/v1/keys") PreKeyCount result = resources.getJerseyTest()
.target("/v1/keys")
.request()
.header("Authorization", .header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyCount.class); .get(PreKeyCount.class);
@ -146,7 +153,9 @@ public class KeyControllerTest {
@Test @Test
public void validKeyStatusTestV2() throws Exception { public void validKeyStatusTestV2() throws Exception {
PreKeyCount result = resources.client().resource("/v2/keys") PreKeyCount result = resources.getJerseyTest()
.target("/v2/keys")
.request()
.header("Authorization", .header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyCount.class); .get(PreKeyCount.class);
@ -158,7 +167,9 @@ public class KeyControllerTest {
@Test @Test
public void getSignedPreKeyV2() throws Exception { public void getSignedPreKeyV2() throws Exception {
SignedPreKey result = resources.client().resource("/v2/keys/signed") SignedPreKey result = resources.getJerseyTest()
.target("/v2/keys/signed")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(SignedPreKey.class); .get(SignedPreKey.class);
@ -168,10 +179,11 @@ public class KeyControllerTest {
@Test @Test
public void putSignedPreKeyV2() throws Exception { public void putSignedPreKeyV2() throws Exception {
SignedPreKey test = new SignedPreKey(9999, "fooozzz", "baaarzzz"); SignedPreKey test = new SignedPreKey(9999, "fooozzz", "baaarzzz");
ClientResponse response = resources.client().resource("/v2/keys/signed") Response response = resources.getJerseyTest()
.target("/v2/keys/signed")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.type(MediaType.APPLICATION_JSON_TYPE) .put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class, test);
assertThat(response.getStatus() == 204); assertThat(response.getStatus() == 204);
@ -181,7 +193,9 @@ public class KeyControllerTest {
@Test @Test
public void validLegacyRequestTest() throws Exception { public void validLegacyRequestTest() throws Exception {
PreKeyV1 result = resources.client().resource(String.format("/v1/keys/%s", EXISTS_NUMBER)) PreKeyV1 result = resources.getJerseyTest()
.target(String.format("/v1/keys/%s", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyV1.class); .get(PreKeyV1.class);
@ -195,7 +209,9 @@ public class KeyControllerTest {
@Test @Test
public void validSingleRequestTestV2() throws Exception { public void validSingleRequestTestV2() throws Exception {
PreKeyResponseV2 result = resources.client().resource(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) PreKeyResponseV2 result = resources.getJerseyTest()
.target(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyResponseV2.class); .get(PreKeyResponseV2.class);
@ -212,7 +228,9 @@ public class KeyControllerTest {
@Test @Test
public void validMultiRequestTestV1() throws Exception { public void validMultiRequestTestV1() throws Exception {
PreKeyResponseV1 results = resources.client().resource(String.format("/v1/keys/%s/*", EXISTS_NUMBER)) PreKeyResponseV1 results = resources.getJerseyTest()
.target(String.format("/v1/keys/%s/*", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyResponseV1.class); .get(PreKeyResponseV1.class);
@ -243,7 +261,9 @@ public class KeyControllerTest {
@Test @Test
public void validMultiRequestTestV2() throws Exception { public void validMultiRequestTestV2() throws Exception {
PreKeyResponseV2 results = resources.client().resource(String.format("/v2/keys/%s/*", EXISTS_NUMBER)) PreKeyResponseV2 results = resources.getJerseyTest()
.target(String.format("/v2/keys/%s/*", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyResponseV2.class); .get(PreKeyResponseV2.class);
@ -292,59 +312,73 @@ public class KeyControllerTest {
@Test @Test
public void invalidRequestTestV1() throws Exception { public void invalidRequestTestV1() throws Exception {
ClientResponse response = resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER)) Response response = resources.getJerseyTest()
.target(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class); .get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
} }
@Test @Test
public void invalidRequestTestV2() throws Exception { public void invalidRequestTestV2() throws Exception {
ClientResponse response = resources.client().resource(String.format("/v2/keys/%s", NOT_EXISTS_NUMBER)) Response response = resources.getJerseyTest()
.target(String.format("/v2/keys/%s", NOT_EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class); .get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
} }
@Test @Test
public void anotherInvalidRequestTestV2() throws Exception { public void anotherInvalidRequestTestV2() throws Exception {
ClientResponse response = resources.client().resource(String.format("/v2/keys/%s/22", EXISTS_NUMBER)) Response response = resources.getJerseyTest()
.target(String.format("/v2/keys/%s/22", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class); .get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
} }
@Test @Test
public void unauthorizedRequestTestV1() throws Exception { public void unauthorizedRequestTestV1() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER)) resources.getJerseyTest()
.target(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD))
.get(ClientResponse.class); .get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
response = response =
resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER)) resources.getJerseyTest()
.get(ClientResponse.class); .target(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.request()
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
} }
@Test @Test
public void unauthorizedRequestTestV2() throws Exception { public void unauthorizedRequestTestV2() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) resources.getJerseyTest()
.target(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD))
.get(ClientResponse.class); .get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
response = response =
resources.client().resource(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) resources.getJerseyTest()
.get(ClientResponse.class); .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
.request()
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
} }
@ -362,13 +396,14 @@ public class KeyControllerTest {
preKeyList.setKeys(preKeys); preKeyList.setKeys(preKeys);
preKeyList.setLastResortKey(lastResortKey); preKeyList.setLastResortKey(lastResortKey);
ClientResponse response = Response response =
resources.client().resource("/v1/keys") resources.getJerseyTest()
.target("/v1/keys")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.type(MediaType.APPLICATION_JSON_TYPE) .put(Entity.entity(preKeyList, MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class, preKeyList);
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(204); assertThat(response.getStatus()).isEqualTo(204);
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class ); ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class );
ArgumentCaptor<PreKeyV1> lastResortCaptor = ArgumentCaptor.forClass(PreKeyV1.class); ArgumentCaptor<PreKeyV1> lastResortCaptor = ArgumentCaptor.forClass(PreKeyV1.class);
@ -400,13 +435,14 @@ public class KeyControllerTest {
PreKeyStateV2 preKeyState = new PreKeyStateV2(identityKey, signedPreKey, preKeys, lastResortKey); PreKeyStateV2 preKeyState = new PreKeyStateV2(identityKey, signedPreKey, preKeys, lastResortKey);
ClientResponse response = Response response =
resources.client().resource("/v2/keys") resources.getJerseyTest()
.target("/v2/keys")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.type(MediaType.APPLICATION_JSON_TYPE) .put(Entity.entity(preKeyState, MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class, preKeyState);
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(204); assertThat(response.getStatus()).isEqualTo(204);
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class); ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);
verify(keys).store(eq(AuthHelper.VALID_NUMBER), eq(1L), listCaptor.capture(), eq(lastResortKey)); verify(keys).store(eq(AuthHelper.VALID_NUMBER), eq(1L), listCaptor.capture(), eq(lastResortKey));

View File

@ -2,10 +2,11 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.MessageController; import org.whispersystems.textsecuregcm.controllers.MessageController;
import org.whispersystems.textsecuregcm.entities.IncomingMessageList; import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope; import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope;
@ -25,7 +26,9 @@ import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -60,7 +63,9 @@ public class MessageControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, .addResource(new MessageController(rateLimiters, pushSender, receiptSender, accountsManager,
messagesManager, federatedClientManager)) messagesManager, federatedClientManager))
.build(); .build();
@ -89,12 +94,12 @@ public class MessageControllerTest {
@Test @Test
public synchronized void testSingleDeviceLegacy() throws Exception { public synchronized void testSingleDeviceLegacy() throws Exception {
ClientResponse response = Response response =
resources.client().resource("/v1/messages/") resources.getJerseyTest().target("/v1/messages/")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/legacy_message_single_device.json"), IncomingMessageList.class)) .post(Entity.entity(mapper.readValue(jsonFixture("fixtures/legacy_message_single_device.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.post(ClientResponse.class);
assertThat("Good Response", response.getStatus(), is(equalTo(200))); assertThat("Good Response", response.getStatus(), is(equalTo(200)));
@ -103,12 +108,13 @@ public class MessageControllerTest {
@Test @Test
public synchronized void testSingleDeviceCurrent() throws Exception { public synchronized void testSingleDeviceCurrent() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT)) resources.getJerseyTest()
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat("Good Response", response.getStatus(), is(equalTo(200))); assertThat("Good Response", response.getStatus(), is(equalTo(200)));
@ -117,17 +123,18 @@ public class MessageControllerTest {
@Test @Test
public synchronized void testMultiDeviceMissing() throws Exception { public synchronized void testMultiDeviceMissing() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) resources.getJerseyTest()
.target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat("Good Response Code", response.getStatus(), is(equalTo(409))); assertThat("Good Response Code", response.getStatus(), is(equalTo(409)));
assertThat("Good Response Body", assertThat("Good Response Body",
asJson(response.getEntity(MismatchedDevices.class)), asJson(response.readEntity(MismatchedDevices.class)),
is(equalTo(jsonFixture("fixtures/missing_device_response.json")))); is(equalTo(jsonFixture("fixtures/missing_device_response.json"))));
verifyNoMoreInteractions(pushSender); verifyNoMoreInteractions(pushSender);
@ -135,17 +142,18 @@ public class MessageControllerTest {
@Test @Test
public synchronized void testMultiDeviceExtra() throws Exception { public synchronized void testMultiDeviceExtra() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) resources.getJerseyTest()
.target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_extra_device.json"), IncomingMessageList.class)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_extra_device.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat("Good Response Code", response.getStatus(), is(equalTo(409))); assertThat("Good Response Code", response.getStatus(), is(equalTo(409)));
assertThat("Good Response Body", assertThat("Good Response Body",
asJson(response.getEntity(MismatchedDevices.class)), asJson(response.readEntity(MismatchedDevices.class)),
is(equalTo(jsonFixture("fixtures/missing_device_response2.json")))); is(equalTo(jsonFixture("fixtures/missing_device_response2.json"))));
verifyNoMoreInteractions(pushSender); verifyNoMoreInteractions(pushSender);
@ -153,12 +161,13 @@ public class MessageControllerTest {
@Test @Test
public synchronized void testMultiDevice() throws Exception { public synchronized void testMultiDevice() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) resources.getJerseyTest()
.target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_multi_device.json"), IncomingMessageList.class)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_multi_device.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat("Good Response Code", response.getStatus(), is(equalTo(200))); assertThat("Good Response Code", response.getStatus(), is(equalTo(200)));
@ -167,17 +176,17 @@ public class MessageControllerTest {
@Test @Test
public synchronized void testRegistrationIdMismatch() throws Exception { public synchronized void testRegistrationIdMismatch() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) resources.getJerseyTest().target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_registration_id.json"), IncomingMessageList.class)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_registration_id.json"), IncomingMessageList.class),
.type(MediaType.APPLICATION_JSON_TYPE) MediaType.APPLICATION_JSON_TYPE));
.put(ClientResponse.class);
assertThat("Good Response Code", response.getStatus(), is(equalTo(410))); assertThat("Good Response Code", response.getStatus(), is(equalTo(410)));
assertThat("Good Response Body", assertThat("Good Response Body",
asJson(response.getEntity(StaleDevices.class)), asJson(response.readEntity(StaleDevices.class)),
is(equalTo(jsonFixture("fixtures/mismatched_registration_id.json")))); is(equalTo(jsonFixture("fixtures/mismatched_registration_id.json"))));
verifyNoMoreInteractions(pushSender); verifyNoMoreInteractions(pushSender);
@ -198,7 +207,8 @@ public class MessageControllerTest {
when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(messages); when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(messages);
OutgoingMessageEntityList response = OutgoingMessageEntityList response =
resources.client().resource("/v1/messages/") resources.getJerseyTest().target("/v1/messages/")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.accept(MediaType.APPLICATION_JSON_TYPE) .accept(MediaType.APPLICATION_JSON_TYPE)
.get(OutgoingMessageEntityList.class); .get(OutgoingMessageEntityList.class);
@ -232,23 +242,29 @@ public class MessageControllerTest {
when(messagesManager.delete(AuthHelper.VALID_NUMBER, "+14152222222", 31339)) when(messagesManager.delete(AuthHelper.VALID_NUMBER, "+14152222222", 31339))
.thenReturn(Optional.<OutgoingMessageEntity>absent()); .thenReturn(Optional.<OutgoingMessageEntity>absent());
ClientResponse response = resources.client().resource(String.format("/v1/messages/%s/%d", "+14152222222", 31337)) Response response = resources.getJerseyTest()
.target(String.format("/v1/messages/%s/%d", "+14152222222", 31337))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.delete(ClientResponse.class); .delete();
assertThat("Good Response Code", response.getStatus(), is(equalTo(204))); assertThat("Good Response Code", response.getStatus(), is(equalTo(204)));
verify(receiptSender).sendReceipt(any(Account.class), eq("+14152222222"), eq(timestamp), eq(Optional.<String>absent())); verify(receiptSender).sendReceipt(any(Account.class), eq("+14152222222"), eq(timestamp), eq(Optional.<String>absent()));
response = resources.client().resource(String.format("/v1/messages/%s/%d", "+14152222222", 31338)) response = resources.getJerseyTest()
.target(String.format("/v1/messages/%s/%d", "+14152222222", 31338))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.delete(ClientResponse.class); .delete();
assertThat("Good Response Code", response.getStatus(), is(equalTo(204))); assertThat("Good Response Code", response.getStatus(), is(equalTo(204)));
verifyNoMoreInteractions(receiptSender); verifyNoMoreInteractions(receiptSender);
response = resources.client().resource(String.format("/v1/messages/%s/%d", "+14152222222", 31339)) response = resources.getJerseyTest()
.target(String.format("/v1/messages/%s/%d", "+14152222222", 31339))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.delete(ClientResponse.class); .delete();
assertThat("Good Response Code", response.getStatus(), is(equalTo(204))); assertThat("Good Response Code", response.getStatus(), is(equalTo(204)));
verifyNoMoreInteractions(receiptSender); verifyNoMoreInteractions(receiptSender);

View File

@ -2,12 +2,13 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse; import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.ReceiptController; import org.whispersystems.textsecuregcm.controllers.ReceiptController;
import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope; import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope;
import org.whispersystems.textsecuregcm.federation.FederatedClientManager; import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
import org.whispersystems.textsecuregcm.push.PushSender; import org.whispersystems.textsecuregcm.push.PushSender;
@ -17,11 +18,14 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import io.dropwizard.testing.junit.ResourceTestRule; import io.dropwizard.testing.junit.ResourceTestRule;
import static org.fest.assertions.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -40,7 +44,9 @@ public class ReceiptControllerTest {
@Rule @Rule
public final ResourceTestRule resources = ResourceTestRule.builder() public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new ReceiptController(receiptSender)) .addResource(new ReceiptController(receiptSender))
.build(); .build();
@ -64,10 +70,13 @@ public class ReceiptControllerTest {
@Test @Test
public synchronized void testSingleDeviceCurrent() throws Exception { public synchronized void testSingleDeviceCurrent() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/receipt/%s/%d", SINGLE_DEVICE_RECIPIENT, 1234)) resources.getJerseyTest()
.target(String.format("/v1/receipt/%s/%d", SINGLE_DEVICE_RECIPIENT, 1234))
.request()
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(ClientResponse.class); .put(null);
assertThat(response.getStatus() == 204); assertThat(response.getStatus() == 204);
@ -76,10 +85,13 @@ public class ReceiptControllerTest {
@Test @Test
public synchronized void testMultiDeviceCurrent() throws Exception { public synchronized void testMultiDeviceCurrent() throws Exception {
ClientResponse response = Response response =
resources.client().resource(String.format("/v1/receipt/%s/%d", MULTI_DEVICE_RECIPIENT, 12345)) resources.getJerseyTest()
.target(String.format("/v1/receipt/%s/%d", MULTI_DEVICE_RECIPIENT, 12345))
.request()
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(ClientResponse.class); .put(null);
assertThat(response.getStatus() == 204); assertThat(response.getStatus() == 204);

View File

@ -1,6 +1,5 @@
package org.whispersystems.textsecuregcm.tests.entities; package org.whispersystems.textsecuregcm.tests.entities;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.textsecuregcm.entities.ClientContact; import org.whispersystems.textsecuregcm.entities.ClientContact;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
@ -8,9 +7,7 @@ import org.whispersystems.textsecuregcm.util.Util;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.asJson; import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.*;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.fromJson;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.jsonFixture;
public class ClientContactTest { public class ClientContactTest {

View File

@ -2,7 +2,6 @@ package org.whispersystems.textsecuregcm.tests.push;
import org.junit.Test; import org.junit.Test;
import org.whispersystems.textsecuregcm.push.ApnFallbackManager;
import org.whispersystems.textsecuregcm.push.ApnFallbackManager.ApnFallbackTask; import org.whispersystems.textsecuregcm.push.ApnFallbackManager.ApnFallbackTask;
import org.whispersystems.textsecuregcm.push.ApnFallbackManager.ApnFallbackTaskQueue; import org.whispersystems.textsecuregcm.push.ApnFallbackManager.ApnFallbackTaskQueue;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;

View File

@ -1,18 +1,18 @@
package org.whispersystems.textsecuregcm.tests.util; package org.whispersystems.textsecuregcm.tests.util;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import org.whispersystems.dropwizard.simpleauth.AuthDynamicFeature;
import org.whispersystems.dropwizard.simpleauth.BasicCredentialAuthFilter;
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator; import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator; import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator;
import org.whispersystems.textsecuregcm.auth.MultiBasicAuthProvider;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration; import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.federation.FederatedPeer; import org.whispersystems.textsecuregcm.federation.FederatedPeer;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.util.Base64;
import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -39,7 +39,7 @@ public class AuthHelper {
private static AuthenticationCredentials VALID_CREDENTIALS = mock(AuthenticationCredentials.class); private static AuthenticationCredentials VALID_CREDENTIALS = mock(AuthenticationCredentials.class);
private static AuthenticationCredentials VALID_CREDENTIALS_TWO = mock(AuthenticationCredentials.class); private static AuthenticationCredentials VALID_CREDENTIALS_TWO = mock(AuthenticationCredentials.class);
public static MultiBasicAuthProvider<FederatedPeer, Account> getAuthenticator() { public static AuthDynamicFeature getAuthFilter() {
when(VALID_CREDENTIALS.verify("foo")).thenReturn(true); when(VALID_CREDENTIALS.verify("foo")).thenReturn(true);
when(VALID_CREDENTIALS_TWO.verify("baz")).thenReturn(true); when(VALID_CREDENTIALS_TWO.verify("baz")).thenReturn(true);
when(VALID_DEVICE.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS); when(VALID_DEVICE.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS);
@ -65,10 +65,14 @@ public class AuthHelper {
FederationConfiguration federationConfiguration = mock(FederationConfiguration.class); FederationConfiguration federationConfiguration = mock(FederationConfiguration.class);
when(federationConfiguration.getPeers()).thenReturn(peer); when(federationConfiguration.getPeers()).thenReturn(peer);
return new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(federationConfiguration), return new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Account>()
FederatedPeer.class, .setAuthenticator(new AccountAuthenticator(ACCOUNTS_MANAGER))
new AccountAuthenticator(ACCOUNTS_MANAGER), .setPrincipal(Account.class)
Account.class, "WhisperServer"); .buildAuthFilter(),
new BasicCredentialAuthFilter.Builder<FederatedPeer>()
.setAuthenticator(new FederatedPeerAuthenticator(federationConfiguration))
.setPrincipal(FederatedPeer.class)
.buildAuthFilter());
} }
public static String getAuthHeader(String number, String password) { public static String getAuthHeader(String number, String password) {

View File

@ -73,21 +73,21 @@ public class WebSocketConnectionTest {
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device)); when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, String[]>() {{ when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, List<String>>() {{
put("login", new String[] {VALID_USER}); put("login", new LinkedList<String>() {{add(VALID_USER);}});
put("password", new String[] {VALID_PASSWORD}); put("password", new LinkedList<String>() {{add(VALID_PASSWORD);}});
}}); }});
Optional<Account> account = webSocketAuthenticator.authenticate(upgradeRequest); Optional<Account> account = webSocketAuthenticator.authenticate(upgradeRequest);
when(sessionContext.getAuthenticated(Account.class)).thenReturn(account); when(sessionContext.getAuthenticated(Account.class)).thenReturn(account.get());
connectListener.onWebSocketConnect(sessionContext); connectListener.onWebSocketConnect(sessionContext);
verify(sessionContext).addListener(any(WebSocketSessionContext.WebSocketEventListener.class)); verify(sessionContext).addListener(any(WebSocketSessionContext.WebSocketEventListener.class));
when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, String[]>() {{ when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, List<String>>() {{
put("login", new String[] {INVALID_USER}); put("login", new LinkedList<String>() {{add(INVALID_USER);}});
put("password", new String[] {INVALID_PASSWORD}); put("password", new LinkedList<String>() {{add(INVALID_PASSWORD);}});
}}); }});
account = webSocketAuthenticator.authenticate(upgradeRequest); account = webSocketAuthenticator.authenticate(upgradeRequest);

View File

@ -1,4 +1,4 @@
{ {
"relay" : "whisper", "token" : "BQVVHxMt5zAFXA",
"token" : "BQVVHxMt5zAFXA" "relay" : "whisper"
} }