Improve error response to the client. Added errorType so that client can handle better than depending on the http status codes (#14784)

This commit is contained in:
Sriharsha Chintalapani 2024-01-21 08:07:07 -08:00 committed by GitHub
parent 62d1ef7c7d
commit 15eb094cff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 297 additions and 133 deletions

View File

@ -130,11 +130,11 @@ public class AirflowRESTClient extends PipelineServiceClient {
}
} catch (IOException | URISyntaxException e) {
throw IngestionPipelineDeploymentException.byMessage(
ingestionPipeline.getName(), e.getMessage());
ingestionPipeline.getName(), DEPLOYEMENT_ERROR, e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw IngestionPipelineDeploymentException.byMessage(
ingestionPipeline.getName(), e.getMessage());
ingestionPipeline.getName(), DEPLOYEMENT_ERROR, e.getMessage());
}
throw new PipelineServiceClientException(
String.format(
@ -181,14 +181,17 @@ public class AirflowRESTClient extends PipelineServiceClient {
return getResponse(200, response.body());
}
} catch (IOException | URISyntaxException e) {
throw IngestionPipelineDeploymentException.byMessage(pipelineName, e.getMessage());
throw IngestionPipelineDeploymentException.byMessage(
pipelineName, TRIGGER_ERROR, e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw IngestionPipelineDeploymentException.byMessage(pipelineName, e.getMessage());
throw IngestionPipelineDeploymentException.byMessage(
pipelineName, TRIGGER_ERROR, e.getMessage());
}
throw IngestionPipelineDeploymentException.byMessage(
pipelineName,
TRIGGER_ERROR,
"Failed to trigger IngestionPipeline",
Response.Status.fromStatusCode(response.statusCode()));
}
@ -318,10 +321,12 @@ public class AirflowRESTClient extends PipelineServiceClient {
return getResponse(200, response.body());
}
} catch (IOException | URISyntaxException e) {
throw IngestionPipelineDeploymentException.byMessage(workflow.getName(), e.getMessage());
throw IngestionPipelineDeploymentException.byMessage(
workflow.getName(), TRIGGER_ERROR, e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw IngestionPipelineDeploymentException.byMessage(workflow.getName(), e.getMessage());
throw IngestionPipelineDeploymentException.byMessage(
workflow.getName(), TRIGGER_ERROR, e.getMessage());
}
throw new PipelineServiceClientException(
String.format(
@ -354,10 +359,12 @@ public class AirflowRESTClient extends PipelineServiceClient {
return getResponse(200, response.body());
}
} catch (IOException | URISyntaxException e) {
throw IngestionPipelineDeploymentException.byMessage(workflowPayload, e.getMessage());
throw IngestionPipelineDeploymentException.byMessage(
workflowPayload, DEPLOYEMENT_ERROR, e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw IngestionPipelineDeploymentException.byMessage(workflowPayload, e.getMessage());
throw IngestionPipelineDeploymentException.byMessage(
workflowPayload, DEPLOYEMENT_ERROR, e.getMessage());
}
throw new PipelineServiceClientException(
String.format(

View File

@ -18,9 +18,10 @@ import org.openmetadata.sdk.exception.WebServiceException;
public final class BadRequestException extends WebServiceException {
private static final String DEFAULT_MESSAGE = "Bad request.";
private static final String ERROR_TYPE = "BAD_REQUEST";
private BadRequestException() {
super(Response.Status.BAD_REQUEST, DEFAULT_MESSAGE);
super(Response.Status.BAD_REQUEST, ERROR_TYPE, DEFAULT_MESSAGE);
}
public static BadRequestException of() {

View File

@ -28,14 +28,22 @@ import org.openmetadata.service.resources.feeds.MessageParser.EntityLink;
import org.openmetadata.service.util.JsonUtils;
public final class CatalogExceptionMessage {
public static final String FAILED_SEND_EMAIL = "FAILED_SEND_EMAIL";
public static final String EMAIL_SENDING_ISSUE =
"There is some issue in sending the Mail. Please contact your administrator.";
public static final String PASSWORD_INVALID_FORMAT =
"Password must be of minimum 8 characters, with one special, one Upper, one lower case character, and one Digit.";
public static final String MAX_FAILED_LOGIN_ATTEMPT =
"Failed Login Attempts Exceeded. Please try after some time.";
public static final String INCORRECT_OLD_PASSWORD = "INCORRECT_OLD_PASSWORD";
public static final String INVALID_USER_OR_PASSWORD = "INVALID_USER_OR_PASSWORD";
public static final String INVALID_USERNAME_PASSWORD =
"You have entered an invalid username or password.";
public static final String PASSWORD_RESET_TOKEN_EXPIRED = "PASSWORD_RESET_TOKEN_EXPIRED";
public static final String ENTITY_ALREADY_EXISTS = "Entity already exists";
public static final String FERNET_KEY_NULL = "Fernet key is null";
public static final String FIELD_NOT_TOKENIZED = "Field is not tokenized";
@ -62,17 +70,26 @@ public final class CatalogExceptionMessage {
"Unexpected error occurred while building the teams hierarchy";
public static final String LDAP_MISSING_ATTR =
"Username or Email Attribute is incorrect. Please check Openmetadata Configuration.";
public static final String MULTIPLE_EMAIL_ENTRIES_ERROR = "MULTIPLE_EMAIL_ENTRIES_ERROR";
public static final String MULTIPLE_EMAIL_ENTRIES =
"Email corresponds to multiple entries in Directory.";
public static final String INVALID_EMAIL_PASSWORD =
"You have entered an invalid email or password.";
public static final String EMAIL_EXISTS = "EMAIL_EXISTS";
public static final String SELF_SIGNUP_NOT_ENABLED = "SELF_SIGNUP_NOT_ENABLED";
public static final String SELF_SIGNUP_ERROR = "Signup is not supported.";
public static final String NOT_IMPLEMENTED_METHOD = "Method not implemented.";
public static final String AUTHENTICATOR_OPERATION_NOT_SUPPORTED =
"AUTHENTICATOR_OPERATION_NOT_SUPPORTED";
public static final String FORBIDDEN_AUTHENTICATOR_OP =
"Operation is not permitted with the Selected Authenticator.";
public static final String INVALID_TOKEN = "INVALID_TOKEN";
public static final String TOKEN_EXPIRED = "TOKEN_EXPIRED";
public static final String TOKEN_EXPIRY_ERROR =
"Email Verification Token %s is expired. Please issue a new request for email verification.";
public static final String INVALID_BOT_USER = "Revoke Token can only be applied to Bot Users.";

View File

@ -4,11 +4,11 @@ import javax.ws.rs.core.Response;
import org.openmetadata.sdk.exception.WebServiceException;
public class CustomExceptionMessage extends WebServiceException {
public CustomExceptionMessage(Response.Status status, String message) {
super(status.getStatusCode(), message);
public CustomExceptionMessage(Response.Status status, String errorType, String message) {
super(status.getStatusCode(), errorType, message);
}
public CustomExceptionMessage(int status, String message) {
super(status, message);
public CustomExceptionMessage(int status, String errorType, String message) {
super(status, errorType, message);
}
}

View File

@ -17,8 +17,9 @@ import javax.ws.rs.core.Response;
import org.openmetadata.sdk.exception.WebServiceException;
public class EntityMaskException extends WebServiceException {
private static final String ERROR_TYPE = "ENTITY_MASK_ERROR";
public EntityMaskException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, message);
super(Response.Status.INTERNAL_SERVER_ERROR, ERROR_TYPE, message);
}
}

View File

@ -25,12 +25,14 @@ public class EntityNotFoundException extends WebServiceException {
private static final String BY_PARSER_SCHEMA_MESSAGE =
"Parser schema not found for entity with id [%s].";
private static final String ERROR_TYPE = "ENTITY_NOT_FOUND";
public EntityNotFoundException(String message) {
super(Response.Status.NOT_FOUND, message);
super(Response.Status.NOT_FOUND, ERROR_TYPE, message);
}
private EntityNotFoundException(String message, Throwable cause) {
super(Response.Status.NOT_FOUND, message, cause);
super(Response.Status.NOT_FOUND, ERROR_TYPE, message, cause);
}
public static EntityNotFoundException byId(String id) {

View File

@ -5,13 +5,14 @@ import org.openmetadata.schema.tests.type.TestCaseResolutionStatusTypes;
import org.openmetadata.sdk.exception.WebServiceException;
public class IncidentManagerException extends WebServiceException {
private static final String ERROR_TYPE = "INCIDENT_INVALID_STATUS";
protected IncidentManagerException(Response.Status status, String message) {
super(status.getStatusCode(), message);
super(status.getStatusCode(), ERROR_TYPE, message);
}
public IncidentManagerException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, message);
super(Response.Status.INTERNAL_SERVER_ERROR, ERROR_TYPE, message);
}
public static IncidentManagerException invalidStatus(

View File

@ -19,23 +19,27 @@ import org.openmetadata.sdk.exception.WebServiceException;
public class IngestionPipelineDeploymentException extends WebServiceException {
private static final String BY_NAME_MESSAGE = "Failed to deploy pipeline [%s] due to [%s].";
private static final String ERROR_TYPE = "DEPLOYMENT_ERROR";
public IngestionPipelineDeploymentException(String message) {
super(Response.Status.BAD_REQUEST, message);
super(Response.Status.BAD_REQUEST, ERROR_TYPE, message);
}
private IngestionPipelineDeploymentException(Response.Status status, String message) {
super(status, message);
private IngestionPipelineDeploymentException(
Response.Status status, String errorType, String message) {
super(status, errorType, message);
}
public static IngestionPipelineDeploymentException byMessage(
String name, String errorMessage, Response.Status status) {
return new IngestionPipelineDeploymentException(status, buildMessageByName(name, errorMessage));
String name, String errorType, String errorMessage, Response.Status status) {
return new IngestionPipelineDeploymentException(
status, errorType, buildMessageByName(name, errorMessage));
}
public static IngestionPipelineDeploymentException byMessage(String name, String errorMessage) {
public static IngestionPipelineDeploymentException byMessage(
String name, String errorType, String errorMessage) {
return new IngestionPipelineDeploymentException(
Response.Status.BAD_REQUEST, buildMessageByName(name, errorMessage));
Response.Status.BAD_REQUEST, errorType, buildMessageByName(name, errorMessage));
}
public static String buildMessageByName(String name, String errorMessage) {

View File

@ -6,13 +6,14 @@ import org.openmetadata.sdk.exception.WebServiceException;
public class InvalidServiceConnectionException extends WebServiceException {
private static final String BY_NAME_MESSAGE =
"InvalidServiceConnectionException for service [%s] due to [%s].";
private static final String ERROR_TYPE = "INVALID_SERVICE_EXCEPTION";
public InvalidServiceConnectionException(String message) {
super(Response.Status.BAD_REQUEST, message);
super(Response.Status.BAD_REQUEST, ERROR_TYPE, message);
}
private InvalidServiceConnectionException(Response.Status status, String message) {
super(status, message);
super(status, ERROR_TYPE, message);
}
public static InvalidServiceConnectionException byMessage(

View File

@ -1,32 +0,0 @@
package org.openmetadata.service.exception;
import javax.ws.rs.core.Response;
import org.openmetadata.sdk.exception.WebServiceException;
public class OpenMetadataClientSecurityConfigException extends WebServiceException {
private static final String BY_NAME_MESSAGE = "Airflow Exception [%s] due to [%s].";
public OpenMetadataClientSecurityConfigException(String message) {
super(Response.Status.BAD_REQUEST, message);
}
private OpenMetadataClientSecurityConfigException(Response.Status status, String message) {
super(status, message);
}
public static OpenMetadataClientSecurityConfigException byMessage(
String name, String errorMessage, Response.Status status) {
return new OpenMetadataClientSecurityConfigException(
status, buildMessageByName(name, errorMessage));
}
public static OpenMetadataClientSecurityConfigException byMessage(
String name, String errorMessage) {
return new OpenMetadataClientSecurityConfigException(
Response.Status.BAD_REQUEST, buildMessageByName(name, errorMessage));
}
private static String buildMessageByName(String name, String errorMessage) {
return String.format(BY_NAME_MESSAGE, name, errorMessage);
}
}

View File

@ -18,7 +18,9 @@ import org.openmetadata.sdk.exception.WebServiceException;
public class ReflectionException extends WebServiceException {
public static final String REFLECTION_ERROR = "REFLECTION_ERROR";
public ReflectionException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, message);
super(Response.Status.INTERNAL_SERVER_ERROR, REFLECTION_ERROR, message);
}
}

View File

@ -20,12 +20,14 @@ public class SecretsManagerException extends WebServiceException {
private static final String BY_NAME_MESSAGE =
"SecretsManagerException for secret manager [%s] when using the secret name [%s] due to [%s].";
public static final String SECRETS_MANAGER_ERROR = "SECRETS_MANAGER_ERROR";
public SecretsManagerException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, message);
super(Response.Status.INTERNAL_SERVER_ERROR, SECRETS_MANAGER_ERROR, message);
}
public SecretsManagerException(Response.Status status, String message) {
super(status.getStatusCode(), message);
super(status.getStatusCode(), SECRETS_MANAGER_ERROR, message);
}
public static SecretsManagerException byMessage(

View File

@ -20,11 +20,20 @@ public class UnhandledServerException extends WebServiceException {
private static final String MESSAGE =
"An exception with message [%s] was thrown while processing request.";
public static final String UNHANDLED_ERROR = "REFLECTION_ERROR";
public UnhandledServerException(String exceptionMessage) {
super(Response.Status.INTERNAL_SERVER_ERROR, String.format(MESSAGE, exceptionMessage));
super(
Response.Status.INTERNAL_SERVER_ERROR,
UNHANDLED_ERROR,
String.format(MESSAGE, exceptionMessage));
}
public UnhandledServerException(String exceptionMessage, Throwable cause) {
super(Response.Status.INTERNAL_SERVER_ERROR, String.format(MESSAGE, exceptionMessage), cause);
super(
Response.Status.INTERNAL_SERVER_ERROR,
UNHANDLED_ERROR,
String.format(MESSAGE, exceptionMessage),
cause);
}
}

View File

@ -171,7 +171,10 @@ public class SystemRepository {
SettingsCache.invalidateSettings(setting.getConfigType().value());
} catch (Exception ex) {
LOG.error("Failing in Updating Setting.", ex);
throw new CustomExceptionMessage(Response.Status.INTERNAL_SERVER_ERROR, ex.getMessage());
throw new CustomExceptionMessage(
Response.Status.INTERNAL_SERVER_ERROR,
"FAILED_TO_UPDATE_SLACK_OR_EMAIL",
ex.getMessage());
}
}

View File

@ -1272,7 +1272,8 @@ public class UserResource extends EntityResource<User, UserRepository> {
UserTokenCache.invalidateToken(user.getName());
return Response.status(Response.Status.OK).entity(personalAccessToken).build();
}
throw new CustomExceptionMessage(BAD_REQUEST, "Bots cannot have a Personal Access Token.");
throw new CustomExceptionMessage(
BAD_REQUEST, "NO_PERSONAL_TOKEN_FOR_BOTS", "Bots cannot have a Personal Access Token.");
}
@GET
@ -1371,7 +1372,8 @@ public class UserResource extends EntityResource<User, UserRepository> {
public void validateEmailAlreadyExists(String email) {
if (repository.checkEmailAlreadyExists(email)) {
throw new CustomExceptionMessage(BAD_REQUEST, "User with Email Already Exists");
throw new CustomExceptionMessage(
BAD_REQUEST, "EMAIL_EXISTS", "User with Email Already Exists");
}
}

View File

@ -54,6 +54,8 @@ public interface SearchClient {
String REMOVE_TEST_SUITE_CHILDREN_SCRIPT =
"for (int i = 0; i < ctx._source.testSuites.length; i++) { if (ctx._source.testSuites[i].id == '%s') { ctx._source.testSuites.remove(i) }}";
String NOT_IMPLEMENTED_ERROR_TYPE = "NOT_IMPLEMENTED";
boolean isClientAvailable();
ElasticSearchConfiguration.SearchType getSearchType();
@ -128,22 +130,26 @@ public interface SearchClient {
throws IOException, ParseException;
default BulkResponse bulk(BulkRequest data, RequestOptions options) throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default es.org.elasticsearch.action.bulk.BulkResponse bulk(
es.org.elasticsearch.action.bulk.BulkRequest data,
es.org.elasticsearch.client.RequestOptions options)
throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default int getSuccessFromBulkResponse(BulkResponse response) {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default int getSuccessFromBulkResponse(es.org.elasticsearch.action.bulk.BulkResponse response) {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
void close();

View File

@ -22,6 +22,7 @@ import static org.openmetadata.service.search.EntityBuilderConstant.UNIFIED;
import static org.openmetadata.service.search.UpdateSearchEventsConstant.SENDING_REQUEST_TO_ELASTIC_SEARCH;
import com.fasterxml.jackson.databind.JsonNode;
import es.org.elasticsearch.ElasticsearchStatusException;
import es.org.elasticsearch.action.ActionListener;
import es.org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import es.org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@ -65,6 +66,7 @@ import es.org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import es.org.elasticsearch.index.reindex.BulkByScrollResponse;
import es.org.elasticsearch.index.reindex.DeleteByQueryRequest;
import es.org.elasticsearch.index.reindex.UpdateByQueryRequest;
import es.org.elasticsearch.rest.RestStatus;
import es.org.elasticsearch.script.Script;
import es.org.elasticsearch.script.ScriptType;
import es.org.elasticsearch.search.SearchModule;
@ -115,6 +117,8 @@ import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.schema.DataInsightInterface;
import org.openmetadata.schema.dataInsight.DataInsightChartResult;
import org.openmetadata.schema.service.configuration.elasticsearch.ElasticSearchConfiguration;
import org.openmetadata.sdk.exception.SearchException;
import org.openmetadata.sdk.exception.SearchIndexNotFoundException;
import org.openmetadata.service.Entity;
import org.openmetadata.service.dataInsight.DataInsightAggregatorInterface;
import org.openmetadata.service.jdbi3.DataInsightChartRepository;
@ -422,14 +426,23 @@ public class ElasticSearchClient implements SearchClient {
}
searchSourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
String response =
client
.search(
new es.org.elasticsearch.action.search.SearchRequest(request.getIndex())
.source(searchSourceBuilder),
RequestOptions.DEFAULT)
.toString();
return Response.status(OK).entity(response).build();
try {
String response =
client
.search(
new es.org.elasticsearch.action.search.SearchRequest(request.getIndex())
.source(searchSourceBuilder),
RequestOptions.DEFAULT)
.toString();
return Response.status(OK).entity(response).build();
} catch (ElasticsearchStatusException e) {
if (e.status() == RestStatus.NOT_FOUND) {
throw new SearchIndexNotFoundException(
String.format("Failed to to find index %s", request.getIndex()));
} else {
throw new SearchException(String.format("Search failed due to %s", e.getMessage()));
}
}
}
@Override

View File

@ -22,6 +22,7 @@ import static org.openmetadata.service.search.EntityBuilderConstant.UNIFIED;
import static org.openmetadata.service.search.UpdateSearchEventsConstant.SENDING_REQUEST_TO_ELASTIC_SEARCH;
import com.fasterxml.jackson.databind.JsonNode;
import es.org.elasticsearch.index.IndexNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
@ -48,6 +49,7 @@ import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.schema.DataInsightInterface;
import org.openmetadata.schema.dataInsight.DataInsightChartResult;
import org.openmetadata.schema.service.configuration.elasticsearch.ElasticSearchConfiguration;
import org.openmetadata.sdk.exception.SearchIndexNotFoundException;
import org.openmetadata.service.Entity;
import org.openmetadata.service.dataInsight.DataInsightAggregatorInterface;
import org.openmetadata.service.jdbi3.DataInsightChartRepository;
@ -418,14 +420,19 @@ public class OpenSearchClient implements SearchClient {
}
searchSourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
String response =
client
.search(
new os.org.opensearch.action.search.SearchRequest(request.getIndex())
.source(searchSourceBuilder),
RequestOptions.DEFAULT)
.toString();
return Response.status(OK).entity(response).build();
try {
String response =
client
.search(
new os.org.opensearch.action.search.SearchRequest(request.getIndex())
.source(searchSourceBuilder),
RequestOptions.DEFAULT)
.toString();
return Response.status(OK).entity(response).build();
} catch (IndexNotFoundException e) {
throw new SearchIndexNotFoundException(
String.format("Failed to to find index %s", request.getIndex()));
}
}
@Override

View File

@ -23,6 +23,8 @@ import org.openmetadata.service.exception.CustomExceptionMessage;
import org.openmetadata.service.security.jwt.JWTTokenGenerator;
public interface AuthenticatorHandler {
String NOT_IMPLEMENTED_ERROR_TYPE = "NOT_IMPLEMENTED";
void init(OpenMetadataApplicationConfig config);
JwtResponse loginUser(LoginRequest loginRequest) throws IOException, TemplateException;
@ -38,42 +40,51 @@ public interface AuthenticatorHandler {
User lookUserInProvider(String userName);
default User registerUser(RegistrationRequest registrationRequest) {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void sendEmailVerification(UriInfo uriInfo, User user) throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void confirmEmailRegistration(UriInfo uriInfo, String emailToken) {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void resendRegistrationToken(UriInfo uriInfo, User registeredUser) throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void sendPasswordResetLink(
UriInfo uriInfo, User user, String subject, String templateFilePath) throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void resetUserPasswordWithToken(UriInfo uriInfo, PasswordResetRequest req)
throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void changeUserPwdWithOldPwd(UriInfo uriInfo, String userName, ChangePasswordRequest req)
throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default RefreshToken createRefreshTokenForLogin(UUID currentUserId) {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default JwtResponse getNewAccessToken(TokenRefreshRequest request) {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default void sendInviteMailToUser(
@ -83,7 +94,8 @@ public interface AuthenticatorHandler {
CreateUser.CreatePasswordType requestType,
String pwd)
throws IOException {
throw new CustomExceptionMessage(Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_METHOD);
throw new CustomExceptionMessage(
Response.Status.NOT_IMPLEMENTED, NOT_IMPLEMENTED_ERROR_TYPE, NOT_IMPLEMENTED_METHOD);
}
default JwtResponse getJwtResponse(User storedUser, long expireInSeconds) {

View File

@ -22,10 +22,18 @@ import static org.openmetadata.schema.auth.ChangePasswordRequest.RequestType.USE
import static org.openmetadata.schema.auth.TokenType.EMAIL_VERIFICATION;
import static org.openmetadata.schema.auth.TokenType.PASSWORD_RESET;
import static org.openmetadata.schema.entity.teams.AuthenticationMechanism.AuthType.BASIC;
import static org.openmetadata.service.exception.CatalogExceptionMessage.EMAIL_EXISTS;
import static org.openmetadata.service.exception.CatalogExceptionMessage.EMAIL_SENDING_ISSUE;
import static org.openmetadata.service.exception.CatalogExceptionMessage.FAILED_SEND_EMAIL;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INCORRECT_OLD_PASSWORD;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INVALID_TOKEN;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INVALID_USERNAME_PASSWORD;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INVALID_USER_OR_PASSWORD;
import static org.openmetadata.service.exception.CatalogExceptionMessage.MAX_FAILED_LOGIN_ATTEMPT;
import static org.openmetadata.service.exception.CatalogExceptionMessage.PASSWORD_RESET_TOKEN_EXPIRED;
import static org.openmetadata.service.exception.CatalogExceptionMessage.SELF_SIGNUP_ERROR;
import static org.openmetadata.service.exception.CatalogExceptionMessage.SELF_SIGNUP_NOT_ENABLED;
import static org.openmetadata.service.exception.CatalogExceptionMessage.TOKEN_EXPIRED;
import static org.openmetadata.service.exception.CatalogExceptionMessage.TOKEN_EXPIRY_ERROR;
import static org.openmetadata.service.resources.teams.UserResource.USER_PROTECTED_FIELDS;
import static org.openmetadata.service.util.EmailUtil.getSmtpSettings;
@ -126,7 +134,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
registeredUser.setAuthenticationMechanism(null);
return registeredUser;
} else {
throw new CustomExceptionMessage(NOT_IMPLEMENTED, SELF_SIGNUP_ERROR);
throw new CustomExceptionMessage(NOT_IMPLEMENTED, SELF_SIGNUP_NOT_ENABLED, SELF_SIGNUP_ERROR);
}
}
@ -146,6 +154,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
if (emailVerificationToken.getExpiryDate().compareTo(Instant.now().toEpochMilli()) < 0) {
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR,
TOKEN_EXPIRED,
String.format(TOKEN_EXPIRY_ERROR, emailVerificationToken.getToken()));
}
@ -180,7 +189,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
EmailUtil.sendEmailVerification(emailVerificationLink, user);
} catch (TemplateException e) {
LOG.error("Error in sending mail to the User : {}", e.getMessage(), e);
throw new CustomExceptionMessage(424, EMAIL_SENDING_ISSUE);
throw new CustomExceptionMessage(424, FAILED_SEND_EMAIL, EMAIL_SENDING_ISSUE);
}
// insert the token
tokenRepository.insertToken(emailVerificationToken);
@ -204,7 +213,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
EmailUtil.sendPasswordResetLink(passwordResetLink, user, subject, templateFilePath);
} catch (TemplateException e) {
LOG.error("Error in sending mail to the User : {}", e.getMessage(), e);
throw new CustomExceptionMessage(424, EMAIL_SENDING_ISSUE);
throw new CustomExceptionMessage(424, FAILED_SEND_EMAIL, EMAIL_SENDING_ISSUE);
}
// don't persist tokens delete existing
tokenRepository.deleteTokenByUserAndType(user.getId(), PASSWORD_RESET.toString());
@ -226,7 +235,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
new EntityUtil.Fields(fields, String.join(",", fields)));
// token validity
if (!passwordResetToken.getUserId().equals(storedUser.getId())) {
throw new CustomExceptionMessage(BAD_REQUEST, "Token does not belong to the user.");
throw new CustomExceptionMessage(BAD_REQUEST, INVALID_TOKEN, "Invalid Token.");
}
verifyPasswordResetTokenExpiry(passwordResetToken);
// passwords validity
@ -252,7 +261,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
EmailUtil.sendAccountStatus(storedUser, "Update Password", "Change Successful");
} catch (TemplateException ex) {
LOG.error("Error in sending Password Change Mail to User. Reason : " + ex.getMessage(), ex);
throw new CustomExceptionMessage(424, EMAIL_SENDING_ISSUE);
throw new CustomExceptionMessage(424, FAILED_SEND_EMAIL, EMAIL_SENDING_ISSUE);
}
loginAttemptCache.recordSuccessfulLogin(request.getUsername());
}
@ -291,7 +300,8 @@ public class BasicAuthenticator implements AuthenticatorHandler {
&& !BCrypt.verifyer()
.verify(request.getOldPassword().toCharArray(), storedHashPassword)
.verified) {
throw new CustomExceptionMessage(BAD_REQUEST, "Old Password is not correct");
throw new CustomExceptionMessage(
BAD_REQUEST, INCORRECT_OLD_PASSWORD, "Old Password is not correct");
}
storedBasicAuthMechanism.setPassword(newHashedPassword);
@ -393,6 +403,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
if (token.getExpiryDate().compareTo(Instant.now().toEpochMilli()) < 0) {
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR,
PASSWORD_RESET_TOKEN_EXPIRED,
String.format(
"Password Reset Token %s Expired token. Please issue a new request",
token.getToken()));
@ -400,6 +411,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
if (Boolean.FALSE.equals(token.getIsActive())) {
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR,
PASSWORD_RESET_TOKEN_EXPIRED,
String.format("Password Reset Token %s Token was marked inactive", token.getToken()));
}
}
@ -412,6 +424,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
if (storedRefreshToken.getExpiryDate().compareTo(Instant.now().toEpochMilli()) < 0) {
throw new CustomExceptionMessage(
BAD_REQUEST,
PASSWORD_RESET_TOKEN_EXPIRED,
"Expired token. Please login again : " + storedRefreshToken.getToken().toString());
}
// TODO: currently allow single login from a place, later multiple login can be added
@ -449,7 +462,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
public void validateEmailAlreadyExists(String email) {
if (userRepository.checkEmailAlreadyExists(email)) {
throw new CustomExceptionMessage(BAD_REQUEST, "User with Email Already Exists");
throw new CustomExceptionMessage(BAD_REQUEST, EMAIL_EXISTS, "User with Email Already Exists");
}
}
@ -523,10 +536,12 @@ public class BasicAuthenticator implements AuthenticatorHandler {
}
if (storedUser != null && Boolean.TRUE.equals(storedUser.getIsBot())) {
throw new CustomExceptionMessage(BAD_REQUEST, INVALID_USERNAME_PASSWORD);
throw new CustomExceptionMessage(
BAD_REQUEST, INVALID_USER_OR_PASSWORD, INVALID_USERNAME_PASSWORD);
}
} catch (Exception ex) {
throw new CustomExceptionMessage(BAD_REQUEST, INVALID_USERNAME_PASSWORD);
throw new CustomExceptionMessage(
BAD_REQUEST, INVALID_USER_OR_PASSWORD, INVALID_USERNAME_PASSWORD);
}
return storedUser;
}

View File

@ -5,6 +5,7 @@ import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;
import static org.openmetadata.schema.auth.TokenType.REFRESH_TOKEN;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INVALID_EMAIL_PASSWORD;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INVALID_USER_OR_PASSWORD;
import static org.openmetadata.service.exception.CatalogExceptionMessage.LDAP_MISSING_ATTR;
import static org.openmetadata.service.exception.CatalogExceptionMessage.MAX_FAILED_LOGIN_ATTEMPT;
import static org.openmetadata.service.exception.CatalogExceptionMessage.MULTIPLE_EMAIL_ENTRIES;
@ -200,14 +201,16 @@ public class LdapAuthenticator implements AuthenticatorHandler {
&& Objects.equals(
bindingResult.getResultCode().getName(), ResultCode.INVALID_CREDENTIALS.getName())) {
recordFailedLoginAttempt(providedIdentity, storedUser);
throw new CustomExceptionMessage(UNAUTHORIZED, INVALID_EMAIL_PASSWORD);
throw new CustomExceptionMessage(
UNAUTHORIZED, INVALID_USER_OR_PASSWORD, INVALID_EMAIL_PASSWORD);
}
}
if (bindingResult != null) {
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR, bindingResult.getResultCode().getName());
INTERNAL_SERVER_ERROR, INVALID_USER_OR_PASSWORD, bindingResult.getResultCode().getName());
} else {
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, INVALID_EMAIL_PASSWORD);
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR, INVALID_USER_OR_PASSWORD, INVALID_EMAIL_PASSWORD);
}
}
@ -234,15 +237,17 @@ public class LdapAuthenticator implements AuthenticatorHandler {
if (!CommonUtil.nullOrEmpty(userDN) && emailAttr != null) {
return getUserForLdap(email).withName(userDN);
} else {
throw new CustomExceptionMessage(FORBIDDEN, LDAP_MISSING_ATTR);
throw new CustomExceptionMessage(FORBIDDEN, INVALID_USER_OR_PASSWORD, LDAP_MISSING_ATTR);
}
} else if (result.getSearchEntries().size() > 1) {
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, MULTIPLE_EMAIL_ENTRIES);
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR, MULTIPLE_EMAIL_ENTRIES, MULTIPLE_EMAIL_ENTRIES);
} else {
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, INVALID_EMAIL_PASSWORD);
throw new CustomExceptionMessage(
INTERNAL_SERVER_ERROR, MULTIPLE_EMAIL_ENTRIES, INVALID_EMAIL_PASSWORD);
}
} catch (LDAPException ex) {
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, ex.getMessage());
throw new CustomExceptionMessage(INTERNAL_SERVER_ERROR, "LDAP_ERROR", ex.getMessage());
}
}

View File

@ -1,5 +1,6 @@
package org.openmetadata.service.security.auth;
import static org.openmetadata.service.exception.CatalogExceptionMessage.AUTHENTICATOR_OPERATION_NOT_SUPPORTED;
import static org.openmetadata.service.exception.CatalogExceptionMessage.FORBIDDEN_AUTHENTICATOR_OP;
import javax.ws.rs.core.Response;
@ -17,26 +18,41 @@ public class NoopAuthenticator implements AuthenticatorHandler {
@Override
public JwtResponse loginUser(LoginRequest loginRequest) {
throw new CustomExceptionMessage(Response.Status.FORBIDDEN, FORBIDDEN_AUTHENTICATOR_OP);
throw new CustomExceptionMessage(
Response.Status.FORBIDDEN,
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
FORBIDDEN_AUTHENTICATOR_OP);
}
@Override
public void checkIfLoginBlocked(String userName) {
throw new CustomExceptionMessage(Response.Status.FORBIDDEN, FORBIDDEN_AUTHENTICATOR_OP);
throw new CustomExceptionMessage(
Response.Status.FORBIDDEN,
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
FORBIDDEN_AUTHENTICATOR_OP);
}
@Override
public void recordFailedLoginAttempt(String providedIdentity, User user) {
throw new CustomExceptionMessage(Response.Status.FORBIDDEN, FORBIDDEN_AUTHENTICATOR_OP);
throw new CustomExceptionMessage(
Response.Status.FORBIDDEN,
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
FORBIDDEN_AUTHENTICATOR_OP);
}
@Override
public void validatePassword(String providedIdentity, User storedUser, String reqPassword) {
throw new CustomExceptionMessage(Response.Status.FORBIDDEN, FORBIDDEN_AUTHENTICATOR_OP);
throw new CustomExceptionMessage(
Response.Status.FORBIDDEN,
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
FORBIDDEN_AUTHENTICATOR_OP);
}
@Override
public User lookUserInProvider(String userName) {
throw new CustomExceptionMessage(Response.Status.FORBIDDEN, FORBIDDEN_AUTHENTICATOR_OP);
throw new CustomExceptionMessage(
Response.Status.FORBIDDEN,
AUTHENTICATOR_OPERATION_NOT_SUPPORTED,
FORBIDDEN_AUTHENTICATOR_OP);
}
}

View File

@ -77,6 +77,9 @@ public abstract class PipelineServiceClient {
public static final String STATUS_KEY = "status";
public static final String APP_TRIGGER = "run_application";
public static final String APP_VALIDATE = "validate_registration";
public static final String DEPLOYEMENT_ERROR = "DEPLOYMENT_ERROR";
public static final String TRIGGER_ERROR = "TRIGGER_ERROR";
public static final Map<String, String> TYPE_TO_TASK =
Map.of(
PipelineType.METADATA.toString(),

View File

@ -17,13 +17,14 @@ import javax.ws.rs.core.Response;
public class PipelineServiceClientException extends WebServiceException {
private static final String BY_NAME_MESSAGE = "Airflow Exception [%s] due to [%s].";
private static final String ERROR_TYPE = "PIPELINE_SERVICE_ERROR";
public PipelineServiceClientException(String message) {
super(Response.Status.BAD_REQUEST, message);
super(Response.Status.BAD_REQUEST, ERROR_TYPE, message);
}
private PipelineServiceClientException(Response.Status status, String message) {
super(status, message);
super(status, ERROR_TYPE, message);
}
public static PipelineServiceClientException byMessage(

View File

@ -19,13 +19,14 @@ public class PipelineServiceVersionException extends WebServiceException {
private static final String BY_NAME_MESSAGE =
"Pipeline Service [%s] Version mismatch due to [%s].";
private static final String ERROR_TYPE = "PIPELINE_SERVICE_VERSION_MISMATCH";
public PipelineServiceVersionException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, message);
super(Response.Status.INTERNAL_SERVER_ERROR, ERROR_TYPE, message);
}
private PipelineServiceVersionException(Response.Status status, String message) {
super(status, message);
super(status, ERROR_TYPE, message);
}
public static PipelineServiceVersionException byMessage(

View File

@ -0,0 +1,30 @@
package org.openmetadata.sdk.exception;
import javax.ws.rs.core.Response;
public class SearchException extends WebServiceException {
private static final String BY_NAME_MESSAGE =
"Search Index Not Found Exception [%s] due to [%s].";
private static final String ERROR_TYPE = "SEARCH_ERROR";
public SearchException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, ERROR_TYPE, message);
}
private SearchException(Response.Status status, String message) {
super(status, ERROR_TYPE, message);
}
public static SearchException byMessage(
String name, String errorMessage, Response.Status status) {
return new SearchException(status, buildMessageByName(name, errorMessage));
}
public static SearchException byMessage(String name, String errorMessage) {
return new SearchException(Response.Status.BAD_REQUEST, buildMessageByName(name, errorMessage));
}
private static String buildMessageByName(String name, String errorMessage) {
return String.format(BY_NAME_MESSAGE, name, errorMessage);
}
}

View File

@ -0,0 +1,31 @@
package org.openmetadata.sdk.exception;
import javax.ws.rs.core.Response;
public class SearchIndexNotFoundException extends WebServiceException {
private static final String BY_NAME_MESSAGE =
"Search Index Not Found Exception [%s] due to [%s].";
private static final String ERROR_TYPE = "SEARCH_INDEX_NOT_FOUND";
public SearchIndexNotFoundException(String message) {
super(Response.Status.INTERNAL_SERVER_ERROR, ERROR_TYPE, message);
}
private SearchIndexNotFoundException(Response.Status status, String message) {
super(status, ERROR_TYPE, message);
}
public static SearchIndexNotFoundException byMessage(
String name, String errorMessage, Response.Status status) {
return new SearchIndexNotFoundException(status, buildMessageByName(name, errorMessage));
}
public static SearchIndexNotFoundException byMessage(String name, String errorMessage) {
return new SearchIndexNotFoundException(
Response.Status.BAD_REQUEST, buildMessageByName(name, errorMessage));
}
private static String buildMessageByName(String name, String errorMessage) {
return String.format(BY_NAME_MESSAGE, name, errorMessage);
}
}

View File

@ -13,51 +13,55 @@
package org.openmetadata.sdk.exception;
import io.dropwizard.jersey.errors.ErrorMessage;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lombok.Getter;
@Getter
public abstract class WebServiceException extends RuntimeException {
@Getter private final transient Response response;
private final transient Response response;
protected WebServiceException(Response.Status status, String msg) {
protected WebServiceException(Response.Status status, String errorType, String msg) {
super(msg);
response =
Response.status(status)
.entity(convertToErrorResponseMessage(msg))
.entity(convertToErrorResponseMessage(errorType, msg))
.type(MediaType.APPLICATION_JSON_TYPE)
.build();
}
protected WebServiceException(int status, String msg) {
protected WebServiceException(int status, String errorType, String msg) {
super(msg);
response =
Response.status(status)
.entity(new ErrorMessage(status, msg))
.entity(convertToErrorResponseMessage(errorType, msg))
.type(MediaType.APPLICATION_JSON_TYPE)
.build();
}
protected WebServiceException(Response.Status status, String msg, Throwable cause) {
protected WebServiceException(
Response.Status status, String errorType, String msg, Throwable cause) {
super(msg, cause);
response =
Response.status(status)
.entity(convertToErrorResponseMessage(msg))
.entity(convertToErrorResponseMessage(errorType, msg))
.type(MediaType.APPLICATION_JSON_TYPE)
.build();
}
private static ErrorResponse convertToErrorResponseMessage(String msg) {
return new ErrorResponse(msg);
private static ErrorResponse convertToErrorResponseMessage(String errorType, String msg) {
return new ErrorResponse(errorType, msg);
}
private static class ErrorResponse {
/** Response message. */
@Getter private final String responseMessage;
ErrorResponse(String responseMessage) {
@Getter private final String errorType;
ErrorResponse(String errorType, String responseMessage) {
this.responseMessage = responseMessage;
this.errorType = errorType;
}
}
}