Collapse various account meters into a single, multi-dimensional counter.

This commit is contained in:
Jon Chambers 2021-06-29 18:15:46 -04:00 committed by Jon Chambers
parent 3d581941ab
commit 84f85ae098
1 changed files with 31 additions and 30 deletions

View File

@ -5,45 +5,34 @@
package org.whispersystems.textsecuregcm.auth; package org.whispersystems.textsecuregcm.auth;
import com.codahale.metrics.Meter; import static com.codahale.metrics.MetricRegistry.name;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import io.dropwizard.auth.basic.BasicCredentials; import io.dropwizard.auth.basic.BasicCredentials;
import io.micrometer.core.instrument.DistributionSummary; import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Metrics;
import org.slf4j.Logger; import io.micrometer.core.instrument.Tags;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.Util;
import java.time.Clock; import java.time.Clock;
import java.time.Duration; import java.time.Duration;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Optional; import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import static com.codahale.metrics.MetricRegistry.name; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.util.Util;
public class BaseAccountAuthenticator { public class BaseAccountAuthenticator {
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME); private static final String AUTHENTICATION_COUNTER_NAME = name(BaseAccountAuthenticator.class, "authentication");
private final Meter authenticationFailedMeter = metricRegistry.meter(name(getClass(), "authentication", "failed" )); private static final String AUTHENTICATION_SUCCEEDED_TAG_NAME = "succeeded";
private final Meter authenticationSucceededMeter = metricRegistry.meter(name(getClass(), "authentication", "succeeded" )); private static final String AUTHENTICATION_FAILURE_REASON_TAG_NAME = "reason";
private final Meter noSuchAccountMeter = metricRegistry.meter(name(getClass(), "authentication", "noSuchAccount" )); private static final String AUTHENTICATION_ENABLED_REQUIRED_TAG_NAME = "enabledRequired";
private final Meter noSuchDeviceMeter = metricRegistry.meter(name(getClass(), "authentication", "noSuchDevice" ));
private final Meter accountDisabledMeter = metricRegistry.meter(name(getClass(), "authentication", "accountDisabled"));
private final Meter deviceDisabledMeter = metricRegistry.meter(name(getClass(), "authentication", "deviceDisabled" ));
private final Meter invalidAuthHeaderMeter = metricRegistry.meter(name(getClass(), "authentication", "invalidHeader" ));
private final String daysSinceLastSeenDistributionName = name(getClass(), "authentication", "daysSinceLastSeen"); private final String daysSinceLastSeenDistributionName = name(getClass(), "authentication", "daysSinceLastSeen");
private static final String IS_PRIMARY_DEVICE_TAG = "isPrimary"; private static final String IS_PRIMARY_DEVICE_TAG = "isPrimary";
private final Logger logger = LoggerFactory.getLogger(BaseAccountAuthenticator.class);
private final AccountsManager accountsManager; private final AccountsManager accountsManager;
private final Clock clock; private final Clock clock;
@ -58,46 +47,58 @@ public class BaseAccountAuthenticator {
} }
public Optional<Account> authenticate(BasicCredentials basicCredentials, boolean enabledRequired) { public Optional<Account> authenticate(BasicCredentials basicCredentials, boolean enabledRequired) {
boolean succeeded = false;
String failureReason = null;
try { try {
AuthorizationHeader authorizationHeader = AuthorizationHeader.fromUserAndPassword(basicCredentials.getUsername(), basicCredentials.getPassword()); AuthorizationHeader authorizationHeader = AuthorizationHeader.fromUserAndPassword(basicCredentials.getUsername(), basicCredentials.getPassword());
Optional<Account> account = accountsManager.get(authorizationHeader.getIdentifier()); Optional<Account> account = accountsManager.get(authorizationHeader.getIdentifier());
if (!account.isPresent()) { if (!account.isPresent()) {
noSuchAccountMeter.mark(); failureReason = "noSuchAccount";
return Optional.empty(); return Optional.empty();
} }
Optional<Device> device = account.get().getDevice(authorizationHeader.getDeviceId()); Optional<Device> device = account.get().getDevice(authorizationHeader.getDeviceId());
if (!device.isPresent()) { if (!device.isPresent()) {
noSuchDeviceMeter.mark(); failureReason = "noSuchDevice";
return Optional.empty(); return Optional.empty();
} }
if (enabledRequired) { if (enabledRequired) {
if (!device.get().isEnabled()) { if (!device.get().isEnabled()) {
deviceDisabledMeter.mark(); failureReason = "deviceDisabled";
return Optional.empty(); return Optional.empty();
} }
if (!account.get().isEnabled()) { if (!account.get().isEnabled()) {
accountDisabledMeter.mark(); failureReason = "accountDisabled";
return Optional.empty(); return Optional.empty();
} }
} }
if (device.get().getAuthenticationCredentials().verify(basicCredentials.getPassword())) { if (device.get().getAuthenticationCredentials().verify(basicCredentials.getPassword())) {
authenticationSucceededMeter.mark(); succeeded = true;
account.get().setAuthenticatedDevice(device.get()); account.get().setAuthenticatedDevice(device.get());
updateLastSeen(account.get(), device.get()); updateLastSeen(account.get(), device.get());
return account; return account;
} }
authenticationFailedMeter.mark();
return Optional.empty(); return Optional.empty();
} catch (IllegalArgumentException | InvalidAuthorizationHeaderException iae) { } catch (IllegalArgumentException | InvalidAuthorizationHeaderException iae) {
invalidAuthHeaderMeter.mark(); failureReason = "invalidHeader";
return Optional.empty(); return Optional.empty();
} finally {
Tags tags = Tags.of(
AUTHENTICATION_SUCCEEDED_TAG_NAME, String.valueOf(succeeded),
AUTHENTICATION_ENABLED_REQUIRED_TAG_NAME, String.valueOf(enabledRequired));
if (StringUtils.isNotBlank(failureReason)) {
tags = tags.and(AUTHENTICATION_FAILURE_REASON_TAG_NAME, failureReason);
}
Metrics.counter(AUTHENTICATION_COUNTER_NAME, tags).increment();
} }
} }