Skip to content

Instantly share code, notes, and snippets.

@goeh
Last active May 14, 2018 07:47
Show Gist options
  • Save goeh/c7348c9fa7f9f52c3220 to your computer and use it in GitHub Desktop.
Save goeh/c7348c9fa7f9f52c3220 to your computer and use it in GitHub Desktop.
Trying to create a JWT token enhancer that work with Ribbon/Eureka service names instead of URLs, but I could not get it to work. Service not found.
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.oauth2.resource.JwtAccessTokenConverterConfigurer;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerTokenServicesConfiguration;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A JwtTokenServicesConfiguration that uses a load balanced rest template.
*/
@Configuration
@Import(ResourceServerTokenServicesConfiguration.class)
public class JwtTokenServicesConfiguration {
private static final Log logger = LogFactory.getLog(JwtTokenServicesConfiguration.class);
@Autowired
private ResourceServerProperties resource;
@Autowired(required = false)
private List<JwtAccessTokenConverterConfigurer> configurers = Collections.emptyList();
@Autowired
private LoadBalancerClient loadBalancerClient;
private RestTemplate keyUriRestTemplate = new RestTemplate();
@Bean
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
public DefaultTokenServices jwtTokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
services.setTokenStore(jwtTokenStore());
return services;
}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
@Bean
@Primary
public JwtAccessTokenConverter jwtTokenEnhancer() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
String keyValue = this.resource.getJwt().getKeyValue();
if (!StringUtils.hasText(keyValue)) {
try {
keyValue = getKeyFromServer();
} catch (Exception ex) {
logger.warn("Failed to fetch token key (you may need to refresh "
+ "when the auth server is back)", ex);
}
}
if (StringUtils.hasText(keyValue) && !keyValue.startsWith("-----BEGIN")) {
converter.setSigningKey(keyValue);
}
if (keyValue != null) {
converter.setVerifierKey(keyValue);
}
AnnotationAwareOrderComparator.sort(this.configurers);
for (JwtAccessTokenConverterConfigurer configurer : this.configurers) {
configurer.configure(converter);
}
return converter;
}
private String getKeyFromServer() {
HttpHeaders headers = new HttpHeaders();
String username = this.resource.getClientId();
String password = this.resource.getClientSecret();
if (username != null && password != null) {
byte[] token = Base64.encode((username + ":" + password).getBytes());
headers.add("Authorization", "Basic " + new String(token));
}
HttpEntity<Void> request = new HttpEntity<Void>(headers);
ServiceInstance authService = loadBalancerClient.choose("auth-server");
if(authService == null) {
throw new IllegalStateException("No auth-server instance found");
}
URI serviceUri = URI.create(this.resource.getJwt().getKeyUri());
URI url = loadBalancerClient.reconstructURI(authService, serviceUri);
return (String) this.keyUriRestTemplate.exchange(url, HttpMethod.GET, request, Map.class)
.getBody().get("value");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment