From b9c39afad262a24df91f023b78081b96c039b1d0 Mon Sep 17 00:00:00 2001
From: Milton Ch <86965029+Milton-Ch@users.noreply.github.com>
Date: Thu, 13 Jan 2022 05:01:23 -0400
Subject: [PATCH] feat: add correlation id in pages and rest endpoints to track
logs (#410)
---
.../io/jans/as/model/config/Constants.java | 2 +
.../as/model/error/ErrorResponseFactory.java | 11 +++-
.../as/server/filter/CorrelationIdFilter.java | 56 +++++++++++++++++++
.../server/par/ws/rs/ParRestWebService.java | 16 +++++-
server/src/main/resources/log4j2.xml | 12 ++--
.../main/webapp/auth/otp_sms/otp_sms.xhtml | 6 ++
.../main/webapp/auth/register/register.xhtml | 6 ++
.../webapp/auth/thumbsignin/tsLogin.xhtml | 6 ++
server/src/main/webapp/casa/login.xhtml | 8 ++-
server/src/main/webapp/casa/otp.xhtml | 6 ++
server/src/main/webapp/ciba/home.xhtml | 7 +++
.../main/webapp/device_authorization.xhtml | 7 +++
server/src/main/webapp/error.xhtml | 6 ++
server/src/main/webapp/error_service.xhtml | 7 +++
server/src/main/webapp/error_session.xhtml | 7 +++
server/src/main/webapp/login.xhtml | 6 ++
16 files changed, 159 insertions(+), 10 deletions(-)
create mode 100644 server/src/main/java/io/jans/as/server/filter/CorrelationIdFilter.java
diff --git a/model/src/main/java/io/jans/as/model/config/Constants.java b/model/src/main/java/io/jans/as/model/config/Constants.java
index a440c4324d1..57a7cdfa679 100644
--- a/model/src/main/java/io/jans/as/model/config/Constants.java
+++ b/model/src/main/java/io/jans/as/model/config/Constants.java
@@ -57,4 +57,6 @@ private Constants() {
public static final String AUTHORIZATION_BASIC = "Authorization: Basic ";
public static final String REASON_CLIENT_NOT_AUTHORIZED = "The client is not authorized.";
+
+ public static final String CORRELATION_ID_HEADER = "X-Correlation-Id";
}
diff --git a/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java b/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java
index 8566712d2f1..7a127da72c1 100644
--- a/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java
+++ b/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java
@@ -12,6 +12,7 @@
import io.jans.as.model.ciba.BackchannelAuthenticationErrorResponseType;
import io.jans.as.model.clientinfo.ClientInfoErrorResponseType;
import io.jans.as.model.common.ComponentType;
+import io.jans.as.model.config.Constants;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.configuration.Configuration;
import io.jans.as.model.fido.u2f.U2fErrorResponseType;
@@ -22,6 +23,8 @@
import io.jans.as.model.uma.UmaErrorResponseType;
import io.jans.as.model.userinfo.UserInfoErrorResponseType;
import io.jans.as.model.util.Util;
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.ThreadContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -32,6 +35,7 @@
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
/**
@@ -190,7 +194,12 @@ public DefaultErrorResponse getErrorResponse(IErrorType type) {
if (list != null) {
final ErrorMessage m = getError(list, type);
- response.setErrorDescription(m.getDescription());
+
+ String description = Optional.ofNullable(ThreadContext.get(Constants.CORRELATION_ID_HEADER))
+ .map(id -> m.getDescription().concat(" CorrelationId: " + id))
+ .orElse(m.getDescription());
+
+ response.setErrorDescription(description);
response.setErrorUri(m.getUri());
}
}
diff --git a/server/src/main/java/io/jans/as/server/filter/CorrelationIdFilter.java b/server/src/main/java/io/jans/as/server/filter/CorrelationIdFilter.java
new file mode 100644
index 00000000000..8c6e2c3a5ca
--- /dev/null
+++ b/server/src/main/java/io/jans/as/server/filter/CorrelationIdFilter.java
@@ -0,0 +1,56 @@
+package io.jans.as.server.filter;
+
+import io.jans.as.server.uma.authorization.UmaWebException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import static io.jans.as.model.config.Constants.CORRELATION_ID_HEADER;
+
+@WebFilter(filterName = "CorrelationIdFilter", asyncSupported = true, urlPatterns = {"/*"})
+public class CorrelationIdFilter implements Filter {
+
+ private static final Logger log = LoggerFactory.getLogger(UmaWebException.class);
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+
+ String correlationId = httpRequest.getHeader(CORRELATION_ID_HEADER);
+ if (StringUtils.isBlank(correlationId)) {
+ correlationId = UUID.randomUUID().toString();
+
+ Cookie[] cookies = httpRequest.getCookies();
+ if (cookies == null || Stream.of(cookies).noneMatch(cookie -> cookie.getName().contains(CORRELATION_ID_HEADER))) {
+ Cookie cookie = new Cookie(CORRELATION_ID_HEADER, correlationId);
+ cookie.setSecure(true);
+ cookie.setHttpOnly(true);
+ httpResponse.addCookie(cookie);
+ }
+ }
+
+ ThreadContext.put(CORRELATION_ID_HEADER, correlationId);
+
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+}
diff --git a/server/src/main/java/io/jans/as/server/par/ws/rs/ParRestWebService.java b/server/src/main/java/io/jans/as/server/par/ws/rs/ParRestWebService.java
index 5f2124f4d30..e1134a46c54 100644
--- a/server/src/main/java/io/jans/as/server/par/ws/rs/ParRestWebService.java
+++ b/server/src/main/java/io/jans/as/server/par/ws/rs/ParRestWebService.java
@@ -7,6 +7,7 @@
import io.jans.as.model.common.ComponentType;
import io.jans.as.model.common.ResponseMode;
import io.jans.as.model.common.ResponseType;
+import io.jans.as.model.config.Constants;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.error.ErrorResponse;
import io.jans.as.model.error.ErrorResponseFactory;
@@ -19,6 +20,7 @@
import io.jans.as.server.util.QueryStringDecoder;
import io.jans.as.server.util.ServerUtil;
import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.ThreadContext;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
@@ -40,6 +42,8 @@
import javax.ws.rs.core.SecurityContext;
import java.net.URI;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
/**
* Implementation based on https://datatracker.ietf.org/doc/html/draft-ietf-oauth-par-08
@@ -199,8 +203,16 @@ private ErrorResponse createErrorResponseFromRedirectErrorUri(@NotNull URI locat
locationRedirect.parseQueryString(location.getQuery());
final ErrorResponse response = new ErrorResponse();
- response.setErrorCode(locationRedirect.getResponseParameter("error"));
- response.setErrorDescription(locationRedirect.getResponseParameter("error_description"));
+
+ String errorDescription = locationRedirect.getResponseParameter("error_description");
+ errorDescription = Optional.ofNullable(errorDescription)
+ .map(description -> Optional.ofNullable(ThreadContext.get(Constants.CORRELATION_ID_HEADER))
+ .map(id -> description.concat(" CorrelationId: " + id))
+ .orElse(description))
+ .orElse(null);
+
+ response.setErrorCode(errorDescription);
+ response.setErrorDescription(errorDescription);
return response;
}
diff --git a/server/src/main/resources/log4j2.xml b/server/src/main/resources/log4j2.xml
index 752189af9a8..9c45202bcd9 100644
--- a/server/src/main/resources/log4j2.xml
+++ b/server/src/main/resources/log4j2.xml
@@ -19,7 +19,7 @@
+ Correlation Id:
+ Correlation Id:
+ Correlation Id:
+ Correlation Id:
+ Correlation Id:
+ Correlation Id: