extracted validation exception, refactored protected resource registration endpoint to use this format

pull/612/head
Justin Richer 2014-06-06 11:13:41 -04:00
parent b7a8bbdddc
commit 52e53ba219
3 changed files with 135 additions and 81 deletions

View File

@ -0,0 +1,47 @@
package org.mitre.openid.connect.exception;
import org.springframework.http.HttpStatus;
/**
* Thrown by utility methods when a client fails to validate. Contains information
* to be returned.
* @author jricher
*
*/
public class ValidationException extends Exception {
private static final long serialVersionUID = 1820497072989294627L;
private String error;
private String errorDescription;
private HttpStatus status;
public ValidationException(String error, String errorDescription,
HttpStatus status) {
this.error = error;
this.errorDescription = errorDescription;
this.status = status;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getErrorDescription() {
return errorDescription;
}
public void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
public HttpStatus getStatus() {
return status;
}
public void setStatus(HttpStatus status) {
this.status = status;
}
@Override
public String toString() {
return "ValidationException [error=" + error + ", errorDescription="
+ errorDescription + ", status=" + status + "]";
}
}

View File

@ -32,6 +32,7 @@ import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.oauth2.service.SystemScopeService; import org.mitre.oauth2.service.SystemScopeService;
import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.mitre.openid.connect.exception.ValidationException;
import org.mitre.openid.connect.service.BlacklistedSiteService; import org.mitre.openid.connect.service.BlacklistedSiteService;
import org.mitre.openid.connect.service.OIDCTokenService; import org.mitre.openid.connect.service.OIDCTokenService;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -510,41 +511,4 @@ public class ClientDynamicRegistrationEndpoint {
return newClient; return newClient;
} }
/**
* Thrown by utility methods when a client fails to validate. Contains information
* to be returned.
* @author jricher
*
*/
private class ValidationException extends Exception {
private String error;
private String errorDescription;
private HttpStatus status;
public ValidationException(String error, String errorDescription,
HttpStatus status) {
this.error = error;
this.errorDescription = errorDescription;
this.status = status;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getErrorDescription() {
return errorDescription;
}
public void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
public HttpStatus getStatus() {
return status;
}
public void setStatus(HttpStatus status) {
this.status = status;
}
}
} }

View File

@ -31,6 +31,7 @@ import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.oauth2.service.SystemScopeService; import org.mitre.oauth2.service.SystemScopeService;
import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor; import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.mitre.openid.connect.exception.ValidationException;
import org.mitre.openid.connect.service.BlacklistedSiteService; import org.mitre.openid.connect.service.BlacklistedSiteService;
import org.mitre.openid.connect.service.OIDCTokenService; import org.mitre.openid.connect.service.OIDCTokenService;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -110,40 +111,24 @@ public class ProtectedResourceRegistrationEndpoint {
newClient.setClientId(null); newClient.setClientId(null);
newClient.setClientSecret(null); newClient.setClientSecret(null);
// set of scopes that are OK for clients to dynamically register for // do validation on the fields
Set<SystemScope> dynScopes = scopeService.getDynReg(); try {
newClient = validateScopes(newClient);
// scopes that the client is asking for newClient = validateAuth(newClient);
Set<SystemScope> requestedScopes = scopeService.fromStrings(newClient.getScope()); } catch (ValidationException ve) {
// validation failed, return an error
// the scopes that the client can have must be a subset of the dynamically allowed scopes m.addAttribute("error", ve.getError());
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes); m.addAttribute("errorMessage", ve.getErrorDescription());
m.addAttribute("code", ve.getStatus());
// if the client didn't ask for any, give them the defaults return "jsonErrorView";
if (allowedScopes == null || allowedScopes.isEmpty()) {
allowedScopes = scopeService.getDefaults();
} }
newClient.setScope(scopeService.toStrings(allowedScopes));
// no grant types are allowed // no grant types are allowed
newClient.setGrantTypes(new HashSet<String>()); newClient.setGrantTypes(new HashSet<String>());
newClient.setResponseTypes(new HashSet<String>()); newClient.setResponseTypes(new HashSet<String>());
newClient.setRedirectUris(new HashSet<String>()); newClient.setRedirectUris(new HashSet<String>());
if (newClient.getTokenEndpointAuthMethod() == null) {
newClient.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC);
}
if (newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_BASIC ||
newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_JWT ||
newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_POST) {
// we need to generate a secret
newClient = clientService.generateClientSecret(newClient);
}
// don't issue tokens to this client // don't issue tokens to this client
newClient.setAccessTokenValiditySeconds(0); newClient.setAccessTokenValiditySeconds(0);
newClient.setIdTokenValiditySeconds(0); newClient.setIdTokenValiditySeconds(0);
@ -207,6 +192,26 @@ public class ProtectedResourceRegistrationEndpoint {
} }
private ClientDetailsEntity validateScopes(ClientDetailsEntity newClient) throws ValidationException {
// set of scopes that are OK for clients to dynamically register for
Set<SystemScope> dynScopes = scopeService.getDynReg();
// scopes that the client is asking for
Set<SystemScope> requestedScopes = scopeService.fromStrings(newClient.getScope());
// the scopes that the client can have must be a subset of the dynamically allowed scopes
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes);
// if the client didn't ask for any, give them the defaults
if (allowedScopes == null || allowedScopes.isEmpty()) {
allowedScopes = scopeService.getDefaults();
}
newClient.setScope(scopeService.toStrings(allowedScopes));
return newClient;
}
/** /**
* Get the meta information for a client. * Get the meta information for a client.
* @param clientId * @param clientId
@ -284,28 +289,51 @@ public class ProtectedResourceRegistrationEndpoint {
// a client can't ask to update its own client secret to any particular value // a client can't ask to update its own client secret to any particular value
newClient.setClientSecret(oldClient.getClientSecret()); newClient.setClientSecret(oldClient.getClientSecret());
// we need to copy over all of the local and SECOAUTH fields // no grant types are allowed
newClient.setAccessTokenValiditySeconds(oldClient.getAccessTokenValiditySeconds()); newClient.setGrantTypes(new HashSet<String>());
newClient.setIdTokenValiditySeconds(oldClient.getIdTokenValiditySeconds()); newClient.setResponseTypes(new HashSet<String>());
newClient.setRefreshTokenValiditySeconds(oldClient.getRefreshTokenValiditySeconds()); newClient.setRedirectUris(new HashSet<String>());
newClient.setDynamicallyRegistered(true); // it's still dynamically registered
newClient.setAllowIntrospection(oldClient.isAllowIntrospection());
newClient.setAuthorities(oldClient.getAuthorities());
newClient.setClientDescription(oldClient.getClientDescription());
newClient.setCreatedAt(oldClient.getCreatedAt());
newClient.setReuseRefreshToken(oldClient.isReuseRefreshToken());
// set of scopes that are OK for clients to dynamically register for // don't issue tokens to this client
Set<SystemScope> dynScopes = scopeService.getDynReg(); newClient.setAccessTokenValiditySeconds(0);
newClient.setIdTokenValiditySeconds(0);
newClient.setRefreshTokenValiditySeconds(0);
// scopes that the client is asking for // clear out unused fields
Set<SystemScope> requestedScopes = scopeService.fromStrings(newClient.getScope()); newClient.setDefaultACRvalues(new HashSet<String>());
newClient.setDefaultMaxAge(null);
newClient.setIdTokenEncryptedResponseAlg(null);
newClient.setIdTokenEncryptedResponseEnc(null);
newClient.setIdTokenSignedResponseAlg(null);
newClient.setInitiateLoginUri(null);
newClient.setPostLogoutRedirectUri(null);
newClient.setRequestObjectSigningAlg(null);
newClient.setRequireAuthTime(null);
newClient.setReuseRefreshToken(false);
newClient.setSectorIdentifierUri(null);
newClient.setSubjectType(null);
newClient.setUserInfoEncryptedResponseAlg(null);
newClient.setUserInfoEncryptedResponseEnc(null);
newClient.setUserInfoSignedResponseAlg(null);
// the scopes that the client can have must be a subset of the dynamically allowed scopes // this client has been dynamically registered (obviously)
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes); newClient.setDynamicallyRegistered(true);
// this client has access to the introspection endpoint
newClient.setAllowIntrospection(true);
// do validation on the fields
try {
newClient = validateScopes(newClient);
newClient = validateAuth(newClient);
} catch (ValidationException ve) {
// validation failed, return an error
m.addAttribute("error", ve.getError());
m.addAttribute("errorMessage", ve.getErrorDescription());
m.addAttribute("code", ve.getStatus());
return "jsonErrorView";
}
// make sure that the client doesn't ask for scopes it can't have
newClient.setScope(scopeService.toStrings(allowedScopes));
try { try {
// save the client // save the client
@ -374,4 +402,19 @@ public class ProtectedResourceRegistrationEndpoint {
} }
} }
private ClientDetailsEntity validateAuth(ClientDetailsEntity newClient) throws ValidationException {
if (newClient.getTokenEndpointAuthMethod() == null) {
newClient.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC);
}
if (newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_BASIC ||
newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_JWT ||
newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_POST) {
// we need to generate a secret
newClient = clientService.generateClientSecret(newClient);
}
return newClient;
}
} }