19
19
import java .io .IOException ;
20
20
import java .net .URI ;
21
21
import java .util .Date ;
22
+ import java .util .Calendar ;
22
23
import java .util .HashMap ;
23
24
import java .util .HashSet ;
24
25
import java .util .Map ;
@@ -67,6 +68,11 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
67
68
private IntrospectionConfigurationService introspectionConfigurationService ;
68
69
private IntrospectionAuthorityGranter introspectionAuthorityGranter = new SimpleIntrospectionAuthorityGranter ();
69
70
71
+ private int defaultExpireTime = 300000 ; // 5 minutes in milliseconds
72
+ private boolean forceCacheExpireTime = false ; // force removal of cached tokens based on default expire time
73
+ private boolean cacheNonExpiringTokens = false ;
74
+ private boolean cacheTokens = true ;
75
+
70
76
private HttpClient httpClient = HttpClientBuilder .create ()
71
77
.useSystemProperties ()
72
78
.build ();
@@ -76,10 +82,22 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
76
82
private class TokenCacheObject {
77
83
OAuth2AccessToken token ;
78
84
OAuth2Authentication auth ;
79
-
85
+ Date cacheExpire ;
86
+
80
87
private TokenCacheObject (OAuth2AccessToken token , OAuth2Authentication auth ) {
81
88
this .token = token ;
82
89
this .auth = auth ;
90
+
91
+
92
+ // if the token doesn't have an expire time, use the default expire time
93
+ // also use the default expire time if the token is valid for longer than that time (i.e. force a check of the token, if force check is valid)
94
+ if (this .token .getExpiration () != null || (forceCacheExpireTime && (this .token .getExpiration ().getTime () - System .currentTimeMillis () <= defaultExpireTime ))) {
95
+ this .cacheExpire = this .token .getExpiration ();
96
+ } else {
97
+ Calendar cal = Calendar .getInstance ();
98
+ cal .add (Calendar .MILLISECOND , defaultExpireTime );
99
+ this .cacheExpire = cal .getTime ();
100
+ }
83
101
}
84
102
}
85
103
@@ -117,13 +135,29 @@ public IntrospectionAuthorityGranter getIntrospectionAuthorityGranter() {
117
135
return introspectionAuthorityGranter ;
118
136
}
119
137
138
+ /**
139
+ * get the default cache expire time in milliseconds
140
+ * @return
141
+ */
142
+ public int getDefaultExpireTime () {
143
+ return defaultExpireTime ;
144
+ }
145
+
146
+ /**
147
+ * set the default cache expire time in milliseconds
148
+ * @param defaultExpireTime
149
+ */
150
+ public void setDefaultExpireTime (int defaultExpireTime ) {
151
+ this .defaultExpireTime = defaultExpireTime ;
152
+ }
153
+
120
154
// Check if there is a token and authentication in the cache
121
155
// and check if it is not expired.
122
156
private TokenCacheObject checkCache (String key ) {
123
- if (authCache .containsKey (key )) {
157
+ if (cacheTokens && authCache .containsKey (key )) {
124
158
TokenCacheObject tco = authCache .get (key );
125
- // for this introspection service, null expiration means tokens don't expire
126
- if (tco . token . getExpiration () == null || tco .token . getExpiration () .after (new Date ())) {
159
+
160
+ if (tco != null && tco . cacheExpire != null && tco .cacheExpire .after (new Date ())) {
127
161
return tco ;
128
162
} else {
129
163
// if the token is expired, don't keep things around.
@@ -156,9 +190,9 @@ private OAuth2AccessToken createAccessToken(final JsonObject token, final String
156
190
}
157
191
158
192
// Validate a token string against the introspection endpoint,
159
- // then parse it and store it in the local cache. Return true on
160
- // success, false otherwise.
161
- private boolean parseToken (String accessToken ) {
193
+ // then parse it and store it in the local cache. Return TokenCacheObject
194
+ // if token is valid, otherwise return null
195
+ private TokenCacheObject parseToken (String accessToken ) {
162
196
163
197
// find out which URL to ask
164
198
String introspectionUrl ;
@@ -168,7 +202,7 @@ private boolean parseToken(String accessToken) {
168
202
client = introspectionConfigurationService .getClientConfiguration (accessToken );
169
203
} catch (IllegalArgumentException e ) {
170
204
logger .error ("Unable to load introspection URL or client configuration" , e );
171
- return false ;
205
+ return null ;
172
206
}
173
207
// Use the SpringFramework RestTemplate to send the request to the
174
208
// endpoint
@@ -210,21 +244,21 @@ protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOE
210
244
// parse the json
211
245
JsonElement jsonRoot = new JsonParser ().parse (validatedToken );
212
246
if (!jsonRoot .isJsonObject ()) {
213
- return false ; // didn't get a proper JSON object
247
+ return null ; // didn't get a proper JSON object
214
248
}
215
249
216
250
JsonObject tokenResponse = jsonRoot .getAsJsonObject ();
217
251
218
252
if (tokenResponse .get ("error" ) != null ) {
219
253
// report an error?
220
254
logger .error ("Got an error back: " + tokenResponse .get ("error" ) + ", " + tokenResponse .get ("error_description" ));
221
- return false ;
255
+ return null ;
222
256
}
223
257
224
258
if (!tokenResponse .get ("active" ).getAsBoolean ()) {
225
259
// non-valid token
226
260
logger .info ("Server returned non-active token" );
227
- return false ;
261
+ return null ;
228
262
}
229
263
// create an OAuth2Authentication
230
264
OAuth2Authentication auth = new OAuth2Authentication (createStoredRequest (tokenResponse ), createAuthentication (tokenResponse ));
@@ -233,14 +267,16 @@ protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOE
233
267
234
268
if (token .getExpiration () == null || token .getExpiration ().after (new Date ())) {
235
269
// Store them in the cache
236
- authCache .put (accessToken , new TokenCacheObject (token , auth ));
237
-
238
- return true ;
270
+ TokenCacheObject tco = new TokenCacheObject (token , auth );
271
+ if (cacheTokens && (cacheNonExpiringTokens || token .getExpiration () != null )) {
272
+ authCache .put (accessToken , tco );
273
+ }
274
+ return tco ;
239
275
}
240
276
}
241
277
242
278
// If we never put a token and an authentication in the cache...
243
- return false ;
279
+ return null ;
244
280
}
245
281
246
282
@ Override
@@ -252,13 +288,9 @@ public OAuth2Authentication loadAuthentication(String accessToken) throws Authen
252
288
if (cacheAuth != null ) {
253
289
return cacheAuth .auth ;
254
290
} else {
255
- if (parseToken (accessToken )) {
256
- cacheAuth = authCache .get (accessToken );
257
- if (cacheAuth != null && (cacheAuth .token .getExpiration () == null || cacheAuth .token .getExpiration ().after (new Date ()))) {
258
- return cacheAuth .auth ;
259
- } else {
260
- return null ;
261
- }
291
+ cacheAuth = parseToken (accessToken );
292
+ if (cacheAuth != null ) {
293
+ return cacheAuth .auth ;
262
294
} else {
263
295
return null ;
264
296
}
@@ -274,13 +306,9 @@ public OAuth2AccessToken readAccessToken(String accessToken) {
274
306
if (cacheAuth != null ) {
275
307
return cacheAuth .token ;
276
308
} else {
277
- if (parseToken (accessToken )) {
278
- cacheAuth = authCache .get (accessToken );
279
- if (cacheAuth != null && (cacheAuth .token .getExpiration () == null || cacheAuth .token .getExpiration ().after (new Date ()))) {
280
- return cacheAuth .token ;
281
- } else {
282
- return null ;
283
- }
309
+ cacheAuth = parseToken (accessToken );
310
+ if (cacheAuth != null ) {
311
+ return cacheAuth .token ;
284
312
} else {
285
313
return null ;
286
314
}
0 commit comments