Clean up concepts of enabled account state
1) Rename "active" methods to be "enabled," since they aren't really about "activity." 2) Make authentication fail if a device or account is in dissabled state. 3) Let some controllers authenticate accounts that are in a disabled state.
This commit is contained in:
parent
fe66a59618
commit
35116f9229
|
@ -21,6 +21,8 @@ import com.codahale.metrics.jdbi3.strategies.DefaultNameStrategy;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
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.jdbi.v3.core.Jdbi;
|
import org.jdbi.v3.core.Jdbi;
|
||||||
|
@ -28,6 +30,8 @@ import org.whispersystems.dispatch.DispatchManager;
|
||||||
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
|
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
|
||||||
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
||||||
import org.whispersystems.textsecuregcm.auth.DirectoryCredentialsGenerator;
|
import org.whispersystems.textsecuregcm.auth.DirectoryCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
||||||
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
|
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
|
||||||
|
@ -89,9 +93,11 @@ import java.util.Optional;
|
||||||
|
|
||||||
import static com.codahale.metrics.MetricRegistry.name;
|
import static com.codahale.metrics.MetricRegistry.name;
|
||||||
import io.dropwizard.Application;
|
import io.dropwizard.Application;
|
||||||
import io.dropwizard.auth.AuthDynamicFeature;
|
import io.dropwizard.auth.AuthFilter;
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthDynamicFeature;
|
||||||
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
|
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
|
||||||
|
import io.dropwizard.auth.basic.BasicCredentials;
|
||||||
import io.dropwizard.db.DataSourceFactory;
|
import io.dropwizard.db.DataSourceFactory;
|
||||||
import io.dropwizard.db.PooledDataSourceFactory;
|
import io.dropwizard.db.PooledDataSourceFactory;
|
||||||
import io.dropwizard.jdbi3.JdbiFactory;
|
import io.dropwizard.jdbi3.JdbiFactory;
|
||||||
|
@ -184,9 +190,11 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
APNSender apnSender = new APNSender(accountsManager, config.getApnConfiguration());
|
APNSender apnSender = new APNSender(accountsManager, config.getApnConfiguration());
|
||||||
GCMSender gcmSender = new GCMSender(accountsManager, config.getGcmConfiguration().getApiKey(), directoryQueue);
|
GCMSender gcmSender = new GCMSender(accountsManager, config.getGcmConfiguration().getApiKey(), directoryQueue);
|
||||||
WebsocketSender websocketSender = new WebsocketSender(messagesManager, pubSubManager);
|
WebsocketSender websocketSender = new WebsocketSender(messagesManager, pubSubManager);
|
||||||
AccountAuthenticator deviceAuthenticator = new AccountAuthenticator(accountsManager );
|
|
||||||
RateLimiters rateLimiters = new RateLimiters(config.getLimitsConfiguration(), cacheClient);
|
RateLimiters rateLimiters = new RateLimiters(config.getLimitsConfiguration(), cacheClient);
|
||||||
|
|
||||||
|
AccountAuthenticator accountAuthenticator = new AccountAuthenticator(accountsManager);
|
||||||
|
DisabledPermittedAccountAuthenticator disabledPermittedAccountAuthenticator = new DisabledPermittedAccountAuthenticator(accountsManager);
|
||||||
|
|
||||||
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushSchedulerClient, apnSender, accountsManager);
|
ApnFallbackManager apnFallbackManager = new ApnFallbackManager(pushSchedulerClient, apnSender, accountsManager);
|
||||||
TwilioSmsSender twilioSmsSender = new TwilioSmsSender(config.getTwilioConfiguration());
|
TwilioSmsSender twilioSmsSender = new TwilioSmsSender(config.getTwilioConfiguration());
|
||||||
SmsSender smsSender = new SmsSender(twilioSmsSender);
|
SmsSender smsSender = new SmsSender(twilioSmsSender);
|
||||||
|
@ -222,10 +230,12 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, apnFallbackManager);
|
MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, apnFallbackManager);
|
||||||
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, config.getProfilesConfiguration());
|
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, config.getProfilesConfiguration());
|
||||||
|
|
||||||
environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Account>()
|
AuthFilter<BasicCredentials, Account> accountAuthFilter = new BasicCredentialAuthFilter.Builder<Account>().setAuthenticator(accountAuthenticator).buildAuthFilter ();
|
||||||
.setAuthenticator(deviceAuthenticator)
|
AuthFilter<BasicCredentials, DisabledPermittedAccount> disabledPermittedAccountAuthFilter = new BasicCredentialAuthFilter.Builder<DisabledPermittedAccount>().setAuthenticator(disabledPermittedAccountAuthenticator).buildAuthFilter();
|
||||||
.buildAuthFilter()));
|
|
||||||
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(Account.class));
|
environment.jersey().register(new PolymorphicAuthDynamicFeature<>(ImmutableMap.of(Account.class, accountAuthFilter,
|
||||||
|
DisabledPermittedAccount.class, disabledPermittedAccountAuthFilter)));
|
||||||
|
environment.jersey().register(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)));
|
||||||
|
|
||||||
environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, abusiveHostRules, rateLimiters, smsSender, directoryQueue, messagesManager, turnTokenGenerator, config.getTestDevices(), recaptchaClient));
|
environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, abusiveHostRules, rateLimiters, smsSender, directoryQueue, messagesManager, turnTokenGenerator, config.getTestDevices(), recaptchaClient));
|
||||||
environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, messagesManager, directoryQueue, rateLimiters, config.getMaxDevices()));
|
environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, messagesManager, directoryQueue, rateLimiters, config.getMaxDevices()));
|
||||||
|
@ -242,7 +252,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
|
|
||||||
///
|
///
|
||||||
WebSocketEnvironment webSocketEnvironment = new WebSocketEnvironment(environment, config.getWebSocketConfiguration(), 90000);
|
WebSocketEnvironment webSocketEnvironment = new WebSocketEnvironment(environment, config.getWebSocketConfiguration(), 90000);
|
||||||
webSocketEnvironment.setAuthenticator(new WebSocketAccountAuthenticator(deviceAuthenticator));
|
webSocketEnvironment.setAuthenticator(new WebSocketAccountAuthenticator(accountAuthenticator));
|
||||||
webSocketEnvironment.setConnectListener(new AuthenticatedConnectListener(pushSender, receiptSender, messagesManager, pubSubManager, apnFallbackManager));
|
webSocketEnvironment.setConnectListener(new AuthenticatedConnectListener(pushSender, receiptSender, messagesManager, pubSubManager, apnFallbackManager));
|
||||||
webSocketEnvironment.jersey().register(new KeepAliveController(pubSubManager));
|
webSocketEnvironment.jersey().register(new KeepAliveController(pubSubManager));
|
||||||
webSocketEnvironment.jersey().register(messageController);
|
webSocketEnvironment.jersey().register(messageController);
|
||||||
|
|
|
@ -16,79 +16,23 @@
|
||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecuregcm.auth;
|
package org.whispersystems.textsecuregcm.auth;
|
||||||
|
|
||||||
import com.codahale.metrics.Meter;
|
|
||||||
import com.codahale.metrics.MetricRegistry;
|
|
||||||
import com.codahale.metrics.SharedMetricRegistries;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
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.util.Constants;
|
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static com.codahale.metrics.MetricRegistry.name;
|
|
||||||
import io.dropwizard.auth.AuthenticationException;
|
|
||||||
import io.dropwizard.auth.Authenticator;
|
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 extends BaseAccountAuthenticator implements Authenticator<BasicCredentials, Account> {
|
||||||
|
|
||||||
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
|
|
||||||
private final Meter authenticationFailedMeter = metricRegistry.meter(name(getClass(), "authentication", "failed" ));
|
|
||||||
private final Meter authenticationSucceededMeter = metricRegistry.meter(name(getClass(), "authentication", "succeeded"));
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(AccountAuthenticator.class);
|
|
||||||
|
|
||||||
private final AccountsManager accountsManager;
|
|
||||||
|
|
||||||
public AccountAuthenticator(AccountsManager accountsManager) {
|
public AccountAuthenticator(AccountsManager accountsManager) {
|
||||||
this.accountsManager = accountsManager;
|
super(accountsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Account> authenticate(BasicCredentials basicCredentials)
|
public Optional<Account> authenticate(BasicCredentials basicCredentials) {
|
||||||
throws AuthenticationException
|
return super.authenticate(basicCredentials, true);
|
||||||
{
|
|
||||||
try {
|
|
||||||
AuthorizationHeader authorizationHeader = AuthorizationHeader.fromUserAndPassword(basicCredentials.getUsername(), basicCredentials.getPassword());
|
|
||||||
Optional<Account> account = accountsManager.get(authorizationHeader.getNumber());
|
|
||||||
|
|
||||||
if (!account.isPresent()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<Device> device = account.get().getDevice(authorizationHeader.getDeviceId());
|
|
||||||
|
|
||||||
if (!device.isPresent()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!device.get().isMaster() && device.get().isIdleInactive()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device.get().getAuthenticationCredentials().verify(basicCredentials.getPassword())) {
|
|
||||||
authenticationSucceededMeter.mark();
|
|
||||||
account.get().setAuthenticatedDevice(device.get());
|
|
||||||
updateLastSeen(account.get(), device.get());
|
|
||||||
return account;
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticationFailedMeter.mark();
|
|
||||||
return Optional.empty();
|
|
||||||
} catch (InvalidAuthorizationHeaderException iahe) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLastSeen(Account account, Device device) {
|
|
||||||
if (device.getLastSeen() != Util.todayInMillis()) {
|
|
||||||
device.setLastSeen(Util.todayInMillis());
|
|
||||||
accountsManager.update(account);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package org.whispersystems.textsecuregcm.auth;
|
||||||
|
|
||||||
|
import com.codahale.metrics.Meter;
|
||||||
|
import com.codahale.metrics.MetricRegistry;
|
||||||
|
import com.codahale.metrics.SharedMetricRegistries;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
import org.whispersystems.textsecuregcm.util.Constants;
|
||||||
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.codahale.metrics.MetricRegistry.name;
|
||||||
|
import io.dropwizard.auth.basic.BasicCredentials;
|
||||||
|
|
||||||
|
public class BaseAccountAuthenticator {
|
||||||
|
|
||||||
|
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
|
||||||
|
private final Meter authenticationFailedMeter = metricRegistry.meter(name(getClass(), "authentication", "failed" ));
|
||||||
|
private final Meter authenticationSucceededMeter = metricRegistry.meter(name(getClass(), "authentication", "succeeded" ));
|
||||||
|
private final Meter noSuchAccountMeter = metricRegistry.meter(name(getClass(), "authentication", "noSuchAccount" ));
|
||||||
|
private final Meter noSuchDeviceMeter = metricRegistry.meter(name(getClass(), "authentication", "noSuchDevice" ));
|
||||||
|
private final Meter accountDisabledMeter = metricRegistry.meter(name(getClass(), "authentication", "accountDisabled"));
|
||||||
|
private final Meter deviceDisabledMeter = metricRegistry.meter(name(getClass(), "authentication", "deviceDisabled" ));
|
||||||
|
private final Meter invalidAuthHeaderMeter = metricRegistry.meter(name(getClass(), "authentication", "invalidHeader" ));
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(AccountAuthenticator.class);
|
||||||
|
|
||||||
|
private final AccountsManager accountsManager;
|
||||||
|
|
||||||
|
public BaseAccountAuthenticator(AccountsManager accountsManager) {
|
||||||
|
this.accountsManager = accountsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Account> authenticate(BasicCredentials basicCredentials, boolean enabledRequired) {
|
||||||
|
try {
|
||||||
|
AuthorizationHeader authorizationHeader = AuthorizationHeader.fromUserAndPassword(basicCredentials.getUsername(), basicCredentials.getPassword());
|
||||||
|
Optional<Account> account = accountsManager.get(authorizationHeader.getNumber());
|
||||||
|
|
||||||
|
if (!account.isPresent()) {
|
||||||
|
noSuchAccountMeter.mark();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Device> device = account.get().getDevice(authorizationHeader.getDeviceId());
|
||||||
|
|
||||||
|
if (!device.isPresent()) {
|
||||||
|
noSuchDeviceMeter.mark();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabledRequired) {
|
||||||
|
if (!device.get().isEnabled()) {
|
||||||
|
deviceDisabledMeter.mark();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!account.get().isEnabled()) {
|
||||||
|
accountDisabledMeter.mark();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device.get().getAuthenticationCredentials().verify(basicCredentials.getPassword())) {
|
||||||
|
authenticationSucceededMeter.mark();
|
||||||
|
account.get().setAuthenticatedDevice(device.get());
|
||||||
|
updateLastSeen(account.get(), device.get());
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticationFailedMeter.mark();
|
||||||
|
return Optional.empty();
|
||||||
|
} catch (InvalidAuthorizationHeaderException iahe) {
|
||||||
|
invalidAuthHeaderMeter.mark();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLastSeen(Account account, Device device) {
|
||||||
|
if (device.getLastSeen() != Util.todayInMillis()) {
|
||||||
|
device.setLastSeen(Util.todayInMillis());
|
||||||
|
accountsManager.update(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.whispersystems.textsecuregcm.auth;
|
||||||
|
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
public class DisabledPermittedAccount implements Principal {
|
||||||
|
|
||||||
|
private final Account account;
|
||||||
|
|
||||||
|
public DisabledPermittedAccount(Account account) {
|
||||||
|
this.account = account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getAccount() {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Principal implementation
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean implies(Subject subject) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.whispersystems.textsecuregcm.auth;
|
||||||
|
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import io.dropwizard.auth.Authenticator;
|
||||||
|
import io.dropwizard.auth.basic.BasicCredentials;
|
||||||
|
|
||||||
|
public class DisabledPermittedAccountAuthenticator extends BaseAccountAuthenticator implements Authenticator<BasicCredentials, DisabledPermittedAccount> {
|
||||||
|
|
||||||
|
public DisabledPermittedAccountAuthenticator(AccountsManager accountsManager) {
|
||||||
|
super(accountsManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<DisabledPermittedAccount> authenticate(BasicCredentials credentials) {
|
||||||
|
Optional<Account> account = super.authenticate(credentials, false);
|
||||||
|
return account.map(DisabledPermittedAccount::new);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package org.whispersystems.textsecuregcm.auth;
|
||||||
|
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
import org.whispersystems.textsecuregcm.util.Hex;
|
|
||||||
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -27,7 +26,7 @@ public class OptionalAccess {
|
||||||
|
|
||||||
Optional<Device> targetDevice = targetAccount.get().getDevice(deviceId);
|
Optional<Device> targetDevice = targetAccount.get().getDevice(deviceId);
|
||||||
|
|
||||||
if (targetDevice.isPresent() && targetDevice.get().isActive()) {
|
if (targetDevice.isPresent() && targetDevice.get().isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,23 +45,23 @@ public class OptionalAccess {
|
||||||
Optional<Anonymous> accessKey,
|
Optional<Anonymous> accessKey,
|
||||||
Optional<Account> targetAccount)
|
Optional<Account> targetAccount)
|
||||||
{
|
{
|
||||||
if (requestAccount.isPresent() && targetAccount.isPresent() && targetAccount.get().isActive()) {
|
if (requestAccount.isPresent() && targetAccount.isPresent() && targetAccount.get().isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
if (requestAccount.isPresent() && (!targetAccount.isPresent() || (targetAccount.isPresent() && !targetAccount.get().isActive()))) {
|
if (requestAccount.isPresent() && (!targetAccount.isPresent() || (targetAccount.isPresent() && !targetAccount.get().isEnabled()))) {
|
||||||
throw new WebApplicationException(Response.Status.NOT_FOUND);
|
throw new WebApplicationException(Response.Status.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessKey.isPresent() && targetAccount.isPresent() && targetAccount.get().isActive() && targetAccount.get().isUnrestrictedUnidentifiedAccess()) {
|
if (accessKey.isPresent() && targetAccount.isPresent() && targetAccount.get().isEnabled() && targetAccount.get().isUnrestrictedUnidentifiedAccess()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessKey.isPresent() &&
|
if (accessKey.isPresent() &&
|
||||||
targetAccount.isPresent() &&
|
targetAccount.isPresent() &&
|
||||||
targetAccount.get().getUnidentifiedAccessKey().isPresent() &&
|
targetAccount.get().getUnidentifiedAccessKey().isPresent() &&
|
||||||
targetAccount.get().isActive() &&
|
targetAccount.get().isEnabled() &&
|
||||||
MessageDigest.isEqual(accessKey.get().getAccessKey(), targetAccount.get().getUnidentifiedAccessKey().get()))
|
MessageDigest.isEqual(accessKey.get().getAccessKey(), targetAccount.get().getUnidentifiedAccessKey().get()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthorizationHeader;
|
import org.whispersystems.textsecuregcm.auth.AuthorizationHeader;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.InvalidAuthorizationHeaderException;
|
import org.whispersystems.textsecuregcm.auth.InvalidAuthorizationHeaderException;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
||||||
import org.whispersystems.textsecuregcm.auth.TurnToken;
|
import org.whispersystems.textsecuregcm.auth.TurnToken;
|
||||||
|
@ -63,7 +64,6 @@ import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
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.IOException;
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -260,9 +260,10 @@ public class AccountController {
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/gcm/")
|
@Path("/gcm/")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void setGcmRegistrationId(@Auth Account account, @Valid GcmRegistrationId registrationId) {
|
public void setGcmRegistrationId(@Auth DisabledPermittedAccount disabledPermittedAccount, @Valid GcmRegistrationId registrationId) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
boolean wasAccountActive = account.isActive();
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
|
boolean wasAccountEnabled = account.isEnabled();
|
||||||
|
|
||||||
if (device.getGcmId() != null &&
|
if (device.getGcmId() != null &&
|
||||||
device.getGcmId().equals(registrationId.getGcmRegistrationId()))
|
device.getGcmId().equals(registrationId.getGcmRegistrationId()))
|
||||||
|
@ -277,7 +278,7 @@ public class AccountController {
|
||||||
|
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!wasAccountActive && account.isActive()) {
|
if (!wasAccountEnabled && account.isEnabled()) {
|
||||||
directoryQueue.addRegisteredUser(account.getNumber());
|
directoryQueue.addRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,14 +286,15 @@ public class AccountController {
|
||||||
@Timed
|
@Timed
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/gcm/")
|
@Path("/gcm/")
|
||||||
public void deleteGcmRegistrationId(@Auth Account account) {
|
public void deleteGcmRegistrationId(@Auth DisabledPermittedAccount disabledPermittedAccount) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
device.setGcmId(null);
|
device.setGcmId(null);
|
||||||
device.setFetchesMessages(false);
|
device.setFetchesMessages(false);
|
||||||
|
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!account.isActive()) {
|
if (!account.isEnabled()) {
|
||||||
directoryQueue.deleteRegisteredUser(account.getNumber());
|
directoryQueue.deleteRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,9 +303,10 @@ public class AccountController {
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/apn/")
|
@Path("/apn/")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void setApnRegistrationId(@Auth Account account, @Valid ApnRegistrationId registrationId) {
|
public void setApnRegistrationId(@Auth DisabledPermittedAccount disabledPermittedAccount, @Valid ApnRegistrationId registrationId) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
boolean wasAccountActive = account.isActive();
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
|
boolean wasAccountEnabled = account.isEnabled();
|
||||||
|
|
||||||
device.setApnId(registrationId.getApnRegistrationId());
|
device.setApnId(registrationId.getApnRegistrationId());
|
||||||
device.setVoipApnId(registrationId.getVoipRegistrationId());
|
device.setVoipApnId(registrationId.getVoipRegistrationId());
|
||||||
|
@ -311,7 +314,7 @@ public class AccountController {
|
||||||
device.setFetchesMessages(false);
|
device.setFetchesMessages(false);
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!wasAccountActive && account.isActive()) {
|
if (!wasAccountEnabled && account.isEnabled()) {
|
||||||
directoryQueue.addRegisteredUser(account.getNumber());
|
directoryQueue.addRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,14 +322,15 @@ public class AccountController {
|
||||||
@Timed
|
@Timed
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/apn/")
|
@Path("/apn/")
|
||||||
public void deleteApnRegistrationId(@Auth Account account) {
|
public void deleteApnRegistrationId(@Auth DisabledPermittedAccount disabledPermittedAccount) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
device.setApnId(null);
|
device.setApnId(null);
|
||||||
device.setFetchesMessages(false);
|
device.setFetchesMessages(false);
|
||||||
|
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!account.isActive()) {
|
if (!account.isEnabled()) {
|
||||||
directoryQueue.deleteRegisteredUser(account.getNumber());
|
directoryQueue.deleteRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,7 +355,8 @@ public class AccountController {
|
||||||
@Timed
|
@Timed
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/name/")
|
@Path("/name/")
|
||||||
public void setName(@Auth Account account, @Valid DeviceName deviceName) {
|
public void setName(@Auth DisabledPermittedAccount disabledPermittedAccount, @Valid DeviceName deviceName) {
|
||||||
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
account.getAuthenticatedDevice().get().setName(deviceName.getDeviceName());
|
account.getAuthenticatedDevice().get().setName(deviceName.getDeviceName());
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
}
|
}
|
||||||
|
@ -359,7 +364,8 @@ public class AccountController {
|
||||||
@Timed
|
@Timed
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/signaling_key")
|
@Path("/signaling_key")
|
||||||
public void removeSignalingKey(@Auth Account account) {
|
public void removeSignalingKey(@Auth DisabledPermittedAccount disabledPermittedAccount) {
|
||||||
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
account.getAuthenticatedDevice().get().setSignalingKey(null);
|
account.getAuthenticatedDevice().get().setSignalingKey(null);
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
}
|
}
|
||||||
|
@ -368,11 +374,12 @@ public class AccountController {
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/attributes/")
|
@Path("/attributes/")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void setAccountAttributes(@Auth Account account,
|
public void setAccountAttributes(@Auth DisabledPermittedAccount disabledPermittedAccount,
|
||||||
@HeaderParam("X-Signal-Agent") String userAgent,
|
@HeaderParam("X-Signal-Agent") String userAgent,
|
||||||
@Valid AccountAttributes attributes)
|
@Valid AccountAttributes attributes)
|
||||||
{
|
{
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
|
|
||||||
device.setFetchesMessages(attributes.getFetchesMessages());
|
device.setFetchesMessages(attributes.getFetchesMessages());
|
||||||
device.setName(attributes.getName());
|
device.setName(attributes.getName());
|
||||||
|
@ -476,7 +483,7 @@ public class AccountController {
|
||||||
newUserMeter.mark();
|
newUserMeter.mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.isActive()) {
|
if (account.isEnabled()) {
|
||||||
directoryQueue.addRegisteredUser(number);
|
directoryQueue.addRegisteredUser(number);
|
||||||
} else {
|
} else {
|
||||||
directoryQueue.deleteRegisteredUser(number);
|
directoryQueue.deleteRegisteredUser(number);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.whispersystems.textsecuregcm.entities.AttachmentUri;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.s3.UrlSigner;
|
import org.whispersystems.textsecuregcm.s3.UrlSigner;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.util.Conversions;
|
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
@ -34,7 +33,6 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import io.dropwizard.auth.Auth;
|
import io.dropwizard.auth.Auth;
|
||||||
|
|
|
@ -14,7 +14,6 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
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.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class DeviceController {
|
||||||
account.removeDevice(deviceId);
|
account.removeDevice(deviceId);
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!account.isActive()) {
|
if (!account.isEnabled()) {
|
||||||
directoryQueue.deleteRegisteredUser(account.getNumber());
|
directoryQueue.deleteRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ public class DeviceController {
|
||||||
maxDeviceLimit = maxDeviceConfiguration.get(account.getNumber());
|
maxDeviceLimit = maxDeviceConfiguration.get(account.getNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.getActiveDeviceCount() >= maxDeviceLimit) {
|
if (account.getEnabledDeviceCount() >= maxDeviceLimit) {
|
||||||
throw new DeviceLimitExceededException(account.getDevices().size(), MAX_DEVICES);
|
throw new DeviceLimitExceededException(account.getDevices().size(), MAX_DEVICES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ public class DeviceController {
|
||||||
maxDeviceLimit = maxDeviceConfiguration.get(account.get().getNumber());
|
maxDeviceLimit = maxDeviceConfiguration.get(account.get().getNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.get().getActiveDeviceCount() >= maxDeviceLimit) {
|
if (account.get().getEnabledDeviceCount() >= maxDeviceLimit) {
|
||||||
throw new DeviceLimitExceededException(account.get().getDevices().size(), MAX_DEVICES);
|
throw new DeviceLimitExceededException(account.get().getDevices().size(), MAX_DEVICES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.codahale.metrics.annotation.Timed;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.auth.Anonymous;
|
import org.whispersystems.textsecuregcm.auth.Anonymous;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
||||||
import org.whispersystems.textsecuregcm.entities.PreKey;
|
import org.whispersystems.textsecuregcm.entities.PreKey;
|
||||||
import org.whispersystems.textsecuregcm.entities.PreKeyCount;
|
import org.whispersystems.textsecuregcm.entities.PreKeyCount;
|
||||||
|
@ -85,10 +86,11 @@ public class KeysController {
|
||||||
@Timed
|
@Timed
|
||||||
@PUT
|
@PUT
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void setKeys(@Auth Account account, @Valid PreKeyState preKeys) {
|
public void setKeys(@Auth DisabledPermittedAccount disabledPermittedAccount, @Valid PreKeyState preKeys) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
boolean wasAccountActive = account.isActive();
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
boolean updateAccount = false;
|
boolean wasAccountEnabled = account.isEnabled();
|
||||||
|
boolean updateAccount = false;
|
||||||
|
|
||||||
if (!preKeys.getSignedPreKey().equals(device.getSignedPreKey())) {
|
if (!preKeys.getSignedPreKey().equals(device.getSignedPreKey())) {
|
||||||
device.setSignedPreKey(preKeys.getSignedPreKey());
|
device.setSignedPreKey(preKeys.getSignedPreKey());
|
||||||
|
@ -103,7 +105,7 @@ public class KeysController {
|
||||||
if (updateAccount) {
|
if (updateAccount) {
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!wasAccountActive && account.isActive()) {
|
if (!wasAccountEnabled && account.isEnabled()) {
|
||||||
directoryQueue.addRegisteredUser(account.getNumber());
|
directoryQueue.addRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +140,7 @@ public class KeysController {
|
||||||
List<PreKeyResponseItem> devices = new LinkedList<>();
|
List<PreKeyResponseItem> devices = new LinkedList<>();
|
||||||
|
|
||||||
for (Device device : target.get().getDevices()) {
|
for (Device device : target.get().getDevices()) {
|
||||||
if (device.isActive() && (deviceId.equals("*") || device.getId() == Long.parseLong(deviceId))) {
|
if (device.isEnabled() && (deviceId.equals("*") || device.getId() == Long.parseLong(deviceId))) {
|
||||||
SignedPreKey signedPreKey = device.getSignedPreKey();
|
SignedPreKey signedPreKey = device.getSignedPreKey();
|
||||||
PreKey preKey = null;
|
PreKey preKey = null;
|
||||||
|
|
||||||
|
@ -162,14 +164,15 @@ public class KeysController {
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/signed")
|
@Path("/signed")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void setSignedKey(@Auth Account account, @Valid SignedPreKey signedPreKey) {
|
public void setSignedKey(@Auth DisabledPermittedAccount disabledPermittedAccount, @Valid SignedPreKey signedPreKey) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Account account = disabledPermittedAccount.getAccount();
|
||||||
boolean wasAccountActive = account.isActive();
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
|
boolean wasAccountEnabled = account.isEnabled();
|
||||||
|
|
||||||
device.setSignedPreKey(signedPreKey);
|
device.setSignedPreKey(signedPreKey);
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
|
|
||||||
if (!wasAccountActive && account.isActive()) {
|
if (!wasAccountEnabled && account.isEnabled()) {
|
||||||
directoryQueue.addRegisteredUser(account.getNumber());
|
directoryQueue.addRegisteredUser(account.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,7 @@ public class MessageController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SendMessageResponse(!isSyncMessage && source.isPresent() && source.get().getActiveDeviceCount() > 1);
|
return new SendMessageResponse(!isSyncMessage && source.isPresent() && source.get().getEnabledDeviceCount() > 1);
|
||||||
} catch (NoSuchUserException e) {
|
} catch (NoSuchUserException e) {
|
||||||
throw new WebApplicationException(Response.status(404).build());
|
throw new WebApplicationException(Response.status(404).build());
|
||||||
} catch (MismatchedDevicesException e) {
|
} catch (MismatchedDevicesException e) {
|
||||||
|
@ -301,7 +301,7 @@ public class MessageController {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Device device : account.getDevices()) {
|
for (Device device : account.getDevices()) {
|
||||||
if (device.isActive() &&
|
if (device.isEnabled() &&
|
||||||
!(isSyncMessage && device.getId() == account.getAuthenticatedDevice().get().getId()))
|
!(isSyncMessage && device.getId() == account.getAuthenticatedDevice().get().getId()))
|
||||||
{
|
{
|
||||||
accountDeviceIds.add(device.getId());
|
accountDeviceIds.add(device.getId());
|
||||||
|
|
|
@ -10,8 +10,8 @@ import com.codahale.metrics.annotation.Timed;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
import org.hibernate.validator.valuehandling.UnwrapValidatedValue;
|
import org.hibernate.validator.valuehandling.UnwrapValidatedValue;
|
||||||
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.Anonymous;
|
import org.whispersystems.textsecuregcm.auth.Anonymous;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
||||||
import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum;
|
import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum;
|
||||||
import org.whispersystems.textsecuregcm.configuration.ProfilesConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.ProfilesConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.entities.Profile;
|
import org.whispersystems.textsecuregcm.entities.Profile;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.whispersystems.textsecuregcm.entities;
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
|
|
||||||
public class ApnRegistrationId {
|
public class ApnRegistrationId {
|
||||||
|
@ -28,6 +29,14 @@ public class ApnRegistrationId {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String voipRegistrationId;
|
private String voipRegistrationId;
|
||||||
|
|
||||||
|
public ApnRegistrationId() {}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public ApnRegistrationId(String apnRegistrationId, String voipRegistrationId) {
|
||||||
|
this.apnRegistrationId = apnRegistrationId;
|
||||||
|
this.voipRegistrationId = voipRegistrationId;
|
||||||
|
}
|
||||||
|
|
||||||
public String getApnRegistrationId() {
|
public String getApnRegistrationId() {
|
||||||
return apnRegistrationId;
|
return apnRegistrationId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.whispersystems.textsecuregcm.entities;
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
|
|
||||||
public class GcmRegistrationId {
|
public class GcmRegistrationId {
|
||||||
|
@ -25,9 +26,17 @@ public class GcmRegistrationId {
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String gcmRegistrationId;
|
private String gcmRegistrationId;
|
||||||
|
|
||||||
|
public GcmRegistrationId() {}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public GcmRegistrationId(String id) {
|
||||||
|
this.gcmRegistrationId = id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getGcmRegistrationId() {
|
public String getGcmRegistrationId() {
|
||||||
return gcmRegistrationId;
|
return gcmRegistrationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,13 +115,13 @@ public class Account implements Principal {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUnauthenticatedDeliverySupported() {
|
public boolean isUnauthenticatedDeliverySupported() {
|
||||||
return devices.stream().filter(Device::isActive).allMatch(Device::isUnauthenticatedDeliverySupported);
|
return devices.stream().filter(Device::isEnabled).allMatch(Device::isUnauthenticatedDeliverySupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isEnabled() {
|
||||||
return
|
return
|
||||||
getMasterDevice().isPresent() &&
|
getMasterDevice().isPresent() &&
|
||||||
getMasterDevice().get().isActive() &&
|
getMasterDevice().get().isEnabled() &&
|
||||||
getLastSeen() > (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(365));
|
getLastSeen() > (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(365));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ public class Account implements Principal {
|
||||||
long highestDevice = Device.MASTER_ID;
|
long highestDevice = Device.MASTER_ID;
|
||||||
|
|
||||||
for (Device device : devices) {
|
for (Device device : devices) {
|
||||||
if (!device.isActive()) {
|
if (!device.isEnabled()) {
|
||||||
return device.getId();
|
return device.getId();
|
||||||
} else if (device.getId() > highestDevice) {
|
} else if (device.getId() > highestDevice) {
|
||||||
highestDevice = device.getId();
|
highestDevice = device.getId();
|
||||||
|
@ -139,11 +139,11 @@ public class Account implements Principal {
|
||||||
return highestDevice + 1;
|
return highestDevice + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getActiveDeviceCount() {
|
public int getEnabledDeviceCount() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (Device device : devices) {
|
for (Device device : devices) {
|
||||||
if (device.isActive()) count++;
|
if (device.isEnabled()) count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|
|
@ -53,8 +53,8 @@ public class AccountCleaner implements AccountDatabaseCrawlerListener {
|
||||||
long nowMs = System.currentTimeMillis();
|
long nowMs = System.currentTimeMillis();
|
||||||
int accountUpdateCount = 0;
|
int accountUpdateCount = 0;
|
||||||
for (Account account : chunkAccounts) {
|
for (Account account : chunkAccounts) {
|
||||||
if (account.getMasterDevice().isPresent() &&
|
if (account.getMasterDevice().isPresent() &&
|
||||||
account.getMasterDevice().get().isActive() &&
|
account.getMasterDevice().get().isEnabled() &&
|
||||||
isAccountExpired(account, nowMs))
|
isAccountExpired(account, nowMs))
|
||||||
{
|
{
|
||||||
expiredAccountsMeter.mark();
|
expiredAccountsMeter.mark();
|
||||||
|
|
|
@ -93,7 +93,7 @@ public class AccountsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDirectory(Account account) {
|
private void updateDirectory(Account account) {
|
||||||
if (account.isActive()) {
|
if (account.isEnabled()) {
|
||||||
byte[] token = Util.getContactToken(account.getNumber());
|
byte[] token = Util.getContactToken(account.getNumber());
|
||||||
ClientContact clientContact = new ClientContact(token, null, true, true);
|
ClientContact clientContact = new ClientContact(token, null, true, true);
|
||||||
directory.add(clientContact);
|
directory.add(clientContact);
|
||||||
|
|
|
@ -191,17 +191,13 @@ public class Device {
|
||||||
this.signalingKey = signalingKey;
|
this.signalingKey = signalingKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isEnabled() {
|
||||||
boolean hasChannel = fetchesMessages || !Util.isEmpty(getApnId()) || !Util.isEmpty(getGcmId());
|
boolean hasChannel = fetchesMessages || !Util.isEmpty(getApnId()) || !Util.isEmpty(getGcmId());
|
||||||
|
|
||||||
return (id == MASTER_ID && hasChannel && signedPreKey != null) ||
|
return (id == MASTER_ID && hasChannel && signedPreKey != null) ||
|
||||||
(id != MASTER_ID && hasChannel && signedPreKey != null && !isIdleInactive());
|
(id != MASTER_ID && hasChannel && signedPreKey != null && lastSeen > (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIdleInactive() {
|
|
||||||
return id != MASTER_ID && lastSeen < (System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getFetchesMessages() {
|
public boolean getFetchesMessages() {
|
||||||
return fetchesMessages;
|
return fetchesMessages;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.codahale.metrics.SharedMetricRegistries;
|
import com.codahale.metrics.SharedMetricRegistries;
|
||||||
import com.codahale.metrics.Timer;
|
import com.codahale.metrics.Timer;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.entities.ClientContact;
|
import org.whispersystems.textsecuregcm.entities.ClientContact;
|
||||||
|
@ -80,7 +79,7 @@ public class DirectoryReconciler implements AccountDatabaseCrawlerListener {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (Account account : accounts) {
|
for (Account account : accounts) {
|
||||||
if (account.isActive()) {
|
if (account.isEnabled()) {
|
||||||
byte[] token = Util.getContactToken(account.getNumber());
|
byte[] token = Util.getContactToken(account.getNumber());
|
||||||
ClientContact clientContact = new ClientContact(token, null, true, true);
|
ClientContact clientContact = new ClientContact(token, null, true, true);
|
||||||
directoryManager.add(batchOperation, clientContact);
|
directoryManager.add(batchOperation, clientContact);
|
||||||
|
@ -93,9 +92,10 @@ public class DirectoryReconciler implements AccountDatabaseCrawlerListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||||
private DirectoryReconciliationRequest createChunkRequest(Optional<String> fromNumber, List<Account> accounts) {
|
private DirectoryReconciliationRequest createChunkRequest(Optional<String> fromNumber, List<Account> accounts) {
|
||||||
List<String> numbers = accounts.stream()
|
List<String> numbers = accounts.stream()
|
||||||
.filter(Account::isActive)
|
.filter(Account::isEnabled)
|
||||||
.map(Account::getNumber)
|
.map(Account::getNumber)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ package org.whispersystems.textsecuregcm.websocket;
|
||||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||||
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
|
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
|
||||||
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.List;
|
||||||
|
@ -23,25 +21,21 @@ public class WebSocketAccountAuthenticator implements WebSocketAuthenticator<Acc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthenticationResult<Account> authenticate(UpgradeRequest request) throws AuthenticationException {
|
public AuthenticationResult<Account> authenticate(UpgradeRequest request) {
|
||||||
try {
|
Map<String, List<String>> parameters = request.getParameterMap();
|
||||||
Map<String, List<String>> parameters = request.getParameterMap();
|
List<String> usernames = parameters.get("login");
|
||||||
List<String> usernames = parameters.get("login");
|
List<String> passwords = parameters.get("password");
|
||||||
List<String> passwords = parameters.get("password");
|
|
||||||
|
|
||||||
if (usernames == null || usernames.size() == 0 ||
|
if (usernames == null || usernames.size() == 0 ||
|
||||||
passwords == null || passwords.size() == 0)
|
passwords == null || passwords.size() == 0)
|
||||||
{
|
{
|
||||||
return new AuthenticationResult<>(Optional.empty(), false);
|
return new AuthenticationResult<>(Optional.empty(), false);
|
||||||
}
|
|
||||||
|
|
||||||
BasicCredentials credentials = new BasicCredentials(usernames.get(0).replace(" ", "+"),
|
|
||||||
passwords.get(0).replace(" ", "+"));
|
|
||||||
|
|
||||||
return new AuthenticationResult<>(accountAuthenticator.authenticate(credentials), true);
|
|
||||||
} catch (io.dropwizard.auth.AuthenticationException e) {
|
|
||||||
throw new AuthenticationException(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasicCredentials credentials = new BasicCredentials(usernames.get(0).replace(" ", "+"),
|
||||||
|
passwords.get(0).replace(" ", "+"));
|
||||||
|
|
||||||
|
return new AuthenticationResult<>(accountAuthenticator.authenticate(credentials), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class OptionalAccessTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUnidentifiedMissingTargetDevice() {
|
public void testUnidentifiedMissingTargetDevice() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
when(account.getDevice(eq(10))).thenReturn(Optional.empty());
|
when(account.getDevice(eq(10))).thenReturn(Optional.empty());
|
||||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class OptionalAccessTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUnidentifiedBadTargetDevice() {
|
public void testUnidentifiedBadTargetDevice() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
when(account.getDevice(eq(10))).thenReturn(Optional.empty());
|
when(account.getDevice(eq(10))).thenReturn(Optional.empty());
|
||||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public class OptionalAccessTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUnidentifiedBadCode() {
|
public void testUnidentifiedBadCode() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -72,7 +72,7 @@ public class OptionalAccessTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIdentifiedMissingTarget() {
|
public void testIdentifiedMissingTarget() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OptionalAccess.verify(Optional.of(account), Optional.empty(), Optional.empty());
|
OptionalAccess.verify(Optional.of(account), Optional.empty(), Optional.empty());
|
||||||
|
@ -86,7 +86,7 @@ public class OptionalAccessTest {
|
||||||
public void testUnsolicitedBadTarget() {
|
public void testUnsolicitedBadTarget() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(false);
|
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(false);
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OptionalAccess.verify(Optional.empty(), Optional.empty(), Optional.of(account));
|
OptionalAccess.verify(Optional.empty(), Optional.empty(), Optional.of(account));
|
||||||
|
@ -101,7 +101,7 @@ public class OptionalAccessTest {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
Anonymous random = mock(Anonymous.class);
|
Anonymous random = mock(Anonymous.class);
|
||||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(true);
|
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(true);
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
OptionalAccess.verify(Optional.empty(), Optional.of(random), Optional.of(account));
|
OptionalAccess.verify(Optional.empty(), Optional.of(random), Optional.of(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ public class OptionalAccessTest {
|
||||||
public void testUnidentifiedGoodTarget() {
|
public void testUnidentifiedGoodTarget() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||||
when(account.isActive()).thenReturn(true);
|
when(account.isEnabled()).thenReturn(true);
|
||||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.encodeBytes("1234".getBytes()))), Optional.of(account));
|
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.encodeBytes("1234".getBytes()))), Optional.of(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ public class OptionalAccessTest {
|
||||||
public void testUnidentifiedInactive() {
|
public void testUnidentifiedInactive() {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||||
when(account.isActive()).thenReturn(false);
|
when(account.isEnabled()).thenReturn(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.encodeBytes("1234".getBytes()))), Optional.of(account));
|
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.encodeBytes("1234".getBytes()))), Optional.of(account));
|
||||||
|
@ -131,7 +131,7 @@ public class OptionalAccessTest {
|
||||||
public void testIdentifiedGoodTarget() {
|
public void testIdentifiedGoodTarget() {
|
||||||
Account source = mock(Account.class);
|
Account source = mock(Account.class);
|
||||||
Account target = mock(Account.class);
|
Account target = mock(Account.class);
|
||||||
when(target.isActive()).thenReturn(true);
|
when(target.isEnabled()).thenReturn(true);
|
||||||
OptionalAccess.verify(Optional.of(source), Optional.empty(), Optional.of(target));;
|
OptionalAccess.verify(Optional.of(source), Optional.empty(), Optional.of(target));;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
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.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
||||||
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
|
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
|
||||||
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.ApnRegistrationId;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.GcmRegistrationId;
|
||||||
import org.whispersystems.textsecuregcm.entities.RegistrationLock;
|
import org.whispersystems.textsecuregcm.entities.RegistrationLock;
|
||||||
import org.whispersystems.textsecuregcm.entities.RegistrationLockFailure;
|
import org.whispersystems.textsecuregcm.entities.RegistrationLockFailure;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
|
@ -36,7 +40,7 @@ import java.util.HashMap;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
|
@ -80,7 +84,7 @@ public class AccountControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.addProvider(new RateLimitExceededExceptionMapper())
|
.addProvider(new RateLimitExceededExceptionMapper())
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
|
@ -505,6 +509,51 @@ public class AccountControllerTest {
|
||||||
verify(AuthHelper.VALID_ACCOUNT, never()).setPin(anyString());
|
verify(AuthHelper.VALID_ACCOUNT, never()).setPin(anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetPinDisabled() throws Exception {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/accounts/pin/")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.put(Entity.json(new RegistrationLock("31337")));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
|
|
||||||
|
verify(AuthHelper.VALID_ACCOUNT, never()).setPin(anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetGcmId() throws Exception {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/accounts/gcm/")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.put(Entity.json(new GcmRegistrationId("c00lz0rz")));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(204);
|
||||||
|
|
||||||
|
verify(AuthHelper.DISABLED_DEVICE, times(1)).setGcmId(eq("c00lz0rz"));
|
||||||
|
verify(accountsManager, times(1)).update(eq(AuthHelper.DISABLED_ACCOUNT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetApnId() throws Exception {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/accounts/apn/")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.put(Entity.json(new ApnRegistrationId("first", "second")));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(204);
|
||||||
|
|
||||||
|
verify(AuthHelper.DISABLED_DEVICE, times(1)).setApnId(eq("first"));
|
||||||
|
verify(AuthHelper.DISABLED_DEVICE, times(1)).setVoipApnId(eq("second"));
|
||||||
|
verify(accountsManager, times(1)).update(eq(AuthHelper.DISABLED_ACCOUNT));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
|
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
||||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV1;
|
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV1;
|
||||||
|
@ -14,9 +16,10 @@ import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -34,7 +37,7 @@ public class AttachmentControllerTest {
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new AttachmentControllerV1(rateLimiters, "accessKey", "accessSecret", "attachment-bucket"))
|
.addResource(new AttachmentControllerV1(rateLimiters, "accessKey", "accessSecret", "attachment-bucket"))
|
||||||
|
@ -67,6 +70,18 @@ public class AttachmentControllerTest {
|
||||||
assertThat(descriptor.getSignature()).isNotBlank();
|
assertThat(descriptor.getSignature()).isNotBlank();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testV2FormDisabled() {
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v2/attachments/form/upload")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceleratedPut() {
|
public void testAcceleratedPut() {
|
||||||
AttachmentDescriptorV1 descriptor = resources.getJerseyTest()
|
AttachmentDescriptorV1 descriptor = resources.getJerseyTest()
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
||||||
import org.whispersystems.textsecuregcm.controllers.CertificateController;
|
import org.whispersystems.textsecuregcm.controllers.CertificateController;
|
||||||
import org.whispersystems.textsecuregcm.crypto.Curve;
|
import org.whispersystems.textsecuregcm.crypto.Curve;
|
||||||
|
@ -19,7 +21,7 @@ import javax.ws.rs.core.Response;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static junit.framework.TestCase.assertTrue;
|
import static junit.framework.TestCase.assertTrue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -46,7 +48,7 @@ public class CertificateControllerTest {
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new CertificateController(certificateGenerator))
|
.addResource(new CertificateController(certificateGenerator))
|
||||||
|
@ -110,4 +112,16 @@ public class CertificateControllerTest {
|
||||||
assertEquals(response.getStatus(), 401);
|
assertEquals(response.getStatus(), 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisabledAuthentication() throws Exception {
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/certificate/delivery")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertEquals(response.getStatus(), 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
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.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
||||||
import org.whispersystems.textsecuregcm.controllers.DeviceController;
|
import org.whispersystems.textsecuregcm.controllers.DeviceController;
|
||||||
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
||||||
|
@ -28,7 +30,11 @@ import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.mappers.DeviceLimitExceededExceptionMapper;
|
import org.whispersystems.textsecuregcm.mappers.DeviceLimitExceededExceptionMapper;
|
||||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||||
import org.whispersystems.textsecuregcm.storage.*;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.VerificationCode;
|
import org.whispersystems.textsecuregcm.util.VerificationCode;
|
||||||
|
|
||||||
|
@ -41,7 +47,7 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -83,7 +89,7 @@ public class DeviceControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addProvider(new DeviceLimitExceededExceptionMapper())
|
.addProvider(new DeviceLimitExceededExceptionMapper())
|
||||||
.addResource(new DumbVerificationDeviceController(pendingDevicesManager,
|
.addResource(new DumbVerificationDeviceController(pendingDevicesManager,
|
||||||
|
@ -109,7 +115,7 @@ public class DeviceControllerTest {
|
||||||
when(account.getNumber()).thenReturn(AuthHelper.VALID_NUMBER);
|
when(account.getNumber()).thenReturn(AuthHelper.VALID_NUMBER);
|
||||||
// when(maxedAccount.getActiveDeviceCount()).thenReturn(6);
|
// when(maxedAccount.getActiveDeviceCount()).thenReturn(6);
|
||||||
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(masterDevice));
|
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(masterDevice));
|
||||||
when(account.isActive()).thenReturn(false);
|
when(account.isEnabled()).thenReturn(false);
|
||||||
|
|
||||||
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of(new StoredVerificationCode("5678901", System.currentTimeMillis())));
|
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of(new StoredVerificationCode("5678901", System.currentTimeMillis())));
|
||||||
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(new StoredVerificationCode("1112223", System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(31))));
|
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(new StoredVerificationCode("1112223", System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(31))));
|
||||||
|
@ -141,6 +147,17 @@ public class DeviceControllerTest {
|
||||||
verify(messagesManager).clear(eq(AuthHelper.VALID_NUMBER), eq(42L));
|
verify(messagesManager).clear(eq(AuthHelper.VALID_NUMBER), eq(42L));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disabledDeviceRegisterTest() throws Exception {
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/devices/provisioning/code")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void invalidDeviceRegisterTest() throws Exception {
|
public void invalidDeviceRegisterTest() throws Exception {
|
||||||
VerificationCode deviceCode = resources.getJerseyTest()
|
VerificationCode deviceCode = resources.getJerseyTest()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
@ -8,6 +9,7 @@ import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
import org.whispersystems.textsecuregcm.auth.DirectoryCredentials;
|
import org.whispersystems.textsecuregcm.auth.DirectoryCredentials;
|
||||||
import org.whispersystems.textsecuregcm.auth.DirectoryCredentialsGenerator;
|
import org.whispersystems.textsecuregcm.auth.DirectoryCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
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.entities.DirectoryFeedbackRequest;
|
import org.whispersystems.textsecuregcm.entities.DirectoryFeedbackRequest;
|
||||||
|
@ -27,7 +29,7 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.anyListOf;
|
import static org.mockito.ArgumentMatchers.anyListOf;
|
||||||
|
@ -47,7 +49,7 @@ public class DirectoryControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new DirectoryController(rateLimiters,
|
.addResource(new DirectoryController(rateLimiters,
|
||||||
directoryManager,
|
directoryManager,
|
||||||
|
@ -148,6 +150,18 @@ public class DirectoryControllerTest {
|
||||||
assertThat(token.getPassword()).isEqualTo(validCredentials.getPassword());
|
assertThat(token.getPassword()).isEqualTo(validCredentials.getPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisabledGetAuthToken() {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/directory/auth")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.get();
|
||||||
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testContactIntersection() throws Exception {
|
public void testContactIntersection() throws Exception {
|
||||||
List<String> tokens = new LinkedList<String>() {{
|
List<String> tokens = new LinkedList<String>() {{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
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.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
||||||
import org.whispersystems.textsecuregcm.controllers.KeysController;
|
import org.whispersystems.textsecuregcm.controllers.KeysController;
|
||||||
import org.whispersystems.textsecuregcm.entities.PreKey;
|
import org.whispersystems.textsecuregcm.entities.PreKey;
|
||||||
|
@ -31,7 +33,7 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
@ -67,7 +69,7 @@ public class KeyControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new KeysController(rateLimiters, keys, accounts, directoryQueue))
|
.addResource(new KeysController(rateLimiters, keys, accounts, directoryQueue))
|
||||||
.build();
|
.build();
|
||||||
|
@ -90,10 +92,10 @@ public class KeyControllerTest {
|
||||||
when(sampleDevice2.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
when(sampleDevice2.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
||||||
when(sampleDevice3.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
when(sampleDevice3.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
||||||
when(sampleDevice4.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID4);
|
when(sampleDevice4.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID4);
|
||||||
when(sampleDevice.isActive()).thenReturn(true);
|
when(sampleDevice.isEnabled()).thenReturn(true);
|
||||||
when(sampleDevice2.isActive()).thenReturn(true);
|
when(sampleDevice2.isEnabled()).thenReturn(true);
|
||||||
when(sampleDevice3.isActive()).thenReturn(false);
|
when(sampleDevice3.isEnabled()).thenReturn(false);
|
||||||
when(sampleDevice4.isActive()).thenReturn(true);
|
when(sampleDevice4.isEnabled()).thenReturn(true);
|
||||||
when(sampleDevice.getSignedPreKey()).thenReturn(SAMPLE_SIGNED_KEY);
|
when(sampleDevice.getSignedPreKey()).thenReturn(SAMPLE_SIGNED_KEY);
|
||||||
when(sampleDevice2.getSignedPreKey()).thenReturn(SAMPLE_SIGNED_KEY2);
|
when(sampleDevice2.getSignedPreKey()).thenReturn(SAMPLE_SIGNED_KEY2);
|
||||||
when(sampleDevice3.getSignedPreKey()).thenReturn(SAMPLE_SIGNED_KEY3);
|
when(sampleDevice3.getSignedPreKey()).thenReturn(SAMPLE_SIGNED_KEY3);
|
||||||
|
@ -109,7 +111,7 @@ public class KeyControllerTest {
|
||||||
when(existsAccount.getDevice(4L)).thenReturn(Optional.of(sampleDevice4));
|
when(existsAccount.getDevice(4L)).thenReturn(Optional.of(sampleDevice4));
|
||||||
when(existsAccount.getDevice(22L)).thenReturn(Optional.<Device>empty());
|
when(existsAccount.getDevice(22L)).thenReturn(Optional.<Device>empty());
|
||||||
when(existsAccount.getDevices()).thenReturn(allDevices);
|
when(existsAccount.getDevices()).thenReturn(allDevices);
|
||||||
when(existsAccount.isActive()).thenReturn(true);
|
when(existsAccount.isEnabled()).thenReturn(true);
|
||||||
when(existsAccount.getIdentityKey()).thenReturn("existsidentitykey");
|
when(existsAccount.getIdentityKey()).thenReturn("existsidentitykey");
|
||||||
when(existsAccount.getNumber()).thenReturn(EXISTS_NUMBER);
|
when(existsAccount.getNumber()).thenReturn(EXISTS_NUMBER);
|
||||||
when(existsAccount.getUnidentifiedAccessKey()).thenReturn(Optional.of("1337".getBytes()));
|
when(existsAccount.getUnidentifiedAccessKey()).thenReturn(Optional.of("1337".getBytes()));
|
||||||
|
@ -180,6 +182,21 @@ public class KeyControllerTest {
|
||||||
verify(accounts).update(eq(AuthHelper.VALID_ACCOUNT));
|
verify(accounts).update(eq(AuthHelper.VALID_ACCOUNT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disabledPutSignedPreKeyV2() throws Exception {
|
||||||
|
SignedPreKey test = new SignedPreKey(9999, "fooozzz", "baaarzzz");
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v2/keys/signed")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(204);
|
||||||
|
|
||||||
|
verify(AuthHelper.DISABLED_DEVICE).setSignedPreKey(eq(test));
|
||||||
|
verify(accounts).update(eq(AuthHelper.DISABLED_ACCOUNT));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void validSingleRequestTestV2() throws Exception {
|
public void validSingleRequestTestV2() throws Exception {
|
||||||
PreKeyResponse result = resources.getJerseyTest()
|
PreKeyResponse result = resources.getJerseyTest()
|
||||||
|
@ -367,5 +384,39 @@ public class KeyControllerTest {
|
||||||
verify(accounts).update(AuthHelper.VALID_ACCOUNT);
|
verify(accounts).update(AuthHelper.VALID_ACCOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disabledPutKeysTestV2() throws Exception {
|
||||||
|
final PreKey preKey = new PreKey(31337, "foobar");
|
||||||
|
final SignedPreKey signedPreKey = new SignedPreKey(31338, "foobaz", "myvalidsig");
|
||||||
|
final String identityKey = "barbar";
|
||||||
|
|
||||||
|
List<PreKey> preKeys = new LinkedList<PreKey>() {{
|
||||||
|
add(preKey);
|
||||||
|
}};
|
||||||
|
|
||||||
|
PreKeyState preKeyState = new PreKeyState(identityKey, signedPreKey, preKeys);
|
||||||
|
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v2/keys")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.put(Entity.entity(preKeyState, MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(204);
|
||||||
|
|
||||||
|
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);
|
||||||
|
verify(keys).store(eq(AuthHelper.DISABLED_NUMBER), eq(1L), listCaptor.capture());
|
||||||
|
|
||||||
|
List<PreKey> capturedList = listCaptor.getValue();
|
||||||
|
assertThat(capturedList.size()).isEqualTo(1);
|
||||||
|
assertThat(capturedList.get(0).getKeyId()).isEqualTo(31337);
|
||||||
|
assertThat(capturedList.get(0).getPublicKey()).isEqualTo("foobar");
|
||||||
|
|
||||||
|
verify(AuthHelper.DISABLED_ACCOUNT).setIdentityKey(eq("barbar"));
|
||||||
|
verify(AuthHelper.DISABLED_DEVICE).setSignedPreKey(eq(signedPreKey));
|
||||||
|
verify(accounts).update(AuthHelper.DISABLED_ACCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
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.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
||||||
import org.whispersystems.textsecuregcm.controllers.MessageController;
|
import org.whispersystems.textsecuregcm.controllers.MessageController;
|
||||||
import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
|
import org.whispersystems.textsecuregcm.entities.IncomingMessageList;
|
||||||
|
@ -38,7 +40,7 @@ import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
@ -68,7 +70,7 @@ public class MessageControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new MessageController(rateLimiters, pushSender, receiptSender, accountsManager,
|
.addResource(new MessageController(rateLimiters, pushSender, receiptSender, accountsManager,
|
||||||
messagesManager, apnFallbackManager))
|
messagesManager, apnFallbackManager))
|
||||||
|
@ -95,7 +97,20 @@ public class MessageControllerTest {
|
||||||
|
|
||||||
when(rateLimiters.getMessagesLimiter()).thenReturn(rateLimiter);
|
when(rateLimiters.getMessagesLimiter()).thenReturn(rateLimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public synchronized void testSendFromDisabledAccount() throws Exception {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT))
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class),
|
||||||
|
MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat("Unauthorized response", response.getStatus(), is(equalTo(401)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public synchronized void testSingleDeviceCurrent() throws Exception {
|
public synchronized void testSingleDeviceCurrent() throws Exception {
|
||||||
Response response =
|
Response response =
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.configuration.ProfilesConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.ProfilesConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.controllers.ProfileController;
|
import org.whispersystems.textsecuregcm.controllers.ProfileController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
|
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
|
||||||
|
@ -18,7 +20,7 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
@ -40,7 +42,7 @@ public class ProfileControllerTest {
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new ProfileController(rateLimiters,
|
.addResource(new ProfileController(rateLimiters,
|
||||||
|
@ -58,7 +60,7 @@ public class ProfileControllerTest {
|
||||||
when(profileAccount.getProfileName()).thenReturn("baz");
|
when(profileAccount.getProfileName()).thenReturn("baz");
|
||||||
when(profileAccount.getAvatar()).thenReturn("profiles/bang");
|
when(profileAccount.getAvatar()).thenReturn("profiles/bang");
|
||||||
when(profileAccount.getAvatarDigest()).thenReturn("buh");
|
when(profileAccount.getAvatarDigest()).thenReturn("buh");
|
||||||
when(profileAccount.isActive()).thenReturn(true);
|
when(profileAccount.isEnabled()).thenReturn(true);
|
||||||
|
|
||||||
when(accountsManager.get(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(profileAccount));
|
when(accountsManager.get(AuthHelper.VALID_NUMBER_TWO)).thenReturn(Optional.of(profileAccount));
|
||||||
}
|
}
|
||||||
|
@ -91,4 +93,15 @@ public class ProfileControllerTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(401);
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProfileGetDisabled() throws Exception {
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO)
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
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.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.controllers.TransparentDataController;
|
import org.whispersystems.textsecuregcm.controllers.TransparentDataController;
|
||||||
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
|
import org.whispersystems.textsecuregcm.entities.SignedPreKey;
|
||||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||||
|
@ -24,6 +26,7 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.AuthValueFactoryProvider;
|
||||||
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static junit.framework.TestCase.*;
|
import static junit.framework.TestCase.*;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
@ -42,7 +45,7 @@ public class TransparentDataControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.addProvider(new RateLimitExceededExceptionMapper())
|
.addProvider(new RateLimitExceededExceptionMapper())
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
import org.whispersystems.textsecuregcm.controllers.VoiceVerificationController;
|
import org.whispersystems.textsecuregcm.controllers.VoiceVerificationController;
|
||||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
@ -11,10 +13,9 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
import io.dropwizard.testing.FixtureHelpers;
|
import io.dropwizard.testing.FixtureHelpers;
|
||||||
import io.dropwizard.testing.junit.ResourceTestRule;
|
import io.dropwizard.testing.junit.ResourceTestRule;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -24,7 +25,7 @@ public class VoiceVerificationControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.addProvider(new RateLimitExceededExceptionMapper())
|
.addProvider(new RateLimitExceededExceptionMapper())
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
|
|
|
@ -67,43 +67,43 @@ public class AccountCleanerTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
when(activeUnexpiredDevice.isActive()).thenReturn(true);
|
when(activeUnexpiredDevice.isEnabled()).thenReturn(true);
|
||||||
when(activeUnexpiredAccount.getLastSeen()).thenReturn(Long.MAX_VALUE);
|
when(activeUnexpiredAccount.getLastSeen()).thenReturn(Long.MAX_VALUE);
|
||||||
when(activeUnexpiredAccount.getMasterDevice()).thenReturn(Optional.of(activeUnexpiredDevice));
|
when(activeUnexpiredAccount.getMasterDevice()).thenReturn(Optional.of(activeUnexpiredDevice));
|
||||||
|
|
||||||
when(activeExpiredAccount.getNumber()).thenReturn(AuthHelper.VALID_NUMBER);
|
when(activeExpiredAccount.getNumber()).thenReturn(AuthHelper.VALID_NUMBER);
|
||||||
when(activeExpiredDevice.isActive()).thenReturn(true);
|
when(activeExpiredDevice.isEnabled()).thenReturn(true);
|
||||||
when(activeExpiredAccount.getLastSeen()).thenReturn(0L);
|
when(activeExpiredAccount.getLastSeen()).thenReturn(0L);
|
||||||
when(activeExpiredAccount.getMasterDevice()).thenReturn(Optional.of(activeExpiredDevice));
|
when(activeExpiredAccount.getMasterDevice()).thenReturn(Optional.of(activeExpiredDevice));
|
||||||
|
|
||||||
when(inactiveUnexpiredDevice.isActive()).thenReturn(false);
|
when(inactiveUnexpiredDevice.isEnabled()).thenReturn(false);
|
||||||
when(inactiveUnexpiredAccount.getLastSeen()).thenReturn(Long.MAX_VALUE);
|
when(inactiveUnexpiredAccount.getLastSeen()).thenReturn(Long.MAX_VALUE);
|
||||||
when(inactiveUnexpiredAccount.getMasterDevice()).thenReturn(Optional.of(inactiveUnexpiredDevice));
|
when(inactiveUnexpiredAccount.getMasterDevice()).thenReturn(Optional.of(inactiveUnexpiredDevice));
|
||||||
|
|
||||||
when(inactiveExpiredDevice.isActive()).thenReturn(false);
|
when(inactiveExpiredDevice.isEnabled()).thenReturn(false);
|
||||||
when(inactiveExpiredAccount.getLastSeen()).thenReturn(0L);
|
when(inactiveExpiredAccount.getLastSeen()).thenReturn(0L);
|
||||||
when(inactiveExpiredAccount.getMasterDevice()).thenReturn(Optional.of(inactiveExpiredDevice));
|
when(inactiveExpiredAccount.getMasterDevice()).thenReturn(Optional.of(inactiveExpiredDevice));
|
||||||
|
|
||||||
this.nowMs = System.currentTimeMillis();
|
this.nowMs = System.currentTimeMillis();
|
||||||
|
|
||||||
when(oldMasterDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(366));
|
when(oldMasterDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(366));
|
||||||
when(oldMasterDevice.isActive()).thenReturn(true);
|
when(oldMasterDevice.isEnabled()).thenReturn(true);
|
||||||
when(oldMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
when(oldMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
||||||
|
|
||||||
when(recentMasterDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(1));
|
when(recentMasterDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(1));
|
||||||
when(recentMasterDevice.isActive()).thenReturn(true);
|
when(recentMasterDevice.isEnabled()).thenReturn(true);
|
||||||
when(recentMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
when(recentMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
||||||
|
|
||||||
when(agingSecondaryDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(31));
|
when(agingSecondaryDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(31));
|
||||||
when(agingSecondaryDevice.isActive()).thenReturn(false);
|
when(agingSecondaryDevice.isEnabled()).thenReturn(false);
|
||||||
when(agingSecondaryDevice.getId()).thenReturn(2L);
|
when(agingSecondaryDevice.getId()).thenReturn(2L);
|
||||||
|
|
||||||
when(recentSecondaryDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(1));
|
when(recentSecondaryDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(1));
|
||||||
when(recentSecondaryDevice.isActive()).thenReturn(true);
|
when(recentSecondaryDevice.isEnabled()).thenReturn(true);
|
||||||
when(recentSecondaryDevice.getId()).thenReturn(2L);
|
when(recentSecondaryDevice.getId()).thenReturn(2L);
|
||||||
|
|
||||||
when(oldSecondaryDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(366));
|
when(oldSecondaryDevice.getLastSeen()).thenReturn(nowMs - TimeUnit.DAYS.toMillis(366));
|
||||||
when(oldSecondaryDevice.isActive()).thenReturn(false);
|
when(oldSecondaryDevice.isEnabled()).thenReturn(false);
|
||||||
when(oldSecondaryDevice.getId()).thenReturn(2L);
|
when(oldSecondaryDevice.getId()).thenReturn(2L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,9 +114,9 @@ public class AccountCleanerTest {
|
||||||
accountCleaner.onCrawlChunk(Optional.empty(), Arrays.asList(activeUnexpiredAccount, inactiveUnexpiredAccount, inactiveExpiredAccount));
|
accountCleaner.onCrawlChunk(Optional.empty(), Arrays.asList(activeUnexpiredAccount, inactiveUnexpiredAccount, inactiveExpiredAccount));
|
||||||
accountCleaner.onCrawlEnd(Optional.empty());
|
accountCleaner.onCrawlEnd(Optional.empty());
|
||||||
|
|
||||||
verify(activeUnexpiredDevice, atLeastOnce()).isActive();
|
verify(activeUnexpiredDevice, atLeastOnce()).isEnabled();
|
||||||
verify(inactiveUnexpiredDevice, atLeastOnce()).isActive();
|
verify(inactiveUnexpiredDevice, atLeastOnce()).isEnabled();
|
||||||
verify(inactiveExpiredDevice, atLeastOnce()).isActive();
|
verify(inactiveExpiredDevice, atLeastOnce()).isEnabled();
|
||||||
|
|
||||||
verifyNoMoreInteractions(activeUnexpiredDevice);
|
verifyNoMoreInteractions(activeUnexpiredDevice);
|
||||||
verifyNoMoreInteractions(activeExpiredDevice);
|
verifyNoMoreInteractions(activeExpiredDevice);
|
||||||
|
|
|
@ -25,23 +25,23 @@ public class AccountTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
when(oldMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366));
|
when(oldMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366));
|
||||||
when(oldMasterDevice.isActive()).thenReturn(true);
|
when(oldMasterDevice.isEnabled()).thenReturn(true);
|
||||||
when(oldMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
when(oldMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
||||||
|
|
||||||
when(recentMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
|
when(recentMasterDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
|
||||||
when(recentMasterDevice.isActive()).thenReturn(true);
|
when(recentMasterDevice.isEnabled()).thenReturn(true);
|
||||||
when(recentMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
when(recentMasterDevice.getId()).thenReturn(Device.MASTER_ID);
|
||||||
|
|
||||||
when(agingSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31));
|
when(agingSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31));
|
||||||
when(agingSecondaryDevice.isActive()).thenReturn(false);
|
when(agingSecondaryDevice.isEnabled()).thenReturn(false);
|
||||||
when(agingSecondaryDevice.getId()).thenReturn(2L);
|
when(agingSecondaryDevice.getId()).thenReturn(2L);
|
||||||
|
|
||||||
when(recentSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
|
when(recentSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
|
||||||
when(recentSecondaryDevice.isActive()).thenReturn(true);
|
when(recentSecondaryDevice.isEnabled()).thenReturn(true);
|
||||||
when(recentSecondaryDevice.getId()).thenReturn(2L);
|
when(recentSecondaryDevice.getId()).thenReturn(2L);
|
||||||
|
|
||||||
when(oldSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366));
|
when(oldSecondaryDevice.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(366));
|
||||||
when(oldSecondaryDevice.isActive()).thenReturn(false);
|
when(oldSecondaryDevice.isEnabled()).thenReturn(false);
|
||||||
when(oldSecondaryDevice.getId()).thenReturn(2L);
|
when(oldSecondaryDevice.getId()).thenReturn(2L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,21 +52,21 @@ public class AccountTest {
|
||||||
add(recentSecondaryDevice);
|
add(recentSecondaryDevice);
|
||||||
}}, "1234".getBytes());
|
}}, "1234".getBytes());
|
||||||
|
|
||||||
assertTrue(recentAccount.isActive());
|
assertTrue(recentAccount.isEnabled());
|
||||||
|
|
||||||
Account oldSecondaryAccount = new Account("+14152222222", new HashSet<Device>() {{
|
Account oldSecondaryAccount = new Account("+14152222222", new HashSet<Device>() {{
|
||||||
add(recentMasterDevice);
|
add(recentMasterDevice);
|
||||||
add(agingSecondaryDevice);
|
add(agingSecondaryDevice);
|
||||||
}}, "1234".getBytes());
|
}}, "1234".getBytes());
|
||||||
|
|
||||||
assertTrue(oldSecondaryAccount.isActive());
|
assertTrue(oldSecondaryAccount.isEnabled());
|
||||||
|
|
||||||
Account agingPrimaryAccount = new Account("+14152222222", new HashSet<Device>() {{
|
Account agingPrimaryAccount = new Account("+14152222222", new HashSet<Device>() {{
|
||||||
add(oldMasterDevice);
|
add(oldMasterDevice);
|
||||||
add(agingSecondaryDevice);
|
add(agingSecondaryDevice);
|
||||||
}}, "1234".getBytes());
|
}}, "1234".getBytes());
|
||||||
|
|
||||||
assertTrue(agingPrimaryAccount.isActive());
|
assertTrue(agingPrimaryAccount.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -76,7 +76,7 @@ public class AccountTest {
|
||||||
add(oldSecondaryDevice);
|
add(oldSecondaryDevice);
|
||||||
}}, "1234".getBytes());
|
}}, "1234".getBytes());
|
||||||
|
|
||||||
assertFalse(oldPrimaryAccount.isActive());
|
assertFalse(oldPrimaryAccount.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,9 @@ public class DirectoryReconcilerTest {
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
when(activeAccount.getNumber()).thenReturn(VALID_NUMBER);
|
when(activeAccount.getNumber()).thenReturn(VALID_NUMBER);
|
||||||
when(activeAccount.isActive()).thenReturn(true);
|
when(activeAccount.isEnabled()).thenReturn(true);
|
||||||
when(inactiveAccount.getNumber()).thenReturn(INACTIVE_NUMBER);
|
when(inactiveAccount.getNumber()).thenReturn(INACTIVE_NUMBER);
|
||||||
when(inactiveAccount.isActive()).thenReturn(false);
|
when(inactiveAccount.isEnabled()).thenReturn(false);
|
||||||
when(directoryManager.startBatchOperation()).thenReturn(batchOperationHandle);
|
when(directoryManager.startBatchOperation()).thenReturn(batchOperationHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,9 +69,9 @@ public class DirectoryReconcilerTest {
|
||||||
directoryReconciler.onCrawlChunk(Optional.of(VALID_NUMBER), Arrays.asList(activeAccount, inactiveAccount));
|
directoryReconciler.onCrawlChunk(Optional.of(VALID_NUMBER), Arrays.asList(activeAccount, inactiveAccount));
|
||||||
|
|
||||||
verify(activeAccount, times(2)).getNumber();
|
verify(activeAccount, times(2)).getNumber();
|
||||||
verify(activeAccount, times(2)).isActive();
|
verify(activeAccount, times(2)).isEnabled();
|
||||||
verify(inactiveAccount, times(2)).getNumber();
|
verify(inactiveAccount, times(2)).getNumber();
|
||||||
verify(inactiveAccount, times(2)).isActive();
|
verify(inactiveAccount, times(2)).isEnabled();
|
||||||
|
|
||||||
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
ArgumentCaptor<DirectoryReconciliationRequest> request = ArgumentCaptor.forClass(DirectoryReconciliationRequest.class);
|
||||||
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
verify(reconciliationClient, times(1)).sendChunk(request.capture());
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.util;
|
package org.whispersystems.textsecuregcm.tests.util;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
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.DisabledPermittedAccount;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
||||||
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;
|
||||||
|
@ -9,9 +12,10 @@ import org.whispersystems.textsecuregcm.util.Base64;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import io.dropwizard.auth.AuthDynamicFeature;
|
import io.dropwizard.auth.AuthFilter;
|
||||||
|
import io.dropwizard.auth.PolymorphicAuthDynamicFeature;
|
||||||
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
|
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
|
||||||
import static org.mockito.Matchers.anyLong;
|
import io.dropwizard.auth.basic.BasicCredentials;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -26,43 +30,76 @@ public class AuthHelper {
|
||||||
public static final String INVVALID_NUMBER = "+14151111111";
|
public static final String INVVALID_NUMBER = "+14151111111";
|
||||||
public static final String INVALID_PASSWORD = "bar";
|
public static final String INVALID_PASSWORD = "bar";
|
||||||
|
|
||||||
|
public static final String DISABLED_NUMBER = "+78888888";
|
||||||
|
public static final String DISABLED_PASSWORD = "poof";
|
||||||
|
|
||||||
public static final String VALID_IDENTITY = "BcxxDU9FGMda70E7+Uvm7pnQcEdXQ64aJCpPUeRSfcFo";
|
public static final String VALID_IDENTITY = "BcxxDU9FGMda70E7+Uvm7pnQcEdXQ64aJCpPUeRSfcFo";
|
||||||
|
|
||||||
public static AccountsManager ACCOUNTS_MANAGER = mock(AccountsManager.class );
|
public static AccountsManager ACCOUNTS_MANAGER = mock(AccountsManager.class);
|
||||||
public static Account VALID_ACCOUNT = mock(Account.class );
|
public static Account VALID_ACCOUNT = mock(Account.class );
|
||||||
public static Account VALID_ACCOUNT_TWO = mock(Account.class);
|
public static Account VALID_ACCOUNT_TWO = mock(Account.class );
|
||||||
public static Device VALID_DEVICE = mock(Device.class );
|
public static Account DISABLED_ACCOUNT = mock(Account.class );
|
||||||
public static Device VALID_DEVICE_TWO = mock(Device.class);
|
|
||||||
private static AuthenticationCredentials VALID_CREDENTIALS = mock(AuthenticationCredentials.class);
|
|
||||||
private static AuthenticationCredentials VALID_CREDENTIALS_TWO = mock(AuthenticationCredentials.class);
|
|
||||||
|
|
||||||
public static AuthDynamicFeature getAuthFilter() {
|
public static Device VALID_DEVICE = mock(Device.class);
|
||||||
|
public static Device VALID_DEVICE_TWO = mock(Device.class);
|
||||||
|
public static Device DISABLED_DEVICE = mock(Device.class);
|
||||||
|
|
||||||
|
private static AuthenticationCredentials VALID_CREDENTIALS = mock(AuthenticationCredentials.class);
|
||||||
|
private static AuthenticationCredentials VALID_CREDENTIALS_TWO = mock(AuthenticationCredentials.class);
|
||||||
|
private static AuthenticationCredentials DISABLED_CREDENTIALS = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
|
public static PolymorphicAuthDynamicFeature 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(DISABLED_CREDENTIALS.verify(DISABLED_PASSWORD)).thenReturn(true);
|
||||||
|
|
||||||
when(VALID_DEVICE.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS);
|
when(VALID_DEVICE.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS);
|
||||||
when(VALID_DEVICE_TWO.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS_TWO);
|
when(VALID_DEVICE_TWO.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS_TWO);
|
||||||
|
when(DISABLED_DEVICE.getAuthenticationCredentials()).thenReturn(DISABLED_CREDENTIALS);
|
||||||
|
|
||||||
when(VALID_DEVICE.isMaster()).thenReturn(true);
|
when(VALID_DEVICE.isMaster()).thenReturn(true);
|
||||||
when(VALID_DEVICE_TWO.isMaster()).thenReturn(true);
|
when(VALID_DEVICE_TWO.isMaster()).thenReturn(true);
|
||||||
|
when(DISABLED_DEVICE.isMaster()).thenReturn(true);
|
||||||
|
|
||||||
when(VALID_DEVICE.getId()).thenReturn(1L);
|
when(VALID_DEVICE.getId()).thenReturn(1L);
|
||||||
when(VALID_DEVICE_TWO.getId()).thenReturn(1L);
|
when(VALID_DEVICE_TWO.getId()).thenReturn(1L);
|
||||||
|
when(DISABLED_DEVICE.getId()).thenReturn(1L);
|
||||||
|
|
||||||
|
when(VALID_DEVICE.isEnabled()).thenReturn(true);
|
||||||
|
when(VALID_DEVICE_TWO.isEnabled()).thenReturn(true);
|
||||||
|
when(DISABLED_DEVICE.isEnabled()).thenReturn(false);
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getDevice(1L)).thenReturn(Optional.of(VALID_DEVICE));
|
when(VALID_ACCOUNT.getDevice(1L)).thenReturn(Optional.of(VALID_DEVICE));
|
||||||
when(VALID_ACCOUNT_TWO.getDevice(eq(1L))).thenReturn(Optional.of(VALID_DEVICE_TWO));
|
when(VALID_ACCOUNT_TWO.getDevice(eq(1L))).thenReturn(Optional.of(VALID_DEVICE_TWO));
|
||||||
when(VALID_ACCOUNT_TWO.getActiveDeviceCount()).thenReturn(6);
|
when(DISABLED_ACCOUNT.getDevice(eq(1L))).thenReturn(Optional.of(DISABLED_DEVICE));
|
||||||
|
|
||||||
|
when(VALID_ACCOUNT_TWO.getEnabledDeviceCount()).thenReturn(6);
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getNumber()).thenReturn(VALID_NUMBER);
|
when(VALID_ACCOUNT.getNumber()).thenReturn(VALID_NUMBER);
|
||||||
when(VALID_ACCOUNT_TWO.getNumber()).thenReturn(VALID_NUMBER_TWO);
|
when(VALID_ACCOUNT_TWO.getNumber()).thenReturn(VALID_NUMBER_TWO);
|
||||||
|
when(DISABLED_ACCOUNT.getNumber()).thenReturn(DISABLED_NUMBER);
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getAuthenticatedDevice()).thenReturn(Optional.of(VALID_DEVICE));
|
when(VALID_ACCOUNT.getAuthenticatedDevice()).thenReturn(Optional.of(VALID_DEVICE));
|
||||||
when(VALID_ACCOUNT_TWO.getAuthenticatedDevice()).thenReturn(Optional.of(VALID_DEVICE_TWO));
|
when(VALID_ACCOUNT_TWO.getAuthenticatedDevice()).thenReturn(Optional.of(VALID_DEVICE_TWO));
|
||||||
|
when(DISABLED_ACCOUNT.getAuthenticatedDevice()).thenReturn(Optional.of(DISABLED_DEVICE));
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getRelay()).thenReturn(Optional.<String>empty());
|
when(VALID_ACCOUNT.getRelay()).thenReturn(Optional.<String>empty());
|
||||||
when(VALID_ACCOUNT_TWO.getRelay()).thenReturn(Optional.<String>empty());
|
when(VALID_ACCOUNT_TWO.getRelay()).thenReturn(Optional.<String>empty());
|
||||||
when(VALID_ACCOUNT.isActive()).thenReturn(true);
|
|
||||||
when(VALID_ACCOUNT_TWO.isActive()).thenReturn(true);
|
when(VALID_ACCOUNT.isEnabled()).thenReturn(true);
|
||||||
|
when(VALID_ACCOUNT_TWO.isEnabled()).thenReturn(true);
|
||||||
|
when(DISABLED_ACCOUNT.isEnabled()).thenReturn(false);
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getIdentityKey()).thenReturn(VALID_IDENTITY);
|
when(VALID_ACCOUNT.getIdentityKey()).thenReturn(VALID_IDENTITY);
|
||||||
when(ACCOUNTS_MANAGER.get(VALID_NUMBER)).thenReturn(Optional.of(VALID_ACCOUNT));
|
when(ACCOUNTS_MANAGER.get(VALID_NUMBER)).thenReturn(Optional.of(VALID_ACCOUNT));
|
||||||
when(ACCOUNTS_MANAGER.get(VALID_NUMBER_TWO)).thenReturn(Optional.of(VALID_ACCOUNT_TWO));
|
when(ACCOUNTS_MANAGER.get(VALID_NUMBER_TWO)).thenReturn(Optional.of(VALID_ACCOUNT_TWO));
|
||||||
|
when(ACCOUNTS_MANAGER.get(DISABLED_NUMBER)).thenReturn(Optional.of(DISABLED_ACCOUNT));
|
||||||
|
|
||||||
return new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Account>()
|
AuthFilter<BasicCredentials, Account> accountAuthFilter = new BasicCredentialAuthFilter.Builder<Account>().setAuthenticator(new AccountAuthenticator(ACCOUNTS_MANAGER)).buildAuthFilter ();
|
||||||
.setAuthenticator(new AccountAuthenticator(ACCOUNTS_MANAGER))
|
AuthFilter<BasicCredentials, DisabledPermittedAccount> disabledPermittedAccountAuthFilter = new BasicCredentialAuthFilter.Builder<DisabledPermittedAccount>().setAuthenticator(new DisabledPermittedAccountAuthenticator(ACCOUNTS_MANAGER)).buildAuthFilter();
|
||||||
.buildAuthFilter());
|
|
||||||
|
return new PolymorphicAuthDynamicFeature<>(ImmutableMap.of(Account.class, accountAuthFilter,
|
||||||
|
DisabledPermittedAccount.class, disabledPermittedAccountAuthFilter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAuthHeader(String number, String password) {
|
public static String getAuthHeader(String number, String password) {
|
||||||
|
|
Loading…
Reference in New Issue