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>
<artifactId>TextSecureServer</artifactId>
<version>0.54</version>
<version>0.60-RC3</version>
<properties>
<dropwizard.version>0.7.1</dropwizard.version>
<jackson.api.version>2.3.3</jackson.api.version>
<commons-codec.version>1.6</commons-codec.version>
<dropwizard.version>0.9.0-rc3</dropwizard.version>
</properties>
<dependencies>
@ -58,78 +56,67 @@
<artifactId>dropwizard-papertrail</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</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>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>140</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>
<version>1.46</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.4.1</version>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.10.6</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0</version>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.6.2</version>
<version>2.7.3</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio-java-sdk</artifactId>
<version>3.4.5</version>
<version>4.4.4</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-tcp</artifactId>
<version>4.0.0</version>
<version>9.4-1201-jdbc41</version>
</dependency>
<dependency>
<groupId>org.whispersystems</groupId>
<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>
</dependencies>
@ -137,14 +124,14 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.api.version}</version>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.1</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

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

View File

@ -22,6 +22,7 @@ import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.base.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.dropwizard.simpleauth.Authenticator;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
@ -29,7 +30,6 @@ import org.whispersystems.textsecuregcm.util.Constants;
import static com.codahale.metrics.MetricRegistry.name;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.dropwizard.simpleauth.Authenticator;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.federation.FederatedPeer;
import org.whispersystems.textsecuregcm.util.Constants;
@ -30,7 +31,6 @@ import java.util.List;
import static com.codahale.metrics.MetricRegistry.name;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
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,8 +29,8 @@ public class KeepAliveController {
@Timed
@GET
public Response getKeepAlive(@Auth(required = false) Account account,
@WebSocketSession WebSocketSessionContext context)
public Response getKeepAlive(@Auth Account account,
@WebSocketSession WebSocketSessionContext context)
{
if (account != null) {
WebsocketAddress address = new WebsocketAddress(account.getNumber(),

View File

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

View File

@ -17,20 +17,17 @@
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.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 com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
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.client.CredentialsProvider;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.bouncycastle.openssl.PEMReader;
import org.glassfish.jersey.SslConfigurator;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.PreKeyResponseV1;
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.TrustManagerFactory;
import javax.ws.rs.ProcessingException;
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.Response;
import java.io.ByteArrayInputStream;
@ -59,7 +61,10 @@ import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
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 {
@ -75,15 +80,14 @@ public class FederatedClient {
private final FederatedPeer peer;
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
{
try {
this.client = Client.create(getClientConfig(peer));
this.peer = peer;
this.authorizationHeader = getAuthorizationHeader(federationName, peer);
this.client = createClient(environment, configuration, federationName, peer);
this.peer = peer;
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (KeyStoreException | KeyManagementException | CertificateException e) {
@ -93,20 +97,14 @@ public class FederatedClient {
public URL getSignedAttachmentUri(long attachmentId) throws IOException {
try {
WebResource resource = client.resource(peer.getUrl())
.path(String.format(ATTACHMENT_URI_PATH, attachmentId));
AttachmentUri response = client.target(peer.getUrl())
.path(String.format(ATTACHMENT_URI_PATH, attachmentId))
.request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(AttachmentUri.class);
ClientResponse response = resource.accept(MediaType.APPLICATION_JSON)
.header("Authorization", authorizationHeader)
.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) {
return response.getLocation();
} catch (ProcessingException e) {
logger.warn("Bad URI", e);
throw new IOException(e);
}
@ -114,19 +112,14 @@ public class FederatedClient {
public Optional<PreKeyResponseV1> getKeysV1(String destination, String device) {
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)
.header("Authorization", authorizationHeader)
.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) {
return Optional.of(response);
} catch (ProcessingException e) {
logger.warn("PreKey", e);
return Optional.absent();
}
@ -134,34 +127,29 @@ public class FederatedClient {
public Optional<PreKeyResponseV2> getKeysV2(String destination, String device) {
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)
.header("Authorization", authorizationHeader)
.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) {
return Optional.of(response);
} catch (ProcessingException e) {
logger.warn("PreKey", e);
return Optional.absent();
}
}
public int getUserCount() {
try {
WebResource resource = client.resource(peer.getUrl()).path(USER_COUNT_PATH);
AccountCount count = resource.accept(MediaType.APPLICATION_JSON)
.header("Authorization", authorizationHeader)
.get(AccountCount.class);
AccountCount count = client.target(peer.getUrl())
.path(USER_COUNT_PATH)
.request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(AccountCount.class);
return count.getCount();
} catch (UniformInterfaceException | ClientHandlerException e) {
} catch (ProcessingException e) {
logger.warn("User Count", e);
return 0;
}
@ -169,13 +157,14 @@ public class FederatedClient {
public List<ClientContact> getUserTokens(int offset) {
try {
WebResource resource = client.resource(peer.getUrl()).path(String.format(USER_TOKENS_PATH, offset));
ClientContacts contacts = resource.accept(MediaType.APPLICATION_JSON)
.header("Authorization", authorizationHeader)
.get(ClientContacts.class);
ClientContacts contacts = client.target(peer.getUrl())
.path(String.format(USER_TOKENS_PATH, offset))
.request()
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(ClientContacts.class);
return contacts.getContacts();
} catch (UniformInterfaceException | ClientHandlerException e) {
} catch (ProcessingException e) {
logger.warn("User Tokens", e);
return null;
}
@ -185,16 +174,16 @@ public class FederatedClient {
throws IOException
{
try {
WebResource resource = client.resource(peer.getUrl()).path(String.format(RELAY_MESSAGE_PATH, source, sourceDeviceId, destination));
ClientResponse response = resource.type(MediaType.APPLICATION_JSON)
.header("Authorization", authorizationHeader)
.entity(messages)
.put(ClientResponse.class);
Response response = client.target(peer.getUrl())
.path(String.format(RELAY_MESSAGE_PATH, source, sourceDeviceId, destination))
.request()
.put(Entity.entity(messages, MediaType.APPLICATION_JSON_TYPE));
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);
throw new IOException(e);
}
@ -204,26 +193,22 @@ public class FederatedClient {
throws IOException
{
try {
String path = String.format(RECEIPT_PATH, source, sourceDeviceId, destination, messageId);
WebResource resource = client.resource(peer.getUrl()).path(path);
ClientResponse response = resource.type(MediaType.APPLICATION_JSON)
.header("Authorization", authorizationHeader)
.put(ClientResponse.class);
Response response = client.target(peer.getUrl())
.path(String.format(RECEIPT_PATH, source, sourceDeviceId, destination, messageId))
.request()
.put(Entity.json(null));
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);
throw new IOException(e);
}
}
private String getAuthorizationHeader(String federationName, FederatedPeer peer) {
return "Basic " + Base64.encodeBytes((federationName + ":" + peer.getAuthenticationToken()).getBytes());
}
private ClientConfig getClientConfig(FederatedPeer peer)
private Client createClient(Environment environment, JerseyClientConfiguration configuration,
String federationName, FederatedPeer peer)
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException
{
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
@ -232,13 +217,16 @@ public class FederatedClient {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), SecureRandom.getInstance("SHA1PRNG"));
ClientConfig config = new DefaultClientConfig();
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
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));
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier());
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build();
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)
@ -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() {
return peer.getName();
}

View File

@ -25,13 +25,18 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import io.dropwizard.client.JerseyClientConfiguration;
import io.dropwizard.setup.Environment;
public class FederatedClientManager {
private final Logger logger = LoggerFactory.getLogger(FederatedClientManager.class);
private final HashMap<String, FederatedClient> clients = new HashMap<>();
public FederatedClientManager(FederationConfiguration federationConfig)
public FederatedClientManager(Environment environment,
JerseyClientConfiguration clientConfig,
FederationConfiguration federationConfig)
throws IOException
{
List<FederatedPeer> peers = federationConfig.getPeers();
@ -40,7 +45,7 @@ public class FederatedClientManager {
if (peers != null) {
for (FederatedPeer peer : peers) {
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.cli.ConfiguredCommand;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.db.DatabaseConfiguration;
import io.dropwizard.db.ManagedDataSource;
import io.dropwizard.db.PooledDataSourceFactory;
import io.dropwizard.setup.Bootstrap;
import liquibase.Liquibase;
import liquibase.exception.LiquibaseException;
@ -40,10 +40,8 @@ public abstract class AbstractLiquibaseCommand<T extends Configuration> extends
@Override
@SuppressWarnings("UseOfSystemOutOrSystemErr")
protected void run(Bootstrap<T> bootstrap, Namespace namespace, T configuration) throws Exception {
final DataSourceFactory dbConfig = strategy.getDataSourceFactory(configuration);
dbConfig.setMaxSize(1);
dbConfig.setMinSize(1);
dbConfig.setInitialSize(1);
final PooledDataSourceFactory dbConfig = strategy.getDataSourceFactory(configuration);
dbConfig.asSingleConnectionPool();
try (final CloseableLiquibase liquibase = openLiquibase(dbConfig, namespace)) {
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
{
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;
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.LoggerFactory;
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.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.Response;
import java.io.IOException;
import java.util.List;
@ -57,16 +57,17 @@ public class PushServiceClient {
private void sendPush(String path, Object entity) throws TransientPushFailureException {
try {
ClientResponse response = client.resource("http://" + host + ":" + port + path)
.header("Authorization", authorization)
.entity(entity, MediaType.APPLICATION_JSON)
.put(ClientResponse.class);
Response response = client.target("http://" + host + ":" + port)
.path(path)
.request()
.header("Authorization", authorization)
.put(Entity.entity(entity, MediaType.APPLICATION_JSON_TYPE));
if (response.getStatus() != 204 && response.getStatus() != 200) {
logger.warn("PushServer response: " + response.getStatus() + " " + response.getStatusInfo().getReasonPhrase());
throw new TransientPushFailureException("Bad response: " + response.getStatus());
}
} catch (UniformInterfaceException | ClientHandlerException e) {
} catch (ProcessingException e) {
logger.warn("Push error: ", e);
throw new TransientPushFailureException(e);
}
@ -74,12 +75,14 @@ public class PushServiceClient {
private List<UnregisteredEvent> getFeedback(String path) throws IOException {
try {
UnregisteredEventList unregisteredEvents = client.resource("http://" + host + ":" + port + path)
UnregisteredEventList unregisteredEvents = client.target("http://" + host + ":" + port)
.path(path)
.request()
.header("Authorization", authorization)
.get(UnregisteredEventList.class);
return unregisteredEvents.getDevices();
} catch (UniformInterfaceException | ClientHandlerException e) {
} catch (ProcessingException e) {
logger.warn("Request error:", e);
throw new IOException(e);
}

View File

@ -47,7 +47,7 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener {
@Override
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 long connectTime = System.currentTimeMillis();
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.WebSocketAuthenticator;
import java.util.List;
import java.util.Map;
import io.dropwizard.auth.basic.BasicCredentials;
@ -24,18 +25,18 @@ public class WebSocketAccountAuthenticator implements WebSocketAuthenticator<Acc
@Override
public Optional<Account> authenticate(UpgradeRequest request) throws AuthenticationException {
try {
Map<String, String[]> parameters = request.getParameterMap();
String[] usernames = parameters.get("login");
String[] passwords = parameters.get("password");
Map<String, List<String>> parameters = request.getParameterMap();
List<String> usernames = parameters.get("login");
List<String> passwords = parameters.get("password");
if (usernames == null || usernames.length == 0 ||
passwords == null || passwords.length == 0)
if (usernames == null || usernames.size() == 0 ||
passwords == null || passwords.size() == 0)
{
return Optional.absent();
}
BasicCredentials credentials = new BasicCredentials(usernames[0].replace(" ", "+"),
passwords[0].replace(" ", "+"));
BasicCredentials credentials = new BasicCredentials(usernames.get(0).replace(" ", "+"),
passwords.get(0).replace(" ", "+"));
return accountAuthenticator.authenticate(credentials);
} 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.DirectoryManager;
import io.dropwizard.Application;
import io.dropwizard.cli.ConfiguredCommand;
import io.dropwizard.cli.EnvironmentCommand;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.jdbi.ImmutableListContainerFactory;
import io.dropwizard.jdbi.ImmutableSetContainerFactory;
import io.dropwizard.jdbi.OptionalContainerFactory;
import io.dropwizard.jdbi.args.OptionalArgumentFactory;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
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);
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
protected void run(Bootstrap<WhisperServerConfiguration> bootstrap,
Namespace namespace,
WhisperServerConfiguration config)
protected void run(Environment environment, Namespace namespace,
WhisperServerConfiguration configuration)
throws Exception
{
try {
DataSourceFactory dbConfig = config.getDataSourceFactory();
DataSourceFactory dbConfig = configuration.getDataSourceFactory();
DBI dbi = new DBI(dbConfig.getUrl(), dbConfig.getUser(), dbConfig.getPassword());
dbi.registerArgumentFactory(new OptionalArgumentFactory(dbConfig.getDriverClass()));
@ -60,11 +69,13 @@ public class DirectoryCommand extends ConfiguredCommand<WhisperServerConfigurati
dbi.registerContainerFactory(new OptionalContainerFactory());
Accounts accounts = dbi.onDemand(Accounts.class);
JedisPool cacheClient = new RedisClientFactory(config.getCacheConfiguration().getUrl()).getRedisClientPool();
JedisPool redisClient = new RedisClientFactory(config.getDirectoryConfiguration().getUrl()).getRedisClientPool();
JedisPool cacheClient = new RedisClientFactory(configuration.getCacheConfiguration().getUrl()).getRedisClientPool();
JedisPool redisClient = new RedisClientFactory(configuration.getDirectoryConfiguration().getUrl()).getRedisClientPool();
DirectoryManager directory = new DirectoryManager(redisClient);
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);

View File

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

View File

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

View File

@ -1,12 +1,12 @@
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.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.DirectoryController;
import org.whispersystems.textsecuregcm.entities.ClientContactTokens;
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.util.Base64;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.LinkedList;
import java.util.List;
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.Mockito.mock;
import static org.mockito.Mockito.when;
@ -33,7 +35,9 @@ public class DirectoryControllerTest {
@Rule
public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator())
.addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new DirectoryController(rateLimiters,
directoryManager))
.build();
@ -64,17 +68,17 @@ public class DirectoryControllerTest {
List<String> expectedResponse = new LinkedList<>(tokens);
expectedResponse.remove(0);
ClientResponse response =
resources.client().resource("/v1/directory/tokens/")
.entity(new ClientContactTokens(tokens))
.type(MediaType.APPLICATION_JSON_TYPE)
Response response =
resources.getJerseyTest()
.target("/v1/directory/tokens/")
.request()
.header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER,
AuthHelper.VALID_PASSWORD))
.put(ClientResponse.class);
.put(Entity.entity(new ClientContactTokens(tokens), MediaType.APPLICATION_JSON_TYPE));
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.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.Rule;
import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.FederationControllerV1;
import org.whispersystems.textsecuregcm.controllers.FederationControllerV2;
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.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.LinkedList;
import java.util.Set;
@ -64,7 +67,9 @@ public class FederatedControllerTest {
@Rule
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 FederationControllerV2(accountsManager, null, messageController, keysControllerV2))
.build();
@ -97,12 +102,13 @@ public class FederatedControllerTest {
@Test
public void testSingleDeviceCurrent() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/federation/messages/+14152223333/1/%s", SINGLE_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo"))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
Response response =
resources.getJerseyTest()
.target(String.format("/v1/federation/messages/+14152223333/1/%s", SINGLE_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader("cyanogen", "foofoo"))
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response", response.getStatus(), is(equalTo(204)));
@ -112,7 +118,9 @@ public class FederatedControllerTest {
@Test
public void testSignedPreKeyV2() throws Exception {
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"))
.get(PreKeyResponseV2.class);

View File

@ -1,14 +1,14 @@
package org.whispersystems.textsecuregcm.tests.controllers;
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.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.KeysControllerV1;
import org.whispersystems.textsecuregcm.controllers.KeysControllerV2;
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.entities.PreKeyCount;
import org.whispersystems.textsecuregcm.entities.PreKeyResponseV1;
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.PreKeyV1;
import org.whispersystems.textsecuregcm.entities.PreKeyV2;
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
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.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.LinkedList;
import java.util.List;
import java.util.Set;
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.*;
public class KeyControllerTest {
@ -63,7 +66,9 @@ public class KeyControllerTest {
@Rule
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 KeysControllerV2(rateLimiters, keys, accounts, null))
.build();
@ -134,10 +139,12 @@ public class KeyControllerTest {
@Test
public void validKeyStatusTestV1() throws Exception {
PreKeyCount result = resources.client().resource("/v1/keys")
.header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyCount.class);
PreKeyCount result = resources.getJerseyTest()
.target("/v1/keys")
.request()
.header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyCount.class);
assertThat(result.getCount() == 4);
@ -146,7 +153,9 @@ public class KeyControllerTest {
@Test
public void validKeyStatusTestV2() throws Exception {
PreKeyCount result = resources.client().resource("/v2/keys")
PreKeyCount result = resources.getJerseyTest()
.target("/v2/keys")
.request()
.header("Authorization",
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyCount.class);
@ -158,7 +167,9 @@ public class KeyControllerTest {
@Test
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))
.get(SignedPreKey.class);
@ -168,10 +179,11 @@ public class KeyControllerTest {
@Test
public void putSignedPreKeyV2() throws Exception {
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))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class, test);
.put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus() == 204);
@ -181,9 +193,11 @@ public class KeyControllerTest {
@Test
public void validLegacyRequestTest() throws Exception {
PreKeyV1 result = resources.client().resource(String.format("/v1/keys/%s", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyV1.class);
PreKeyV1 result = resources.getJerseyTest()
.target(String.format("/v1/keys/%s", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyV1.class);
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId());
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey());
@ -195,7 +209,9 @@ public class KeyControllerTest {
@Test
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))
.get(PreKeyResponseV2.class);
@ -212,9 +228,11 @@ public class KeyControllerTest {
@Test
public void validMultiRequestTestV1() throws Exception {
PreKeyResponseV1 results = resources.client().resource(String.format("/v1/keys/%s/*", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyResponseV1.class);
PreKeyResponseV1 results = resources.getJerseyTest()
.target(String.format("/v1/keys/%s/*", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKeyResponseV1.class);
assertThat(results.getKeys().size()).isEqualTo(3);
@ -243,7 +261,9 @@ public class KeyControllerTest {
@Test
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))
.get(PreKeyResponseV2.class);
@ -292,59 +312,73 @@ public class KeyControllerTest {
@Test
public void invalidRequestTestV1() throws Exception {
ClientResponse response = resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class);
Response response = resources.getJerseyTest()
.target(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
}
@Test
public void invalidRequestTestV2() throws Exception {
ClientResponse response = resources.client().resource(String.format("/v2/keys/%s", NOT_EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class);
Response response = resources.getJerseyTest()
.target(String.format("/v2/keys/%s", NOT_EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
}
@Test
public void anotherInvalidRequestTestV2() throws Exception {
ClientResponse response = resources.client().resource(String.format("/v2/keys/%s/22", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(ClientResponse.class);
Response response = resources.getJerseyTest()
.target(String.format("/v2/keys/%s/22", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404);
}
@Test
public void unauthorizedRequestTestV1() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD))
.get(ClientResponse.class);
Response response =
resources.getJerseyTest()
.target(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD))
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
response =
resources.client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.get(ClientResponse.class);
resources.getJerseyTest()
.target(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
.request()
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
}
@Test
public void unauthorizedRequestTestV2() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
Response response =
resources.getJerseyTest()
.target(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD))
.get(ClientResponse.class);
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
response =
resources.client().resource(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
.get(ClientResponse.class);
resources.getJerseyTest()
.target(String.format("/v2/keys/%s/1", EXISTS_NUMBER))
.request()
.get();
assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401);
}
@ -362,13 +396,14 @@ public class KeyControllerTest {
preKeyList.setKeys(preKeys);
preKeyList.setLastResortKey(lastResortKey);
ClientResponse response =
resources.client().resource("/v1/keys")
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class, preKeyList);
Response response =
resources.getJerseyTest()
.target("/v1/keys")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(preKeyList, MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(204);
assertThat(response.getStatus()).isEqualTo(204);
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class );
ArgumentCaptor<PreKeyV1> lastResortCaptor = ArgumentCaptor.forClass(PreKeyV1.class);
@ -400,13 +435,14 @@ public class KeyControllerTest {
PreKeyStateV2 preKeyState = new PreKeyStateV2(identityKey, signedPreKey, preKeys, lastResortKey);
ClientResponse response =
resources.client().resource("/v2/keys")
Response response =
resources.getJerseyTest()
.target("/v2/keys")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class, preKeyState);
.put(Entity.entity(preKeyState, MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(204);
assertThat(response.getStatus()).isEqualTo(204);
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);
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.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.Rule;
import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.MessageController;
import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
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.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.LinkedList;
import java.util.List;
@ -60,7 +63,9 @@ public class MessageControllerTest {
@Rule
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,
messagesManager, federatedClientManager))
.build();
@ -89,12 +94,12 @@ public class MessageControllerTest {
@Test
public synchronized void testSingleDeviceLegacy() throws Exception {
ClientResponse response =
resources.client().resource("/v1/messages/")
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/legacy_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.post(ClientResponse.class);
Response response =
resources.getJerseyTest().target("/v1/messages/")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.post(Entity.entity(mapper.readValue(jsonFixture("fixtures/legacy_message_single_device.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response", response.getStatus(), is(equalTo(200)));
@ -103,12 +108,13 @@ public class MessageControllerTest {
@Test
public synchronized void testSingleDeviceCurrent() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
Response response =
resources.getJerseyTest()
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response", response.getStatus(), is(equalTo(200)));
@ -117,17 +123,18 @@ public class MessageControllerTest {
@Test
public synchronized void testMultiDeviceMissing() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
Response response =
resources.getJerseyTest()
.target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response Code", response.getStatus(), is(equalTo(409)));
assertThat("Good Response Body",
asJson(response.getEntity(MismatchedDevices.class)),
asJson(response.readEntity(MismatchedDevices.class)),
is(equalTo(jsonFixture("fixtures/missing_device_response.json"))));
verifyNoMoreInteractions(pushSender);
@ -135,17 +142,18 @@ public class MessageControllerTest {
@Test
public synchronized void testMultiDeviceExtra() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_extra_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
Response response =
resources.getJerseyTest()
.target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_extra_device.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response Code", response.getStatus(), is(equalTo(409)));
assertThat("Good Response Body",
asJson(response.getEntity(MismatchedDevices.class)),
asJson(response.readEntity(MismatchedDevices.class)),
is(equalTo(jsonFixture("fixtures/missing_device_response2.json"))));
verifyNoMoreInteractions(pushSender);
@ -153,12 +161,13 @@ public class MessageControllerTest {
@Test
public synchronized void testMultiDevice() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_multi_device.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
Response response =
resources.getJerseyTest()
.target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_multi_device.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response Code", response.getStatus(), is(equalTo(200)));
@ -167,17 +176,17 @@ public class MessageControllerTest {
@Test
public synchronized void testRegistrationIdMismatch() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.entity(mapper.readValue(jsonFixture("fixtures/current_message_registration_id.json"), IncomingMessageList.class))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
Response response =
resources.getJerseyTest().target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_registration_id.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE));
assertThat("Good Response Code", response.getStatus(), is(equalTo(410)));
assertThat("Good Response Body",
asJson(response.getEntity(StaleDevices.class)),
asJson(response.readEntity(StaleDevices.class)),
is(equalTo(jsonFixture("fixtures/mismatched_registration_id.json"))));
verifyNoMoreInteractions(pushSender);
@ -198,7 +207,8 @@ public class MessageControllerTest {
when(messagesManager.getMessagesForDevice(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(messages);
OutgoingMessageEntityList response =
resources.client().resource("/v1/messages/")
resources.getJerseyTest().target("/v1/messages/")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(OutgoingMessageEntityList.class);
@ -232,23 +242,29 @@ public class MessageControllerTest {
when(messagesManager.delete(AuthHelper.VALID_NUMBER, "+14152222222", 31339))
.thenReturn(Optional.<OutgoingMessageEntity>absent());
ClientResponse response = resources.client().resource(String.format("/v1/messages/%s/%d", "+14152222222", 31337))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.delete(ClientResponse.class);
Response response = resources.getJerseyTest()
.target(String.format("/v1/messages/%s/%d", "+14152222222", 31337))
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.delete();
assertThat("Good Response Code", response.getStatus(), is(equalTo(204)));
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))
.delete(ClientResponse.class);
.delete();
assertThat("Good Response Code", response.getStatus(), is(equalTo(204)));
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))
.delete(ClientResponse.class);
.delete();
assertThat("Good Response Code", response.getStatus(), is(equalTo(204)));
verifyNoMoreInteractions(receiptSender);

View File

@ -2,12 +2,13 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Rule;
import org.junit.Test;
import org.whispersystems.dropwizard.simpleauth.AuthValueFactoryProvider;
import org.whispersystems.textsecuregcm.controllers.ReceiptController;
import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.entities.MessageProtos.Envelope;
import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
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.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.Set;
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.Mockito.*;
@ -40,7 +44,9 @@ public class ReceiptControllerTest {
@Rule
public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthenticator())
.addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new ReceiptController(receiptSender))
.build();
@ -64,10 +70,13 @@ public class ReceiptControllerTest {
@Test
public synchronized void testSingleDeviceCurrent() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/receipt/%s/%d", SINGLE_DEVICE_RECIPIENT, 1234))
Response response =
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))
.put(ClientResponse.class);
.put(null);
assertThat(response.getStatus() == 204);
@ -76,10 +85,13 @@ public class ReceiptControllerTest {
@Test
public synchronized void testMultiDeviceCurrent() throws Exception {
ClientResponse response =
resources.client().resource(String.format("/v1/receipt/%s/%d", MULTI_DEVICE_RECIPIENT, 12345))
Response response =
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))
.put(ClientResponse.class);
.put(null);
assertThat(response.getStatus() == 204);

View File

@ -1,6 +1,5 @@
package org.whispersystems.textsecuregcm.tests.entities;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.whispersystems.textsecuregcm.entities.ClientContact;
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.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.asJson;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.fromJson;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.jsonFixture;
import static org.whispersystems.textsecuregcm.tests.util.JsonHelpers.*;
public class ClientContactTest {

View File

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

View File

@ -1,18 +1,18 @@
package org.whispersystems.textsecuregcm.tests.util;
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.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator;
import org.whispersystems.textsecuregcm.auth.MultiBasicAuthProvider;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.federation.FederatedPeer;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.util.Base64;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@ -39,7 +39,7 @@ public class AuthHelper {
private static AuthenticationCredentials VALID_CREDENTIALS = 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_TWO.verify("baz")).thenReturn(true);
when(VALID_DEVICE.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS);
@ -65,10 +65,14 @@ public class AuthHelper {
FederationConfiguration federationConfiguration = mock(FederationConfiguration.class);
when(federationConfiguration.getPeers()).thenReturn(peer);
return new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(federationConfiguration),
FederatedPeer.class,
new AccountAuthenticator(ACCOUNTS_MANAGER),
Account.class, "WhisperServer");
return new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Account>()
.setAuthenticator(new AccountAuthenticator(ACCOUNTS_MANAGER))
.setPrincipal(Account.class)
.buildAuthFilter(),
new BasicCredentialAuthFilter.Builder<FederatedPeer>()
.setAuthenticator(new FederatedPeerAuthenticator(federationConfiguration))
.setPrincipal(FederatedPeer.class)
.buildAuthFilter());
}
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(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, String[]>() {{
put("login", new String[] {VALID_USER});
put("password", new String[] {VALID_PASSWORD});
when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, List<String>>() {{
put("login", new LinkedList<String>() {{add(VALID_USER);}});
put("password", new LinkedList<String>() {{add(VALID_PASSWORD);}});
}});
Optional<Account> account = webSocketAuthenticator.authenticate(upgradeRequest);
when(sessionContext.getAuthenticated(Account.class)).thenReturn(account);
when(sessionContext.getAuthenticated(Account.class)).thenReturn(account.get());
connectListener.onWebSocketConnect(sessionContext);
verify(sessionContext).addListener(any(WebSocketSessionContext.WebSocketEventListener.class));
when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, String[]>() {{
put("login", new String[] {INVALID_USER});
put("password", new String[] {INVALID_PASSWORD});
when(upgradeRequest.getParameterMap()).thenReturn(new HashMap<String, List<String>>() {{
put("login", new LinkedList<String>() {{add(INVALID_USER);}});
put("password", new LinkedList<String>() {{add(INVALID_PASSWORD);}});
}});
account = webSocketAuthenticator.authenticate(upgradeRequest);

View File

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