Skip to content

Commit

Permalink
refactor(openapi): Refactor consumer authentication filters and relat…
Browse files Browse the repository at this point in the history
…ed services
  • Loading branch information
youngzil committed Nov 21, 2024
1 parent ace5076 commit a622f56
Show file tree
Hide file tree
Showing 8 changed files with 19 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@
import com.ctrip.framework.apollo.openapi.entity.ConsumerToken;
import com.ctrip.framework.apollo.openapi.util.ConsumerAuditUtil;
import com.ctrip.framework.apollo.openapi.util.ConsumerAuthUtil;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
Expand All @@ -48,21 +46,18 @@ public class ConsumerAuthenticationFilter implements Filter {

private final ConsumerAuthUtil consumerAuthUtil;
private final ConsumerAuditUtil consumerAuditUtil;
private final PortalConfig portalConfig;

private static final int WARMUP_MILLIS = 1000; // ms
private static final int RATE_LIMITER_CACHE_MAX_SIZE = 50000;
private static final int RATE_LIMITER_CACHE_MAX_SIZE = 20000;

private static final int TOO_MANY_REQUESTS = 429;

private static final Cache<String, ImmutablePair<Long, RateLimiter>> LIMITER = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.DAYS)
.maximumSize(RATE_LIMITER_CACHE_MAX_SIZE).build();

public ConsumerAuthenticationFilter(ConsumerAuthUtil consumerAuthUtil, ConsumerAuditUtil consumerAuditUtil, PortalConfig portalConfig) {
public ConsumerAuthenticationFilter(ConsumerAuthUtil consumerAuthUtil, ConsumerAuditUtil consumerAuditUtil) {
this.consumerAuthUtil = consumerAuthUtil;
this.consumerAuditUtil = consumerAuditUtil;
this.portalConfig = portalConfig;
}

@Override
Expand All @@ -87,7 +82,7 @@ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain
Integer rateLimit = consumerToken.getRateLimit();
if (null != rateLimit && rateLimit > 0) {
try {
ImmutablePair<Long, RateLimiter> rateLimiterPair = getOrCreateRateLimiterPair(token, rateLimit);
ImmutablePair<Long, RateLimiter> rateLimiterPair = getOrCreateRateLimiterPair(consumerToken.getToken(), rateLimit);
long warmupToMillis = rateLimiterPair.getLeft() + WARMUP_MILLIS;
if (System.currentTimeMillis() > warmupToMillis && !rateLimiterPair.getRight().tryAcquire()) {
response.sendError(TOO_MANY_REQUESTS, "Too Many Requests, the flow is limited");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ public Consumer createConsumer(Consumer consumer) {

public ConsumerToken generateAndSaveConsumerToken(Consumer consumer, Integer rateLimit, Date expires) {
Preconditions.checkArgument(consumer != null, "Consumer can not be null");
Preconditions.checkArgument(rateLimit != null && rateLimit >= 0, "Rate limit must be non-negative");

ConsumerToken consumerToken = generateConsumerToken(consumer, rateLimit, expires);
consumerToken.setId(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.ctrip.framework.apollo.openapi.filter.ConsumerAuthenticationFilter;
import com.ctrip.framework.apollo.openapi.util.ConsumerAuditUtil;
import com.ctrip.framework.apollo.openapi.util.ConsumerAuthUtil;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -30,16 +29,14 @@ public class AuthFilterConfiguration {
@Bean
public FilterRegistrationBean<ConsumerAuthenticationFilter> openApiAuthenticationFilter(
ConsumerAuthUtil consumerAuthUtil,
ConsumerAuditUtil consumerAuditUtil,
PortalConfig portalConfig) {
ConsumerAuditUtil consumerAuditUtil) {

FilterRegistrationBean<ConsumerAuthenticationFilter> openApiFilter = new FilterRegistrationBean<>();

openApiFilter.setFilter(new ConsumerAuthenticationFilter(consumerAuthUtil, consumerAuditUtil, portalConfig));
openApiFilter.setFilter(new ConsumerAuthenticationFilter(consumerAuthUtil, consumerAuditUtil));
openApiFilter.addUrlPatterns("/openapi/*");

return openApiFilter;
}


}
6 changes: 3 additions & 3 deletions apollo-portal/src/main/resources/static/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -654,11 +654,11 @@
"Open.Manage.Consumer.AllowCreateApplicationTips": "(Allow third-party applications to create apps and grant them app administrator privileges.",
"Open.Manage.Consumer.AllowCreateApplication.No": "no",
"Open.Manage.Consumer.AllowCreateApplication.Yes": "yes",
"Open.Manage.Consumer.RateLimit.Enabled": "Whether to enable current limit",
"Open.Manage.Consumer.RateLimit.Enabled": "Whether to enable rate limit",
"Open.Manage.Consumer.RateLimit.Enabled.Tips": "(After enabling this feature, when third-party applications publish configurations on Apollo, their traffic will be controlled according to the configured QPS limit)",
"Open.Manage.Consumer.RateLimitValue": "Current limiting QPS",
"Open.Manage.Consumer.RateLimitValue": "Rate limiting QPS",
"Open.Manage.Consumer.RateLimitValueTips": "(Unit: times/second, for example: 100 means that the configuration is published at most 100 times per second)",
"Open.Manage.Consumer.RateLimitValue.Error": "The minimum current limiting QPS is 1",
"Open.Manage.Consumer.RateLimitValue.Error": "The minimum rate limiting QPS is 1",
"Namespace.Role.Title": "Permission Management",
"Namespace.Role.GrantModifyTo": "Permission to edit",
"Namespace.Role.GrantModifyTo2": "(Can edit the configuration)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public ConsumerAuthUtil consumerAuthUtil() {

ConsumerToken someConsumerToken = new ConsumerToken();
someConsumerToken.setConsumerId(1L);
someConsumerToken.setToken("some-token");
someConsumerToken.setRateLimit(20);
when(mock.getConsumerToken(any())).thenReturn(someConsumerToken);
return mock;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.ctrip.framework.apollo.openapi.util.ConsumerAuditUtil;
import com.ctrip.framework.apollo.openapi.util.ConsumerAuthUtil;

import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -61,8 +60,6 @@ public class ConsumerAuthenticationFilterTest {
private ConsumerAuthUtil consumerAuthUtil;
@Mock
private ConsumerAuditUtil consumerAuditUtil;
@Mock
private PortalConfig portalConfig;

@Mock
private HttpServletRequest request;
Expand All @@ -73,7 +70,7 @@ public class ConsumerAuthenticationFilterTest {

@Before
public void setUp() throws Exception {
authenticationFilter = new ConsumerAuthenticationFilter(consumerAuthUtil, consumerAuditUtil, portalConfig);
authenticationFilter = new ConsumerAuthenticationFilter(consumerAuthUtil, consumerAuditUtil);
}

@Test
Expand Down Expand Up @@ -115,7 +112,7 @@ public void testRateLimitSuccessfully() throws Exception {
String someToken = "someToken";
Long someConsumerId = 1L;
int qps = 5;
int durationInSeconds = 10;
int durationInSeconds = 3;

setupRateLimitMocks(someToken, someConsumerId, qps);

Expand Down Expand Up @@ -145,7 +142,7 @@ public void testRateLimitPartFailure() throws Exception {
String someToken = "someToken";
Long someConsumerId = 1L;
int qps = 5;
int durationInSeconds = 10;
int durationInSeconds = 3;

setupRateLimitMocks(someToken, someConsumerId, qps);

Expand All @@ -159,10 +156,11 @@ public void testRateLimitPartFailure() throws Exception {
}
};

executeWithQps(qps + 1, task, durationInSeconds);
int realQps = qps + 10;
executeWithQps(realQps, task, durationInSeconds);

int leastTimes = qps * durationInSeconds;
int mostTimes = (qps + 1) * durationInSeconds;
int mostTimes = realQps * durationInSeconds;

verify(response, atLeastOnce()).sendError(eq(TOO_MANY_REQUESTS), anyString());

Expand All @@ -180,6 +178,7 @@ private void setupRateLimitMocks(String someToken, Long someConsumerId, int qps)
ConsumerToken someConsumerToken = new ConsumerToken();
someConsumerToken.setConsumerId(someConsumerId);
someConsumerToken.setRateLimit(qps);
someConsumerToken.setToken(someToken);

when(request.getHeader(HttpHeaders.AUTHORIZATION)).thenReturn(someToken);
when(consumerAuthUtil.getConsumerToken(someToken)).thenReturn(someConsumerToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.client.HttpClientErrorException;
import static org.hamcrest.Matchers.containsString;
Expand All @@ -37,10 +34,6 @@
*/
@ActiveProfiles("skipAuthorization")
public class NamespaceControllerTest extends AbstractControllerTest {

static final HttpHeaders HTTP_HEADERS_WITH_TOKEN = new HttpHeaders() {{
set(HttpHeaders.AUTHORIZATION, "test-token");
}};
@Autowired
private ConsumerPermissionValidator consumerPermissionValidator;

Expand All @@ -54,11 +47,9 @@ public void shouldFailWhenAppNamespaceNameIsInvalid() {
dto.setFormat(ConfigFileFormat.Properties.getValue());
dto.setDataChangeCreatedBy("apollo");
try {
restTemplate.exchange(
restTemplate.postForEntity(
url("/openapi/v1/apps/{appId}/appnamespaces"),
HttpMethod.POST,
new HttpEntity<>(dto, HTTP_HEADERS_WITH_TOKEN),
OpenAppNamespaceDTO.class, dto.getAppId()
dto, OpenAppNamespaceDTO.class, dto.getAppId()
);
Assert.fail("should throw");
} catch (HttpClientErrorException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void createWithCompatibility() {

Mockito.verify(consumerService, Mockito.times(1)).createConsumer(Mockito.any());
Mockito.verify(consumerService, Mockito.times(1))
.generateAndSaveConsumerToken(Mockito.any(), Mockito.any(),Mockito.any());
.generateAndSaveConsumerToken(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.verify(consumerService, Mockito.times(0))
.assignCreateApplicationRoleToConsumer(Mockito.any());
Mockito.verify(consumerService, Mockito.times(1)).getConsumerInfoByAppId(Mockito.any());
Expand Down

0 comments on commit a622f56

Please sign in to comment.