Skip to content

Commit b3486c3

Browse files
committed
added cache to user info fetcher, closes mitreid-connect#833
1 parent d338352 commit b3486c3

File tree

1 file changed

+88
-62
lines changed

1 file changed

+88
-62
lines changed

openid-connect-client/src/main/java/org/mitre/openid/connect/client/UserInfoFetcher.java

Lines changed: 88 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.io.IOException;
2020
import java.net.URI;
21+
import java.util.concurrent.ExecutionException;
22+
import java.util.concurrent.TimeUnit;
2123

2224
import org.apache.http.client.HttpClient;
2325
import org.apache.http.client.utils.URIBuilder;
@@ -37,11 +39,15 @@
3739
import org.springframework.web.client.RestTemplate;
3840

3941
import com.google.common.base.Strings;
42+
import com.google.common.cache.CacheBuilder;
43+
import com.google.common.cache.CacheLoader;
44+
import com.google.common.cache.LoadingCache;
45+
import com.google.common.util.concurrent.UncheckedExecutionException;
4046
import com.google.gson.JsonObject;
4147
import com.google.gson.JsonParser;
4248

4349
/**
44-
* Utility class to fetch userinfo from the userinfo endpoint, if available.
50+
* Utility class to fetch userinfo from the userinfo endpoint, if available. Caches the results.
4551
* @author jricher
4652
*
4753
*/
@@ -52,75 +58,95 @@ public class UserInfoFetcher {
5258
*/
5359
private static final Logger logger = LoggerFactory.getLogger(UserInfoFetcher.class);
5460

61+
private LoadingCache<PendingOIDCAuthenticationToken, UserInfo> cache;
62+
63+
public UserInfoFetcher() {
64+
cache = CacheBuilder.newBuilder()
65+
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
66+
.maximumSize(100)
67+
.build(new UserInfoLoader());
68+
}
69+
5570
public UserInfo loadUserInfo(final PendingOIDCAuthenticationToken token) {
56-
57-
ServerConfiguration serverConfiguration = token.getServerConfiguration();
58-
59-
if (serverConfiguration == null) {
60-
logger.warn("No server configuration found.");
61-
return null;
62-
}
63-
64-
if (Strings.isNullOrEmpty(serverConfiguration.getUserInfoUri())) {
65-
logger.warn("No userinfo endpoint, not fetching.");
71+
try {
72+
return cache.get(token);
73+
} catch (UncheckedExecutionException | ExecutionException e) {
74+
logger.warn("Couldn't load User Info from token: " + e.getMessage());
6675
return null;
6776
}
6877

69-
try {
70-
71-
// if we got this far, try to actually get the userinfo
72-
HttpClient httpClient = HttpClientBuilder.create()
73-
.useSystemProperties()
74-
.build();
75-
76-
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
77-
78-
String userInfoString = null;
79-
80-
if (serverConfiguration.getUserInfoTokenMethod() == null || serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.HEADER)) {
81-
RestTemplate restTemplate = new RestTemplate(factory) {
82-
83-
@Override
84-
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
85-
ClientHttpRequest httpRequest = super.createRequest(url, method);
86-
httpRequest.getHeaders().add("Authorization", String.format("Bearer %s", token.getAccessTokenValue()));
87-
return httpRequest;
88-
}
89-
};
90-
91-
userInfoString = restTemplate.getForObject(serverConfiguration.getUserInfoUri(), String.class);
92-
93-
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.FORM)) {
94-
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
95-
form.add("access_token", token.getAccessTokenValue());
96-
97-
RestTemplate restTemplate = new RestTemplate(factory);
98-
userInfoString = restTemplate.postForObject(serverConfiguration.getUserInfoUri(), form, String.class);
99-
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.QUERY)) {
100-
URIBuilder builder = new URIBuilder(serverConfiguration.getUserInfoUri());
101-
builder.setParameter("access_token", token.getAccessTokenValue());
102-
103-
RestTemplate restTemplate = new RestTemplate(factory);
104-
userInfoString = restTemplate.getForObject(builder.toString(), String.class);
78+
}
79+
80+
81+
private class UserInfoLoader extends CacheLoader<PendingOIDCAuthenticationToken, UserInfo> {
82+
private HttpClient httpClient = HttpClientBuilder.create()
83+
.useSystemProperties()
84+
.build();
85+
private HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
86+
87+
public UserInfo load(final PendingOIDCAuthenticationToken token) {
88+
89+
ServerConfiguration serverConfiguration = token.getServerConfiguration();
90+
91+
if (serverConfiguration == null) {
92+
logger.warn("No server configuration found.");
93+
return null;
10594
}
106-
107-
108-
if (!Strings.isNullOrEmpty(userInfoString)) {
109-
110-
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
111-
112-
UserInfo userInfo = fromJson(userInfoJson);
113-
114-
return userInfo;
115-
} else {
116-
// didn't get anything, return null
95+
96+
if (Strings.isNullOrEmpty(serverConfiguration.getUserInfoUri())) {
97+
logger.warn("No userinfo endpoint, not fetching.");
11798
return null;
11899
}
119-
} catch (Exception e) {
120-
logger.warn("Error fetching userinfo", e);
121-
return null;
100+
101+
try {
102+
103+
String userInfoString = null;
104+
105+
if (serverConfiguration.getUserInfoTokenMethod() == null || serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.HEADER)) {
106+
RestTemplate restTemplate = new RestTemplate(factory) {
107+
108+
@Override
109+
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
110+
ClientHttpRequest httpRequest = super.createRequest(url, method);
111+
httpRequest.getHeaders().add("Authorization", String.format("Bearer %s", token.getAccessTokenValue()));
112+
return httpRequest;
113+
}
114+
};
115+
116+
userInfoString = restTemplate.getForObject(serverConfiguration.getUserInfoUri(), String.class);
117+
118+
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.FORM)) {
119+
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
120+
form.add("access_token", token.getAccessTokenValue());
121+
122+
RestTemplate restTemplate = new RestTemplate(factory);
123+
userInfoString = restTemplate.postForObject(serverConfiguration.getUserInfoUri(), form, String.class);
124+
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.QUERY)) {
125+
URIBuilder builder = new URIBuilder(serverConfiguration.getUserInfoUri());
126+
builder.setParameter("access_token", token.getAccessTokenValue());
127+
128+
RestTemplate restTemplate = new RestTemplate(factory);
129+
userInfoString = restTemplate.getForObject(builder.toString(), String.class);
130+
}
131+
132+
133+
if (!Strings.isNullOrEmpty(userInfoString)) {
134+
135+
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
136+
137+
UserInfo userInfo = fromJson(userInfoJson);
138+
139+
return userInfo;
140+
} else {
141+
// didn't get anything, return null
142+
return null;
143+
}
144+
} catch (Exception e) {
145+
logger.warn("Error fetching userinfo", e);
146+
return null;
147+
}
148+
122149
}
123-
124150
}
125151

126152
protected UserInfo fromJson(JsonObject userInfoJson) {

0 commit comments

Comments
 (0)