Add a counter for cases where clients use both an authenticated identity and UAK when fetching profiles
This commit is contained in:
parent
144c4c9223
commit
f62f79c95c
|
@ -97,6 +97,7 @@ import org.whispersystems.websocket.auth.Mutable;
|
||||||
import org.whispersystems.websocket.auth.ReadOnly;
|
import org.whispersystems.websocket.auth.ReadOnly;
|
||||||
import software.amazon.awssdk.services.s3.S3Client;
|
import software.amazon.awssdk.services.s3.S3Client;
|
||||||
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||||
@Path("/v1/profile")
|
@Path("/v1/profile")
|
||||||
|
@ -123,6 +124,7 @@ public class ProfileController {
|
||||||
private static final String EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE = "expiringProfileKey";
|
private static final String EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE = "expiringProfileKey";
|
||||||
|
|
||||||
private static final String VERSION_NOT_FOUND_COUNTER_NAME = name(ProfileController.class, "versionNotFound");
|
private static final String VERSION_NOT_FOUND_COUNTER_NAME = name(ProfileController.class, "versionNotFound");
|
||||||
|
private static final String DUPLICATE_AUTHENTICATION_COUNTER_NAME = name(ProfileController.class, "duplicateAuthentication");
|
||||||
|
|
||||||
public ProfileController(
|
public ProfileController(
|
||||||
Clock clock,
|
Clock clock,
|
||||||
|
@ -230,11 +232,12 @@ public class ProfileController {
|
||||||
@HeaderParam(HeaderUtils.UNIDENTIFIED_ACCESS_KEY) Optional<Anonymous> accessKey,
|
@HeaderParam(HeaderUtils.UNIDENTIFIED_ACCESS_KEY) Optional<Anonymous> accessKey,
|
||||||
@Context ContainerRequestContext containerRequestContext,
|
@Context ContainerRequestContext containerRequestContext,
|
||||||
@PathParam("identifier") AciServiceIdentifier accountIdentifier,
|
@PathParam("identifier") AciServiceIdentifier accountIdentifier,
|
||||||
@PathParam("version") String version)
|
@PathParam("version") String version,
|
||||||
|
@HeaderParam(HttpHeaders.USER_AGENT) String userAgent)
|
||||||
throws RateLimitExceededException {
|
throws RateLimitExceededException {
|
||||||
|
|
||||||
final Optional<Account> maybeRequester = auth.map(AuthenticatedDevice::getAccount);
|
final Optional<Account> maybeRequester = auth.map(AuthenticatedDevice::getAccount);
|
||||||
final Account targetAccount = verifyPermissionToReceiveProfile(maybeRequester, accessKey, accountIdentifier);
|
final Account targetAccount = verifyPermissionToReceiveProfile(maybeRequester, accessKey, accountIdentifier, "getVersionedProfile", userAgent);
|
||||||
|
|
||||||
return buildVersionedProfileResponse(targetAccount,
|
return buildVersionedProfileResponse(targetAccount,
|
||||||
version,
|
version,
|
||||||
|
@ -253,7 +256,8 @@ public class ProfileController {
|
||||||
@PathParam("identifier") AciServiceIdentifier accountIdentifier,
|
@PathParam("identifier") AciServiceIdentifier accountIdentifier,
|
||||||
@PathParam("version") String version,
|
@PathParam("version") String version,
|
||||||
@PathParam("credentialRequest") String credentialRequest,
|
@PathParam("credentialRequest") String credentialRequest,
|
||||||
@QueryParam("credentialType") String credentialType)
|
@QueryParam("credentialType") String credentialType,
|
||||||
|
@HeaderParam(HttpHeaders.USER_AGENT) String userAgent)
|
||||||
throws RateLimitExceededException {
|
throws RateLimitExceededException {
|
||||||
|
|
||||||
if (!EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE.equals(credentialType)) {
|
if (!EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE.equals(credentialType)) {
|
||||||
|
@ -261,7 +265,7 @@ public class ProfileController {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Optional<Account> maybeRequester = auth.map(AuthenticatedDevice::getAccount);
|
final Optional<Account> maybeRequester = auth.map(AuthenticatedDevice::getAccount);
|
||||||
final Account targetAccount = verifyPermissionToReceiveProfile(maybeRequester, accessKey, accountIdentifier);
|
final Account targetAccount = verifyPermissionToReceiveProfile(maybeRequester, accessKey, accountIdentifier, "credentialRequest", userAgent);
|
||||||
final boolean isSelf = maybeRequester.map(requester -> ProfileHelper.isSelfProfileRequest(requester.getUuid(), accountIdentifier)).orElse(false);
|
final boolean isSelf = maybeRequester.map(requester -> ProfileHelper.isSelfProfileRequest(requester.getUuid(), accountIdentifier)).orElse(false);
|
||||||
|
|
||||||
return buildExpiringProfileKeyCredentialProfileResponse(targetAccount,
|
return buildExpiringProfileKeyCredentialProfileResponse(targetAccount,
|
||||||
|
@ -303,7 +307,7 @@ public class ProfileController {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
targetAccount = verifyPermissionToReceiveProfile(
|
targetAccount = verifyPermissionToReceiveProfile(
|
||||||
maybeRequester, accessKey.filter(ignored -> identifier.identityType() == IdentityType.ACI), identifier);
|
maybeRequester, accessKey.filter(ignored -> identifier.identityType() == IdentityType.ACI), identifier, "getUnversionedProfile", userAgent);
|
||||||
}
|
}
|
||||||
return switch (identifier.identityType()) {
|
return switch (identifier.identityType()) {
|
||||||
case ACI -> buildBaseProfileResponseForAccountIdentity(targetAccount,
|
case ACI -> buildBaseProfileResponseForAccountIdentity(targetAccount,
|
||||||
|
@ -386,7 +390,7 @@ public class ProfileController {
|
||||||
profileKeyCredentialResponse = ProfileHelper.getExpiringProfileKeyCredential(HexFormat.of().parseHex(encodedCredentialRequest),
|
profileKeyCredentialResponse = ProfileHelper.getExpiringProfileKeyCredential(HexFormat.of().parseHex(encodedCredentialRequest),
|
||||||
profile, new ServiceId.Aci(account.getUuid()), zkProfileOperations);
|
profile, new ServiceId.Aci(account.getUuid()), zkProfileOperations);
|
||||||
} catch (VerificationFailedException | InvalidInputException e) {
|
} catch (VerificationFailedException | InvalidInputException e) {
|
||||||
throw new BadRequestException(Response.status(Response.Status.BAD_REQUEST).build(), e);
|
throw new BadRequestException(e);
|
||||||
}
|
}
|
||||||
return profileKeyCredentialResponse;
|
return profileKeyCredentialResponse;
|
||||||
})
|
})
|
||||||
|
@ -474,7 +478,15 @@ public class ProfileController {
|
||||||
*/
|
*/
|
||||||
private Account verifyPermissionToReceiveProfile(final Optional<Account> maybeRequester,
|
private Account verifyPermissionToReceiveProfile(final Optional<Account> maybeRequester,
|
||||||
final Optional<Anonymous> maybeAccessKey,
|
final Optional<Anonymous> maybeAccessKey,
|
||||||
final ServiceIdentifier accountIdentifier) throws RateLimitExceededException {
|
final ServiceIdentifier accountIdentifier,
|
||||||
|
final String endpoint,
|
||||||
|
@Nullable final String userAgent) throws RateLimitExceededException {
|
||||||
|
|
||||||
|
if (maybeRequester.isPresent() && maybeAccessKey.isPresent()) {
|
||||||
|
Metrics.counter(DUPLICATE_AUTHENTICATION_COUNTER_NAME,
|
||||||
|
Tags.of(UserAgentTagUtil.getPlatformTag(userAgent), io.micrometer.core.instrument.Tag.of("endpoint", endpoint)))
|
||||||
|
.increment();
|
||||||
|
}
|
||||||
|
|
||||||
if (maybeRequester.isPresent()) {
|
if (maybeRequester.isPresent()) {
|
||||||
rateLimiters.getProfileLimiter().validate(maybeRequester.get().getUuid());
|
rateLimiters.getProfileLimiter().validate(maybeRequester.get().getUuid());
|
||||||
|
|
Loading…
Reference in New Issue