aboutsummaryrefslogtreecommitdiff
path: root/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisticLogger.java
diff options
context:
space:
mode:
Diffstat (limited to 'ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisticLogger.java')
-rw-r--r--ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisticLogger.java223
1 files changed, 223 insertions, 0 deletions
diff --git a/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisticLogger.java b/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisticLogger.java
new file mode 100644
index 00000000..06fb1aba
--- /dev/null
+++ b/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisticLogger.java
@@ -0,0 +1,223 @@
+package at.asitplus.eidas.specific.core.logger;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+
+import at.asitplus.eidas.specific.core.MsEidasNodeConstants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.log.statistic.DetailedMatchtingStatistic;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IStatusMessenger;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger;
+import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Extended statistic logger that use a JSON based data model.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class AdvancedStatisticLogger implements IStatisticLogger {
+
+ private static final String DATEFORMATER = "yyyy.MM.dd-HH:mm:ss,SSS";
+ private static final String DEFAULT_NO_IDP_ID = "no idpId available";
+ private static final String DEFAULT_NO_SP_ID = "no appId available";
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+ private static final JavaPropsMapper propsMapper = new JavaPropsMapper();
+
+ private final IStatusMessenger messageService;
+
+ /**
+ * Build a JSON based statistic logger that uses error messages from a specific source.
+ *
+ * @param source i18n message source
+ */
+ public AdvancedStatisticLogger(IStatusMessenger source) {
+ this.messageService = source;
+
+ }
+
+ @Override
+ public void logSuccessOperation(IRequest protocolRequest, IAuthData authData, boolean isSsoSession) {
+ final StatisticLogEntry entry = buildCoreEntry(protocolRequest);
+ entry.setSuccess(SuccessEntry.builder()
+ .spSector(protocolRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier())
+ .spCountry("AT")
+ .citizenCountryCode(authData.getCiticenCountryCode())
+ .build());
+ entry.setMatching(MatchingDetails.builder()
+ .matchingMethod(extractMatchingState(protocolRequest))
+ .matchingDetails(extractMatchingDetails(protocolRequest))
+ .build());
+ writeEntryToLog(entry);
+
+ }
+
+ @Override
+ public void logErrorOperation(Throwable throwable) {
+ log.trace("Advanced statistic logger only logs on SP level");
+
+ }
+
+ @Override
+ public void logErrorOperation(Throwable throwable, IRequest errorRequest) {
+ final StatisticLogEntry entry = buildCoreEntry(errorRequest);
+ entry.setError(new ErrorEntry(messageService.getResponseErrorCode(throwable), throwable.getMessage()));
+ entry.setMatching(MatchingDetails.builder()
+ .matchingMethod(extractMatchingState(errorRequest))
+ .matchingDetails(extractMatchingDetails(errorRequest))
+ .build());
+ writeEntryToLog(entry);
+
+ }
+
+ @Override
+ public void internalTesting() throws Exception {
+ log.trace("Not implemented for a File-based logger");
+
+ }
+
+ private StatisticLogEntry buildCoreEntry(IRequest errorRequest) {
+ Object appId = errorRequest.getRawData(MsEidasNodeConstants.DATA_REQUESTERID);
+ return new StatisticLogEntry(
+ LocalDateTime.now(),
+ errorRequest.getUniqueTransactionIdentifier(),
+ errorRequest.getServiceProviderConfiguration() != null
+ && errorRequest.getServiceProviderConfiguration().getUniqueIdentifier() != null
+ ? errorRequest.getServiceProviderConfiguration().getUniqueIdentifier() : DEFAULT_NO_IDP_ID,
+ appId instanceof String && StringUtils.isNotEmpty((String)appId)
+ ? (String)appId : DEFAULT_NO_SP_ID);
+
+ }
+
+ private String extractMatchingState(IRequest protocolRequest) {
+ Object state = protocolRequest.getRawData(MsEidasNodeConstants.DATA_MATCHING_STATE);
+ return state != null ? state.toString() : MsEidasNodeConstants.MatchingStates.NO_REQUIRED.toString();
+
+ }
+
+ private DetailedMatchtingStatistic extractMatchingDetails(IRequest protocolRequest) {
+ try {
+ if (!MsEidasNodeConstants.MatchingStates.NO_REQUIRED.toString().equals(
+ extractMatchingState(protocolRequest))) {
+ return MatchingTaskUtils.getDetailedMatchingStatistic(protocolRequest);
+
+ }
+
+ } catch (EaafStorageException e) {
+ log.warn("Can not generate detailed matching statistic", e);
+
+ }
+
+ return null;
+ }
+
+ private void writeEntryToLog(StatisticLogEntry entry) {
+ try {
+ log.info(mapper.writeValueAsString(propsMapper.writeValueAsProperties(entry)));
+
+ } catch (final IOException e) {
+ log.error("Can NOT generate statistic entry for logging", e);
+
+ }
+ }
+
+
+ @Getter
+ @Setter
+ @RequiredArgsConstructor
+ @JsonInclude(Include.NON_NULL)
+ private static class StatisticLogEntry {
+
+ @JsonSerialize(using = LocalDateTimeSerializer.class)
+ @JsonDeserialize(using = LocalDateTimeDeserializer.class)
+ @JsonFormat(pattern = DATEFORMATER)
+ @JsonProperty("timestamp")
+ private final LocalDateTime timestamp;
+
+ @JsonProperty("txId")
+ private final String transactionId;
+
+ @JsonProperty("entityid")
+ private final String idpEntityId;
+
+ @JsonProperty("unique-sp-id")
+ private final String uniqueId;
+
+ @JsonProperty("result")
+ private SuccessEntry success;
+
+ @JsonProperty("error")
+ private ErrorEntry error;
+
+ @JsonProperty("identityMatching")
+ private MatchingDetails matching;
+
+ }
+
+ @Getter
+ @Setter
+ @Builder
+ @JsonInclude(Include.NON_NULL)
+ private static class SuccessEntry {
+
+ @JsonProperty("spSector")
+ private final String spSector;
+
+ @JsonProperty("spCountry")
+ private final String spCountry;
+
+ @JsonProperty("citizenCountryCode")
+ private final String citizenCountryCode;
+
+ }
+
+ @Getter
+ @Setter
+ @Builder
+ @JsonInclude(Include.NON_NULL)
+ private static class MatchingDetails {
+
+ @JsonProperty("finalMatchingMethod")
+ private final String matchingMethod;
+
+ @JsonProperty("matchingProcessDetails")
+ private final DetailedMatchtingStatistic matchingDetails;
+
+ }
+
+ @Getter
+ @Setter
+ @RequiredArgsConstructor
+ private static class ErrorEntry {
+
+ @JsonProperty("code")
+ private final String errorCode;
+
+ @JsonProperty("msg")
+ private final String errorMessage;
+
+ }
+
+}