From f10be893ce5cd7d3f556c34a685633eb41a03f41 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Wed, 20 Jan 2021 16:09:30 -0500 Subject: [PATCH] Drop the old feature flag controller. --- service/config/sample.yml | 7 - .../textsecuregcm/WhisperServerService.java | 3 - .../controllers/FeatureFlagsController.java | 92 ---------- .../FeatureFlagsControllerTest.java | 163 ------------------ 4 files changed, 265 deletions(-) delete mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsController.java delete mode 100644 service/src/test/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsControllerTest.java diff --git a/service/config/sample.yml b/service/config/sample.yml index 1179f2f37..7ed2002f1 100644 --- a/service/config/sample.yml +++ b/service/config/sample.yml @@ -134,12 +134,5 @@ remoteConfig: - # Nth authorized token globalConfig: # keys and values that are given to clients on GET /v1/config -featureFlag: - authorizedTokens: - - # 1st authorized token - - # 2nd authorized token - - # ... - - # Nth authorized token - paymentService: userAuthenticationTokenSharedSecret: # hex-encoded 32-byte secret shared with MobileCoin services used to generate auth tokens for Signal users diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 448ee01d1..d13a8c791 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -55,7 +55,6 @@ import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV3; import org.whispersystems.textsecuregcm.controllers.CertificateController; import org.whispersystems.textsecuregcm.controllers.DeviceController; import org.whispersystems.textsecuregcm.controllers.DirectoryController; -import org.whispersystems.textsecuregcm.controllers.FeatureFlagsController; import org.whispersystems.textsecuregcm.controllers.KeepAliveController; import org.whispersystems.textsecuregcm.controllers.KeysController; import org.whispersystems.textsecuregcm.controllers.MessageController; @@ -395,7 +394,6 @@ public class WhisperServerService extends Application accountAuthFilter = new BasicCredentialAuthFilter.Builder().setAuthenticator(accountAuthenticator).buildAuthFilter (); AuthFilter disabledPermittedAccountAuthFilter = new BasicCredentialAuthFilter.Builder().setAuthenticator(disabledPermittedAccountAuthenticator).buildAuthFilter(); @@ -425,7 +423,6 @@ public class WhisperServerService extends Application webSocketEnvironment = new WebSocketEnvironment<>(environment, config.getWebSocketConfiguration(), 90000); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsController.java deleted file mode 100644 index 1d5b1eaff..000000000 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsController.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2013-2020 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.controllers; - -import com.codahale.metrics.annotation.Timed; -import com.google.common.annotations.VisibleForTesting; -import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager; - -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Path("/v1/featureflag") -public class FeatureFlagsController { - - private final FeatureFlagsManager featureFlagsManager; - private final List authorizedTokens; - - public FeatureFlagsController(final FeatureFlagsManager featureFlagsManager, final List authorizedTokens) { - this.featureFlagsManager = featureFlagsManager; - this.authorizedTokens = authorizedTokens.stream().map(token -> token.getBytes(StandardCharsets.UTF_8)).collect(Collectors.toList()); - } - - @Timed - @GET - @Produces(MediaType.APPLICATION_JSON) - public Map get(@HeaderParam("Token") final String token) { - if (!isAuthorized(token)) { - throw new WebApplicationException(Response.Status.UNAUTHORIZED); - } - - return featureFlagsManager.getAllFlags(); - } - - @Timed - @PUT - @Path("/{featureFlag}") - public void set(@HeaderParam("Token") final String token, @PathParam("featureFlag") final String featureFlag, @FormParam("active") final boolean active) { - if (!isAuthorized(token)) { - throw new WebApplicationException(Response.Status.UNAUTHORIZED); - } - - featureFlagsManager.setFeatureFlag(featureFlag, active); - } - - @Timed - @DELETE - @Path("/{featureFlag}") - public void delete(@HeaderParam("Token") final String token, @PathParam("featureFlag") final String featureFlag) { - if (!isAuthorized(token)) { - throw new WebApplicationException(Response.Status.UNAUTHORIZED); - } - - featureFlagsManager.deleteFeatureFlag(featureFlag); - } - - @VisibleForTesting - boolean isAuthorized(final String token) { - if (token == null) { - return false; - } - - final byte[] tokenBytes = token.getBytes(StandardCharsets.UTF_8); - - boolean authorized = false; - - for (final byte[] authorizedToken : authorizedTokens) { - //noinspection IfStatementMissingBreakInLoop - if (MessageDigest.isEqual(authorizedToken, tokenBytes)) { - authorized = true; - } - } - - return authorized; - } -} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsControllerTest.java deleted file mode 100644 index 975b8ddb2..000000000 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/FeatureFlagsControllerTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2013-2020 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.controllers; - -import com.google.common.collect.ImmutableSet; -import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider; -import io.dropwizard.testing.junit.ResourceTestRule; -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount; -import org.whispersystems.textsecuregcm.mappers.DeviceLimitExceededExceptionMapper; -import org.whispersystems.textsecuregcm.storage.Account; -import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager; -import org.whispersystems.textsecuregcm.tests.util.AuthHelper; - -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Form; -import javax.ws.rs.core.Response; -import java.util.List; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -@RunWith(JUnitParamsRunner.class) -public class FeatureFlagsControllerTest { - - private static final FeatureFlagsManager FEATURE_FLAG_MANAGER = mock(FeatureFlagsManager.class); - private static final FeatureFlagsController FEATURE_FLAG_CONTROLLER = new FeatureFlagsController(FEATURE_FLAG_MANAGER, List.of("first", "second")); - - @Rule - public final ResourceTestRule resources = ResourceTestRule.builder() - .addProvider(AuthHelper.getAuthFilter()) - .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class))) - .setTestContainerFactory(new GrizzlyWebTestContainerFactory()) - .addProvider(new DeviceLimitExceededExceptionMapper()) - .addResource(FEATURE_FLAG_CONTROLLER) - .build(); - - @Before - public void setUp() { - reset(FEATURE_FLAG_MANAGER); - } - - @Test - public void testSet() { - { - final Response response = resources.getJerseyTest() - .target("/v1/featureflag/testFlag") - .request() - .header("Token", "first") - .put(Entity.form(new Form().param("active", "true"))); - - assertEquals(204, response.getStatus()); - verify(FEATURE_FLAG_MANAGER).setFeatureFlag("testFlag", true); - } - - { - final Response response = resources.getJerseyTest() - .target("/v1/featureflag/secondFlag") - .request() - .header("Token", "first") - .put(Entity.form(new Form().param("active", "false"))); - - assertEquals(204, response.getStatus()); - verify(FEATURE_FLAG_MANAGER).setFeatureFlag("secondFlag", false); - } - - { - final Response response = resources.getJerseyTest() - .target("/v1/featureflag/testFlag") - .request() - .header("Token", "bogus-token") - .put(Entity.form(new Form().param("active", "true"))); - - assertEquals(401, response.getStatus()); - verifyNoMoreInteractions(FEATURE_FLAG_MANAGER); - } - } - - @SuppressWarnings("rawtypes") - @Test - public void testGet() { - final Map managedFlags = Map.of("activeFlag", true, "inactiveFlag", false); - when(FEATURE_FLAG_MANAGER.getAllFlags()).thenReturn(managedFlags); - - { - final Map returnedFlags = resources.getJerseyTest() - .target("/v1/featureflag") - .request() - .header("Token", "first") - .get(Map.class); - - verify(FEATURE_FLAG_MANAGER).getAllFlags(); - assertEquals(managedFlags, returnedFlags); - } - - { - final Response response = resources.getJerseyTest() - .target("/v1/featureflag") - .request() - .header("Token", "bogus-token") - .get(); - - assertEquals(401, response.getStatus()); - verifyNoMoreInteractions(FEATURE_FLAG_MANAGER); - } - } - - @Test - public void testDelete() { - { - final Response response = resources.getJerseyTest() - .target("/v1/featureflag/testFlag") - .request() - .header("Token", "first") - .delete(); - - assertEquals(204, response.getStatus()); - verify(FEATURE_FLAG_MANAGER).deleteFeatureFlag("testFlag"); - } - - { - final Response response = resources.getJerseyTest() - .target("/v1/featureflag/testFlag") - .request() - .header("Token", "bogus-token") - .delete(); - - assertEquals(401, response.getStatus()); - verifyNoMoreInteractions(FEATURE_FLAG_MANAGER); - } - } - - @Test - @Parameters(method = "argumentsForTestIsAuthorized") - public void testIsAuthorized(final String token, final boolean expectAuthorized) { - assertEquals(expectAuthorized, FEATURE_FLAG_CONTROLLER.isAuthorized(token)); - } - - @SuppressWarnings("unused") - private Object argumentsForTestIsAuthorized() { - return new Object[] { - new Object[] { "first", true }, - new Object[] { "second", true }, - new Object[] { "third", false }, - new Object[] { "firstfirstfirst", false }, - new Object[] { null, false } - }; - } -}