diff --git a/conf/log4j2.xml.template b/conf/log4j2.xml.template
index 6aedf7652ff..37fc8acf036 100644
--- a/conf/log4j2.xml.template
+++ b/conf/log4j2.xml.template
@@ -20,6 +20,10 @@
+
+ rest-audit.log
+ rest-audit-%d{yyyy-MM-dd}-%i.log
+
@@ -27,6 +31,14 @@
+
+
+
+
+
+
+
@@ -43,5 +55,8 @@
+
+
+
diff --git a/docs/deployment/settings.md b/docs/deployment/settings.md
index 15b0be9c49a..b006330f977 100644
--- a/docs/deployment/settings.md
+++ b/docs/deployment/settings.md
@@ -607,6 +607,10 @@ Kyuubi uses [log4j](https://logging.apache.org/log4j/2.x/) for logging. You can
+
+ rest-audit.log
+ rest-audit-%d{yyyy-MM-dd}-%i.log
+
@@ -614,6 +618,14 @@ Kyuubi uses [log4j](https://logging.apache.org/log4j/2.x/) for logging. You can
+
+
+
+
+
+
+
@@ -630,6 +642,9 @@ Kyuubi uses [log4j](https://logging.apache.org/log4j/2.x/) for logging. You can
+
+
+
```
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationAuditLogger.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationAuditLogger.scala
new file mode 100644
index 00000000000..ac1ee2a63a6
--- /dev/null
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationAuditLogger.scala
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kyuubi.server.http.authentication
+
+import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
+
+import org.apache.kyuubi.Logging
+import org.apache.kyuubi.server.http.authentication.AuthenticationFilter.{HTTP_AUTH_TYPE, HTTP_CLIENT_IP_ADDRESS, HTTP_CLIENT_USER_NAME, HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS}
+
+object AuthenticationAuditLogger extends Logging {
+ final private val AUDIT_BUFFER = new ThreadLocal[StringBuilder]() {
+ override protected def initialValue: StringBuilder = new StringBuilder()
+ }
+
+ def audit(request: HttpServletRequest, response: HttpServletResponse): Unit = {
+ val sb = AUDIT_BUFFER.get()
+ sb.setLength(0)
+ sb.append(s"user=${HTTP_CLIENT_USER_NAME.get()}(auth:${HTTP_AUTH_TYPE.get()})").append("\t")
+ sb.append(s"ip=${HTTP_CLIENT_IP_ADDRESS.get()}").append("\t")
+ sb.append(s"proxyIp=${HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.get()}").append("\t")
+ sb.append(s"method=${request.getMethod}").append("\t")
+ sb.append(s"uri=${request.getRequestURI}").append("\t")
+ sb.append(s"protocol=${request.getProtocol}").append("\t")
+ sb.append(s"status=${response.getStatus}")
+ info(sb.toString())
+ }
+}
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala
index ece0baf56aa..740937d8ec9 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala
@@ -106,29 +106,34 @@ class AuthenticationFilter(conf: KyuubiConf) extends Filter with Logging {
val authorization = httpRequest.getHeader(AUTHORIZATION_HEADER)
val matchedHandler = getMatchedHandler(authorization).orNull
+ HTTP_CLIENT_IP_ADDRESS.set(httpRequest.getRemoteAddr)
+ HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.set(
+ httpRequest.getHeader(conf.get(FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER)))
if (matchedHandler == null) {
debug(s"No auth scheme matched for url: ${httpRequest.getRequestURL}")
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
+ AuthenticationAuditLogger.audit(httpRequest, httpResponse)
httpResponse.sendError(
HttpServletResponse.SC_UNAUTHORIZED,
s"No auth scheme matched for $authorization")
} else {
- HTTP_CLIENT_IP_ADDRESS.set(httpRequest.getRemoteAddr)
- HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.set(
- httpRequest.getHeader(conf.get(FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER)))
+ HTTP_AUTH_TYPE.set(matchedHandler.authScheme.toString)
try {
val authUser = matchedHandler.authenticate(httpRequest, httpResponse)
if (authUser != null) {
HTTP_CLIENT_USER_NAME.set(authUser)
doFilter(filterChain, httpRequest, httpResponse)
}
+ AuthenticationAuditLogger.audit(httpRequest, httpResponse)
} catch {
case e: AuthenticationException =>
+ httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN)
+ AuthenticationAuditLogger.audit(httpRequest, httpResponse)
HTTP_CLIENT_USER_NAME.remove()
HTTP_CLIENT_IP_ADDRESS.remove()
HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.remove()
- httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN)
+ HTTP_AUTH_TYPE.remove()
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage)
}
}
@@ -171,10 +176,15 @@ object AuthenticationFilter {
final val HTTP_CLIENT_USER_NAME = new ThreadLocal[String]() {
override protected def initialValue: String = null
}
+ final val HTTP_AUTH_TYPE = new ThreadLocal[String]() {
+ override protected def initialValue(): String = null
+ }
def getUserIpAddress: String = HTTP_CLIENT_IP_ADDRESS.get
def getUserProxyHeaderIpAddress: String = HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.get()
def getUserName: String = HTTP_CLIENT_USER_NAME.get
+
+ def getAuthType: String = HTTP_AUTH_TYPE.get()
}
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala
index 4556f1c823d..ca95fda3d9a 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala
@@ -79,6 +79,8 @@ class KyuubiHttpAuthenticationFactory(conf: KyuubiConf) {
}
AuthenticationFilter.HTTP_CLIENT_USER_NAME.remove()
AuthenticationFilter.HTTP_CLIENT_IP_ADDRESS.remove()
+ AuthenticationFilter.HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.remove()
+ AuthenticationFilter.HTTP_AUTH_TYPE.remove()
}
}
diff --git a/kyuubi-server/src/test/resources/log4j2-test.xml b/kyuubi-server/src/test/resources/log4j2-test.xml
index bfc40dd6df4..623dd71fd14 100644
--- a/kyuubi-server/src/test/resources/log4j2-test.xml
+++ b/kyuubi-server/src/test/resources/log4j2-test.xml
@@ -19,6 +19,9 @@
+
+ target/rest-audit.log
+
@@ -33,11 +36,17 @@
+
+
+
+
+
+