Skip to content

Commit 458e8ca

Browse files
authored
Fix: Disable JWT auth on platform /health endpoint (#1885)
### Description This disables the JWT auth requirement on the platform health endpoint. ### Context If auth is enabled, using `/health` as a liveness probe will fail as it expects JWT auth. ### Testing - `./gradlew test` - Tested locally that this disables auth on the `/health` endpoint. ### Documentation N/A ### Known limitations N/A
1 parent bf9cb7b commit 458e8ca

File tree

7 files changed

+110
-2
lines changed

7 files changed

+110
-2
lines changed

.github/workflows/sub_extended_tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ jobs:
157157
uses: mydea/action-wait-for-api@v1
158158
with:
159159
url: "http://localhost:8085/health"
160-
expected-status: "403"
160+
expected-status: "200"
161161
interval: "1"
162162
timeout: "600"
163163

@@ -183,7 +183,7 @@ jobs:
183183
uses: mydea/action-wait-for-api@v1
184184
with:
185185
url: "http://localhost:8085/health"
186-
expected-status: "403"
186+
expected-status: "200"
187187
interval: "1"
188188
timeout: "600"
189189

core/src/main/java/org/stellar/anchor/filter/AbstractJwtFilter.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ public void doFilter(
4949
request.getRequestURL().toString(),
5050
request.getQueryString());
5151

52+
if (shouldSkip(request)) {
53+
filterChain.doFilter(servletRequest, servletResponse);
54+
return;
55+
}
56+
5257
if (request.getMethod().equals("OPTIONS")) {
5358
filterChain.doFilter(servletRequest, servletResponse);
5459
return;
@@ -88,6 +93,10 @@ public abstract void check(
8893
String jwtCipher, HttpServletRequest request, ServletResponse servletResponse)
8994
throws Exception;
9095

96+
protected boolean shouldSkip(HttpServletRequest request) {
97+
return false;
98+
}
99+
91100
private static void sendForbiddenError(HttpServletResponse response) throws IOException {
92101
error("Forbidden: JwtTokenFilter failed to authenticate the request.");
93102
response.setStatus(HttpStatus.SC_FORBIDDEN);

core/src/main/java/org/stellar/anchor/filter/ApiKeyFilter.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public void doFilter(
4747
request.getRequestURL().toString(),
4848
request.getQueryString());
4949

50+
if (shouldSkip(request)) {
51+
filterChain.doFilter(servletRequest, servletResponse);
52+
return;
53+
}
54+
5055
if (request.getMethod().equals(OPTIONS)) {
5156
filterChain.doFilter(servletRequest, servletResponse);
5257
return;
@@ -63,6 +68,10 @@ public void doFilter(
6368
filterChain.doFilter(servletRequest, servletResponse);
6469
}
6570

71+
protected boolean shouldSkip(HttpServletRequest request) {
72+
return "/health".equals(FilterUtils.getRequestPath(request));
73+
}
74+
6675
private static void sendForbiddenError(HttpServletResponse response) throws IOException {
6776
error("Forbidden: ApiKeyFilter failed to authenticate the request.");
6877
response.setStatus(HttpStatus.SC_FORBIDDEN);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.stellar.anchor.filter;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
5+
final class FilterUtils {
6+
static String getRequestPath(HttpServletRequest request) {
7+
String servletPath = request.getServletPath();
8+
if (servletPath != null && !servletPath.isEmpty()) {
9+
return servletPath;
10+
}
11+
12+
String pathInfo = request.getPathInfo();
13+
if (pathInfo != null && !pathInfo.isEmpty()) {
14+
return pathInfo;
15+
}
16+
17+
String requestUri = request.getRequestURI();
18+
if (requestUri == null) {
19+
return "";
20+
}
21+
22+
String contextPath = request.getContextPath();
23+
if (contextPath != null && !contextPath.isEmpty() && requestUri.startsWith(contextPath)) {
24+
return requestUri.substring(contextPath.length());
25+
}
26+
27+
return requestUri;
28+
}
29+
30+
private FilterUtils() {}
31+
}

core/src/main/java/org/stellar/anchor/filter/PlatformAuthJwtFilter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ public PlatformAuthJwtFilter(JwtService jwtService, String authorizationHeader)
1212
super(jwtService, authorizationHeader);
1313
}
1414

15+
@Override
16+
protected boolean shouldSkip(HttpServletRequest request) {
17+
return "/health".equals(FilterUtils.getRequestPath(request));
18+
}
19+
1520
@Override
1621
public void check(String jwtCipher, HttpServletRequest request, ServletResponse servletResponse)
1722
throws Exception {

core/src/test/kotlin/org/stellar/anchor/filter/ApiKeyFilterTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ internal class ApiKeyFilterTest {
111111
verify { mockFilterChain.doFilter(request, response) }
112112
}
113113

114+
@Test
115+
fun `health endpoint bypasses api key auth`() {
116+
every { request.method } returns "GET"
117+
every { request.servletPath } returns "/health"
118+
every { request.getHeader("X-Api-Key") } returns null
119+
120+
apiKeyFilter.doFilter(request, response, mockFilterChain)
121+
122+
verify { mockFilterChain.doFilter(request, response) }
123+
verify(exactly = 0) { response.setStatus(HttpStatus.SC_FORBIDDEN) }
124+
}
125+
114126
@ParameterizedTest
115127
@ValueSource(strings = ["GET", "PUT", "POST", "DELETE"])
116128
fun `make sure FORBIDDEN is returned when the filter requires header names other than X-Api-Key`(
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.stellar.anchor.filter
2+
3+
import io.mockk.every
4+
import io.mockk.mockk
5+
import io.mockk.spyk
6+
import io.mockk.verify
7+
import jakarta.servlet.FilterChain
8+
import jakarta.servlet.http.HttpServletRequest
9+
import jakarta.servlet.http.HttpServletResponse
10+
import org.apache.hc.core5.http.HttpStatus
11+
import org.junit.jupiter.api.BeforeEach
12+
import org.junit.jupiter.api.Test
13+
import org.stellar.anchor.auth.JwtService
14+
15+
internal class PlatformAuthJwtFilterTest {
16+
private lateinit var jwtService: JwtService
17+
private lateinit var request: HttpServletRequest
18+
private lateinit var response: HttpServletResponse
19+
private lateinit var mockFilterChain: FilterChain
20+
21+
@BeforeEach
22+
fun setup() {
23+
this.jwtService = mockk(relaxed = true)
24+
this.request = mockk(relaxed = true)
25+
this.response = mockk(relaxed = true)
26+
this.mockFilterChain = mockk(relaxed = true)
27+
}
28+
29+
@Test
30+
fun `health endpoint bypasses jwt auth`() {
31+
every { request.method } returns "GET"
32+
every { request.servletPath } returns "/health"
33+
every { request.getHeader("Authorization") } returns null
34+
val filter = spyk(PlatformAuthJwtFilter(jwtService, "Authorization"))
35+
36+
filter.doFilter(request, response, mockFilterChain)
37+
38+
verify { mockFilterChain.doFilter(request, response) }
39+
verify(exactly = 0) { response.setStatus(HttpStatus.SC_FORBIDDEN) }
40+
verify(exactly = 0) { filter.check(any(), any(), any()) }
41+
}
42+
}

0 commit comments

Comments
 (0)