added dynamic discovery to client
parent
33af3b1ad6
commit
f76f44b999
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.mitre.openid.connect.client.service.ServerConfigurationService;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
*
|
||||
* Dynamically fetches OpenID Connect server configurations based on the issuer. Caches the server configurations.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class DynamicServerConfigurationService implements ServerConfigurationService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||
|
||||
// map of issuer -> server configuration, loaded dynamically from service discovery
|
||||
private LoadingCache<String, ServerConfiguration> servers;
|
||||
|
||||
public DynamicServerConfigurationService() {
|
||||
// initialize the cache
|
||||
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerConfiguration getServerConfiguration(String issuer) {
|
||||
try {
|
||||
return servers.get(issuer);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load configuration for " + issuer, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
|
||||
@Override
|
||||
public ServerConfiguration load(String issuer) throws Exception {
|
||||
|
||||
// data holder
|
||||
ServerConfiguration conf = new ServerConfiguration();
|
||||
|
||||
// construct the well-known URI
|
||||
String url = issuer + "/.well-known/openid-configuration";
|
||||
|
||||
// fetch the value
|
||||
String jsonString = restTemplate.getForObject(url, String.class);
|
||||
|
||||
JsonElement parsed = new JsonParser().parse(jsonString);
|
||||
if (parsed.isJsonObject()) {
|
||||
|
||||
JsonObject o = parsed.getAsJsonObject();
|
||||
|
||||
// sanity checks
|
||||
if (!issuer.equals(o.get("issuer").getAsString())) {
|
||||
throw new IllegalStateException("Discovered issuers didn't match, expected " + issuer + " got " + o.get("issuer").getAsString());
|
||||
}
|
||||
|
||||
conf.setIssuer(o.get("issuer").getAsString());
|
||||
conf.setAuthorizationEndpointUri(o.get("authorization_endpoint").getAsString());
|
||||
conf.setTokenEndpointUri(o.get("token_endpoint").getAsString());
|
||||
conf.setJwksUri(o.get("jwks_uri").getAsString());
|
||||
conf.setUserInfoUri(o.get("userinfo_endpoint").getAsString());
|
||||
|
||||
return conf;
|
||||
} else {
|
||||
throw new IllegalStateException("Couldn't parse server discovery results for " + url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,8 @@ import org.apache.http.client.HttpClient;
|
|||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.mitre.jose.keystore.JWKSetKeyStore;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
@ -31,7 +33,8 @@ import com.nimbusds.jose.jwk.RSAKey;
|
|||
|
||||
/**
|
||||
*
|
||||
* Creates a
|
||||
* Creates a caching map of JOSE signers and validators keyed on the JWK Set URI.
|
||||
* Dynamically loads JWK Sets to create the signing and validation services.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
|
@ -39,6 +42,9 @@ import com.nimbusds.jose.jwk.RSAKey;
|
|||
@Service
|
||||
public class JWKSetSigningAndValidationServiceCacheService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JWKSetSigningAndValidationServiceCacheService.class);
|
||||
|
||||
// map of jwk set uri -> signing/validation service built on the keys found in that jwk set
|
||||
private LoadingCache<String, JwtSigningAndValidationService> cache;
|
||||
|
||||
public JWKSetSigningAndValidationServiceCacheService() {
|
||||
|
@ -48,17 +54,16 @@ public class JWKSetSigningAndValidationServiceCacheService {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param jwksUri
|
||||
* @return
|
||||
* @throws ExecutionException
|
||||
* @see com.google.common.cache.Cache#get(java.lang.Object)
|
||||
*/
|
||||
public JwtSigningAndValidationService get(String key) {
|
||||
public JwtSigningAndValidationService get(String jwksUri) {
|
||||
try {
|
||||
return cache.get(key);
|
||||
return cache.get(jwksUri);
|
||||
} catch (ExecutionException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue