1717
1818package org .apache .servicecomb .serviceregistry .auth ;
1919
20+ import java .net .URI ;
2021import java .util .Map ;
21- import java .util .Objects ;
22- import java .util .Optional ;
2322import java .util .concurrent .ExecutorService ;
2423import java .util .concurrent .Executors ;
2524import java .util .concurrent .TimeUnit ;
2827
2928import org .apache .commons .lang3 .StringUtils ;
3029import 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 ;
3331import org .apache .servicecomb .registry .api .event .ServiceCenterEventBus ;
3432import org .apache .servicecomb .service .center .client .ServiceCenterClient ;
3533import org .apache .servicecomb .service .center .client .model .RbacTokenRequest ;
3634import org .apache .servicecomb .service .center .client .model .RbacTokenResponse ;
37- import org .apache .servicecomb .serviceregistry .event .NotPermittedEvent ;
3835import org .slf4j .Logger ;
3936import 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
0 commit comments