Skip to content

Commit 698fe55

Browse files
author
Stephen Moore
committed
IntrospectingTokenService now takes parameters (cacheTokens, cacheNonExpiringTokens, defaultExpireTime, forceCacheExpireTime) to change the behavior or even disable the caching of responses from the IntrospectionEndpoint.
1 parent 286d433 commit 698fe55

File tree

1 file changed

+57
-29
lines changed

1 file changed

+57
-29
lines changed

openid-connect-client/src/main/java/org/mitre/oauth2/introspectingfilter/IntrospectingTokenService.java

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.net.URI;
2121
import java.util.Date;
22+
import java.util.Calendar;
2223
import java.util.HashMap;
2324
import java.util.HashSet;
2425
import java.util.Map;
@@ -67,6 +68,11 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
6768
private IntrospectionConfigurationService introspectionConfigurationService;
6869
private IntrospectionAuthorityGranter introspectionAuthorityGranter = new SimpleIntrospectionAuthorityGranter();
6970

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+
7076
private HttpClient httpClient = HttpClientBuilder.create()
7177
.useSystemProperties()
7278
.build();
@@ -76,10 +82,22 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
7682
private class TokenCacheObject {
7783
OAuth2AccessToken token;
7884
OAuth2Authentication auth;
79-
85+
Date cacheExpire;
86+
8087
private TokenCacheObject(OAuth2AccessToken token, OAuth2Authentication auth) {
8188
this.token = token;
8289
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+
}
83101
}
84102
}
85103

@@ -117,13 +135,29 @@ public IntrospectionAuthorityGranter getIntrospectionAuthorityGranter() {
117135
return introspectionAuthorityGranter;
118136
}
119137

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+
120154
// Check if there is a token and authentication in the cache
121155
// and check if it is not expired.
122156
private TokenCacheObject checkCache(String key) {
123-
if (authCache.containsKey(key)) {
157+
if (cacheTokens && authCache.containsKey(key)) {
124158
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())) {
127161
return tco;
128162
} else {
129163
// if the token is expired, don't keep things around.
@@ -156,9 +190,9 @@ private OAuth2AccessToken createAccessToken(final JsonObject token, final String
156190
}
157191

158192
// 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) {
162196

163197
// find out which URL to ask
164198
String introspectionUrl;
@@ -168,7 +202,7 @@ private boolean parseToken(String accessToken) {
168202
client = introspectionConfigurationService.getClientConfiguration(accessToken);
169203
} catch (IllegalArgumentException e) {
170204
logger.error("Unable to load introspection URL or client configuration", e);
171-
return false;
205+
return null;
172206
}
173207
// Use the SpringFramework RestTemplate to send the request to the
174208
// endpoint
@@ -210,21 +244,21 @@ protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOE
210244
// parse the json
211245
JsonElement jsonRoot = new JsonParser().parse(validatedToken);
212246
if (!jsonRoot.isJsonObject()) {
213-
return false; // didn't get a proper JSON object
247+
return null; // didn't get a proper JSON object
214248
}
215249

216250
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
217251

218252
if (tokenResponse.get("error") != null) {
219253
// report an error?
220254
logger.error("Got an error back: " + tokenResponse.get("error") + ", " + tokenResponse.get("error_description"));
221-
return false;
255+
return null;
222256
}
223257

224258
if (!tokenResponse.get("active").getAsBoolean()) {
225259
// non-valid token
226260
logger.info("Server returned non-active token");
227-
return false;
261+
return null;
228262
}
229263
// create an OAuth2Authentication
230264
OAuth2Authentication auth = new OAuth2Authentication(createStoredRequest(tokenResponse), createAuthentication(tokenResponse));
@@ -233,14 +267,16 @@ protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOE
233267

234268
if (token.getExpiration() == null || token.getExpiration().after(new Date())) {
235269
// 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;
239275
}
240276
}
241277

242278
// If we never put a token and an authentication in the cache...
243-
return false;
279+
return null;
244280
}
245281

246282
@Override
@@ -252,13 +288,9 @@ public OAuth2Authentication loadAuthentication(String accessToken) throws Authen
252288
if (cacheAuth != null) {
253289
return cacheAuth.auth;
254290
} 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;
262294
} else {
263295
return null;
264296
}
@@ -274,13 +306,9 @@ public OAuth2AccessToken readAccessToken(String accessToken) {
274306
if (cacheAuth != null) {
275307
return cacheAuth.token;
276308
} 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;
284312
} else {
285313
return null;
286314
}

0 commit comments

Comments
 (0)