Simplify validation logic in ResourceServerProperties

Closes gh-8306
Closes gh-8317
This commit is contained in:
Madhura Bhave 2017-02-15 17:29:22 -08:00 committed by Andy Wilkinson
parent 3e0e4e81b9
commit 605b0aefc6
3 changed files with 119 additions and 75 deletions

View File

@ -204,40 +204,34 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
} }
ResourceServerProperties resource = (ResourceServerProperties) target; ResourceServerProperties resource = (ResourceServerProperties) target;
validate(resource, errors); validate(resource, errors);
} }
private void validate(ResourceServerProperties target, Errors errors) { private void validate(ResourceServerProperties target, Errors errors) {
if ((StringUtils.hasText(this.jwt.getKeyUri()) boolean jwtConfigPresent = StringUtils.hasText(this.jwt.getKeyUri())
|| StringUtils.hasText(this.jwt.getKeyValue())) || StringUtils.hasText(this.jwt.getKeyValue());
&& StringUtils.hasText(this.jwk.getKeySetUri())) { boolean jwkConfigPresent = StringUtils.hasText(this.jwk.getKeySetUri());
if (jwtConfigPresent && jwkConfigPresent) {
errors.reject("ambiguous.keyUri", errors.reject("ambiguous.keyUri",
"Only one of jwt.keyUri (or jwt.keyValue) and " "Only one of jwt.keyUri (or jwt.keyValue) and jwk.keySetUri should"
+ "jwk.keySetUri should be configured."); + " be configured.");
} }
else { else {
if (StringUtils.hasText(this.clientId)) { if (jwtConfigPresent || jwkConfigPresent) {
if (!StringUtils.hasText(this.clientSecret)) {
if (!StringUtils.hasText(target.getUserInfoUri())) {
errors.rejectValue("userInfoUri", "missing.userInfoUri",
"Missing userInfoUri (no client secret available)");
}
}
else {
if (isPreferTokenInfo()
&& !StringUtils.hasText(target.getTokenInfoUri())) {
if (StringUtils.hasText(getJwt().getKeyUri())
|| StringUtils.hasText(getJwt().getKeyValue())
|| StringUtils.hasText(getJwk().getKeySetUri())) {
// It's a JWT decoder // It's a JWT decoder
return; return;
} }
if (!StringUtils.hasText(target.getUserInfoUri())) { if (!StringUtils.hasText(target.getUserInfoUri())
&& !StringUtils.hasText(target.getTokenInfoUri())) {
errors.rejectValue("tokenInfoUri", "missing.tokenInfoUri", errors.rejectValue("tokenInfoUri", "missing.tokenInfoUri",
"Missing tokenInfoUri and userInfoUri and there is no " "Missing tokenInfoUri and userInfoUri and there is no "
+ "JWT verifier key"); + "JWT verifier key");
} }
} if (StringUtils.hasText(target.getTokenInfoUri()) && isPreferTokenInfo()) {
if (StringUtils.hasText(this.clientId)
&& !StringUtils.hasText(this.clientSecret)) {
errors.rejectValue("clientSecret", "missing.clientSecret",
"Missing client secret");
} }
} }
} }
@ -276,22 +270,8 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
} }
public String getKeyUri() { public String getKeyUri() {
if (this.keyUri != null) {
return this.keyUri; return this.keyUri;
} }
if (ResourceServerProperties.this.userInfoUri != null
&& ResourceServerProperties.this.userInfoUri.endsWith("/userinfo")) {
return ResourceServerProperties.this.userInfoUri.replace("/userinfo",
"/token_key");
}
if (ResourceServerProperties.this.tokenInfoUri != null
&& ResourceServerProperties.this.tokenInfoUri
.endsWith("/check_token")) {
return ResourceServerProperties.this.tokenInfoUri.replace("/check_token",
"/token_key");
}
return null;
}
} }

View File

@ -42,6 +42,8 @@ public class ResourceServerPropertiesTests {
private ResourceServerProperties properties = new ResourceServerProperties("client", private ResourceServerProperties properties = new ResourceServerProperties("client",
"secret"); "secret");
private Errors errors = mock(Errors.class);
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void json() throws Exception { public void json() throws Exception {
@ -54,39 +56,109 @@ public class ResourceServerPropertiesTests {
} }
@Test @Test
public void tokenKeyDerivedFromUserInfoUri() throws Exception { public void validateWhenBothJwtAndJwkKeyUrisPresentShouldFail() throws Exception {
this.properties.setUserInfoUri("http://example.com/userinfo");
assertThat(this.properties.getJwt().getKeyUri())
.isEqualTo("http://example.com/token_key");
}
@Test
public void tokenKeyDerivedFromTokenInfoUri() throws Exception {
this.properties.setTokenInfoUri("http://example.com/check_token");
assertThat(this.properties.getJwt().getKeyUri())
.isEqualTo("http://example.com/token_key");
}
@Test
public void validateWhenBothJwtAndJwtKeyConfigurationPresentShouldFail()
throws Exception {
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys"); this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
this.properties.getJwt().setKeyUri("http://my-auth-server/token_key"); this.properties.getJwt().setKeyUri("http://my-auth-server/token_key");
setListableBeanFactory(); setListableBeanFactory();
Errors errors = mock(Errors.class); this.properties.validate(this.properties, this.errors);
this.properties.validate(this.properties, errors); verify(this.errors).reject("ambiguous.keyUri",
verify(errors).reject("ambiguous.keyUri",
"Only one of jwt.keyUri (or jwt.keyValue) and jwk.keySetUri should be configured."); "Only one of jwt.keyUri (or jwt.keyValue) and jwk.keySetUri should be configured.");
} }
@Test @Test
public void validateWhenKeySetUriProvidedShouldSucceed() throws Exception { public void validateWhenBothJwtKeyValueAndJwkKeyUriPresentShouldFail()
throws Exception {
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
this.properties.getJwt().setKeyValue("my-key");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verify(this.errors).reject("ambiguous.keyUri",
"Only one of jwt.keyUri (or jwt.keyValue) and jwk.keySetUri should be configured.");
}
@Test
public void validateWhenJwkKeySetUriProvidedShouldSucceed() throws Exception {
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys"); this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
setListableBeanFactory(); setListableBeanFactory();
Errors errors = mock(Errors.class); this.properties.validate(this.properties, this.errors);
this.properties.validate(this.properties, errors); verifyZeroInteractions(this.errors);
verifyZeroInteractions(errors); }
@Test
public void validateWhenKeyValuePresentShouldSucceed() throws Exception {
this.properties.getJwt().setKeyValue("my-key");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenKeysUriOrValuePresentAndUserInfoAbsentShouldNotFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenKeyConfigAbsentAndInfoUrisNotConfiguredShouldFail()
throws Exception {
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verify(this.errors).rejectValue("tokenInfoUri", "missing.tokenInfoUri",
"Missing tokenInfoUri and userInfoUri and there is no JWT verifier key");
}
@Test
public void validateWhenTokenUriConfiguredShouldNotFail() throws Exception {
this.properties.setTokenInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenUserInfoUriConfiguredShouldNotFail() throws Exception {
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenTokenUriPreferredAndClientSecretAbsentShouldFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.setTokenInfoUri("http://my-auth-server/check_token");
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verify(this.errors).rejectValue("clientSecret", "missing.clientSecret",
"Missing client secret");
}
@Test
public void validateWhenTokenUriAbsentAndClientSecretAbsentShouldNotFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenTokenUriNotPreferredAndClientSecretAbsentShouldNotFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.setPreferTokenInfo(false);
this.properties.setTokenInfoUri("http://my-auth-server/check_token");
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate(this.properties, this.errors);
verifyZeroInteractions(this.errors);
} }
private void setListableBeanFactory() { private void setListableBeanFactory() {

View File

@ -90,14 +90,6 @@ public class ResourceServerTokenServicesConfigurationTests {
} }
} }
@Test
public void defaultIsRemoteTokenServices() {
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.web(false).run();
RemoteTokenServices services = this.context.getBean(RemoteTokenServices.class);
assertThat(services).isNotNull();
}
@Test @Test
public void useRemoteTokenServices() { public void useRemoteTokenServices() {
EnvironmentTestUtils.addEnvironment(this.environment, EnvironmentTestUtils.addEnvironment(this.environment,