@ -112,169 +112,21 @@ public class ClientDynamicRegistrationEndpoint {
newClient . setClientId ( null ) ;
newClient . setClientSecret ( null ) ;
// 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 ) ) ;
// set default grant types if needed
if ( newClient . getGrantTypes ( ) = = null | | newClient . getGrantTypes ( ) . isEmpty ( ) ) {
if ( newClient . getScope ( ) . contains ( "offline_access" ) ) { // client asked for offline access
newClient . setGrantTypes ( Sets . newHashSet ( "authorization_code" , "refresh_token" ) ) ; // allow authorization code and refresh token grant types by default
} else {
newClient . setGrantTypes ( Sets . newHashSet ( "authorization_code" ) ) ; // allow authorization code grant type by default
}
}
if ( newClient . getResponseTypes ( ) = = null ) {
newClient . setResponseTypes ( new HashSet < String > ( ) ) ;
}
// filter out unknown grant types
// TODO: make this a pluggable service
Set < String > requestedGrantTypes = new HashSet < String > ( newClient . getGrantTypes ( ) ) ;
requestedGrantTypes . removeAll (
ImmutableSet . of ( "authorization_code" , "implicit" ,
"password" , "client_credentials" , "refresh_token" ,
"urn:ietf:params:oauth:grant_type:redelegate" ) ) ;
if ( ! requestedGrantTypes . isEmpty ( ) ) {
// return an error, there were unknown grant types requested
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Unknown grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
// don't allow "password" grant type for dynamic registration
if ( newClient . getGrantTypes ( ) . contains ( "password" ) ) {
// return an error, you can't dynamically register for the password grant
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "The password grant type is not allowed in dynamic registration on this server." ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
// do validation on the fields
try {
newClient = validateScopes ( newClient ) ;
newClient = validateResponseTypes ( newClient ) ;
newClient = validateGrantTypes ( newClient ) ;
newClient = validateRedirectUris ( 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" ;
}
// don't allow clients to have multiple incompatible grant types and scopes
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "implicit" ) | |
newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// return an error, you can't have these grant types together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
if ( newClient . getResponseTypes ( ) . contains ( "token" ) ) {
// return an error, you can't have this grant type and response type together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible response types requested: " + newClient . getGrantTypes ( ) + " / " + newClient . getResponseTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
newClient . getResponseTypes ( ) . add ( "code" ) ;
}
if ( newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | |
newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// return an error, you can't have these grant types together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
if ( newClient . getResponseTypes ( ) . contains ( "code" ) ) {
// return an error, you can't have this grant type and response type together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible response types requested: " + newClient . getGrantTypes ( ) + " / " + newClient . getResponseTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
newClient . getResponseTypes ( ) . add ( "token" ) ;
// don't allow refresh tokens in implicit clients
newClient . getGrantTypes ( ) . remove ( "refresh_token" ) ;
newClient . getScope ( ) . remove ( "offline_access" ) ;
}
if ( newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | |
newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
// return an error, you can't have these grant types together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
if ( ! newClient . getResponseTypes ( ) . isEmpty ( ) ) {
// return an error, you can't have this grant type and response type together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible response types requested: " + newClient . getGrantTypes ( ) + " / " + newClient . getResponseTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
// don't allow refresh tokens or id tokens in client_credentials clients
newClient . getGrantTypes ( ) . remove ( "refresh_token" ) ;
newClient . getScope ( ) . remove ( "offline_access" ) ;
newClient . getScope ( ) . remove ( "openid" ) ;
}
if ( newClient . getGrantTypes ( ) . isEmpty ( ) ) {
// return an error, you need at least one grant type selected
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Clients must register at least one grant type." ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
// check to make sure this client registered a redirect URI if using a redirect flow
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | | newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
if ( newClient . getRedirectUris ( ) = = null | | newClient . getRedirectUris ( ) . isEmpty ( ) ) {
// return an error
m . addAttribute ( "error" , "invalid_client_uri" ) ;
m . addAttribute ( "errorMessage" , "Clients using a redirect-based grant type must register at least one redirect URI." ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
for ( String uri : newClient . getRedirectUris ( ) ) {
if ( blacklistService . isBlacklisted ( uri ) ) {
// return an error
m . addAttribute ( "error" , "invalid_client_uri" ) ;
m . addAttribute ( "errorMessage" , "Redirect URI is not allowed: " + uri ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
}
}
if ( newClient . getTokenEndpointAuthMethod ( ) = = null ) {
newClient . setTokenEndpointAuthMethod ( AuthMethod . SECRET_BASIC ) ;
}
@ -420,147 +272,21 @@ public class ClientDynamicRegistrationEndpoint {
newClient . setCreatedAt ( oldClient . getCreatedAt ( ) ) ;
newClient . setReuseRefreshToken ( oldClient . isReuseRefreshToken ( ) ) ;
// 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 ( ) ;
}
// make sure that the client doesn't ask for scopes it can't have
newClient . setScope ( scopeService . toStrings ( allowedScopes ) ) ;
if ( newClient . getResponseTypes ( ) = = null ) {
newClient . setResponseTypes ( new HashSet < String > ( ) ) ;
}
// filter out unknown grant types
// TODO: make this a pluggable service
Set < String > requestedGrantTypes = new HashSet < String > ( newClient . getGrantTypes ( ) ) ;
requestedGrantTypes . removeAll (
ImmutableSet . of ( "authorization_code" , "implicit" ,
"password" , "client_credentials" , "refresh_token" ,
"urn:ietf:params:oauth:grant_type:redelegate" ) ) ;
if ( ! requestedGrantTypes . isEmpty ( ) ) {
// return an error, there were unknown grant types requested
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Unknown grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
// don't allow "password" grant type for dynamic registration
if ( newClient . getGrantTypes ( ) . contains ( "password" ) ) {
// return an error, you can't dynamically register for the password grant
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "The password grant type is not allowed in dynamic registration on this server." ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
// do validation on the fields
try {
newClient = validateScopes ( newClient ) ;
newClient = validateResponseTypes ( newClient ) ;
newClient = validateGrantTypes ( newClient ) ;
newClient = validateRedirectUris ( 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" ;
}
// don't allow clients to have multiple incompatible grant types and scopes
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "implicit" ) | |
newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// return an error, you can't have these grant types together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
newClient . getResponseTypes ( ) . add ( "code" ) ;
}
if ( newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | |
newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// return an error, you can't have these grant types together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
newClient . getResponseTypes ( ) . add ( "token" ) ;
// don't allow refresh tokens in implicit clients
newClient . getGrantTypes ( ) . remove ( "refresh_token" ) ;
newClient . getScope ( ) . remove ( "offline_access" ) ;
}
if ( newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | |
newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
// return an error, you can't have these grant types together
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
// don't allow refresh tokens or id tokens in client_credentials clients
newClient . getGrantTypes ( ) . remove ( "refresh_token" ) ;
newClient . getScope ( ) . remove ( "offline_access" ) ;
newClient . getScope ( ) . remove ( "openid" ) ;
}
if ( newClient . getGrantTypes ( ) . isEmpty ( ) ) {
// return an error, you need at least one grant type selected
m . addAttribute ( "error" , "invalid_client_metadata" ) ;
m . addAttribute ( "errorMessage" , "Clients must register at least one grant type." ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
// check to make sure this client registered a redirect URI if using a redirect flow
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | | newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
if ( newClient . getRedirectUris ( ) = = null | | newClient . getRedirectUris ( ) . isEmpty ( ) ) {
// return an error
m . addAttribute ( "error" , "invalid_client_uri" ) ;
m . addAttribute ( "errorMessage" , "Clients using a redirect-based grant type must register at least one redirect URI." ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
for ( String uri : newClient . getRedirectUris ( ) ) {
if ( blacklistService . isBlacklisted ( uri ) ) {
// return an error
m . addAttribute ( "error" , "invalid_client_uri" ) ;
m . addAttribute ( "errorMessage" , "Redirect URI is not allowed: " + uri ) ;
m . addAttribute ( "code" , HttpStatus . BAD_REQUEST ) ;
return "jsonErrorView" ;
}
}
}
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 ) ;
}
try {
// save the client
ClientDetailsEntity savedClient = clientService . updateClient ( oldClient , newClient ) ;
@ -627,4 +353,198 @@ public class ClientDynamicRegistrationEndpoint {
}
}
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 ;
}
private ClientDetailsEntity validateResponseTypes ( ClientDetailsEntity newClient ) throws ValidationException {
if ( newClient . getResponseTypes ( ) = = null ) {
newClient . setResponseTypes ( new HashSet < String > ( ) ) ;
}
return newClient ;
}
private ClientDetailsEntity validateGrantTypes ( ClientDetailsEntity newClient ) throws ValidationException {
// set default grant types if needed
if ( newClient . getGrantTypes ( ) = = null | | newClient . getGrantTypes ( ) . isEmpty ( ) ) {
if ( newClient . getScope ( ) . contains ( "offline_access" ) ) { // client asked for offline access
newClient . setGrantTypes ( Sets . newHashSet ( "authorization_code" , "refresh_token" ) ) ; // allow authorization code and refresh token grant types by default
} else {
newClient . setGrantTypes ( Sets . newHashSet ( "authorization_code" ) ) ; // allow authorization code grant type by default
}
}
// filter out unknown grant types
// TODO: make this a pluggable service
Set < String > requestedGrantTypes = new HashSet < String > ( newClient . getGrantTypes ( ) ) ;
requestedGrantTypes . removeAll (
ImmutableSet . of ( "authorization_code" , "implicit" ,
"password" , "client_credentials" , "refresh_token" ,
"urn:ietf:params:oauth:grant_type:redelegate" ) ) ;
if ( ! requestedGrantTypes . isEmpty ( ) ) {
// return an error, there were unknown grant types requested
throw new ValidationException ( "invalid_client_metadata" , "Unknown grant types requested: " + newClient . getGrantTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
// don't allow "password" grant type for dynamic registration
if ( newClient . getGrantTypes ( ) . contains ( "password" ) ) {
// return an error, you can't dynamically register for the password grant
throw new ValidationException ( "invalid_client_metadata" , "The password grant type is not allowed in dynamic registration on this server." , HttpStatus . BAD_REQUEST ) ;
}
// don't allow clients to have multiple incompatible grant types and scopes
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "implicit" ) | |
newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// return an error, you can't have these grant types together
throw new ValidationException ( "invalid_client_metadata" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
if ( newClient . getResponseTypes ( ) . contains ( "token" ) ) {
// return an error, you can't have this grant type and response type together
throw new ValidationException ( "invalid_client_metadata" , "Incompatible response types requested: " + newClient . getGrantTypes ( ) + " / " + newClient . getResponseTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
newClient . getResponseTypes ( ) . add ( "code" ) ;
}
if ( newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | |
newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// return an error, you can't have these grant types together
throw new ValidationException ( "invalid_client_metadata" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
if ( newClient . getResponseTypes ( ) . contains ( "code" ) ) {
// return an error, you can't have this grant type and response type together
throw new ValidationException ( "invalid_client_metadata" , "Incompatible response types requested: " + newClient . getGrantTypes ( ) + " / " + newClient . getResponseTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
newClient . getResponseTypes ( ) . add ( "token" ) ;
// don't allow refresh tokens in implicit clients
newClient . getGrantTypes ( ) . remove ( "refresh_token" ) ;
newClient . getScope ( ) . remove ( "offline_access" ) ;
}
if ( newClient . getGrantTypes ( ) . contains ( "client_credentials" ) ) {
// check for incompatible grants
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | |
newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
// return an error, you can't have these grant types together
throw new ValidationException ( "invalid_client_metadata" , "Incompatible grant types requested: " + newClient . getGrantTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
if ( ! newClient . getResponseTypes ( ) . isEmpty ( ) ) {
// return an error, you can't have this grant type and response type together
throw new ValidationException ( "invalid_client_metadata" , "Incompatible response types requested: " + newClient . getGrantTypes ( ) + " / " + newClient . getResponseTypes ( ) , HttpStatus . BAD_REQUEST ) ;
}
// don't allow refresh tokens or id tokens in client_credentials clients
newClient . getGrantTypes ( ) . remove ( "refresh_token" ) ;
newClient . getScope ( ) . remove ( "offline_access" ) ;
newClient . getScope ( ) . remove ( "openid" ) ;
}
if ( newClient . getGrantTypes ( ) . isEmpty ( ) ) {
// return an error, you need at least one grant type selected
throw new ValidationException ( "invalid_client_metadata" , "Clients must register at least one grant type." , HttpStatus . BAD_REQUEST ) ;
}
return newClient ;
}
private ClientDetailsEntity validateRedirectUris ( ClientDetailsEntity newClient ) throws ValidationException {
// check to make sure this client registered a redirect URI if using a redirect flow
if ( newClient . getGrantTypes ( ) . contains ( "authorization_code" ) | | newClient . getGrantTypes ( ) . contains ( "implicit" ) ) {
if ( newClient . getRedirectUris ( ) = = null | | newClient . getRedirectUris ( ) . isEmpty ( ) ) {
// return an error
throw new ValidationException ( "invalid_client_uri" , "Clients using a redirect-based grant type must register at least one redirect URI." , HttpStatus . BAD_REQUEST ) ;
}
for ( String uri : newClient . getRedirectUris ( ) ) {
if ( blacklistService . isBlacklisted ( uri ) ) {
// return an error
throw new ValidationException ( "invalid_client_uri" , "Redirect URI is not allowed: " + uri , HttpStatus . BAD_REQUEST ) ;
}
}
}
return newClient ;
}
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 ;
}
/ * *
* 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 ;
}
}
}