diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AmbiguousIdentifier.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/AmbiguousIdentifier.java deleted file mode 100644 index aab3d837b..000000000 --- a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AmbiguousIdentifier.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.auth; - -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Tag; -import io.micrometer.core.instrument.Tags; -import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil; -import javax.annotation.Nullable; -import java.util.UUID; - -import static com.codahale.metrics.MetricRegistry.name; - -public class AmbiguousIdentifier { - - private final UUID uuid; - private final String number; - - private static final String REQUEST_COUNTER_NAME = name(AmbiguousIdentifier.class, "request"); - - public AmbiguousIdentifier(String target) { - if (target.startsWith("+")) { - this.uuid = null; - this.number = target; - } else { - this.uuid = UUID.fromString(target); - this.number = null; - } - } - - public UUID getUuid() { - return uuid; - } - - public String getNumber() { - return number; - } - - public boolean hasUuid() { - return uuid != null; - } - - public boolean hasNumber() { - return number != null; - } - - @Override - public String toString() { - return hasUuid() ? uuid.toString() : number; - } - - public void incrementRequestCounter(final String context, @Nullable final String userAgent) { - Metrics.counter(REQUEST_COUNTER_NAME, Tags.of( - Tag.of("type", hasUuid() ? "uuid" : "e164"), - Tag.of("context", context), - UserAgentTagUtil.getPlatformTag(userAgent))).increment(); - } -} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java deleted file mode 100644 index 723738627..000000000 --- a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AuthorizationHeader.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013-2020 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ -package org.whispersystems.textsecuregcm.auth; - - -import org.whispersystems.textsecuregcm.util.Util; - -import java.io.IOException; -import java.util.Base64; - -public class AuthorizationHeader { - - private final AmbiguousIdentifier identifier; - private final long deviceId; - private final String password; - - private AuthorizationHeader(AmbiguousIdentifier identifier, long deviceId, String password) { - this.identifier = identifier; - this.deviceId = deviceId; - this.password = password; - } - - public static AuthorizationHeader fromUserAndPassword(String user, String password) throws InvalidAuthorizationHeaderException { - try { - String[] numberAndId = user.split("\\."); - return new AuthorizationHeader(new AmbiguousIdentifier(numberAndId[0]), - numberAndId.length > 1 ? Long.parseLong(numberAndId[1]) : 1, - password); - } catch (NumberFormatException nfe) { - throw new InvalidAuthorizationHeaderException(nfe); - } - } - - public static AuthorizationHeader fromFullHeader(String header) throws InvalidAuthorizationHeaderException { - try { - if (header == null) { - throw new InvalidAuthorizationHeaderException("Null header"); - } - - String[] headerParts = header.split(" "); - - if (headerParts == null || headerParts.length < 2) { - throw new InvalidAuthorizationHeaderException("Invalid authorization header: " + header); - } - - if (!"Basic".equals(headerParts[0])) { - throw new InvalidAuthorizationHeaderException("Unsupported authorization method: " + headerParts[0]); - } - - String concatenatedValues = new String(Base64.getDecoder().decode(headerParts[1])); - - if (Util.isEmpty(concatenatedValues)) { - throw new InvalidAuthorizationHeaderException("Bad decoded value: " + concatenatedValues); - } - - String[] credentialParts = concatenatedValues.split(":"); - - if (credentialParts == null || credentialParts.length < 2) { - throw new InvalidAuthorizationHeaderException("Badly formated credentials: " + concatenatedValues); - } - - return fromUserAndPassword(credentialParts[0], credentialParts[1]); - } catch (IllegalArgumentException e) { - throw new InvalidAuthorizationHeaderException(e); - } - } - - public AmbiguousIdentifier getIdentifier() { - return identifier; - } - - public long getDeviceId() { - return deviceId; - } - - public String getPassword() { - return password; - } -} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticator.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticator.java index 1cf04d7e0..9bcb64c04 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticator.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticator.java @@ -15,11 +15,13 @@ import java.time.Clock; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Optional; +import java.util.UUID; import org.apache.commons.lang3.StringUtils; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.RefreshingAccountAndDeviceSupplier; +import org.whispersystems.textsecuregcm.util.Pair; import org.whispersystems.textsecuregcm.util.Util; public class BaseAccountAuthenticator { @@ -28,7 +30,6 @@ public class BaseAccountAuthenticator { private static final String AUTHENTICATION_SUCCEEDED_TAG_NAME = "succeeded"; private static final String AUTHENTICATION_FAILURE_REASON_TAG_NAME = "reason"; private static final String AUTHENTICATION_ENABLED_REQUIRED_TAG_NAME = "enabledRequired"; - private static final String AUTHENTICATION_CREDENTIAL_TYPE_TAG_NAME = "credentialType"; private static final String DAYS_SINCE_LAST_SEEN_DISTRIBUTION_NAME = name(BaseAccountAuthenticator.class, "daysSinceLastSeen"); private static final String IS_PRIMARY_DEVICE_TAG = "isPrimary"; @@ -46,24 +47,45 @@ public class BaseAccountAuthenticator { this.clock = clock; } + static Pair getIdentifierAndDeviceId(final String basicUsername) { + final String identifier; + final long deviceId; + + final int deviceIdSeparatorIndex = basicUsername.indexOf('.'); + + if (deviceIdSeparatorIndex == -1) { + identifier = basicUsername; + deviceId = Device.MASTER_ID; + } else { + identifier = basicUsername.substring(0, deviceIdSeparatorIndex); + deviceId = Long.parseLong(basicUsername.substring(deviceIdSeparatorIndex + 1)); + } + + return new Pair<>(identifier, deviceId); + } + public Optional authenticate(BasicCredentials basicCredentials, boolean enabledRequired) { boolean succeeded = false; String failureReason = null; - String credentialType = null; try { - AuthorizationHeader authorizationHeader = AuthorizationHeader.fromUserAndPassword(basicCredentials.getUsername(), - basicCredentials.getPassword()); - Optional account = accountsManager.get(authorizationHeader.getIdentifier()); + final UUID accountUuid; + final long deviceId; + { + final Pair identifierAndDeviceId = getIdentifierAndDeviceId(basicCredentials.getUsername()); - credentialType = authorizationHeader.getIdentifier().hasNumber() ? "e164" : "uuid"; + accountUuid = UUID.fromString(identifierAndDeviceId.first()); + deviceId = identifierAndDeviceId.second(); + } + + Optional account = accountsManager.get(accountUuid); if (account.isEmpty()) { failureReason = "noSuchAccount"; return Optional.empty(); } - Optional device = account.get().getDevice(authorizationHeader.getDeviceId()); + Optional device = account.get().getDevice(deviceId); if (device.isEmpty()) { failureReason = "noSuchDevice"; @@ -102,10 +124,6 @@ public class BaseAccountAuthenticator { tags = tags.and(AUTHENTICATION_FAILURE_REASON_TAG_NAME, failureReason); } - if (StringUtils.isNotBlank(credentialType)) { - tags = tags.and(AUTHENTICATION_CREDENTIAL_TYPE_TAG_NAME, credentialType); - } - Metrics.counter(AUTHENTICATION_COUNTER_NAME, tags).increment(); } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeader.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeader.java new file mode 100644 index 000000000..122a8c4dd --- /dev/null +++ b/service/src/main/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeader.java @@ -0,0 +1,96 @@ +/* + * Copyright 2013-2021 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ +package org.whispersystems.textsecuregcm.auth; + +import java.util.Base64; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; +import org.whispersystems.textsecuregcm.storage.Device; +import org.whispersystems.textsecuregcm.util.Pair; + +public class BasicAuthorizationHeader { + + private final String username; + private final long deviceId; + private final String password; + + private BasicAuthorizationHeader(final String username, final long deviceId, final String password) { + this.username = username; + this.deviceId = deviceId; + this.password = password; + } + + public static BasicAuthorizationHeader fromString(final String header) throws InvalidAuthorizationHeaderException { + try { + if (StringUtils.isBlank(header)) { + throw new InvalidAuthorizationHeaderException("Blank header"); + } + + final int spaceIndex = header.indexOf(' '); + + if (spaceIndex == -1) { + throw new InvalidAuthorizationHeaderException("Invalid authorization header: " + header); + } + + final String authorizationType = header.substring(0, spaceIndex); + + if (!"Basic".equals(authorizationType)) { + throw new InvalidAuthorizationHeaderException("Unsupported authorization method: " + authorizationType); + } + + final String credentials; + + try { + credentials = new String(Base64.getDecoder().decode(header.substring(spaceIndex + 1))); + } catch (final IndexOutOfBoundsException e) { + throw new InvalidAuthorizationHeaderException("Missing credentials"); + } + + if (StringUtils.isEmpty(credentials)) { + throw new InvalidAuthorizationHeaderException("Bad decoded value: " + credentials); + } + + final int credentialSeparatorIndex = credentials.indexOf(':'); + + if (credentialSeparatorIndex == -1) { + throw new InvalidAuthorizationHeaderException("Badly-formatted credentials: " + credentials); + } + + final String usernameComponent = credentials.substring(0, credentialSeparatorIndex); + + final String username; + final long deviceId; + { + final Pair identifierAndDeviceId = + BaseAccountAuthenticator.getIdentifierAndDeviceId(usernameComponent); + + username = identifierAndDeviceId.first(); + deviceId = identifierAndDeviceId.second(); + } + + final String password = credentials.substring(credentialSeparatorIndex + 1); + + if (StringUtils.isAnyBlank(username, password)) { + throw new InvalidAuthorizationHeaderException("Username or password were blank"); + } + + return new BasicAuthorizationHeader(username, deviceId, password); + } catch (final IllegalArgumentException | IndexOutOfBoundsException e) { + throw new InvalidAuthorizationHeaderException(e); + } + } + + public String getUsername() { + return username; + } + + public long getDeviceId() { + return deviceId; + } + + public String getPassword() { + return password; + } +} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/InvalidAuthorizationHeaderException.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/InvalidAuthorizationHeaderException.java index b88fbf25d..d5b85daa9 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/auth/InvalidAuthorizationHeaderException.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/auth/InvalidAuthorizationHeaderException.java @@ -5,12 +5,15 @@ package org.whispersystems.textsecuregcm.auth; -public class InvalidAuthorizationHeaderException extends Exception { +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response.Status; + +public class InvalidAuthorizationHeaderException extends WebApplicationException { public InvalidAuthorizationHeaderException(String s) { - super(s); + super(s, Status.UNAUTHORIZED); } public InvalidAuthorizationHeaderException(Exception e) { - super(e); + super(e, Status.UNAUTHORIZED); } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java index ba1578e8f..c1de10b36 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java @@ -41,11 +41,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; -import org.whispersystems.textsecuregcm.auth.AuthorizationHeader; +import org.whispersystems.textsecuregcm.auth.BasicAuthorizationHeader; import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator; import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials; -import org.whispersystems.textsecuregcm.auth.InvalidAuthorizationHeaderException; import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock; import org.whispersystems.textsecuregcm.auth.StoredVerificationCode; import org.whispersystems.textsecuregcm.auth.TurnToken; @@ -326,79 +325,70 @@ public class AccountController { @Produces(MediaType.APPLICATION_JSON) @Path("/code/{verification_code}") public AccountCreationResult verifyAccount(@PathParam("verification_code") String verificationCode, - @HeaderParam("Authorization") String authorizationHeader, - @HeaderParam("X-Signal-Agent") String signalAgent, - @HeaderParam("User-Agent") String userAgent, - @QueryParam("transfer") Optional availableForTransfer, - @Valid AccountAttributes accountAttributes) + @HeaderParam("Authorization") BasicAuthorizationHeader authorizationHeader, + @HeaderParam("X-Signal-Agent") String signalAgent, + @HeaderParam("User-Agent") String userAgent, + @QueryParam("transfer") Optional availableForTransfer, + @Valid AccountAttributes accountAttributes) throws RateLimitExceededException, InterruptedException { - try { - AuthorizationHeader header = AuthorizationHeader.fromFullHeader(authorizationHeader); - String number = header.getIdentifier().getNumber(); - String password = header.getPassword(); - if (number == null) { - throw new WebApplicationException(400); - } + String number = authorizationHeader.getUsername(); + String password = authorizationHeader.getPassword(); - rateLimiters.getVerifyLimiter().validate(number); + rateLimiters.getVerifyLimiter().validate(number); - Optional storedVerificationCode = pendingAccounts.getCodeForNumber(number); + Optional storedVerificationCode = pendingAccounts.getCodeForNumber(number); - if (storedVerificationCode.isEmpty() || !storedVerificationCode.get().isValid(verificationCode)) { - throw new WebApplicationException(Response.status(403).build()); - } - - storedVerificationCode.flatMap(StoredVerificationCode::getTwilioVerificationSid) - .ifPresent(smsSender::reportVerificationSucceeded); - - Optional existingAccount = accounts.get(number); - Optional existingRegistrationLock = existingAccount.map(Account::getRegistrationLock); - Optional existingBackupCredentials = existingAccount.map(Account::getUuid) - .map(uuid -> backupServiceCredentialGenerator.generateFor(uuid.toString())); - - if (existingRegistrationLock.isPresent() && existingRegistrationLock.get().requiresClientRegistrationLock()) { - rateLimiters.getVerifyLimiter().clear(number); - - if (!Util.isEmpty(accountAttributes.getRegistrationLock())) { - rateLimiters.getPinLimiter().validate(number); - } - - if (!existingRegistrationLock.get().verify(accountAttributes.getRegistrationLock())) { - throw new WebApplicationException(Response.status(423) - .entity(new RegistrationLockFailure(existingRegistrationLock.get().getTimeRemaining(), - existingRegistrationLock.get().needsFailureCredentials() ? existingBackupCredentials.orElseThrow() : null)) - .build()); - } - - rateLimiters.getPinLimiter().clear(number); - } - - if (availableForTransfer.orElse(false) && existingAccount.map(Account::isTransferSupported).orElse(false)) { - throw new WebApplicationException(Response.status(409).build()); - } - - Account account = accounts.create(number, password, signalAgent, accountAttributes); - - { - metricRegistry.meter(name(AccountController.class, "verify", Util.getCountryCode(number))).mark(); - - final List tags = new ArrayList<>(); - tags.add(Tag.of(COUNTRY_CODE_TAG_NAME, Util.getCountryCode(number))); - tags.add(UserAgentTagUtil.getPlatformTag(userAgent)); - tags.add(Tag.of(VERIFY_EXPERIMENT_TAG_NAME, String.valueOf(storedVerificationCode.get().getTwilioVerificationSid().isPresent()))); - - Metrics.counter(ACCOUNT_VERIFY_COUNTER_NAME, tags).increment(); - - Metrics.timer(name(AccountController.class, "verifyDuration"), tags) - .record(Instant.now().toEpochMilli() - storedVerificationCode.get().getTimestamp(), TimeUnit.MILLISECONDS); - } - - return new AccountCreationResult(account.getUuid(), existingAccount.map(Account::isStorageSupported).orElse(false)); - } catch (InvalidAuthorizationHeaderException e) { - logger.info("Bad Authorization Header", e); - throw new WebApplicationException(Response.status(401).build()); + if (storedVerificationCode.isEmpty() || !storedVerificationCode.get().isValid(verificationCode)) { + throw new WebApplicationException(Response.status(403).build()); } + + storedVerificationCode.flatMap(StoredVerificationCode::getTwilioVerificationSid) + .ifPresent(smsSender::reportVerificationSucceeded); + + Optional existingAccount = accounts.get(number); + Optional existingRegistrationLock = existingAccount.map(Account::getRegistrationLock); + Optional existingBackupCredentials = existingAccount.map(Account::getUuid) + .map(uuid -> backupServiceCredentialGenerator.generateFor(uuid.toString())); + + if (existingRegistrationLock.isPresent() && existingRegistrationLock.get().requiresClientRegistrationLock()) { + rateLimiters.getVerifyLimiter().clear(number); + + if (!Util.isEmpty(accountAttributes.getRegistrationLock())) { + rateLimiters.getPinLimiter().validate(number); + } + + if (!existingRegistrationLock.get().verify(accountAttributes.getRegistrationLock())) { + throw new WebApplicationException(Response.status(423) + .entity(new RegistrationLockFailure(existingRegistrationLock.get().getTimeRemaining(), + existingRegistrationLock.get().needsFailureCredentials() ? existingBackupCredentials.orElseThrow() : null)) + .build()); + } + + rateLimiters.getPinLimiter().clear(number); + } + + if (availableForTransfer.orElse(false) && existingAccount.map(Account::isTransferSupported).orElse(false)) { + throw new WebApplicationException(Response.status(409).build()); + } + + Account account = accounts.create(number, password, signalAgent, accountAttributes); + + { + metricRegistry.meter(name(AccountController.class, "verify", Util.getCountryCode(number))).mark(); + + final List tags = new ArrayList<>(); + tags.add(Tag.of(COUNTRY_CODE_TAG_NAME, Util.getCountryCode(number))); + tags.add(UserAgentTagUtil.getPlatformTag(userAgent)); + tags.add(Tag.of(VERIFY_EXPERIMENT_TAG_NAME, String.valueOf(storedVerificationCode.get().getTwilioVerificationSid().isPresent()))); + + Metrics.counter(ACCOUNT_VERIFY_COUNTER_NAME, tags).increment(); + + Metrics.timer(name(AccountController.class, "verifyDuration"), tags) + .record(Instant.now().toEpochMilli() - storedVerificationCode.get().getTimestamp(), TimeUnit.MILLISECONDS); + } + + return new AccountCreationResult(account.getUuid(), existingAccount.map(Account::isStorageSupported).orElse(false)); } @Timed diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java index bc9c994e7..f9d2308cc 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java @@ -24,12 +24,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; -import org.whispersystems.textsecuregcm.auth.AuthorizationHeader; -import org.whispersystems.textsecuregcm.auth.InvalidAuthorizationHeaderException; +import org.whispersystems.textsecuregcm.auth.BasicAuthorizationHeader; import org.whispersystems.textsecuregcm.auth.StoredVerificationCode; import org.whispersystems.textsecuregcm.entities.AccountAttributes; import org.whispersystems.textsecuregcm.entities.DeviceInfo; @@ -51,8 +48,6 @@ import org.whispersystems.textsecuregcm.util.ua.UserAgentUtil; @Path("/v1/devices") public class DeviceController { - private final Logger logger = LoggerFactory.getLogger(DeviceController.class); - private static final int MAX_DEVICES = 6; private final StoredVerificationCodeManager pendingDevices; @@ -149,55 +144,52 @@ public class DeviceController { @Consumes(MediaType.APPLICATION_JSON) @Path("/{verification_code}") public DeviceResponse verifyDeviceToken(@PathParam("verification_code") String verificationCode, - @HeaderParam("Authorization") String authorizationHeader, - @HeaderParam("User-Agent") String userAgent, - @Valid AccountAttributes accountAttributes) + @HeaderParam("Authorization") BasicAuthorizationHeader authorizationHeader, + @HeaderParam("User-Agent") String userAgent, + @Valid AccountAttributes accountAttributes) throws RateLimitExceededException, DeviceLimitExceededException { - try { - AuthorizationHeader header = AuthorizationHeader.fromFullHeader(authorizationHeader); - String number = header.getIdentifier().getNumber(); - String password = header.getPassword(); - if (number == null) throw new WebApplicationException(400); + String number = authorizationHeader.getUsername(); + String password = authorizationHeader.getPassword(); - rateLimiters.getVerifyDeviceLimiter().validate(number); + rateLimiters.getVerifyDeviceLimiter().validate(number); - Optional storedVerificationCode = pendingDevices.getCodeForNumber(number); + Optional storedVerificationCode = pendingDevices.getCodeForNumber(number); - if (!storedVerificationCode.isPresent() || !storedVerificationCode.get().isValid(verificationCode)) { - throw new WebApplicationException(Response.status(403).build()); - } + if (!storedVerificationCode.isPresent() || !storedVerificationCode.get().isValid(verificationCode)) { + throw new WebApplicationException(Response.status(403).build()); + } - Optional account = accounts.get(number); + Optional account = accounts.get(number); - if (!account.isPresent()) { - throw new WebApplicationException(Response.status(403).build()); - } + if (!account.isPresent()) { + throw new WebApplicationException(Response.status(403).build()); + } - int maxDeviceLimit = MAX_DEVICES; + int maxDeviceLimit = MAX_DEVICES; - if (maxDeviceConfiguration.containsKey(account.get().getNumber())) { - maxDeviceLimit = maxDeviceConfiguration.get(account.get().getNumber()); - } + if (maxDeviceConfiguration.containsKey(account.get().getNumber())) { + maxDeviceLimit = maxDeviceConfiguration.get(account.get().getNumber()); + } - if (account.get().getEnabledDeviceCount() >= maxDeviceLimit) { - throw new DeviceLimitExceededException(account.get().getDevices().size(), MAX_DEVICES); - } + if (account.get().getEnabledDeviceCount() >= maxDeviceLimit) { + throw new DeviceLimitExceededException(account.get().getDevices().size(), MAX_DEVICES); + } - final DeviceCapabilities capabilities = accountAttributes.getCapabilities(); - if (capabilities != null && isCapabilityDowngrade(account.get(), capabilities, userAgent)) { - throw new WebApplicationException(Response.status(409).build()); - } + final DeviceCapabilities capabilities = accountAttributes.getCapabilities(); + if (capabilities != null && isCapabilityDowngrade(account.get(), capabilities, userAgent)) { + throw new WebApplicationException(Response.status(409).build()); + } - Device device = new Device(); - device.setName(accountAttributes.getName()); - device.setAuthenticationCredentials(new AuthenticationCredentials(password)); - device.setFetchesMessages(accountAttributes.getFetchesMessages()); - device.setRegistrationId(accountAttributes.getRegistrationId()); - device.setLastSeen(Util.todayInMillis()); - device.setCreated(System.currentTimeMillis()); - device.setCapabilities(accountAttributes.getCapabilities()); + Device device = new Device(); + device.setName(accountAttributes.getName()); + device.setAuthenticationCredentials(new AuthenticationCredentials(password)); + device.setFetchesMessages(accountAttributes.getFetchesMessages()); + device.setRegistrationId(accountAttributes.getRegistrationId()); + device.setLastSeen(Util.todayInMillis()); + device.setCreated(System.currentTimeMillis()); + device.setCapabilities(accountAttributes.getCapabilities()); accounts.update(account.get(), a -> { device.setId(a.getNextDeviceId()); @@ -205,13 +197,9 @@ public class DeviceController { a.addDevice(device); }); - pendingDevices.remove(number); + pendingDevices.remove(number); - return new DeviceResponse(device.getId()); - } catch (InvalidAuthorizationHeaderException e) { - logger.info("Bad Authorization Header", e); - throw new WebApplicationException(Response.status(401).build()); - } + return new DeviceResponse(device.getId()); } @Timed diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java index 063202523..93db57cca 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java @@ -15,6 +15,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.UUID; import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -26,7 +27,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.Anonymous; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; @@ -63,7 +63,6 @@ public class KeysController { private static final String SOURCE_COUNTRY_TAG_NAME = "sourceCountry"; private static final String INTERNATIONAL_TAG_NAME = "international"; - private static final String PREKEY_TARGET_IDENTIFIER_TAG_NAME = "identifierType"; public KeysController(RateLimiters rateLimiters, KeysDynamoDb keysDynamoDb, AccountsManager accounts, PreKeyRateLimiter preKeyRateLimiter, @@ -119,20 +118,18 @@ public class KeysController { @Produces(MediaType.APPLICATION_JSON) public Response getDeviceKeys(@Auth Optional auth, @HeaderParam(OptionalAccess.UNIDENTIFIED) Optional accessKey, - @PathParam("identifier") AmbiguousIdentifier targetName, + @PathParam("identifier") UUID targetUuid, @PathParam("device_id") String deviceId, @HeaderParam("User-Agent") String userAgent) throws RateLimitExceededException, RateLimitChallengeException, ServerRejectedException { - targetName.incrementRequestCounter("getDeviceKeys", userAgent); - - if (auth.isEmpty() && accessKey.isEmpty()) { + if (!auth.isPresent() && !accessKey.isPresent()) { throw new WebApplicationException(Response.Status.UNAUTHORIZED); } final Optional account = auth.map(AuthenticatedAccount::getAccount); - Optional target = accounts.get(targetName); + Optional target = accounts.get(targetUuid); OptionalAccess.verify(account, accessKey, target, deviceId); assert (target.isPresent()); @@ -143,8 +140,7 @@ public class KeysController { Metrics.counter(PREKEY_REQUEST_COUNTER_NAME, Tags.of( SOURCE_COUNTRY_TAG_NAME, sourceCountryCode, - INTERNATIONAL_TAG_NAME, String.valueOf(!sourceCountryCode.equals(targetCountryCode)), - PREKEY_TARGET_IDENTIFIER_TAG_NAME, targetName.hasNumber() ? "number" : "uuid" + INTERNATIONAL_TAG_NAME, String.valueOf(!sourceCountryCode.equals(targetCountryCode)) )).increment(); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java index eaf93801b..e08575d68 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java @@ -65,7 +65,6 @@ import javax.ws.rs.core.Response.Status; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.Anonymous; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.CombinedUnidentifiedSenderAccessKeys; @@ -154,7 +153,6 @@ public class MessageController { private static final String EPHEMERAL_TAG_NAME = "ephemeral"; private static final String SENDER_TYPE_TAG_NAME = "senderType"; private static final String SENDER_COUNTRY_TAG_NAME = "senderCountry"; - private static final String DESTINATION_TYPE_TAG_NAME = "destinationType"; private static final long MAX_MESSAGE_SIZE = DataSize.kibibytes(256).toBytes(); @@ -202,17 +200,15 @@ public class MessageController { @HeaderParam(OptionalAccess.UNIDENTIFIED) Optional accessKey, @HeaderParam("User-Agent") String userAgent, @HeaderParam("X-Forwarded-For") String forwardedFor, - @PathParam("destination") AmbiguousIdentifier destinationName, + @PathParam("destination") UUID destinationUuid, @Valid IncomingMessageList messages) throws RateLimitExceededException, RateLimitChallengeException { - destinationName.incrementRequestCounter("sendMessage", userAgent); - if (source.isEmpty() && accessKey.isEmpty()) { throw new WebApplicationException(Response.Status.UNAUTHORIZED); } - if (source.isPresent() && !source.get().getAccount().isFor(destinationName)) { + if (source.isPresent() && !source.get().getAccount().getUuid().equals(destinationUuid)) { assert source.get().getAccount().getMasterDevice().isPresent(); final Device masterDevice = source.get().getAccount().getMasterDevice().get(); @@ -227,7 +223,7 @@ public class MessageController { final String senderType; - if (source.isPresent() && !source.get().getAccount().isFor(destinationName)) { + if (source.isPresent() && !source.get().getAccount().getUuid().equals(destinationUuid)) { identifiedMeter.mark(); senderType = "identified"; } else if (source.isEmpty()) { @@ -257,12 +253,12 @@ public class MessageController { } try { - boolean isSyncMessage = source.isPresent() && source.get().getAccount().isFor(destinationName); + boolean isSyncMessage = source.isPresent() && source.get().getAccount().getUuid().equals(destinationUuid); Optional destination; if (!isSyncMessage) { - destination = accountsManager.get(destinationName); + destination = accountsManager.get(destinationUuid); } else { destination = source.map(AuthenticatedAccount::getAccount); } @@ -270,7 +266,7 @@ public class MessageController { OptionalAccess.verify(source.map(AuthenticatedAccount::getAccount), accessKey, destination); assert (destination.isPresent()); - if (source.isPresent() && !source.get().getAccount().isFor(destinationName)) { + if (source.isPresent() && !source.get().getAccount().getUuid().equals(destinationUuid)) { rateLimiters.getMessagesLimiter().validate(source.get().getAccount().getUuid(), destination.get().getUuid()); final String senderCountryCode = Util.getCountryCode(source.get().getAccount().getNumber()); @@ -320,8 +316,7 @@ public class MessageController { final List tags = List.of(UserAgentTagUtil.getPlatformTag(userAgent), Tag.of(EPHEMERAL_TAG_NAME, String.valueOf(messages.isOnline())), - Tag.of(SENDER_TYPE_TAG_NAME, senderType), - Tag.of(DESTINATION_TYPE_TAG_NAME, destinationName.hasNumber() ? "e164" : "uuid")); + Tag.of(SENDER_TYPE_TAG_NAME, senderType)); for (IncomingMessage incomingMessage : messages.getMessages()) { Optional destinationDevice = destination.get().getDevice(incomingMessage.getDestinationDeviceId()); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java index 410a278a7..1509ffc16 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -39,7 +39,6 @@ import org.signal.zkgroup.profiles.ProfileKeyCredentialResponse; import org.signal.zkgroup.profiles.ServerZkProfileOperations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.Anonymous; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.OptionalAccess; @@ -339,12 +338,10 @@ public class ProfileController { public Profile getProfile(@Auth Optional auth, @HeaderParam(OptionalAccess.UNIDENTIFIED) Optional accessKey, @HeaderParam("User-Agent") String userAgent, - @PathParam("identifier") AmbiguousIdentifier identifier, + @PathParam("identifier") UUID identifier, @QueryParam("ca") boolean useCaCertificate) throws RateLimitExceededException { - identifier.incrementRequestCounter("getProfile", userAgent); - if (auth.isEmpty() && accessKey.isEmpty()) { throw new WebApplicationException(Response.Status.UNAUTHORIZED); } @@ -356,12 +353,7 @@ public class ProfileController { Optional accountProfile = accountsManager.get(identifier); OptionalAccess.verify(auth.map(AuthenticatedAccount::getAccount), accessKey, accountProfile); - Optional username = Optional.empty(); - - if (!identifier.hasNumber()) { - //noinspection OptionalGetWithoutIsPresent - username = usernamesManager.get(accountProfile.get().getUuid()); - } + Optional username = usernamesManager.get(accountProfile.get().getUuid()); return new Profile(accountProfile.get().getProfileName(), null, diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java index 757dabded..090c38cbd 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java @@ -14,7 +14,6 @@ import java.util.Set; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock; import org.whispersystems.textsecuregcm.entities.AccountAttributes; @@ -335,14 +334,6 @@ public class Account { this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess; } - public boolean isFor(AmbiguousIdentifier identifier) { - requireNotStale(); - - if (identifier.hasUuid()) return identifier.getUuid().equals(uuid); - else if (identifier.hasNumber()) return identifier.getNumber().equals(number); - else throw new AssertionError(); - } - public boolean isDiscoverableByPhoneNumber() { requireNotStale(); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java index d7d44d267..4efa29ed7 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java @@ -36,7 +36,6 @@ import net.logstash.logback.argument.StructuredArguments; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; import org.whispersystems.textsecuregcm.controllers.AccountController; import org.whispersystems.textsecuregcm.entities.AccountAttributes; @@ -373,12 +372,6 @@ public class AccountsManager { }); } - public Optional get(AmbiguousIdentifier identifier) { - if (identifier.hasNumber()) return get(identifier.getNumber()); - else if (identifier.hasUuid()) return get(identifier.getUuid()); - else throw new AssertionError(); - } - public Optional get(String number) { try (Timer.Context ignored = getByNumberTimer.time()) { Optional account = redisGet(number); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticatorTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticatorTest.java new file mode 100644 index 000000000..c6f570647 --- /dev/null +++ b/service/src/test/java/org/whispersystems/textsecuregcm/auth/BaseAccountAuthenticatorTest.java @@ -0,0 +1,344 @@ +/* + * Copyright 2013-2021 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.textsecuregcm.auth; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.Clock; +import java.time.Instant; +import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Stream; +import io.dropwizard.auth.basic.BasicCredentials; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; +import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; +import org.whispersystems.textsecuregcm.auth.BaseAccountAuthenticator; +import org.whispersystems.textsecuregcm.storage.Account; +import org.whispersystems.textsecuregcm.storage.AccountsManager; +import org.whispersystems.textsecuregcm.storage.Device; +import org.whispersystems.textsecuregcm.tests.util.AccountsHelper; +import org.whispersystems.textsecuregcm.tests.util.AuthHelper; +import org.whispersystems.textsecuregcm.util.Pair; + +class BaseAccountAuthenticatorTest { + + private final Random random = new Random(867_5309L); + private final long today = 1590451200000L; + private final long yesterday = today - 86_400_000L; + private final long oldTime = yesterday - 86_400_000L; + private final long currentTime = today + 68_000_000L; + + private AccountsManager accountsManager; + private BaseAccountAuthenticator baseAccountAuthenticator; + private Clock clock; + private Account acct1; + private Account acct2; + private Account oldAccount; + + @BeforeEach + void setup() { + accountsManager = mock(AccountsManager.class); + clock = mock(Clock.class); + baseAccountAuthenticator = new BaseAccountAuthenticator(accountsManager, clock); + + acct1 = new Account("+14088675309", AuthHelper.getRandomUUID(random), Set.of(new Device(1, null, null, null, + null, null, null, false, 0, null, yesterday, 0, null, 0, null)), null); + acct2 = new Account("+14098675309", AuthHelper.getRandomUUID(random), Set.of(new Device(1, null, null, null, + null, null, null, false, 0, null, yesterday, 0, null, 0, null)), null); + oldAccount = new Account("+14108675309", AuthHelper.getRandomUUID(random), Set.of(new Device(1, null, null, null, + null, null, null, false, 0, null, oldTime, 0, null, 0, null)), null); + + AccountsHelper.setupMockUpdate(accountsManager); + } + + @Test + void testUpdateLastSeenMiddleOfDay() { + when(clock.instant()).thenReturn(Instant.ofEpochMilli(currentTime)); + + final Device device1 = acct1.getDevices().stream().findFirst().get(); + final Device device2 = acct2.getDevices().stream().findFirst().get(); + + final Account updatedAcct1 = baseAccountAuthenticator.updateLastSeen(acct1, device1); + final Account updatedAcct2 = baseAccountAuthenticator.updateLastSeen(acct2, device2); + + verify(accountsManager, never()).updateDeviceLastSeen(eq(acct1), any(), anyLong()); + verify(accountsManager).updateDeviceLastSeen(eq(acct2), eq(device2), anyLong()); + + assertThat(device1.getLastSeen()).isEqualTo(yesterday); + assertThat(device2.getLastSeen()).isEqualTo(today); + + assertThat(acct1).isSameAs(updatedAcct1); + assertThat(acct2).isNotSameAs(updatedAcct2); + } + + @Test + void testUpdateLastSeenStartOfDay() { + when(clock.instant()).thenReturn(Instant.ofEpochMilli(today)); + + final Device device1 = acct1.getDevices().stream().findFirst().get(); + final Device device2 = acct2.getDevices().stream().findFirst().get(); + + final Account updatedAcct1 = baseAccountAuthenticator.updateLastSeen(acct1, device1); + final Account updatedAcct2 = baseAccountAuthenticator.updateLastSeen(acct2, device2); + + verify(accountsManager, never()).updateDeviceLastSeen(eq(acct1), any(), anyLong()); + verify(accountsManager, never()).updateDeviceLastSeen(eq(acct2), any(), anyLong()); + + assertThat(device1.getLastSeen()).isEqualTo(yesterday); + assertThat(device2.getLastSeen()).isEqualTo(yesterday); + + assertThat(acct1).isSameAs(updatedAcct1); + assertThat(acct2).isSameAs(updatedAcct2); + } + + @Test + void testUpdateLastSeenEndOfDay() { + when(clock.instant()).thenReturn(Instant.ofEpochMilli(today + 86_400_000L - 1)); + + final Device device1 = acct1.getDevices().stream().findFirst().get(); + final Device device2 = acct2.getDevices().stream().findFirst().get(); + + final Account updatedAcct1 = baseAccountAuthenticator.updateLastSeen(acct1, device1); + final Account updatedAcct2 = baseAccountAuthenticator.updateLastSeen(acct2, device2); + + verify(accountsManager).updateDeviceLastSeen(eq(acct1), eq(device1), anyLong()); + verify(accountsManager).updateDeviceLastSeen(eq(acct2), eq(device2), anyLong()); + + assertThat(device1.getLastSeen()).isEqualTo(today); + assertThat(device2.getLastSeen()).isEqualTo(today); + + assertThat(updatedAcct1).isNotSameAs(acct1); + assertThat(updatedAcct2).isNotSameAs(acct2); + } + + @Test + void testNeverWriteYesterday() { + when(clock.instant()).thenReturn(Instant.ofEpochMilli(today)); + + final Device device = oldAccount.getDevices().stream().findFirst().get(); + + baseAccountAuthenticator.updateLastSeen(oldAccount, device); + + verify(accountsManager).updateDeviceLastSeen(eq(oldAccount), eq(device), anyLong()); + + assertThat(device.getLastSeen()).isEqualTo(today); + } + + @Test + void testAuthenticate() { + final UUID uuid = UUID.randomUUID(); + final long deviceId = 1; + final String password = "12345"; + + final Account account = mock(Account.class); + final Device device = mock(Device.class); + final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class); + + when(clock.instant()).thenReturn(Instant.now()); + when(accountsManager.get(uuid)).thenReturn(Optional.of(account)); + when(account.getUuid()).thenReturn(uuid); + when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.isEnabled()).thenReturn(true); + when(device.getId()).thenReturn(deviceId); + when(device.isEnabled()).thenReturn(true); + when(device.getAuthenticationCredentials()).thenReturn(credentials); + when(credentials.verify(password)).thenReturn(true); + + final Optional maybeAuthenticatedAccount = + baseAccountAuthenticator.authenticate(new BasicCredentials(uuid.toString(), password), true); + + assertThat(maybeAuthenticatedAccount).isPresent(); + assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(device); + } + + @Test + void testAuthenticateNonDefaultDevice() { + final UUID uuid = UUID.randomUUID(); + final long deviceId = 2; + final String password = "12345"; + + final Account account = mock(Account.class); + final Device device = mock(Device.class); + final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class); + + when(clock.instant()).thenReturn(Instant.now()); + when(accountsManager.get(uuid)).thenReturn(Optional.of(account)); + when(account.getUuid()).thenReturn(uuid); + when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.isEnabled()).thenReturn(true); + when(device.getId()).thenReturn(deviceId); + when(device.isEnabled()).thenReturn(true); + when(device.getAuthenticationCredentials()).thenReturn(credentials); + when(credentials.verify(password)).thenReturn(true); + + final Optional maybeAuthenticatedAccount = + baseAccountAuthenticator.authenticate(new BasicCredentials(uuid + "." + deviceId, password), true); + + assertThat(maybeAuthenticatedAccount).isPresent(); + assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(device); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testAuthenticateEnabledRequired(final boolean enabledRequired) { + final UUID uuid = UUID.randomUUID(); + final long deviceId = 1; + final String password = "12345"; + + final Account account = mock(Account.class); + final Device device = mock(Device.class); + final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class); + + when(clock.instant()).thenReturn(Instant.now()); + when(accountsManager.get(uuid)).thenReturn(Optional.of(account)); + when(account.getUuid()).thenReturn(uuid); + when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.isEnabled()).thenReturn(false); + when(device.getId()).thenReturn(deviceId); + when(device.isEnabled()).thenReturn(false); + when(device.getAuthenticationCredentials()).thenReturn(credentials); + when(credentials.verify(password)).thenReturn(true); + + final Optional maybeAuthenticatedAccount = + baseAccountAuthenticator.authenticate(new BasicCredentials(uuid.toString(), password), enabledRequired); + + if (enabledRequired) { + assertThat(maybeAuthenticatedAccount).isEmpty(); + } else { + assertThat(maybeAuthenticatedAccount).isPresent(); + assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(device); + } + } + + @Test + void testAuthenticateAccountNotFound() { + assertThat(baseAccountAuthenticator.authenticate(new BasicCredentials(UUID.randomUUID().toString(), "password"), true)) + .isEmpty(); + } + + @Test + void testAuthenticateDeviceNotFound() { + final UUID uuid = UUID.randomUUID(); + final long deviceId = 1; + final String password = "12345"; + + final Account account = mock(Account.class); + final Device device = mock(Device.class); + final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class); + + when(clock.instant()).thenReturn(Instant.now()); + when(accountsManager.get(uuid)).thenReturn(Optional.of(account)); + when(account.getUuid()).thenReturn(uuid); + when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.isEnabled()).thenReturn(true); + when(device.getId()).thenReturn(deviceId); + when(device.isEnabled()).thenReturn(true); + when(device.getAuthenticationCredentials()).thenReturn(credentials); + when(credentials.verify(password)).thenReturn(true); + + final Optional maybeAuthenticatedAccount = + baseAccountAuthenticator.authenticate(new BasicCredentials(uuid + "." + (deviceId + 1), password), true); + + assertThat(maybeAuthenticatedAccount).isEmpty(); + verify(account).getDevice(deviceId + 1); + } + + @Test + void testAuthenticateIncorrectPassword() { + final UUID uuid = UUID.randomUUID(); + final long deviceId = 1; + final String password = "12345"; + + final Account account = mock(Account.class); + final Device device = mock(Device.class); + final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class); + + when(clock.instant()).thenReturn(Instant.now()); + when(accountsManager.get(uuid)).thenReturn(Optional.of(account)); + when(account.getUuid()).thenReturn(uuid); + when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.isEnabled()).thenReturn(true); + when(device.getId()).thenReturn(deviceId); + when(device.isEnabled()).thenReturn(true); + when(device.getAuthenticationCredentials()).thenReturn(credentials); + when(credentials.verify(password)).thenReturn(true); + + final String incorrectPassword = password + "incorrect"; + + final Optional maybeAuthenticatedAccount = + baseAccountAuthenticator.authenticate(new BasicCredentials(uuid.toString(), incorrectPassword), true); + + assertThat(maybeAuthenticatedAccount).isEmpty(); + verify(credentials).verify(incorrectPassword); + } + + @ParameterizedTest + @MethodSource + void testAuthenticateMalformedCredentials(final String username) { + final Optional maybeAuthenticatedAccount = assertDoesNotThrow( + () -> baseAccountAuthenticator.authenticate(new BasicCredentials(username, "password"), true)); + + assertThat(maybeAuthenticatedAccount).isEmpty(); + verify(accountsManager, never()).get(any(UUID.class)); + } + + private static Stream testAuthenticateMalformedCredentials() { + return Stream.of( + "", + ".4", + "This is definitely not a valid UUID", + UUID.randomUUID() + "."); + } + + @ParameterizedTest + @MethodSource + void testGetIdentifierAndDeviceId(final String username, final String expectedIdentifier, final long expectedDeviceId) { + final Pair identifierAndDeviceId = BaseAccountAuthenticator.getIdentifierAndDeviceId(username); + + assertEquals(expectedIdentifier, identifierAndDeviceId.first()); + assertEquals(expectedDeviceId, identifierAndDeviceId.second()); + } + + private static Stream testGetIdentifierAndDeviceId() { + return Stream.of( + Arguments.of("", "", Device.MASTER_ID), + Arguments.of("test", "test", Device.MASTER_ID), + Arguments.of("test.7", "test", 7)); + } + + @ParameterizedTest + @ValueSource(strings = { + ".", + ".....", + "test.7.8", + "test." + }) + void testGetIdentifierAndDeviceIdMalformed(final String malformedUsername) { + assertThrows(IllegalArgumentException.class, + () -> BaseAccountAuthenticator.getIdentifierAndDeviceId(malformedUsername)); + } +} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeaderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeaderTest.java new file mode 100644 index 000000000..ddee28320 --- /dev/null +++ b/service/src/test/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeaderTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2013-2021 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.textsecuregcm.auth; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.whispersystems.textsecuregcm.storage.Device; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +class BasicAuthorizationHeaderTest { + + @Test + void fromString() throws InvalidAuthorizationHeaderException { + { + final BasicAuthorizationHeader header = + BasicAuthorizationHeader.fromString("Basic YWxhZGRpbjpvcGVuc2VzYW1l"); + + assertEquals("aladdin", header.getUsername()); + assertEquals("opensesame", header.getPassword()); + assertEquals(Device.MASTER_ID, header.getDeviceId()); + } + + { + final BasicAuthorizationHeader header = BasicAuthorizationHeader.fromString("Basic " + + Base64.getEncoder().encodeToString("username.7:password".getBytes(StandardCharsets.UTF_8))); + + assertEquals("username", header.getUsername()); + assertEquals("password", header.getPassword()); + assertEquals(7, header.getDeviceId()); + } + } + + @ParameterizedTest + @MethodSource + void fromStringMalformed(final String header) { + assertThrows(InvalidAuthorizationHeaderException.class, + () -> BasicAuthorizationHeader.fromString(header)); + } + + private static Stream fromStringMalformed() { + return Stream.of( + null, + "", + " ", + "Obviously not a valid authorization header", + "Digest YWxhZGRpbjpvcGVuc2VzYW1l", + "Basic", + "Basic ", + "Basic &&&&&&", + "Basic " + Base64.getEncoder().encodeToString("".getBytes(StandardCharsets.UTF_8)), + "Basic " + Base64.getEncoder().encodeToString(":".getBytes(StandardCharsets.UTF_8)), + "Basic " + Base64.getEncoder().encodeToString("test".getBytes(StandardCharsets.UTF_8)), + "Basic " + Base64.getEncoder().encodeToString("test.".getBytes(StandardCharsets.UTF_8)), + "Basic " + Base64.getEncoder().encodeToString("test.:".getBytes(StandardCharsets.UTF_8)), + "Basic " + Base64.getEncoder().encodeToString("test.:password".getBytes(StandardCharsets.UTF_8)), + "Basic " + Base64.getEncoder().encodeToString(":password".getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ChallengeControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ChallengeControllerTest.java index d83126d58..d135c2131 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ChallengeControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ChallengeControllerTest.java @@ -63,7 +63,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(pushChallengeJson)); assertEquals(200, response.getStatus()); @@ -82,7 +82,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(pushChallengeJson)); assertEquals(413, response.getStatus()); @@ -100,7 +100,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() .header("X-Forwarded-For", "10.0.0.1") - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(recaptchaChallengeJson)); assertEquals(200, response.getStatus()); @@ -121,7 +121,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() .header("X-Forwarded-For", "10.0.0.1") - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(recaptchaChallengeJson)); assertEquals(413, response.getStatus()); @@ -138,7 +138,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(recaptchaChallengeJson)); assertEquals(400, response.getStatus()); @@ -154,7 +154,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() .header("X-Forwarded-For", "10.0.0.1") - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(unrecognizedJson)); assertEquals(400, response.getStatus()); @@ -167,7 +167,7 @@ class ChallengeControllerTest { { final Response response = EXTENSION.target("/v1/challenge/push") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .post(Entity.text("")); assertEquals(200, response.getStatus()); @@ -178,7 +178,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge/push") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .post(Entity.text("")); assertEquals(404, response.getStatus()); @@ -193,7 +193,7 @@ class ChallengeControllerTest { final Response response = EXTENSION.target("/v1/challenge") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(unrecognizedJson)); assertEquals(422, response.getStatus()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/auth/BaseAccountAuthenticatorTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/auth/BaseAccountAuthenticatorTest.java deleted file mode 100644 index 8aa6780bc..000000000 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/auth/BaseAccountAuthenticatorTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2013-2020 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.tests.auth; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.time.Clock; -import java.time.Instant; -import java.util.Random; -import java.util.Set; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.whispersystems.textsecuregcm.auth.BaseAccountAuthenticator; -import org.whispersystems.textsecuregcm.storage.Account; -import org.whispersystems.textsecuregcm.storage.AccountsManager; -import org.whispersystems.textsecuregcm.storage.Device; -import org.whispersystems.textsecuregcm.tests.util.AccountsHelper; -import org.whispersystems.textsecuregcm.tests.util.AuthHelper; - -class BaseAccountAuthenticatorTest { - - private final Random random = new Random(867_5309L); - private final long today = 1590451200000L; - private final long yesterday = today - 86_400_000L; - private final long oldTime = yesterday - 86_400_000L; - private final long currentTime = today + 68_000_000L; - - private AccountsManager accountsManager; - private BaseAccountAuthenticator baseAccountAuthenticator; - private Clock clock; - private Account acct1; - private Account acct2; - private Account oldAccount; - - @BeforeEach - void setup() { - accountsManager = mock(AccountsManager.class); - clock = mock(Clock.class); - baseAccountAuthenticator = new BaseAccountAuthenticator(accountsManager, clock); - - acct1 = new Account("+14088675309", AuthHelper.getRandomUUID(random), Set.of(new Device(1, null, null, null, - null, null, null, false, 0, null, yesterday, 0, null, 0, null)), null); - acct2 = new Account("+14098675309", AuthHelper.getRandomUUID(random), Set.of(new Device(1, null, null, null, - null, null, null, false, 0, null, yesterday, 0, null, 0, null)), null); - oldAccount = new Account("+14108675309", AuthHelper.getRandomUUID(random), Set.of(new Device(1, null, null, null, - null, null, null, false, 0, null, oldTime, 0, null, 0, null)), null); - - AccountsHelper.setupMockUpdate(accountsManager); - } - - @Test - void testUpdateLastSeenMiddleOfDay() { - when(clock.instant()).thenReturn(Instant.ofEpochMilli(currentTime)); - - final Device device1 = acct1.getDevices().stream().findFirst().get(); - final Device device2 = acct2.getDevices().stream().findFirst().get(); - - final Account updatedAcct1 = baseAccountAuthenticator.updateLastSeen(acct1, device1); - final Account updatedAcct2 = baseAccountAuthenticator.updateLastSeen(acct2, device2); - - verify(accountsManager, never()).updateDeviceLastSeen(eq(acct1), any(), anyLong()); - verify(accountsManager).updateDeviceLastSeen(eq(acct2), eq(device2), anyLong()); - - assertThat(device1.getLastSeen()).isEqualTo(yesterday); - assertThat(device2.getLastSeen()).isEqualTo(today); - - assertThat(acct1).isSameAs(updatedAcct1); - assertThat(acct2).isNotSameAs(updatedAcct2); - } - - @Test - void testUpdateLastSeenStartOfDay() { - when(clock.instant()).thenReturn(Instant.ofEpochMilli(today)); - - final Device device1 = acct1.getDevices().stream().findFirst().get(); - final Device device2 = acct2.getDevices().stream().findFirst().get(); - - final Account updatedAcct1 = baseAccountAuthenticator.updateLastSeen(acct1, device1); - final Account updatedAcct2 = baseAccountAuthenticator.updateLastSeen(acct2, device2); - - verify(accountsManager, never()).updateDeviceLastSeen(eq(acct1), any(), anyLong()); - verify(accountsManager, never()).updateDeviceLastSeen(eq(acct2), any(), anyLong()); - - assertThat(device1.getLastSeen()).isEqualTo(yesterday); - assertThat(device2.getLastSeen()).isEqualTo(yesterday); - - assertThat(acct1).isSameAs(updatedAcct1); - assertThat(acct2).isSameAs(updatedAcct2); - } - - @Test - void testUpdateLastSeenEndOfDay() { - when(clock.instant()).thenReturn(Instant.ofEpochMilli(today + 86_400_000L - 1)); - - final Device device1 = acct1.getDevices().stream().findFirst().get(); - final Device device2 = acct2.getDevices().stream().findFirst().get(); - - final Account updatedAcct1 = baseAccountAuthenticator.updateLastSeen(acct1, device1); - final Account updatedAcct2 = baseAccountAuthenticator.updateLastSeen(acct2, device2); - - verify(accountsManager).updateDeviceLastSeen(eq(acct1), eq(device1), anyLong()); - verify(accountsManager).updateDeviceLastSeen(eq(acct2), eq(device2), anyLong()); - - assertThat(device1.getLastSeen()).isEqualTo(today); - assertThat(device2.getLastSeen()).isEqualTo(today); - - assertThat(updatedAcct1).isNotSameAs(acct1); - assertThat(updatedAcct2).isNotSameAs(acct2); - } - - @Test - void testNeverWriteYesterday() { - when(clock.instant()).thenReturn(Instant.ofEpochMilli(today)); - - final Device device = oldAccount.getDevices().stream().findFirst().get(); - - baseAccountAuthenticator.updateLastSeen(oldAccount, device); - - verify(accountsManager).updateDeviceLastSeen(eq(oldAccount), eq(device), anyLong()); - - assertThat(device.getLastSeen()).isEqualTo(today); - } -} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java index 6a627e499..ee2c80449 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java @@ -932,7 +932,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "1234")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER, "bar")) .put(Entity.entity(new AccountAttributes(), MediaType.APPLICATION_JSON_TYPE), AccountCreationResult.class); verify(accountsManager).create(eq(SENDER), eq("bar"), any(), any()); @@ -942,13 +942,24 @@ class AccountControllerTest { } } + @Test + void testVerifyCodeBadCredentials() { + final Response response = resources.getJerseyTest() + .target(String.format("/v1/accounts/code/%s", "1234")) + .request() + .header("Authorization", "This is not a valid authorization header") + .put(Entity.entity(new AccountAttributes(), MediaType.APPLICATION_JSON_TYPE)); + + assertThat(response.getStatus()).isEqualTo(401); + } + @Test void testVerifyCodeOld() { Response response = resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "1234")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_OLD, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_OLD, "bar")) .put(Entity.entity(new AccountAttributes(false, 2222, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -963,7 +974,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "1111")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER, "bar")) .put(Entity.entity(new AccountAttributes(false, 3333, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -978,7 +989,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "666666")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_REG_LOCK, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar")) .put(Entity.entity(new AccountAttributes(false, 3333, null, Hex.toStringCondensed(registration_lock_key), true, null), MediaType.APPLICATION_JSON_TYPE), AccountCreationResult.class); @@ -993,7 +1004,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "666666")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_REG_LOCK, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar")) .put(Entity.entity(new AccountAttributes(false, 3333, null, Hex.toStringCondensed(registration_lock_key), true, null), MediaType.APPLICATION_JSON_TYPE), AccountCreationResult.class); @@ -1016,7 +1027,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "666666")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_REG_LOCK, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar")) .put(Entity.entity(new AccountAttributes(false, 3333, null, null, true, null), MediaType.APPLICATION_JSON_TYPE), AccountCreationResult.class); @@ -1034,7 +1045,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "666666")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_REG_LOCK, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar")) .put(Entity.entity(new AccountAttributes(false, 3333, null, Hex.toStringCondensed(new byte[32]), true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -1050,7 +1061,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "666666")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_REG_LOCK, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar")) .put(Entity.entity(new AccountAttributes(false, 3333, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -1075,7 +1086,7 @@ class AccountControllerTest { .target(String.format("/v1/accounts/code/%s", "1234")) .queryParam("transfer", true) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_TRANSFER, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_TRANSFER, "bar")) .put(Entity.entity(new AccountAttributes(false, 2222, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -1091,7 +1102,7 @@ class AccountControllerTest { .target(String.format("/v1/accounts/code/%s", "1234")) .queryParam("transfer", true) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_TRANSFER, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_TRANSFER, "bar")) .put(Entity.entity(new AccountAttributes(false, 2222, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -1106,7 +1117,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(String.format("/v1/accounts/code/%s", "1234")) .request() - .header("Authorization", AuthHelper.getAuthHeader(SENDER_TRANSFER, "bar")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_TRANSFER, "bar")) .put(Entity.entity(new AccountAttributes(false, 2222, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -1119,7 +1130,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/registration_lock/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(new RegistrationLock("1234567890123456789012345678901234567890123456789012345678901234"))); assertThat(response.getStatus()).isEqualTo(204); @@ -1141,7 +1152,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/registration_lock/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(new RegistrationLock("313"))); assertThat(response.getStatus()).isEqualTo(422); @@ -1153,34 +1164,19 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/registration_lock/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.json(new RegistrationLock("1234567890123456789012345678901234567890123456789012345678901234"))); assertThat(response.getStatus()).isEqualTo(401); } @Test - void testSetGcmId() throws Exception { + void testSetGcmId() { 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)).updateDevice(eq(AuthHelper.DISABLED_ACCOUNT), anyLong(), any()); - } - - @Test - void testSetGcmIdByUuid() throws Exception { - Response response = - resources.getJerseyTest() - .target("/v1/accounts/gcm/") - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID.toString(), AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.json(new GcmRegistrationId("z000"))); assertThat(response.getStatus()).isEqualTo(204); @@ -1190,12 +1186,12 @@ class AccountControllerTest { } @Test - void testSetApnId() throws Exception { + void testSetApnId() { Response response = resources.getJerseyTest() .target("/v1/accounts/apn/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.json(new ApnRegistrationId("first", "second"))); assertThat(response.getStatus()).isEqualTo(204); @@ -1206,12 +1202,12 @@ class AccountControllerTest { } @Test - void testSetApnIdNoVoip() throws Exception { + void testSetApnIdNoVoip() { Response response = resources.getJerseyTest() .target("/v1/accounts/apn/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.json(new ApnRegistrationId("first", null))); assertThat(response.getStatus()).isEqualTo(204); @@ -1221,22 +1217,6 @@ class AccountControllerTest { verify(accountsManager, times(1)).updateDevice(eq(AuthHelper.DISABLED_ACCOUNT), anyLong(), any()); } - @Test - void testSetApnIdByUuid() throws Exception { - Response response = - resources.getJerseyTest() - .target("/v1/accounts/apn/") - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID.toString(), AuthHelper.DISABLED_PASSWORD)) - .put(Entity.json(new ApnRegistrationId("third", "fourth"))); - - assertThat(response.getStatus()).isEqualTo(204); - - verify(AuthHelper.DISABLED_DEVICE, times(1)).setApnId(eq("third")); - verify(AuthHelper.DISABLED_DEVICE, times(1)).setVoipApnId(eq("fourth")); - verify(accountsManager, times(1)).updateDevice(eq(AuthHelper.DISABLED_ACCOUNT), anyLong(), any()); - } - @ParameterizedTest @ValueSource(strings = {"/v1/accounts/whoami/", "/v1/accounts/me/"}) public void testWhoAmI(final String path) { @@ -1244,7 +1224,7 @@ class AccountControllerTest { resources.getJerseyTest() .target(path) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(AccountCreationResult.class); assertThat(response.getUuid()).isEqualTo(AuthHelper.VALID_UUID); @@ -1256,7 +1236,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/n00bkiller") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(200); @@ -1268,7 +1248,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/takenusername") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(409); @@ -1280,7 +1260,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/pаypal") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(400); @@ -1292,7 +1272,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/0n00bkiller") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(400); @@ -1304,7 +1284,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/n00bkiller") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(401); @@ -1316,7 +1296,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .delete(); assertThat(response.getStatus()).isEqualTo(204); @@ -1329,7 +1309,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/username/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .delete(); assertThat(response.getStatus()).isEqualTo(401); @@ -1341,7 +1321,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/attributes/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(new AccountAttributes(false, 2222, null, null, true, null))); assertThat(response.getStatus()).isEqualTo(204); @@ -1353,7 +1333,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/attributes/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.UNDISCOVERABLE_NUMBER, AuthHelper.UNDISCOVERABLE_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.UNDISCOVERABLE_UUID, AuthHelper.UNDISCOVERABLE_PASSWORD)) .put(Entity.json(new AccountAttributes(false, 2222, null, null, true, null))); assertThat(response.getStatus()).isEqualTo(204); @@ -1365,7 +1345,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/attributes/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json(new AccountAttributes(false, 2222, null, null, false, null))); assertThat(response.getStatus()).isEqualTo(204); @@ -1377,7 +1357,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/me") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .delete(); assertThat(response.getStatus()).isEqualTo(204); @@ -1392,7 +1372,7 @@ class AccountControllerTest { resources.getJerseyTest() .target("/v1/accounts/me") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .delete(); assertThat(response.getStatus()).isEqualTo(500); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AttachmentControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AttachmentControllerTest.java index a61226e9f..c52740eb8 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AttachmentControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AttachmentControllerTest.java @@ -97,7 +97,7 @@ class AttachmentControllerTest { AttachmentDescriptorV3 descriptor = resources.getJerseyTest() .target("/v3/attachments/form/upload") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(AttachmentDescriptorV3.class); assertThat(descriptor.getKey()).isNotBlank(); @@ -153,7 +153,7 @@ class AttachmentControllerTest { Response response = resources.getJerseyTest() .target("/v3/attachments/form/upload") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); @@ -164,7 +164,7 @@ class AttachmentControllerTest { AttachmentDescriptorV2 descriptor = resources.getJerseyTest() .target("/v2/attachments/form/upload") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(AttachmentDescriptorV2.class); assertThat(descriptor.getKey()).isEqualTo(descriptor.getAttachmentIdString()); @@ -192,7 +192,7 @@ class AttachmentControllerTest { Response response = resources.getJerseyTest() .target("/v2/attachments/form/upload") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); @@ -204,7 +204,7 @@ class AttachmentControllerTest { AttachmentDescriptorV1 descriptor = resources.getJerseyTest() .target("/v1/attachments/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(AttachmentDescriptorV1.class); assertThat(descriptor.getLocation()).startsWith("https://attachment-bucket.s3-accelerate.amazonaws.com"); @@ -217,7 +217,7 @@ class AttachmentControllerTest { AttachmentDescriptorV1 descriptor = resources.getJerseyTest() .target("/v1/attachments/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .get(AttachmentDescriptorV1.class); assertThat(descriptor.getLocation()).startsWith("https://s3.amazonaws.com"); @@ -230,7 +230,7 @@ class AttachmentControllerTest { AttachmentUri uri = resources.getJerseyTest() .target("/v1/attachments/1234") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(AttachmentUri.class); assertThat(uri.getLocation().getHost()).isEqualTo("attachment-bucket.s3-accelerate.amazonaws.com"); @@ -241,7 +241,7 @@ class AttachmentControllerTest { AttachmentUri uri = resources.getJerseyTest() .target("/v1/attachments/1234") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .get(AttachmentUri.class); assertThat(uri.getLocation().getHost()).isEqualTo("s3.amazonaws.com"); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java index 4f4086299..ab78e124f 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java @@ -79,7 +79,7 @@ class CertificateControllerTest { DeliveryCertificate certificateObject = resources.getJerseyTest() .target("/v1/certificate/delivery") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(DeliveryCertificate.class); @@ -105,7 +105,7 @@ class CertificateControllerTest { .target("/v1/certificate/delivery") .queryParam("includeUuid", "true") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(DeliveryCertificate.class); @@ -131,7 +131,7 @@ class CertificateControllerTest { .queryParam("includeUuid", "true") .queryParam("includeE164", "false") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(DeliveryCertificate.class); @@ -155,7 +155,7 @@ class CertificateControllerTest { Response response = resources.getJerseyTest() .target("/v1/certificate/delivery") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .get(); assertEquals(response.getStatus(), 401); @@ -189,7 +189,7 @@ class CertificateControllerTest { Response response = resources.getJerseyTest() .target("/v1/certificate/delivery") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertEquals(response.getStatus(), 401); @@ -200,7 +200,7 @@ class CertificateControllerTest { GroupCredentials credentials = resources.getJerseyTest() .target("/v1/certificate/group/" + Util.currentDaysSinceEpoch() + "/" + Util.currentDaysSinceEpoch()) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(GroupCredentials.class); assertThat(credentials.getCredentials().size()).isEqualTo(1); @@ -215,7 +215,7 @@ class CertificateControllerTest { GroupCredentials credentials = resources.getJerseyTest() .target("/v1/certificate/group/" + Util.currentDaysSinceEpoch() + "/" + (Util.currentDaysSinceEpoch() + 7)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(GroupCredentials.class); assertThat(credentials.getCredentials().size()).isEqualTo(8); @@ -233,7 +233,7 @@ class CertificateControllerTest { Response response = resources.getJerseyTest() .target("/v1/certificate/group/" + Util.currentDaysSinceEpoch() + "/" + (Util.currentDaysSinceEpoch() + 8)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(400); @@ -244,7 +244,7 @@ class CertificateControllerTest { Response response = resources.getJerseyTest() .target("/v1/certificate/group/" + (Util.currentDaysSinceEpoch() - 1) + "/" + (Util.currentDaysSinceEpoch() + 7)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(400); @@ -255,7 +255,7 @@ class CertificateControllerTest { Response response = resources.getJerseyTest() .target("/v1/certificate/group/" + Util.currentDaysSinceEpoch() + "/" + (Util.currentDaysSinceEpoch() + 7)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java index df235811c..10c87a92e 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java @@ -104,7 +104,7 @@ class DeviceControllerTest { @BeforeEach - void setup() throws Exception { + void setup() { when(rateLimiters.getSmsDestinationLimiter()).thenReturn(rateLimiter); when(rateLimiters.getVoiceDestinationLimiter()).thenReturn(rateLimiter); when(rateLimiters.getVerifyLimiter()).thenReturn(rateLimiter); @@ -147,11 +147,11 @@ class DeviceControllerTest { } @Test - void validDeviceRegisterTest() throws Exception { + void validDeviceRegisterTest() { VerificationCode deviceCode = resources.getJerseyTest() .target("/v1/devices/provisioning/code") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(VerificationCode.class); assertThat(deviceCode).isEqualTo(new VerificationCode(5678901)); @@ -159,7 +159,7 @@ class DeviceControllerTest { DeviceResponse response = resources.getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .put(Entity.entity(new AccountAttributes(false, 1234, null, null, true, null), MediaType.APPLICATION_JSON_TYPE), @@ -172,22 +172,35 @@ class DeviceControllerTest { } @Test - void disabledDeviceRegisterTest() throws Exception { + void verifyDeviceTokenBadCredentials() { + final Response response = resources.getJerseyTest() + .target("/v1/devices/5678901") + .request() + .header("Authorization", "This is not a valid authorization header") + .put(Entity.entity(new AccountAttributes(false, 1234, null, + null, true, null), + MediaType.APPLICATION_JSON_TYPE)); + + assertEquals(401, response.getStatus()); + } + + @Test + void disabledDeviceRegisterTest() { Response response = resources.getJerseyTest() .target("/v1/devices/provisioning/code") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); } @Test - void invalidDeviceRegisterTest() throws Exception { + void invalidDeviceRegisterTest() { VerificationCode deviceCode = resources.getJerseyTest() .target("/v1/devices/provisioning/code") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(VerificationCode.class); assertThat(deviceCode).isEqualTo(new VerificationCode(5678901)); @@ -195,7 +208,7 @@ class DeviceControllerTest { Response response = resources.getJerseyTest() .target("/v1/devices/5678902") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .put(Entity.entity(new AccountAttributes(false, 1234, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -205,11 +218,11 @@ class DeviceControllerTest { } @Test - void oldDeviceRegisterTest() throws Exception { + void oldDeviceRegisterTest() { Response response = resources.getJerseyTest() .target("/v1/devices/1112223") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new AccountAttributes(false, 1234, null, null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -219,11 +232,11 @@ class DeviceControllerTest { } @Test - void maxDevicesTest() throws Exception { + void maxDevicesTest() { Response response = resources.getJerseyTest() .target("/v1/devices/provisioning/code") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .get(); assertEquals(411, response.getStatus()); @@ -231,11 +244,11 @@ class DeviceControllerTest { } @Test - void longNameTest() throws Exception { + void longNameTest() { Response response = resources.getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .put(Entity.entity(new AccountAttributes(false, 1234, "this is a really long name that is longer than 80 characters it's so long that it's even longer than 204 characters. that's a lot of characters. we're talking lots and lots and lots of characters. 12345678", null, true, null), MediaType.APPLICATION_JSON_TYPE)); @@ -245,13 +258,13 @@ class DeviceControllerTest { @ParameterizedTest @MethodSource - void deviceDowngradeCapabilitiesTest(final String userAgent, final boolean gv2, final boolean gv2_2, final boolean gv2_3, final int expectedStatus) throws Exception { + void deviceDowngradeCapabilitiesTest(final String userAgent, final boolean gv2, final boolean gv2_2, final boolean gv2_3, final int expectedStatus) { DeviceCapabilities deviceCapabilities = new DeviceCapabilities(gv2, gv2_2, gv2_3, true, false, true, true, true); AccountAttributes accountAttributes = new AccountAttributes(false, 1234, null, null, true, deviceCapabilities); Response response = resources.getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .header("User-Agent", userAgent) .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); @@ -291,7 +304,7 @@ class DeviceControllerTest { Response response = resources.getJerseyTest() .target("/v1/devices/5678901") .request() - .header("authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) + .header("authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .header("user-agent", "Signal-Android/4.68.3 Android/25") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); @@ -302,7 +315,7 @@ class DeviceControllerTest { response = resources.getJerseyTest() .target("/v1/devices/5678901") .request() - .header("authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1")) + .header("authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .header("user-agent", "Signal-Android/4.68.3 Android/25") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); @@ -318,7 +331,7 @@ class DeviceControllerTest { .getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); @@ -329,7 +342,7 @@ class DeviceControllerTest { .getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); @@ -344,7 +357,7 @@ class DeviceControllerTest { .getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(409); @@ -355,7 +368,7 @@ class DeviceControllerTest { .getJerseyTest() .target("/v1/devices/5678901") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") .put(Entity.entity(accountAttributes, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); @@ -373,7 +386,7 @@ class DeviceControllerTest { .getJerseyTest() .target("/v1/devices/" + deviceId) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.42.8675309 Android/30") .delete(); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DirectoryControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DirectoryControllerTest.java index 48852a9c1..1326f4228 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DirectoryControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DirectoryControllerTest.java @@ -55,7 +55,7 @@ class DirectoryControllerTest { resources.getJerseyTest() .target("/v1/directory/feedback-v3/ok") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.json("{\"reason\": \"test reason\"}")); assertThat(response.getStatusInfo().getFamily()).isEqualTo(Family.SUCCESSFUL); } @@ -66,7 +66,7 @@ class DirectoryControllerTest { resources.getJerseyTest() .target("/v1/directory/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(ExternalServiceCredentials.class); assertThat(token.getUsername()).isEqualTo(validCredentials.getUsername()); assertThat(token.getPassword()).isEqualTo(validCredentials.getPassword()); @@ -78,7 +78,7 @@ class DirectoryControllerTest { resources.getJerseyTest() .target("/v1/directory/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); } @@ -91,7 +91,7 @@ class DirectoryControllerTest { .target("/v1/directory/tokens/") .request() .header("Authorization", - AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, + AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("X-Forwarded-For", "192.168.1.1, 1.1.1.1") .put(Entity.entity(Collections.emptyMap(), MediaType.APPLICATION_JSON_TYPE)); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DonationControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DonationControllerTest.java index 3a473dd2e..0f0fd3ed9 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DonationControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DonationControllerTest.java @@ -85,7 +85,7 @@ public class DonationControllerTest { Response response = resources.getJerseyTest() .target("/v1/donation/authorize-apple-pay") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .post(Entity.entity(request, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); @@ -116,7 +116,7 @@ public class DonationControllerTest { Response response = resources.getJerseyTest() .target("/v1/donation/authorize-apple-pay") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .post(Entity.entity(request, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(422); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeysControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeysControllerTest.java index 885d155cf..2e59784a8 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeysControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/KeysControllerTest.java @@ -8,7 +8,6 @@ package org.whispersystems.textsecuregcm.tests.controllers; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -42,8 +41,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.OptionalAccess; @@ -74,12 +71,12 @@ class KeysControllerTest { private static final String EXISTS_NUMBER = "+14152222222"; private static final UUID EXISTS_UUID = UUID.randomUUID(); - private static String NOT_EXISTS_NUMBER = "+14152222220"; - private static UUID NOT_EXISTS_UUID = UUID.randomUUID(); + private static final String NOT_EXISTS_NUMBER = "+14152222220"; + private static final UUID NOT_EXISTS_UUID = UUID.randomUUID(); - private static int SAMPLE_REGISTRATION_ID = 999; - private static int SAMPLE_REGISTRATION_ID2 = 1002; - private static int SAMPLE_REGISTRATION_ID4 = 1555; + private static final int SAMPLE_REGISTRATION_ID = 999; + private static final int SAMPLE_REGISTRATION_ID2 = 1002; + private static final int SAMPLE_REGISTRATION_ID4 = 1555; private final PreKey SAMPLE_KEY = new PreKey(1234, "test1"); private final PreKey SAMPLE_KEY2 = new PreKey(5667, "test3"); @@ -158,13 +155,9 @@ class KeysControllerTest { when(accounts.get(EXISTS_NUMBER)).thenReturn(Optional.of(existsAccount)); when(accounts.get(EXISTS_UUID)).thenReturn(Optional.of(existsAccount)); - when(accounts.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(EXISTS_NUMBER)))).thenReturn(Optional.of(existsAccount)); - when(accounts.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() && identifier.getUuid().equals(EXISTS_UUID)))).thenReturn(Optional.of(existsAccount)); - when(accounts.get(NOT_EXISTS_NUMBER)).thenReturn(Optional.empty()); + when(accounts.get(NOT_EXISTS_NUMBER)).thenReturn(Optional.empty()); when(accounts.get(NOT_EXISTS_UUID)).thenReturn(Optional.empty()); - when(accounts.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(NOT_EXISTS_NUMBER)))).thenReturn(Optional.empty()); - when(accounts.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() && identifier.getUuid().equals(NOT_EXISTS_UUID)))).thenReturn(Optional.empty()); when(rateLimiters.getPreKeysLimiter()).thenReturn(rateLimiter); @@ -195,26 +188,12 @@ class KeysControllerTest { } @Test - void validKeyStatusTestByNumberV2() throws Exception { + void validKeyStatusTest() { PreKeyCount result = resources.getJerseyTest() .target("/v2/keys") .request() .header("Authorization", - AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .get(PreKeyCount.class); - - assertThat(result.getCount()).isEqualTo(4); - - verify(keysDynamoDb).getCount(eq(AuthHelper.VALID_ACCOUNT), eq(1L)); - } - - @Test - void validKeyStatusTestByUuidV2() throws Exception { - PreKeyCount result = resources.getJerseyTest() - .target("/v2/keys") - .request() - .header("Authorization", - AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) + AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(PreKeyCount.class); assertThat(result.getCount()).isEqualTo(4); @@ -224,11 +203,11 @@ class KeysControllerTest { @Test - void getSignedPreKeyV2ByNumber() throws Exception { + void getSignedPreKeyV2() { SignedPreKey result = resources.getJerseyTest() .target("/v2/keys/signed") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(SignedPreKey.class); assertThat(result.getSignature()).isEqualTo(VALID_DEVICE_SIGNED_KEY.getSignature()); @@ -237,40 +216,12 @@ class KeysControllerTest { } @Test - void getSignedPreKeyV2ByUuid() throws Exception { - SignedPreKey result = resources.getJerseyTest() - .target("/v2/keys/signed") - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) - .get(SignedPreKey.class); - - assertThat(result.getSignature()).isEqualTo(VALID_DEVICE_SIGNED_KEY.getSignature()); - assertThat(result.getKeyId()).isEqualTo(VALID_DEVICE_SIGNED_KEY.getKeyId()); - assertThat(result.getPublicKey()).isEqualTo(VALID_DEVICE_SIGNED_KEY.getPublicKey()); - } - - @Test - void putSignedPreKeyV2ByNumber() throws Exception { - SignedPreKey test = new SignedPreKey(9999, "fooozzz", "baaarzzz"); - Response response = resources.getJerseyTest() - .target("/v2/keys/signed") - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE)); - - assertThat(response.getStatus()).isEqualTo(204); - - verify(AuthHelper.VALID_DEVICE).setSignedPreKey(eq(test)); - verify(accounts).updateDevice(eq(AuthHelper.VALID_ACCOUNT), anyLong(), any()); - } - - @Test - void putSignedPreKeyV2ByUuid() throws Exception { + void putSignedPreKeyV2() { SignedPreKey test = new SignedPreKey(9998, "fooozzz", "baaarzzz"); Response response = resources.getJerseyTest() .target("/v2/keys/signed") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(204); @@ -281,73 +232,23 @@ class KeysControllerTest { @Test - void disabledPutSignedPreKeyV2ByNumber() throws Exception { + void disabledPutSignedPreKeyV2() { 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)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(401); } @Test - void disabledPutSignedPreKeyV2ByUuid() throws Exception { - SignedPreKey test = new SignedPreKey(9999, "fooozzz", "baaarzzz"); - Response response = resources.getJerseyTest() - .target("/v2/keys/signed") - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID.toString(), AuthHelper.DISABLED_PASSWORD)) - .put(Entity.entity(test, MediaType.APPLICATION_JSON_TYPE)); - - assertThat(response.getStatus()).isEqualTo(401); - } - - - @Test - void validSingleRequestTestV2ByNumber() throws Exception { - PreKeyResponse result = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .get(PreKeyResponse.class); - - assertThat(result.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey()); - assertThat(result.getDevicesCount()).isEqualTo(1); - assertThat(result.getDevice(1).getPreKey().getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId()); - assertThat(result.getDevice(1).getPreKey().getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey()); - assertThat(result.getDevice(1).getSignedPreKey()).isEqualTo(existsAccount.getDevice(1).get().getSignedPreKey()); - - verify(keysDynamoDb).take(eq(existsAccount), eq(1L)); - verifyNoMoreInteractions(keysDynamoDb); - } - - @Test - void validSingleRequestTestV2ByUuid() throws Exception { + void validSingleRequestTestV2() { PreKeyResponse result = resources.getJerseyTest() .target(String.format("/v2/keys/%s/1", EXISTS_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) - .get(PreKeyResponse.class); - - assertThat(result.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey()); - assertThat(result.getDevicesCount()).isEqualTo(1); - assertThat(result.getDevice(1).getPreKey().getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId()); - assertThat(result.getDevice(1).getPreKey().getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey()); - assertThat(result.getDevice(1).getSignedPreKey()).isEqualTo(existsAccount.getDevice(1).get().getSignedPreKey()); - - verify(keysDynamoDb).take(eq(existsAccount), eq(1L)); - verifyNoMoreInteractions(keysDynamoDb); - } - - - @Test - void testUnidentifiedRequestByNumber() throws Exception { - PreKeyResponse result = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) - .request() - .header(OptionalAccess.UNIDENTIFIED, AuthHelper.getUnidentifiedAccessHeader("1337".getBytes())) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(PreKeyResponse.class); assertThat(result.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey()); @@ -361,9 +262,9 @@ class KeysControllerTest { } @Test - void testUnidentifiedRequestByUuid() throws Exception { + void testUnidentifiedRequest() { PreKeyResponse result = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_UUID.toString())) + .target(String.format("/v2/keys/%s/1", EXISTS_UUID)) .request() .header(OptionalAccess.UNIDENTIFIED, AuthHelper.getUnidentifiedAccessHeader("1337".getBytes())) .get(PreKeyResponse.class); @@ -384,7 +285,7 @@ class KeysControllerTest { when(existsAccount.getDevices()).thenReturn(Collections.emptySet()); Response result = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/*", EXISTS_UUID.toString())) + .target(String.format("/v2/keys/%s/*", EXISTS_UUID)) .request() .header(OptionalAccess.UNIDENTIFIED, AuthHelper.getUnidentifiedAccessHeader("1337".getBytes())) .get(); @@ -394,9 +295,9 @@ class KeysControllerTest { } @Test - void testUnauthorizedUnidentifiedRequest() throws Exception { + void testUnauthorizedUnidentifiedRequest() { Response response = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) + .target(String.format("/v2/keys/%s/1", EXISTS_UUID)) .request() .header(OptionalAccess.UNIDENTIFIED, AuthHelper.getUnidentifiedAccessHeader("9999".getBytes())) .get(); @@ -406,9 +307,9 @@ class KeysControllerTest { } @Test - void testMalformedUnidentifiedRequest() throws Exception { + void testMalformedUnidentifiedRequest() { Response response = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) + .target(String.format("/v2/keys/%s/1", EXISTS_UUID)) .request() .header(OptionalAccess.UNIDENTIFIED, "$$$$$$$$$") .get(); @@ -419,61 +320,11 @@ class KeysControllerTest { @Test - void validMultiRequestTestV2ByNumber() throws Exception { - PreKeyResponse results = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/*", EXISTS_NUMBER)) - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .get(PreKeyResponse.class); - - assertThat(results.getDevicesCount()).isEqualTo(3); - assertThat(results.getIdentityKey()).isEqualTo(existsAccount.getIdentityKey()); - - PreKey signedPreKey = results.getDevice(1).getSignedPreKey(); - PreKey preKey = results.getDevice(1).getPreKey(); - long registrationId = results.getDevice(1).getRegistrationId(); - long deviceId = results.getDevice(1).getDeviceId(); - - assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId()); - assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey()); - assertThat(registrationId).isEqualTo(SAMPLE_REGISTRATION_ID); - assertThat(signedPreKey.getKeyId()).isEqualTo(SAMPLE_SIGNED_KEY.getKeyId()); - assertThat(signedPreKey.getPublicKey()).isEqualTo(SAMPLE_SIGNED_KEY.getPublicKey()); - assertThat(deviceId).isEqualTo(1); - - signedPreKey = results.getDevice(2).getSignedPreKey(); - preKey = results.getDevice(2).getPreKey(); - registrationId = results.getDevice(2).getRegistrationId(); - deviceId = results.getDevice(2).getDeviceId(); - - assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY2.getKeyId()); - assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY2.getPublicKey()); - assertThat(registrationId).isEqualTo(SAMPLE_REGISTRATION_ID2); - assertThat(signedPreKey.getKeyId()).isEqualTo(SAMPLE_SIGNED_KEY2.getKeyId()); - assertThat(signedPreKey.getPublicKey()).isEqualTo(SAMPLE_SIGNED_KEY2.getPublicKey()); - assertThat(deviceId).isEqualTo(2); - - signedPreKey = results.getDevice(4).getSignedPreKey(); - preKey = results.getDevice(4).getPreKey(); - registrationId = results.getDevice(4).getRegistrationId(); - deviceId = results.getDevice(4).getDeviceId(); - - assertThat(preKey.getKeyId()).isEqualTo(SAMPLE_KEY4.getKeyId()); - assertThat(preKey.getPublicKey()).isEqualTo(SAMPLE_KEY4.getPublicKey()); - assertThat(registrationId).isEqualTo(SAMPLE_REGISTRATION_ID4); - assertThat(signedPreKey).isNull(); - assertThat(deviceId).isEqualTo(4); - - verify(keysDynamoDb).take(eq(existsAccount)); - verifyNoMoreInteractions(keysDynamoDb); - } - - @Test - void validMultiRequestTestV2ByUuid() throws Exception { + void validMultiRequestTestV2() { PreKeyResponse results = resources.getJerseyTest() .target(String.format("/v2/keys/%s/*", EXISTS_UUID.toString())) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(PreKeyResponse.class); assertThat(results.getDevicesCount()).isEqualTo(3); @@ -520,41 +371,41 @@ class KeysControllerTest { @Test - void invalidRequestTestV2() throws Exception { + void invalidRequestTestV2() { Response response = resources.getJerseyTest() - .target(String.format("/v2/keys/%s", NOT_EXISTS_NUMBER)) + .target(String.format("/v2/keys/%s", NOT_EXISTS_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404); } @Test - void anotherInvalidRequestTestV2() throws Exception { + void anotherInvalidRequestTestV2() { Response response = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/22", EXISTS_NUMBER)) + .target(String.format("/v2/keys/%s/22", EXISTS_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(404); } @Test - void unauthorizedRequestTestV2() throws Exception { + void unauthorizedRequestTestV2() { Response response = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) + .target(String.format("/v2/keys/%s/1", EXISTS_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .get(); assertThat(response.getStatusInfo().getStatusCode()).isEqualTo(401); response = resources.getJerseyTest() - .target(String.format("/v2/keys/%s/1", EXISTS_NUMBER)) + .target(String.format("/v2/keys/%s/1", EXISTS_UUID)) .request() .get(); @@ -562,7 +413,7 @@ class KeysControllerTest { } @Test - void putKeysTestV2() throws Exception { + void putKeysTestV2() { final PreKey preKey = new PreKey(31337, "foobar"); final SignedPreKey signedPreKey = new SignedPreKey(31338, "foobaz", "myvalidsig"); final String identityKey = "barbar"; @@ -577,7 +428,7 @@ class KeysControllerTest { resources.getJerseyTest() .target("/v2/keys") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(preKeyState, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(204); @@ -596,7 +447,7 @@ class KeysControllerTest { } @Test - void disabledPutKeysTestV2() throws Exception { + void disabledPutKeysTestV2() { final PreKey preKey = new PreKey(31337, "foobar"); final SignedPreKey signedPreKey = new SignedPreKey(31338, "foobaz", "myvalidsig"); final String identityKey = "barbar"; @@ -611,7 +462,7 @@ class KeysControllerTest { resources.getJerseyTest() .target("/v2/keys") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.entity(preKeyState, MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(204); @@ -657,7 +508,7 @@ class KeysControllerTest { result = resources.getJerseyTest() .target(String.format("/v2/keys/%s/*", EXISTS_UUID.toString())) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.1.2 Android/30") .get(); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java index 376b50963..6d8375ee4 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java @@ -19,7 +19,6 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -66,9 +65,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; import org.mockito.stubbing.Answer; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.OptionalAccess; @@ -156,22 +153,26 @@ class MessageControllerTest { .build(); @BeforeEach - void setup() throws Exception { - Set singleDeviceList = new HashSet() {{ + void setup() { + Set singleDeviceList = new HashSet<>() {{ add(new Device(1, null, "foo", "bar", - "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, true, false, + "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), + System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, true, false, false, false))); }}; - Set multiDeviceList = new HashSet() {{ + Set multiDeviceList = new HashSet<>() {{ add(new Device(1, null, "foo", "bar", - "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, false, false, + "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), + System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, false, false, false, false))); add(new Device(2, null, "foo", "bar", - "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, false, false, + "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), + System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(true, false, false, true, false, false, false, false))); add(new Device(3, null, "foo", "bar", - "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(false, false, false, false, false, false, + "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), + System.currentTimeMillis(), "Test", 0, new Device.DeviceCapabilities(false, false, false, false, false, false, false, false))); }}; @@ -179,12 +180,9 @@ class MessageControllerTest { Account multiDeviceAccount = new Account(MULTI_DEVICE_RECIPIENT, MULTI_DEVICE_UUID, multiDeviceList, "1234".getBytes()); internationalAccount = new Account(INTERNATIONAL_RECIPIENT, INTERNATIONAL_UUID, singleDeviceList, "1234".getBytes()); - when(accountsManager.get(eq(SINGLE_DEVICE_RECIPIENT))).thenReturn(Optional.of(singleDeviceAccount)); - when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(SINGLE_DEVICE_RECIPIENT)))).thenReturn(Optional.of(singleDeviceAccount)); - when(accountsManager.get(eq(MULTI_DEVICE_RECIPIENT))).thenReturn(Optional.of(multiDeviceAccount)); - when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(MULTI_DEVICE_RECIPIENT)))).thenReturn(Optional.of(multiDeviceAccount)); - when(accountsManager.get(INTERNATIONAL_RECIPIENT)).thenReturn(Optional.of(internationalAccount)); - when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(INTERNATIONAL_RECIPIENT)))).thenReturn(Optional.of(internationalAccount)); + when(accountsManager.get(eq(SINGLE_DEVICE_UUID))).thenReturn(Optional.of(singleDeviceAccount)); + when(accountsManager.get(eq(MULTI_DEVICE_UUID))).thenReturn(Optional.of(multiDeviceAccount)); + when(accountsManager.get(INTERNATIONAL_UUID)).thenReturn(Optional.of(internationalAccount)); when(rateLimiters.getMessagesLimiter()).thenReturn(rateLimiter); @@ -221,9 +219,9 @@ class MessageControllerTest { void testSendFromDisabledAccount() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -234,9 +232,9 @@ class MessageControllerTest { void testSingleDeviceCurrent() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -253,9 +251,9 @@ class MessageControllerTest { void testNullMessageInList() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_null_message_in_list.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -283,9 +281,9 @@ class MessageControllerTest { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", INTERNATIONAL_RECIPIENT)) + .target(String.format("/v1/messages/%s", INTERNATIONAL_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("X-Forwarded-For", senderHost) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -333,9 +331,9 @@ class MessageControllerTest { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", INTERNATIONAL_RECIPIENT)) + .target(String.format("/v1/messages/%s", INTERNATIONAL_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.6.4 Android/30") .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -363,9 +361,9 @@ class MessageControllerTest { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", INTERNATIONAL_RECIPIENT)) + .target(String.format("/v1/messages/%s", INTERNATIONAL_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("User-Agent", "Signal-Android/5.1.2 Android/30") .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -385,7 +383,7 @@ class MessageControllerTest { void testSingleDeviceCurrentUnidentified() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .request() .header(OptionalAccess.UNIDENTIFIED, Base64.getEncoder().encodeToString("1234".getBytes())) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), @@ -405,7 +403,7 @@ class MessageControllerTest { void testSendBadAuth() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", SINGLE_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .request() .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -417,9 +415,9 @@ class MessageControllerTest { void testMultiDeviceMissing() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_single_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -436,9 +434,9 @@ class MessageControllerTest { void testMultiDeviceExtra() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_extra_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -455,9 +453,9 @@ class MessageControllerTest { void testMultiDevice() throws Exception { Response response = resources.getJerseyTest() - .target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) + .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_multi_device.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -469,9 +467,9 @@ class MessageControllerTest { @Test void testRegistrationIdMismatch() throws Exception { Response response = - resources.getJerseyTest().target(String.format("/v1/messages/%s", MULTI_DEVICE_RECIPIENT)) + resources.getJerseyTest().target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(mapper.readValue(jsonFixture("fixtures/current_message_registration_id.json"), IncomingMessageList.class), MediaType.APPLICATION_JSON_TYPE)); @@ -506,7 +504,7 @@ class MessageControllerTest { OutgoingMessageEntityList response = resources.getJerseyTest().target("/v1/messages/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .accept(MediaType.APPLICATION_JSON_TYPE) .get(OutgoingMessageEntityList.class); @@ -543,7 +541,7 @@ class MessageControllerTest { Response response = resources.getJerseyTest().target("/v1/messages/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .accept(MediaType.APPLICATION_JSON_TYPE) .get(); @@ -573,7 +571,7 @@ class MessageControllerTest { Response response = resources.getJerseyTest() .target(String.format("/v1/messages/uuid/%s", uuid1)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .delete(); assertThat("Good Response Code", response.getStatus(), is(equalTo(204))); @@ -582,7 +580,7 @@ class MessageControllerTest { response = resources.getJerseyTest() .target(String.format("/v1/messages/uuid/%s", uuid2)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID.toString(), AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .delete(); assertThat("Good Response Code", response.getStatus(), is(equalTo(204))); @@ -591,7 +589,7 @@ class MessageControllerTest { response = resources.getJerseyTest() .target(String.format("/v1/messages/uuid/%s", uuid3)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .delete(); assertThat("Good Response Code", response.getStatus(), is(equalTo(204))); @@ -609,7 +607,7 @@ class MessageControllerTest { resources.getJerseyTest() .target(String.format("/v1/messages/report/%s/%s", senderNumber, messageGuid)) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .post(null); assertThat(response.getStatus(), is(equalTo(202))); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/PaymentsControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/PaymentsControllerTest.java index 188853e27..48d0d6155 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/PaymentsControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/PaymentsControllerTest.java @@ -61,7 +61,7 @@ class PaymentsControllerTest { resources.getJerseyTest() .target("/v1/payments/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(ExternalServiceCredentials.class); assertThat(token.getUsername()).isEqualTo(validCredentials.getUsername()); @@ -74,7 +74,7 @@ class PaymentsControllerTest { resources.getJerseyTest() .target("/v1/payments/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.INVVALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.INVALID_UUID, AuthHelper.INVALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); @@ -86,7 +86,7 @@ class PaymentsControllerTest { resources.getJerseyTest() .target("/v1/payments/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); } @@ -97,7 +97,7 @@ class PaymentsControllerTest { resources.getJerseyTest() .target("/v1/payments/conversions") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(CurrencyConversionEntityList.class); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java index 4b20fc8e9..ba65adfad 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java @@ -7,7 +7,6 @@ package org.whispersystems.textsecuregcm.tests.controllers; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -35,12 +34,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.profiles.ProfileKey; import org.signal.zkgroup.profiles.ProfileKeyCommitment; import org.signal.zkgroup.profiles.ServerZkProfileOperations; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration; @@ -107,7 +104,7 @@ class ProfileControllerTest { .build(); @BeforeEach - void setup() throws Exception { + void setup() { reset(s3client); AccountsHelper.setupMockUpdate(accountsManager); @@ -150,11 +147,9 @@ class ProfileControllerTest { when(accountsManager.get(AuthHelper.VALID_UUID_TWO)).thenReturn(Optional.of(profileAccount)); when(usernamesManager.get(AuthHelper.VALID_UUID_TWO)).thenReturn(Optional.of("n00bkiller")); when(usernamesManager.get("n00bkiller")).thenReturn(Optional.of(AuthHelper.VALID_UUID_TWO)); - when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO)))).thenReturn(Optional.of(profileAccount)); - when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() && identifier.getUuid().equals(AuthHelper.VALID_UUID_TWO)))).thenReturn(Optional.of(profileAccount)); when(accountsManager.get(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of(capabilitiesAccount)); - when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER)))).thenReturn(Optional.of(capabilitiesAccount)); + when(accountsManager.get(AuthHelper.VALID_UUID)).thenReturn(Optional.of(capabilitiesAccount)); when(profilesManager.get(eq(AuthHelper.VALID_UUID), eq("someversion"))).thenReturn(Optional.empty()); when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile( @@ -177,7 +172,7 @@ class ProfileControllerTest { Profile profile= resources.getJerseyTest() .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getIdentityKey()).isEqualTo("bar"); @@ -185,38 +180,17 @@ class ProfileControllerTest { assertThat(profile.getAvatar()).isEqualTo("profiles/bang"); assertThat(profile.getUsername()).isEqualTo("n00bkiller"); - verify(accountsManager, times(1)).get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() && identifier.getUuid().equals(AuthHelper.VALID_UUID_TWO))); + verify(accountsManager).get(AuthHelper.VALID_UUID_TWO); verify(usernamesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO)); verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID); } - @Test - void testProfileGetByNumber() throws RateLimitExceededException { - Profile profile= resources.getJerseyTest() - .target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO) - .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .get(Profile.class); - - assertThat(profile.getIdentityKey()).isEqualTo("bar"); - assertThat(profile.getName()).isEqualTo("baz"); - assertThat(profile.getAvatar()).isEqualTo("profiles/bang"); - assertThat(profile.getCapabilities().isGv2()).isFalse(); - assertThat(profile.getCapabilities().isGv1Migration()).isFalse(); - assertThat(profile.getUsername()).isNull(); - assertThat(profile.getUuid()).isNull(); - - verify(accountsManager, times(1)).get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO))); - verifyNoMoreInteractions(usernamesManager); - verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID); - } - @Test void testProfileGetByUsername() throws RateLimitExceededException { Profile profile= resources.getJerseyTest() .target("/v1/profile/username/n00bkiller") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getIdentityKey()).isEqualTo("bar"); @@ -233,7 +207,7 @@ class ProfileControllerTest { @Test void testProfileGetUnauthorized() { Response response = resources.getJerseyTest() - .target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO) + .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO) .request() .get(); @@ -256,7 +230,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/username/n00bkillerzzzzz") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(404); @@ -269,9 +243,9 @@ class ProfileControllerTest { @Test void testProfileGetDisabled() { Response response = resources.getJerseyTest() - .target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO) + .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_NUMBER, AuthHelper.DISABLED_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); @@ -280,9 +254,9 @@ class ProfileControllerTest { @Test void testProfileCapabilities() { Profile profile= resources.getJerseyTest() - .target("/v1/profile/" + AuthHelper.VALID_NUMBER) + .target("/v1/profile/" + AuthHelper.VALID_UUID) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getCapabilities().isGv2()).isTrue(); @@ -292,9 +266,9 @@ class ProfileControllerTest { profile = resources .getJerseyTest() - .target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO) + .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO) .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .get(Profile.class); assertThat(profile.getCapabilities().isGv2()).isFalse(); @@ -308,7 +282,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/name/123456789012345678901234567890123456789012345678901234567890123456789012") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(204); @@ -321,7 +295,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/name/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(204); @@ -334,7 +308,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/name/1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.text("")); assertThat(response.getStatus()).isEqualTo(400); @@ -350,7 +324,7 @@ class ProfileControllerTest { ProfileAvatarUploadAttributes uploadAttributes = resources.getJerseyTest() .target("/v1/profile/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); @@ -375,7 +349,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", null, null, null, true), MediaType.APPLICATION_JSON_TYPE)); @@ -391,7 +365,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, null, false), MediaType.APPLICATION_JSON_TYPE)); @@ -423,7 +397,7 @@ class ProfileControllerTest { ProfileAvatarUploadAttributes uploadAttributes= resources.getJerseyTest() .target("/v1/profile/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); @@ -449,7 +423,7 @@ class ProfileControllerTest { resources.getJerseyTest() .target("/v1/profile/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, null, null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); ArgumentCaptor profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); @@ -479,7 +453,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, text, null, false), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); @@ -520,7 +494,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "yetanotherversion", name, null, null, paymentAddress, false), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); @@ -558,7 +532,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "yetanotherversion", name, null, null, paymentAddress, false), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(403); @@ -572,7 +546,7 @@ class ProfileControllerTest { Profile profile = resources.getJerseyTest() .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getIdentityKey()).isEqualTo("bar"); @@ -607,7 +581,7 @@ class ProfileControllerTest { Response response = resources.getJerseyTest() .target("/v1/profile") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", name, null, null, paymentAddress, false), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); @@ -623,7 +597,7 @@ class ProfileControllerTest { Profile profile = resources.getJerseyTest() .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getPaymentAddress()).isEqualTo("paymentaddress"); @@ -631,7 +605,7 @@ class ProfileControllerTest { profile = resources.getJerseyTest() .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getPaymentAddress()).isEqualTo("paymentaddress"); @@ -639,7 +613,7 @@ class ProfileControllerTest { profile = resources.getJerseyTest() .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(Profile.class); assertThat(profile.getPaymentAddress()).isNull(); } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/RemoteConfigControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/RemoteConfigControllerTest.java index d7e761bc5..c043b8291 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/RemoteConfigControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/RemoteConfigControllerTest.java @@ -87,7 +87,7 @@ class RemoteConfigControllerTest { UserRemoteConfigList configuration = resources.getJerseyTest() .target("/v1/config/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(UserRemoteConfigList.class); verify(remoteConfigsManager, times(1)).getAll(); @@ -121,7 +121,7 @@ class RemoteConfigControllerTest { UserRemoteConfigList configuration = resources.getJerseyTest() .target("/v1/config/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) .get(UserRemoteConfigList.class); verify(remoteConfigsManager, times(1)).getAll(); @@ -178,7 +178,7 @@ class RemoteConfigControllerTest { Response response = resources.getJerseyTest() .target("/v1/config/") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.INVALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/SecureStorageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/SecureStorageControllerTest.java index ae6d30dd1..9a586437e 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/SecureStorageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/SecureStorageControllerTest.java @@ -43,7 +43,7 @@ class SecureStorageControllerTest { ExternalServiceCredentials credentials = resources.getJerseyTest() .target("/v1/storage/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(ExternalServiceCredentials.class); assertThat(credentials.getPassword()).isNotEmpty(); @@ -55,7 +55,7 @@ class SecureStorageControllerTest { Response response = resources.getJerseyTest() .target("/v1/storage/auth") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.INVVALID_NUMBER, AuthHelper.INVALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.INVALID_UUID, AuthHelper.INVALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(401); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/StickerControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/StickerControllerTest.java index 239a9f8ac..d4894f759 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/StickerControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/StickerControllerTest.java @@ -56,7 +56,7 @@ class StickerControllerTest { StickerPackFormUploadAttributes attributes = resources.getJerseyTest() .target("/v1/sticker/pack/form/10") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(StickerPackFormUploadAttributes.class); assertThat(attributes.getPackId()).isNotNull(); @@ -94,7 +94,7 @@ class StickerControllerTest { Response response = resources.getJerseyTest() .target("/v1/sticker/pack/form/202") .request() - .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .get(); assertThat(response.getStatus()).isEqualTo(400); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java index 5a7839d30..690d11775 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java @@ -5,7 +5,6 @@ package org.whispersystems.textsecuregcm.tests.util; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -21,9 +20,7 @@ import java.util.Base64; import java.util.Optional; import java.util.Random; import java.util.UUID; -import org.mockito.ArgumentMatcher; import org.whispersystems.textsecuregcm.auth.AccountAuthenticator; -import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; @@ -46,7 +43,7 @@ public class AuthHelper { public static final UUID VALID_UUID_TWO = UUID.randomUUID(); public static final String VALID_PASSWORD_TWO = "baz"; - public static final String INVVALID_NUMBER = "+14151111111"; + public static final String INVALID_NUMBER = "+14151111111"; public static final UUID INVALID_UUID = UUID.randomUUID(); public static final String INVALID_PASSWORD = "bar"; @@ -142,35 +139,15 @@ public class AuthHelper { when(ACCOUNTS_MANAGER.get(VALID_NUMBER)).thenReturn(Optional.of(VALID_ACCOUNT)); when(ACCOUNTS_MANAGER.get(VALID_UUID)).thenReturn(Optional.of(VALID_ACCOUNT)); - when(ACCOUNTS_MANAGER.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(VALID_NUMBER)))).thenReturn(Optional.of(VALID_ACCOUNT)); - when(ACCOUNTS_MANAGER.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() && identifier.getUuid().equals(VALID_UUID)))).thenReturn(Optional.of(VALID_ACCOUNT)); when(ACCOUNTS_MANAGER.get(VALID_NUMBER_TWO)).thenReturn(Optional.of(VALID_ACCOUNT_TWO)); when(ACCOUNTS_MANAGER.get(VALID_UUID_TWO)).thenReturn(Optional.of(VALID_ACCOUNT_TWO)); - when(ACCOUNTS_MANAGER.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() - && identifier.getNumber().equals(VALID_NUMBER_TWO)))).thenReturn(Optional.of(VALID_ACCOUNT_TWO)); - when(ACCOUNTS_MANAGER.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() - && identifier.getUuid().equals(VALID_UUID_TWO)))).thenReturn(Optional.of(VALID_ACCOUNT_TWO)); when(ACCOUNTS_MANAGER.get(DISABLED_NUMBER)).thenReturn(Optional.of(DISABLED_ACCOUNT)); when(ACCOUNTS_MANAGER.get(DISABLED_UUID)).thenReturn(Optional.of(DISABLED_ACCOUNT)); - when(ACCOUNTS_MANAGER.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() - && identifier.getNumber().equals(DISABLED_NUMBER)))).thenReturn(Optional.of(DISABLED_ACCOUNT)); - when(ACCOUNTS_MANAGER.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() - && identifier.getUuid().equals(DISABLED_UUID)))).thenReturn(Optional.of(DISABLED_ACCOUNT)); when(ACCOUNTS_MANAGER.get(UNDISCOVERABLE_NUMBER)).thenReturn(Optional.of(UNDISCOVERABLE_ACCOUNT)); when(ACCOUNTS_MANAGER.get(UNDISCOVERABLE_UUID)).thenReturn(Optional.of(UNDISCOVERABLE_ACCOUNT)); - when(ACCOUNTS_MANAGER.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() - && identifier.getNumber().equals(UNDISCOVERABLE_NUMBER)))).thenReturn(Optional.of(UNDISCOVERABLE_ACCOUNT)); - when(ACCOUNTS_MANAGER.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() - && identifier.getUuid().equals(UNDISCOVERABLE_UUID)))).thenReturn(Optional.of(UNDISCOVERABLE_ACCOUNT)); AccountsHelper.setupMockUpdateForAuthHelper(ACCOUNTS_MANAGER); @@ -187,8 +164,16 @@ public class AuthHelper { DisabledPermittedAuthenticatedAccount.class, disabledPermittedAccountAuthFilter)); } - public static String getAuthHeader(String number, String password) { - return "Basic " + Base64.getEncoder().encodeToString((number + ":" + password).getBytes()); + public static String getAuthHeader(UUID uuid, String password) { + return getAuthHeader(uuid.toString(), password); + } + + public static String getProvisioningAuthHeader(String number, String password) { + return getAuthHeader(number, password); + } + + private static String getAuthHeader(String identifier, String password) { + return "Basic " + Base64.getEncoder().encodeToString((identifier + ":" + password).getBytes()); } public static String getUnidentifiedAccessHeader(byte[] key) { @@ -220,7 +205,7 @@ public class AuthHelper { } public String getAuthHeader() { - return AuthHelper.getAuthHeader(number, password); + return AuthHelper.getAuthHeader(uuid, password); } private void setup(final AccountsManager accountsManager) { @@ -237,12 +222,6 @@ public class AuthHelper { when(account.isEnabled()).thenReturn(true); when(accountsManager.get(number)).thenReturn(Optional.of(account)); when(accountsManager.get(uuid)).thenReturn(Optional.of(account)); - when(accountsManager.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() - && identifier.getNumber().equals(number)))).thenReturn(Optional.of(account)); - when(accountsManager.get(argThat( - (ArgumentMatcher) identifier -> identifier != null && identifier.hasUuid() - && identifier.getUuid().equals(uuid)))).thenReturn(Optional.of(account)); } }