Skip to content

Commit

Permalink
Created classes to fetch OIDC metadata
Browse files Browse the repository at this point in the history
[#157639907] https://www.pivotaltracker.com/story/show/157639907

Signed-off-by: Bruce Ricard <bricard@pivotal.io>
Co-authored-by: Bruce Ricard <bricard@pivotal.io>
  • Loading branch information
Jaskanwal Pawar and bruce-ricard committed Oct 17, 2018
1 parent 715d5f5 commit 80ff310
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.cloudfoundry.identity.uaa.provider.oauth;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.net.URL;

@JsonIgnoreProperties(ignoreUnknown = true)
public class OidcMetadata {
@JsonProperty("authorization_endpoint")
private URL authorizationEndpoint;

@JsonProperty("userinfo_endpoint")
private URL userinfoEndpoint;

@JsonProperty("token_endpoint")
private URL tokenEndpoint;

@JsonProperty("jwks_uri")
private URL jsonWebKeysUri;

private String issuer;

public URL getAuthorizationEndpoint() {
return authorizationEndpoint;
}

public void setAuthorizationEndpoint(URL authorizationEndpoint) {
this.authorizationEndpoint = authorizationEndpoint;
}

public URL getUserinfoEndpoint() {
return userinfoEndpoint;
}

public void setUserinfoEndpoint(URL userinfoEndpoint) {
this.userinfoEndpoint = userinfoEndpoint;
}

public URL getTokenEndpoint() {
return tokenEndpoint;
}

public void setTokenEndpoint(URL tokenEndpoint) {
this.tokenEndpoint = tokenEndpoint;
}

public URL getJsonWebKeysUri() {
return jsonWebKeysUri;
}

public void setJsonWebKeysUri(URL jsonWebKeysUri) {
this.jsonWebKeysUri = jsonWebKeysUri;
}

public String getIssuer() {
return issuer;
}

public void setIssuer(String issuer) {
this.issuer = issuer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.cloudfoundry.identity.uaa.provider.oauth;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.cloudfoundry.identity.uaa.cache.UrlContentCache;
import org.cloudfoundry.identity.uaa.provider.OIDCIdentityProviderDefinition;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URL;

public class OidcMetadataDiscoverer {
private final UrlContentCache contentCache;
private final RestTemplate trustingRestTemplate;
private final RestTemplate nonTrustingRestTemplate;

public OidcMetadataDiscoverer(UrlContentCache contentCache,
RestTemplate trustingRestTemplate,
RestTemplate nonTrustingRestTemplate
) {
this.contentCache = contentCache;
this.trustingRestTemplate = trustingRestTemplate;
this.nonTrustingRestTemplate = nonTrustingRestTemplate;
}

public void performDiscoveryAndUpdateDefinition(OIDCIdentityProviderDefinition definition) throws IOException {
if (shouldPerformDiscovery(definition)) {
OidcMetadata oidcMetadata =
performDiscovery(definition.getDiscoveryUrl(), definition.isSkipSslValidation());

updateIdpDefinition(definition, oidcMetadata);
}
}

private OidcMetadata performDiscovery(URL discoveryUrl, boolean shouldDoSslValidation) throws IOException {
byte[] rawContents;
if (shouldDoSslValidation) {
rawContents = contentCache.getUrlContent(discoveryUrl.toString(), trustingRestTemplate);
} else {
rawContents = contentCache.getUrlContent(discoveryUrl.toString(), nonTrustingRestTemplate);
}
return new ObjectMapper().readValue(rawContents, OidcMetadata.class);
}

private void updateIdpDefinition(OIDCIdentityProviderDefinition definition, OidcMetadata oidcMetadata) {
definition.setAuthUrl(oidcMetadata.getAuthorizationEndpoint());
definition.setTokenUrl(oidcMetadata.getTokenEndpoint());
definition.setTokenKeyUrl(oidcMetadata.getJsonWebKeysUri());
definition.setUserInfoUrl(oidcMetadata.getUserinfoEndpoint());
definition.setIssuer(oidcMetadata.getIssuer());
}

private boolean shouldPerformDiscovery(OIDCIdentityProviderDefinition definition) {
return definition.getDiscoveryUrl() != null && !StringUtils.isBlank(definition.getDiscoveryUrl().toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.cloudfoundry.identity.uaa.provider.oauth;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.cloudfoundry.identity.uaa.cache.ExpiringUrlCache;
import org.cloudfoundry.identity.uaa.cache.UrlContentCache;
import org.cloudfoundry.identity.uaa.provider.OIDCIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.util.TimeServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.time.Duration;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class OidcMetadataDiscovererTest {
private OidcMetadataDiscoverer metadataDiscoverer;
private UrlContentCache urlContentCache;
private RestTemplate restTemplate;

private OIDCIdentityProviderDefinition definition;

private ObjectMapper objectMapper = new ObjectMapper();

@BeforeEach
void setUp() {
urlContentCache = new ExpiringUrlCache(Duration.ofMinutes(2), new TimeServiceImpl(), 2);
restTemplate = mock(RestTemplate.class, Answers.RETURNS_DEEP_STUBS);

metadataDiscoverer = new OidcMetadataDiscoverer(urlContentCache, restTemplate, restTemplate);
}

@Test
public void withoutDiscoveryUrl_shouldNotPerformDiscovery() throws IOException {
definition = new OIDCIdentityProviderDefinition();
definition.setAuthUrl(new URL("http://not.updated"));
definition.setTokenUrl(new URL("http://not.updated"));

metadataDiscoverer.performDiscoveryAndUpdateDefinition(definition);

assertThat(definition, is(notNullValue()));
assertThat(definition.getDiscoveryUrl(), nullValue());
assertThat(definition.getAuthUrl().toString(), is("http://not.updated"));
assertThat(definition.getTokenUrl().toString(), is("http://not.updated"));
}

@Test
public void withDiscoveryUrl_shouldPerformDiscovery() throws IOException {
definition = new OIDCIdentityProviderDefinition();
definition.setAuthUrl(new URL("http://should.be.updated"));
definition.setTokenUrl(new URL("http://should.be.updated"));
definition.setDiscoveryUrl(new URL("http://discovery.com"));
when(restTemplate.getForObject(any(URI.class), eq(byte[].class)))
.thenReturn(objectMapper.writeValueAsBytes(buildOidcMetadata()));

metadataDiscoverer.performDiscoveryAndUpdateDefinition(definition);

assertThat(definition, is(notNullValue()));
assertThat(definition.getAuthUrl().toString(), is("http://authz.endpoint"));
assertThat(definition.getTokenUrl().toString(), is("http://token.endpoint"));
assertThat(definition.getUserInfoUrl().toString(), is("http://userinfo.endpoint"));
assertThat(definition.getTokenKeyUrl().toString(), is("http://jwks.uri"));
assertThat(definition.getIssuer(), is("metadataissuer"));
}

@Test
public void withDiscoveryUrl_usesCache() throws IOException {
definition = new OIDCIdentityProviderDefinition();
definition.setAuthUrl(new URL("http://should.be.updated"));
definition.setTokenUrl(new URL("http://should.be.updated"));
definition.setDiscoveryUrl(new URL("http://discovery.com"));
definition.setSkipSslValidation(false);

when(restTemplate.getForObject(any(URI.class), eq(byte[].class)))
.thenReturn(objectMapper.writeValueAsBytes(buildOidcMetadata()))
.thenThrow(new RuntimeException("shouldn't have been called more than once"));

metadataDiscoverer.performDiscoveryAndUpdateDefinition(definition);
metadataDiscoverer.performDiscoveryAndUpdateDefinition(definition);
}

private OidcMetadata buildOidcMetadata() {
try {
OidcMetadata metadata = new OidcMetadata();

metadata.setAuthorizationEndpoint(new URL("http://authz.endpoint"));
metadata.setTokenEndpoint(new URL("http://token.endpoint"));
metadata.setUserinfoEndpoint(new URL("http://userinfo.endpoint"));
metadata.setJsonWebKeysUri(new URL("http://jwks.uri"));
metadata.setIssuer("metadataissuer");

return metadata;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

0 comments on commit 80ff310

Please sign in to comment.