6969/* needs to be larger than a few characters for cache compression to work... */
7070#define OIDC_REFRESH_LOCK_VALUE "needstobelargerthanafewcharacters"
7171
72+ /* needs to be larger than a few characters for cache compression to work... */
73+ #define OIDC_REFRESH_FAILED_LOCK_VALUE "alsoneedstobelargerthanafewcharactersbutdifferent"
74+
7275/*
7376 * cache refresh token grant results for a while to avoid (almost) parallel requests
7477 */
@@ -103,16 +106,23 @@ static void oidc_refresh_token_cache_set(request_rec *r, oidc_cfg_t *c, const ch
103106 json_decref (json );
104107}
105108
109+ typedef enum {
110+ OIDC_REFRESH_CACHE_SUCCESS ,
111+ OIDC_REFRESH_CACHE_ERROR ,
112+ OIDC_REFRESH_CACHE_ABORT
113+ } oidc_refresh_token_cache_result_t ;
106114/*
107115 * obtain recent refresh token grant results from the cache
108116 */
109- static apr_byte_t oidc_refresh_token_cache_get (request_rec * r , oidc_cfg_t * c , const char * refresh_token ,
110- char * * s_access_token , char * * s_token_type , int * expires_in ,
111- char * * s_id_token , char * * s_refresh_token , apr_time_t * ts ) {
117+ static oidc_refresh_token_cache_result_t oidc_refresh_token_cache_get (request_rec * r , oidc_cfg_t * c ,
118+ const char * refresh_token , char * * s_access_token ,
119+ char * * s_token_type , int * expires_in ,
120+ char * * s_id_token , char * * s_refresh_token ,
121+ apr_time_t * ts ) {
112122
113123 char * s_json = NULL ;
114124 json_t * json = NULL , * v = NULL ;
115- apr_byte_t rv = FALSE ;
125+ oidc_refresh_token_cache_result_t rv = OIDC_REFRESH_CACHE_ERROR ;
116126
117127 oidc_cache_mutex_lock (r -> pool , r -> server , oidc_cfg_refresh_mutex_get (c ));
118128
@@ -130,9 +140,20 @@ static apr_byte_t oidc_refresh_token_cache_get(request_rec *r, oidc_cfg_t *c, co
130140 oidc_cache_get_refresh_token (r , refresh_token , & s_json );
131141 }
132142
143+ if (s_json == NULL )
144+ goto no_cache_found ;
145+
146+ /* check if we have run into an error */
147+ if (_oidc_strcmp (s_json , OIDC_REFRESH_FAILED_LOCK_VALUE ) == 0 ) {
148+ oidc_debug (r , "refresh token %s failed to refresh before, do not try to refresh it again but fail" ,
149+ refresh_token );
150+ rv = OIDC_REFRESH_CACHE_ABORT ;
151+ goto end ;
152+ }
153+
133154 /* check if we have run into a timeout */
134- if (( s_json == NULL ) || ( _oidc_strcmp (s_json , OIDC_REFRESH_LOCK_VALUE ) == 0 ) ) {
135- oidc_warn (r , "timeout waiting for refresh grant cache results" );
155+ if (_oidc_strcmp (s_json , OIDC_REFRESH_LOCK_VALUE ) == 0 ) {
156+ oidc_warn (r , "timeout waiting for refresh token %s cache to unlock" , refresh_token );
136157 // TODO: now we are going to refresh ourselves with a refresh token that has already been
137158 // tried before; that is not great in rolling refresh token setups but I guess we have no
138159 // other choice anyhow...
@@ -162,7 +183,7 @@ static apr_byte_t oidc_refresh_token_cache_get(request_rec *r, oidc_cfg_t *c, co
162183 /* cleanup */
163184 json_decref (json );
164185
165- rv = TRUE ;
186+ rv = OIDC_REFRESH_CACHE_SUCCESS ;
166187
167188 goto end ;
168189
@@ -207,6 +228,7 @@ apr_byte_t oidc_refresh_token_grant(request_rec *r, oidc_cfg_t *c, oidc_session_
207228 oidc_jose_error_t err ;
208229 const char * refresh_token = NULL ;
209230 apr_time_t ts = 0 ;
231+ oidc_refresh_token_cache_result_t rv = OIDC_REFRESH_CACHE_ERROR ;
210232
211233 oidc_debug (r , "enter" );
212234
@@ -218,9 +240,13 @@ apr_byte_t oidc_refresh_token_grant(request_rec *r, oidc_cfg_t *c, oidc_session_
218240 }
219241
220242 /* see if it was refreshed very recently and we can re-use the results from the cache */
221- if (oidc_refresh_token_cache_get (r , c , refresh_token , & s_access_token , & s_token_type , & expires_in , & s_id_token ,
222- & s_refresh_token , & ts ) == TRUE)
243+ rv = oidc_refresh_token_cache_get (r , c , refresh_token , & s_access_token , & s_token_type , & expires_in , & s_id_token ,
244+ & s_refresh_token , & ts );
245+ if (rv == OIDC_REFRESH_CACHE_SUCCESS )
223246 goto process ;
247+ if (rv == OIDC_REFRESH_CACHE_ABORT )
248+ /* a prior refresh of the access token failed and we won't try the same again */
249+ goto end ;
224250
225251 oidc_debug (r , "refreshing refresh_token: %s" , refresh_token );
226252
@@ -231,6 +257,10 @@ apr_byte_t oidc_refresh_token_grant(request_rec *r, oidc_cfg_t *c, oidc_session_
231257 & expires_in , & s_refresh_token , & s_scope ) == FALSE) {
232258 OIDC_METRICS_COUNTER_INC (r , c , OM_PROVIDER_REFRESH_ERROR );
233259 oidc_error (r , "access_token could not be refreshed with refresh_token: %s" , refresh_token );
260+ /* release the refresh lock and indicate this refresh token should not be refreshed anymore for at least
261+ * 30 seconds */
262+ oidc_cache_set_refresh_token (r , refresh_token , OIDC_REFRESH_FAILED_LOCK_VALUE ,
263+ apr_time_now () + apr_time_from_sec (OIDC_REFRESH_CACHE_TTL ));
234264 goto end ;
235265 }
236266
0 commit comments