Skip to content

Commit bbe9fd0

Browse files
committed
chassis supports RBAC authentication
1 parent d6fa1d8 commit bbe9fd0

5 files changed

Lines changed: 73 additions & 61 deletions

File tree

clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,16 @@ public void compareAndGetAddressTest() {
313313
Assertions.assertTrue(manager.compareAndGetAddress("192.168.20.16").isEmpty());
314314
Assertions.assertEquals("https://192.168.20.160:30100", manager.compareAndGetAddress("192.168.20.160"));
315315
}
316+
317+
@Test
318+
public void AddressAffinityTest() {
319+
List<String> testAddr = new ArrayList<>();
320+
testAddr.add("https://192.168.20.160:30100?region=region1&availableZone=zone1");
321+
testAddr.add("https://127.0.0.1:30100");
322+
AbstractAddressManager manager = new AbstractAddressManager(testAddr, "region1", "zone1");
323+
Assertions.assertEquals("https://192.168.20.160:30100", manager.address());
324+
325+
AbstractAddressManager manager2 = new AbstractAddressManager("default", testAddr, "region1", "zone1");
326+
Assertions.assertEquals("https://192.168.20.160:30100", manager2.address());
327+
}
316328
}

foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
public interface AuthHeaderProvider {
2424
/**
25-
* Obtain RBAC authentication request header, host is the key of cache, spring-cloud module have specific usage of host
25+
* Obtain RBAC authentication request header, host is the key of cache
2626
*
2727
* @param host engine address ip
2828
* @return auth headers

service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/auth/TokenAuthHeaderProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
public class TokenAuthHeaderProvider implements AuthHeaderProvider {
2828
@Override
2929
public Map<String, String> authHeaders(String host) {
30-
String token = TokenCacheManager.getInstance().getToken(RBACBootStrapService.DEFAULT_REGISTRY_NAME);
30+
String token = TokenCacheManager.getInstance().getToken(host);
3131
if (StringUtils.isEmpty(token)) {
3232
return new HashMap<>();
3333
}

service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/auth/TokenCacheManager.java

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717

1818
package org.apache.servicecomb.serviceregistry.auth;
1919

20+
import java.net.URI;
2021
import java.util.Map;
21-
import java.util.Objects;
22-
import java.util.Optional;
2322
import java.util.concurrent.ExecutorService;
2423
import java.util.concurrent.Executors;
2524
import java.util.concurrent.TimeUnit;
@@ -28,13 +27,11 @@
2827

2928
import org.apache.commons.lang3.StringUtils;
3029
import org.apache.servicecomb.foundation.auth.Cipher;
31-
import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
32-
import org.apache.servicecomb.http.client.event.EngineConnectChangedEvent;
30+
import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
3331
import org.apache.servicecomb.registry.api.event.ServiceCenterEventBus;
3432
import org.apache.servicecomb.service.center.client.ServiceCenterClient;
3533
import org.apache.servicecomb.service.center.client.model.RbacTokenRequest;
3634
import org.apache.servicecomb.service.center.client.model.RbacTokenResponse;
37-
import org.apache.servicecomb.serviceregistry.event.NotPermittedEvent;
3835
import org.slf4j.Logger;
3936
import org.slf4j.LoggerFactory;
4037

@@ -55,42 +52,35 @@ public final class TokenCacheManager {
5552

5653
private static final TokenCacheManager INSTANCE = new TokenCacheManager();
5754

55+
private Map<String, ServiceCenterClient> serviceCenterClients;
5856

59-
private final Map<String, TokenCache> tokenCacheMap;
57+
private TokenCache tokenCache;
6058

61-
private Map<String, ServiceCenterClient> serviceCenterClients;
59+
private static final Object LOCK = new Object();
6260

6361
public static TokenCacheManager getInstance() {
6462
return INSTANCE;
6563
}
6664

6765
private TokenCacheManager() {
68-
tokenCacheMap = new ConcurrentHashMapEx<>();
6966
}
7067

7168
public void setServiceCenterClients(Map<String, ServiceCenterClient> serviceCenterClients) {
7269
this.serviceCenterClients = serviceCenterClients;
7370
}
7471

7572
public void addTokenCache(String registryName, String accountName, String password, Cipher cipher) {
76-
Objects.requireNonNull(registryName, "registryName should not be null!");
77-
if (tokenCacheMap.containsKey(registryName)) {
78-
LOGGER.warn("duplicate token cache registration for serviceRegistry[{}]", registryName);
79-
return;
80-
}
81-
82-
tokenCacheMap.put(registryName, new TokenCache(registryName, accountName, password, cipher));
73+
tokenCache = new TokenCache(registryName, accountName, password, cipher);
8374
}
8475

85-
public String getToken(String registryName) {
86-
return Optional.ofNullable(tokenCacheMap.get(registryName))
87-
.map(TokenCache::getToken)
88-
.orElse(null);
76+
public String getToken(String host) {
77+
if (tokenCache == null) {
78+
return null;
79+
}
80+
return tokenCache.getToken(host);
8981
}
9082

9183
public class TokenCache {
92-
private static final String UN_AUTHORIZED_CODE_HALF_OPEN = "401302";
93-
9484
private static final long TOKEN_REFRESH_TIME_IN_SECONDS = 20 * 60 * 1000;
9585

9686
private final String registryName;
@@ -105,10 +95,6 @@ public class TokenCache {
10595

10696
private final Cipher cipher;
10797

108-
private int lastStatusCode;
109-
110-
private String lastErrorCode;
111-
11298
public TokenCache(String registryName, String accountName, String password,
11399
Cipher cipher) {
114100
this.registryName = registryName;
@@ -133,47 +119,41 @@ public void run() {
133119
.build(new CacheLoader<String, String>() {
134120
@Override
135121
public String load(String key) throws Exception {
136-
return createHeaders();
122+
return createHeaders(key);
137123
}
138124

139125
@Override
140126
public ListenableFuture<String> reload(String key, String oldValue) throws Exception {
141-
return Futures.submit(() -> createHeaders(), executorService);
127+
return Futures.submit(() -> createHeaders(key), executorService);
142128
}
143129
});
144130
ServiceCenterEventBus.getEventBus().register(this);
145131
}
146132
}
147133

148134
@Subscribe
149-
public void onNotPermittedEvent(NotPermittedEvent event) {
150-
this.executorService.submit(() -> {
151-
if (lastStatusCode == Status.UNAUTHORIZED.getStatusCode() && UN_AUTHORIZED_CODE_HALF_OPEN
152-
.equals(lastErrorCode)) {
153-
cache.refresh(registryName);
154-
}
155-
});
135+
public void onUnAuthorizedOperationEvent(UnAuthorizedOperationEvent event) {
136+
LOGGER.warn("address {} unAuthorized, refresh cache token!", event.getAddress());
137+
cache.refresh(getHostByAddress(event.getAddress()));
156138
}
157139

158-
@Subscribe
159-
public void onEngineConnectChangedEvent(EngineConnectChangedEvent event) {
160-
cache.refresh(registryName);
140+
private String getHostByAddress(String address) {
141+
try {
142+
URI uri = URI.create(address);
143+
return uri.getHost();
144+
} catch (Exception e) {
145+
LOGGER.error("get host by address [{}] error!", address, e);
146+
return registryName;
147+
}
161148
}
162149

163-
private String createHeaders() {
164-
LOGGER.info("start to create RBAC headers");
165-
150+
private String createHeaders(String host) {
151+
LOGGER.info("start to create RBAC headers for host: {}", host);
166152
ServiceCenterClient serviceCenterClient = serviceCenterClients.get(this.registryName);
167-
168153
RbacTokenRequest request = new RbacTokenRequest();
169154
request.setName(accountName);
170155
request.setPassword(new String(cipher.decrypt(password.toCharArray())));
171-
172156
RbacTokenResponse rbacTokenResponse = serviceCenterClient.queryToken(request, "");
173-
174-
this.lastStatusCode = rbacTokenResponse.getStatusCode();
175-
this.lastErrorCode = rbacTokenResponse.getErrorCode();
176-
177157
if (Status.UNAUTHORIZED.getStatusCode() == rbacTokenResponse.getStatusCode()
178158
|| Status.FORBIDDEN.getStatusCode() == rbacTokenResponse.getStatusCode()) {
179159
// password wrong, do not try anymore
@@ -185,25 +165,36 @@ private String createHeaders() {
185165
LOGGER.warn("service center do not support RBAC token, you should not config account info");
186166
return INVALID_TOKEN;
187167
}
168+
if (Status.INTERNAL_SERVER_ERROR.getStatusCode() == rbacTokenResponse.getStatusCode()) {
169+
// return null for server_error, so the token information can be re-fetched on the next call.
170+
// It will prompt 'CacheLoader returned null for key xxx'
171+
LOGGER.warn("service center query RBAC token error!");
172+
return null;
173+
}
188174

189-
LOGGER.info("refresh token successfully {}", rbacTokenResponse.getStatusCode());
175+
LOGGER.info("refresh host [{}] token successfully {}", host, rbacTokenResponse.getStatusCode());
190176
return rbacTokenResponse.getToken();
191177
}
192178

193179
protected long refreshTime() {
194180
return TOKEN_REFRESH_TIME_IN_SECONDS;
195181
}
196182

197-
public String getToken() {
183+
public String getToken(String host) {
198184
if (!enabled()) {
199185
return null;
200186
}
201-
202-
try {
203-
return cache.get(registryName);
204-
} catch (Exception e) {
205-
LOGGER.error("failed to create token", e);
206-
return null;
187+
String address = host;
188+
if (StringUtils.isEmpty(address)) {
189+
address = registryName;
190+
}
191+
synchronized (LOCK) {
192+
try {
193+
return cache.get(address);
194+
} catch (Exception e) {
195+
LOGGER.error("failed to create token", e);
196+
return null;
197+
}
207198
}
208199
}
209200

service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.servicecomb.foundation.common.net.IpPort;
3636
import org.apache.servicecomb.foundation.common.utils.JsonUtils;
3737
import org.apache.servicecomb.foundation.vertx.AsyncResultCallback;
38+
import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
3839
import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
3940
import org.apache.servicecomb.registry.api.event.MicroserviceInstanceChangedEvent;
4041
import org.apache.servicecomb.registry.api.registry.FindInstancesResponse;
@@ -152,7 +153,7 @@ public <T> Handler<RestResponse> syncHandler(CountDownLatch countDownLatch, Clas
152153
return;
153154
}
154155
holder.setStatusCode(response.statusCode());
155-
sendUnAuthorizedEvent(response);
156+
sendUnAuthorizedEvent(response, requestContext);
156157
response.exceptionHandler(e -> {
157158
LOGGER.error("error in processing response.", e);
158159
countDownLatch.countDown();
@@ -232,7 +233,7 @@ private Handler<RestResponse> syncHandlerEx(CountDownLatch countDownLatch, Holde
232233

233234
return;
234235
}
235-
sendUnAuthorizedEvent(response);
236+
sendUnAuthorizedEvent(response, requestContext);
236237
response.exceptionHandler(e -> {
237238
LOGGER.error("error in processing response.", e);
238239
countDownLatch.countDown();
@@ -247,12 +248,20 @@ private Handler<RestResponse> syncHandlerEx(CountDownLatch countDownLatch, Holde
247248
};
248249
}
249250

250-
private void sendUnAuthorizedEvent(HttpClientResponse response) {
251+
private void sendUnAuthorizedEvent(HttpClientResponse response, RequestContext requestContext) {
251252
if (response.statusCode() == Status.UNAUTHORIZED.getStatusCode()) {
252-
ServiceCenterEventBus.getEventBus().post(new NotPermittedEvent());
253+
ServiceCenterEventBus.getEventBus().post(new UnAuthorizedOperationEvent(getAddressWithProtocol(requestContext)));
253254
}
254255
}
255256

257+
private String getAddressWithProtocol(RequestContext requestContext) {
258+
String ipAndPort = requestContext.getIpPort().toString();
259+
if (ipAndPort.startsWith("http")) {
260+
return ipAndPort;
261+
}
262+
return "https://" + ipAndPort;
263+
}
264+
256265
private Handler<RestResponse> syncHandlerForInstances(CountDownLatch countDownLatch,
257266
MicroserviceInstances mInstances) {
258267
return restResponse -> {
@@ -1007,7 +1016,7 @@ public <T> Handler<RestResponse> addressSyncHandler(CountDownLatch countDownLatc
10071016
return;
10081017
}
10091018
holder.setStatusCode(response.statusCode());
1010-
sendUnAuthorizedEvent(response);
1019+
sendUnAuthorizedEvent(response, restResponse.getRequestContext());
10111020
countDownLatch.countDown();
10121021
};
10131022
}

0 commit comments

Comments
 (0)