diff options
author | Thomas <> | 2022-11-29 09:07:30 +0100 |
---|---|---|
committer | Thomas <> | 2022-11-29 09:07:30 +0100 |
commit | 20f485434680151111cf7cc7eaf33ca3b92221cb (patch) | |
tree | 0bb3460ecdf55324ff2c4c7dc8a84325c6f716ee /eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth | |
parent | 49d02d8c7c19ab9bb763d3f7fe862273706cc73a (diff) | |
download | EAAF-Components-20f485434680151111cf7cc7eaf33ca3b92221cb.tar.gz EAAF-Components-20f485434680151111cf7cc7eaf33ca3b92221cb.tar.bz2 EAAF-Components-20f485434680151111cf7cc7eaf33ca3b92221cb.zip |
feat(core): add ticket-based error-handling service as EAAF core functionality
Diffstat (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth')
-rw-r--r-- | eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/TicketErrorService.java | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/TicketErrorService.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/TicketErrorService.java new file mode 100644 index 00000000..557614e6 --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/TicketErrorService.java @@ -0,0 +1,234 @@ +package at.gv.egiz.eaaf.core.impl.idp.auth.services; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.CollectionType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.gui.ModifyableGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.data.ErrorConfig; +import at.gv.egiz.eaaf.core.impl.gui.AbstractGuiFormBuilderConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.controller.ProtocolFinalizationController; +import at.gv.egiz.eaaf.core.impl.utils.DefaultYamlMapper; +import at.gv.egiz.eaaf.core.impl.utils.FileUtils; +import at.gv.egiz.eaaf.core.impl.utils.ServletUtils; +import lombok.Builder; +import lombok.Getter; +import lombok.var; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class TicketErrorService implements IErrorService { + private static final String CONFIG_PROP_ERROR_HANDLING_CONFIG_PATH = "core.error.handling.config"; + private static final String TECH_LOG_MSG = "errorCode={0} Message={1}"; + private static final String TICKET_LOG_MSG = "Ticket={2} errorCode={0} Message={1}"; + + private final List<ErrorConfig> errorConfigList = new ArrayList<>(); + + + @Autowired + IConfiguration basicConfig; + + @Autowired + ResourceLoader resourceLoader; + + @Autowired + IPendingRequestIdGenerationStrategy requestIdValidationStragegy; + + @Override + public String getExternalCodeFromInternal(String internalCode) { + ErrorConfig errorConfig = findByInternalCode(internalCode); + return StringUtils.isNotEmpty(errorConfig.getExternalCode()) + ? errorConfig.getExternalCode() + : errorConfig.getUseInternalAsExternal() + ? internalCode + : IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + + } + + @Override + public IHandleData createHandleData(Throwable throwable, boolean supportRedirctToSp) throws EaafException { + String internalErrorId = extractInternalErrorCode(throwable); + ErrorConfig errorFlowConfig = findByInternalCode(internalErrorId); + ActionType errorHandlingFlow = errorFlowConfig.getActionType(); + + return HandleData.builder() + .throwable(throwable) + .internalErrorCode(internalErrorId) + .actionType(errorHandlingFlow) + .logLevel(LogLevel.fromString(errorFlowConfig.getLogLevel())) + .supportTicket(ActionType.TICKET.equals(errorHandlingFlow) ? generateSupportTicket() : null) + .errorIdTokenForRedirect( + supportRedirctToSp ? requestIdValidationStragegy.generateExternalPendingRequestId() : null) + .build(); + + } + + @Override + public void displayErrorData(ModifyableGuiBuilderConfiguration c, IErrorService.IHandleData errorData, + HttpServletRequest httpReq) throws EaafException { + if (!(errorData instanceof TicketErrorService.HandleData)) { + throw new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC); + } + var ed = (TicketErrorService.HandleData) errorData; + + // set SupportTicket + c.putCustomParameter(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_TICKET, ed.getSupportTicket()); + + // set redirect to SP path + if (StringUtils.isNotEmpty(ed.getErrorIdTokenForRedirect())) { + c.putCustomParameterWithOutEscaption( + AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_REDIRECT, + generateRedirect(httpReq, ed.getErrorIdTokenForRedirect())); + + } + } + + /** + * Generate a application-specific support-ticket. + * + * @return Support ticket for error screen + */ + protected abstract String generateSupportTicket(); + + + @Nonnull + private ErrorConfig findByInternalCode(@Nonnull String seekedInternalCode) { + return errorConfigList.stream() + .filter(c -> c.getInternalCode() != null && c.getInternalCode().contains(seekedInternalCode)) + .findFirst() + .orElse( + errorConfigList.stream() + .filter(c -> c.getDefaultConfig() != null && c.getDefaultConfig().equals(true)) + .findFirst() + .orElse(ErrorConfig.builder() + .action(ActionType.TICKET.toString()) + .externalCode(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC) + .logLevel("ERROR") + .defaultConfig(true) + .build()) + ); + + } + + private String extractInternalErrorCode(Throwable throwable) { + Throwable originalException; + if (throwable instanceof TaskExecutionException + && ((TaskExecutionException) throwable).getOriginalException() != null) { + originalException = ((TaskExecutionException) throwable).getOriginalException(); + + } else { + originalException = throwable; + + } + + if (!(originalException instanceof EaafException)) { + return IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC; + + } else { + return ((EaafException) originalException).getErrorId(); + + } + } + + private String generateRedirect(HttpServletRequest httpReq, String errorTokenId) { + String redirectUrl = ServletUtils.getBaseUrl(httpReq); + redirectUrl += ProtocolFinalizationController.ENDPOINT_ERROR_REDIRECT + "?" + + EaafConstants.PARAM_HTTP_ERROR_CODE + "=" + StringEscapeUtils + .escapeHtml4(errorTokenId); + return redirectUrl; + + } + + @PostConstruct + private void initialize() throws EaafException { + final String errorConfPath = basicConfig.getBasicConfiguration(CONFIG_PROP_ERROR_HANDLING_CONFIG_PATH); + log.info("Initializing error-handling service from configuration: {}", errorConfPath); + + if (StringUtils.isEmpty(errorConfPath)) { + log.error("Error: Path to error handling config is not known"); + throw new EaafException("internal.configuration.00", new Object[]{CONFIG_PROP_ERROR_HANDLING_CONFIG_PATH}); + } + + try { + final byte[] raw = readFromFile(errorConfPath); + ObjectMapper mapper = DefaultYamlMapper.getYamlMapper(); + final TypeFactory typeFactory = mapper.getTypeFactory(); + final CollectionType javaType = typeFactory.constructCollectionType(List.class, ErrorConfig.class); + errorConfigList.addAll(mapper.readValue(raw, javaType)); + + log.info("Found #{} configuration-elements for Error Handling", errorConfigList.size()); + + } catch (Exception e) { + log.error("Error reading Configurations file", e); + throw new EaafException("internal.configuration.01", + new Object[]{CONFIG_PROP_ERROR_HANDLING_CONFIG_PATH, "Error reading Configurations file"}); + } + + } + + private byte[] readFromFile(final String filePath) throws URISyntaxException, IOException { + final String fullFilePath = FileUtils.makeAbsoluteUrl(filePath, basicConfig.getConfigurationRootDirectory()); + final Resource ressource = resourceLoader.getResource(fullFilePath); + final InputStream is = ressource.getInputStream(); + final byte[] result = IOUtils.toByteArray(is); + is.close(); + return result; + } + + @Builder + static class HandleData implements IHandleData { + + @Getter + private String errorIdTokenForRedirect; + + @Getter + private String supportTicket; + + @Getter + private final Throwable throwable; + + @Getter + private String internalErrorCode; + + @Getter + private ActionType actionType; + + @Getter + private LogLevel logLevel; + + public String getPreFormatedErrorMessage() { + if (supportTicket != null) { + return MessageFormat.format(TICKET_LOG_MSG, internalErrorCode, throwable.getMessage(), supportTicket); + + } else { + return MessageFormat.format(TECH_LOG_MSG, internalErrorCode, throwable.getMessage()); + + } + } + } + +} |