Convert database errors to 500 instead of 400.

Signed-off-by: Tero Saarni <tero.saarni@est.tech>
This commit is contained in:
Tero Saarni 2024-01-10 19:26:04 +02:00 committed by Pedro Igor
parent f1532565b6
commit 64862d568e
17 changed files with 64 additions and 34 deletions

View file

@ -401,7 +401,7 @@ public class LDAPIdentityStore implements IdentityStore {
} catch (ModelException me) {
throw me;
} catch (Exception e) {
throw new ModelException(e);
throw new ModelException("Error updating password", e);
}
}

View file

@ -22,9 +22,12 @@ import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import jakarta.persistence.EntityExistsException;
import jakarta.persistence.EntityManager;
import jakarta.persistence.OptimisticLockException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -92,11 +95,13 @@ public class PersistenceExceptionConverter implements InvocationHandler {
throwModelDuplicateEx = throwModelDuplicateEx.or(checkDuplicationMessage);
if (t.getCause() != null && throwModelDuplicateEx.test(t.getCause())) {
throw new ModelDuplicateException(t.getCause());
throw new ModelDuplicateException("Duplicate resource error", t.getCause());
} else if (throwModelDuplicateEx.test(t)) {
throw new ModelDuplicateException(t);
throw new ModelDuplicateException("Duplicate resource error", t);
} else if (t instanceof OptimisticLockException) {
throw new ModelIllegalStateException("Database operation failed", t);
} else {
throw new ModelException(t);
throw new ModelException("Database operation failed", t);
}
}

View file

@ -114,7 +114,7 @@ public class PersistentAuthenticatedClientSessionAdapter implements Authenticate
try {
data = JsonSerialization.readValue(model.getData(), PersistentClientSessionData.class);
} catch (IOException ioe) {
throw new ModelException(ioe);
throw new ModelException("Error restoring session", ioe);
}
}
@ -127,7 +127,7 @@ public class PersistentAuthenticatedClientSessionAdapter implements Authenticate
String updatedData = JsonSerialization.writeValueAsString(getData());
this.model.setData(updatedData);
} catch (IOException ioe) {
throw new ModelException(ioe);
throw new ModelException("Error persisting session", ioe);
}
return this.model;

View file

@ -158,7 +158,7 @@ public class PersistentUserSessionAdapter implements OfflineUserSessionModel {
try {
data = JsonSerialization.readValue(model.getData(), PersistentUserSessionData.class);
} catch (IOException ioe) {
throw new ModelException(ioe);
throw new ModelException("Error restoring session", ioe);
}
}
@ -171,7 +171,7 @@ public class PersistentUserSessionAdapter implements OfflineUserSessionModel {
String updatedData = JsonSerialization.writeValueAsString(getData());
this.model.setData(updatedData);
} catch (IOException ioe) {
throw new ModelException(ioe);
throw new ModelException("Error persisting session", ioe);
}
return this.model;

View file

@ -36,8 +36,4 @@ public class ClientTypeException extends ModelException {
public ClientTypeException(String message, Throwable cause) {
super(message, cause);
}
public ClientTypeException(Throwable cause) {
super(cause);
}
}
}

View file

@ -40,10 +40,6 @@ public class ModelDuplicateException extends ModelException {
super(message, cause);
}
public ModelDuplicateException(Throwable cause) {
super(cause);
}
public String getDuplicateFieldName() {
return duplicateFieldName;
}

View file

@ -40,10 +40,6 @@ public class ModelException extends RuntimeException {
super(message, cause);
}
public ModelException(Throwable cause) {
super(cause);
}
public Object[] getParameters() {
return parameters;
}

View file

@ -42,8 +42,4 @@ public class ModelIllegalStateException extends ModelException {
public ModelIllegalStateException(String message, Throwable cause) {
super(message, cause);
}
public ModelIllegalStateException(Throwable cause) {
super(cause);
}
}

View file

@ -38,7 +38,7 @@ public class PasswordPolicyNotMetException extends ModelException {
super(message);
this.username = username;
}
public PasswordPolicyNotMetException(String message, String username, Throwable cause) {
super(message, cause);
this.username = username;
@ -48,10 +48,6 @@ public class PasswordPolicyNotMetException extends ModelException {
super(message, cause);
}
public PasswordPolicyNotMetException(Throwable cause) {
super(cause);
}
public String getUsername() {
return username;
}

View file

@ -13,6 +13,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionTaskWithResult;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.ModelValidationException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
@ -126,7 +127,9 @@ public class KeycloakErrorHandler implements ExceptionMapper<Throwable> {
|| throwable instanceof ModelValidationException) {
status = Response.Status.BAD_REQUEST.getStatusCode();
}
if (throwable instanceof ModelIllegalStateException) {
status = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
}
if (throwable instanceof ModelDuplicateException) {
status = Response.Status.CONFLICT.getStatusCode();
}

View file

@ -32,11 +32,13 @@ import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleMapperModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.storage.ReadOnlyException;
@ -173,6 +175,9 @@ public class ClientRoleMappingsResource {
auth.roles().requireMapRole(roleModel);
user.grantRole(roleModel);
}
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException | ReadOnlyException me) {
logger.warn(me.getMessage(), me);
throw new ErrorResponseException("invalid_request", "Could not add user role mappings!", Response.Status.BAD_REQUEST);
@ -212,6 +217,9 @@ public class ClientRoleMappingsResource {
auth.roles().requireMapRole(roleModel);
try {
user.deleteRoleMapping(roleModel);
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException | ReadOnlyException me) {
logger.warn(me.getMessage(), me);
throw new ErrorResponseException("invalid_request", "Could not remove user role mappings!", Response.Status.BAD_REQUEST);

View file

@ -28,6 +28,7 @@ import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
@ -157,6 +158,9 @@ public class ClientScopeResource {
realm.removeClientScope(clientScope.getId());
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success();
return Response.noContent().build();
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException me) {
throw ErrorResponse.error(me.getMessage(), Response.Status.BAD_REQUEST);
}

View file

@ -86,6 +86,7 @@ import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.UserModel;
@ -424,7 +425,7 @@ public class RealmAdminResource {
if (Config.getAdminRealm().equals(realm.getName()) && (rep.getRealm() != null && !rep.getRealm().equals(Config.getAdminRealm()))) {
throw ErrorResponse.error("Can't rename master realm", Status.BAD_REQUEST);
}
ReservedCharValidator.validate(rep.getRealm());
ReservedCharValidator.validateLocales(rep.getSupportedLocales());
@ -458,14 +459,17 @@ public class RealmAdminResource {
session.getContext().getUri();
adminEvent.operation(OperationType.UPDATE).representation(rep).success();
if (rep.isDuplicateEmailsAllowed() != null && rep.isDuplicateEmailsAllowed() != wasDuplicateEmailsAllowed) {
session.invalidate(InvalidationHandler.ObjectType.REALM, realm.getId());
}
return Response.noContent().build();
} catch (ModelDuplicateException e) {
throw ErrorResponse.exists("Realm with same name exists");
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Status.INTERNAL_SERVER_ERROR);
} catch (ModelException e) {
throw ErrorResponse.error(e.getMessage(), Status.BAD_REQUEST);
} catch (Exception e) {

View file

@ -31,6 +31,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.StripSecretsUtils;
@ -167,6 +168,9 @@ public class RealmsAdminResource {
logger.error("Password policy not met for user " + e.getUsername(), e);
if (session.getTransactionManager().isActive()) session.getTransactionManager().setRollbackOnly();
throw ErrorResponse.error("Password policy not met. See logs for details", Response.Status.BAD_REQUEST);
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException e) {
throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST);
}

View file

@ -31,6 +31,7 @@ import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleMapperModel;
@ -39,6 +40,7 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientMappingsRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.KeycloakOpenAPI;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
@ -243,6 +245,9 @@ public class RoleMapperResource {
auth.roles().requireMapRole(roleModel);
roleMapper.grantRole(roleModel);
}
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException | ReadOnlyException me) {
logger.warn(me.getMessage(), me);
throw new ErrorResponseException("invalid_request", "Could not add user role mappings!", Response.Status.BAD_REQUEST);
@ -283,6 +288,9 @@ public class RoleMapperResource {
auth.roles().requireMapRole(roleModel);
try {
roleMapper.deleteRoleMapping(roleModel);
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException | ReadOnlyException me) {
logger.warn(me.getMessage(), me);
throw new ErrorResponseException("invalid_request", "Could not remove user role mappings!", Response.Status.BAD_REQUEST);

View file

@ -48,6 +48,7 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserCredentialModel;
@ -229,6 +230,9 @@ public class UserResource {
Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
Status.BAD_REQUEST);
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException me) {
logger.warn("Could not update user!", me);
session.getTransactionManager().setRollbackOnly();
@ -696,6 +700,9 @@ public class UserResource {
Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
Status.BAD_REQUEST);
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException e) {
logger.warn("Could not update user password.", e);
Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
@ -1015,6 +1022,9 @@ public class UserResource {
user.leaveGroup(group);
adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(session.getContext().getUri()).success();
}
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException me) {
Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(me.getMessage(), MessageFormat.format(messages.getProperty(me.getMessage(), me.getMessage()), me.getParameters()),

View file

@ -31,6 +31,7 @@ import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelIllegalStateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
@ -164,6 +165,9 @@ public class UsersResource {
Properties messages = AdminRoot.getMessages(session, realm, auth.adminAuth().getToken().getLocale());
throw new ErrorResponseException(e.getMessage(), MessageFormat.format(messages.getProperty(e.getMessage(), e.getMessage()), e.getParameters()),
Response.Status.BAD_REQUEST);
} catch (ModelIllegalStateException e) {
logger.error(e.getMessage(), e);
throw ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
} catch (ModelException me){
logger.warn("Could not create user", me);
throw ErrorResponse.error("Could not create user", Response.Status.BAD_REQUEST);