Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/on_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
complete:
if: always()
needs: [ gradle_build, essential_tests, extended_tests, rust_build ]
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1
4 changes: 2 additions & 2 deletions .github/workflows/sub_extended_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ jobs:
uses: mydea/action-wait-for-api@v1
with:
url: "http://localhost:8085/health"
expected-status: "403"
expected-status: "200"
interval: "1"
timeout: "600"

Expand All @@ -183,7 +183,7 @@ jobs:
uses: mydea/action-wait-for-api@v1
with:
url: "http://localhost:8085/health"
expected-status: "403"
expected-status: "200"
interval: "1"
timeout: "600"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![License](https://badgen.net/badge/license/Apache%202/blue?icon=github&label=License)](https://github.com/stellar/anchor-platform/blob/develop/LICENSE)
[![GitHub Version](https://badgen.net/github/release/stellar/anchor-platform?icon=github&label=Latest%20release)](https://github.com/stellar/anchor-platform/releases)
[![Docker](https://badgen.net/badge/Latest%20Release/v4.1.6/blue?icon=docker)](https://hub.docker.com/r/stellar/anchor-platform/tags?page=1&name=4.1.6)
[![Docker](https://badgen.net/badge/Latest%20Release/v4.1.7/blue?icon=docker)](https://hub.docker.com/r/stellar/anchor-platform/tags?page=1&name=4.1.7)
![Develop Branch](https://github.com/stellar/anchor-platform/actions/workflows/on_push_to_develop.yml/badge.svg?branch=develop)

<div style="text-align: center">
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ subprojects {

allprojects {
group = "org.stellar.anchor-sdk"
version = "4.1.6"
version = "4.1.7"

tasks.jar {
manifest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public void doFilter(
request.getRequestURL().toString(),
request.getQueryString());

if (shouldSkip(request)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}

if (request.getMethod().equals("OPTIONS")) {
filterChain.doFilter(servletRequest, servletResponse);
return;
Expand Down Expand Up @@ -88,6 +93,10 @@ public abstract void check(
String jwtCipher, HttpServletRequest request, ServletResponse servletResponse)
throws Exception;

protected boolean shouldSkip(HttpServletRequest request) {
return false;
}

private static void sendForbiddenError(HttpServletResponse response) throws IOException {
error("Forbidden: JwtTokenFilter failed to authenticate the request.");
response.setStatus(HttpStatus.SC_FORBIDDEN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public void doFilter(
request.getRequestURL().toString(),
request.getQueryString());

if (shouldSkip(request)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}

if (request.getMethod().equals(OPTIONS)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
Expand All @@ -63,6 +68,10 @@ public void doFilter(
filterChain.doFilter(servletRequest, servletResponse);
}

protected boolean shouldSkip(HttpServletRequest request) {
return "/health".equals(FilterUtils.getRequestPath(request));
}

private static void sendForbiddenError(HttpServletResponse response) throws IOException {
error("Forbidden: ApiKeyFilter failed to authenticate the request.");
response.setStatus(HttpStatus.SC_FORBIDDEN);
Expand Down
31 changes: 31 additions & 0 deletions core/src/main/java/org/stellar/anchor/filter/FilterUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.stellar.anchor.filter;

import jakarta.servlet.http.HttpServletRequest;

final class FilterUtils {
static String getRequestPath(HttpServletRequest request) {
String servletPath = request.getServletPath();
if (servletPath != null && !servletPath.isEmpty()) {
return servletPath;
}

String pathInfo = request.getPathInfo();
if (pathInfo != null && !pathInfo.isEmpty()) {
return pathInfo;
}

String requestUri = request.getRequestURI();
if (requestUri == null) {
return "";
}

String contextPath = request.getContextPath();
if (contextPath != null && !contextPath.isEmpty() && requestUri.startsWith(contextPath)) {
return requestUri.substring(contextPath.length());
}

return requestUri;
}

private FilterUtils() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public PlatformAuthJwtFilter(JwtService jwtService, String authorizationHeader)
super(jwtService, authorizationHeader);
}

@Override
protected boolean shouldSkip(HttpServletRequest request) {
return "/health".equals(FilterUtils.getRequestPath(request));
}

@Override
public void check(String jwtCipher, HttpServletRequest request, ServletResponse servletResponse)
throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public Sep12GetCustomerResponse getCustomer(WebAuthJwt token, Sep12GetCustomerRe
populateRequestFromTransactionId(request);

validateGetOrPutRequest(request, token);
if (request.getId() == null && request.getAccount() == null && token.getAccount() != null) {
if (request.getAccount() == null && token.getAccount() != null) {
request.setAccount(token.getAccount());
}

Expand Down
12 changes: 12 additions & 0 deletions core/src/test/kotlin/org/stellar/anchor/filter/ApiKeyFilterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ internal class ApiKeyFilterTest {
verify { mockFilterChain.doFilter(request, response) }
}

@Test
fun `health endpoint bypasses api key auth`() {
every { request.method } returns "GET"
every { request.servletPath } returns "/health"
every { request.getHeader("X-Api-Key") } returns null

apiKeyFilter.doFilter(request, response, mockFilterChain)

verify { mockFilterChain.doFilter(request, response) }
verify(exactly = 0) { response.setStatus(HttpStatus.SC_FORBIDDEN) }
}

@ParameterizedTest
@ValueSource(strings = ["GET", "PUT", "POST", "DELETE"])
fun `make sure FORBIDDEN is returned when the filter requires header names other than X-Api-Key`(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.stellar.anchor.filter

import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.apache.hc.core5.http.HttpStatus
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.stellar.anchor.auth.JwtService

internal class PlatformAuthJwtFilterTest {
private lateinit var jwtService: JwtService
private lateinit var request: HttpServletRequest
private lateinit var response: HttpServletResponse
private lateinit var mockFilterChain: FilterChain

@BeforeEach
fun setup() {
this.jwtService = mockk(relaxed = true)
this.request = mockk(relaxed = true)
this.response = mockk(relaxed = true)
this.mockFilterChain = mockk(relaxed = true)
}

@Test
fun `health endpoint bypasses jwt auth`() {
every { request.method } returns "GET"
every { request.servletPath } returns "/health"
every { request.getHeader("Authorization") } returns null
val filter = spyk(PlatformAuthJwtFilter(jwtService, "Authorization"))

filter.doFilter(request, response, mockFilterChain)

verify { mockFilterChain.doFilter(request, response) }
verify(exactly = 0) { response.setStatus(HttpStatus.SC_FORBIDDEN) }
verify(exactly = 0) { filter.check(any(), any(), any()) }
}
}
37 changes: 37 additions & 0 deletions core/src/test/kotlin/org/stellar/anchor/sep12/Sep12ServiceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,43 @@ class Sep12ServiceTest {
assertEquals(TEST_ACCOUNT, mockGetRequest.account)
}

@Test
fun `Test get customer request with id injects account`() {
val callbackApiGetRequestSlot = slot<GetCustomerRequest>()
val mockCallbackApiGetCustomerResponse = GetCustomerResponse()
mockCallbackApiGetCustomerResponse.id = "customer-id"
every { customerIntegration.getCustomer(capture(callbackApiGetRequestSlot)) } returns
mockCallbackApiGetCustomerResponse

val mockGetRequest = Sep12GetCustomerRequest.builder().id("customer-id").build()
val jwtToken = createJwtToken(TEST_ACCOUNT)

assertDoesNotThrow { sep12Service.getCustomer(jwtToken, mockGetRequest) }

val wantCallbackApiGetRequest =
GetCustomerRequest.builder().id("customer-id").account(TEST_ACCOUNT).build()
assertEquals(wantCallbackApiGetRequest, callbackApiGetRequestSlot.captured)
assertEquals(TEST_ACCOUNT, mockGetRequest.account)
}

@Test
fun `Test put customer request with id injects account`() {
val callbackApiPutRequestSlot = slot<PutCustomerRequest>()
val mockCallbackApiPutCustomerResponse = PutCustomerResponse.builder().id("customer-id").build()
every { customerIntegration.putCustomer(capture(callbackApiPutRequestSlot)) } returns
mockCallbackApiPutCustomerResponse

val mockPutRequest = Sep12PutCustomerRequest.builder().id("customer-id").build()
val jwtToken = createJwtToken(TEST_ACCOUNT)

assertDoesNotThrow { sep12Service.putCustomer(jwtToken, mockPutRequest) }

val wantCallbackApiPutRequest =
PutCustomerRequest.builder().id("customer-id").account(TEST_ACCOUNT).build()
assertEquals(wantCallbackApiPutRequest, callbackApiPutRequestSlot.captured)
assertEquals(TEST_ACCOUNT, mockPutRequest.account)
}

@Test
fun `test delete customer validation`() {
every { customerIntegration.deleteCustomer(any()) } just Runs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:22.04
FROM ubuntu:24.04
RUN mkdir /config_files
ENV STELLAR_ANCHOR_CONFIG=file:/config/anchor-config.yaml
ENV REFERENCE_SERVER_CONFIG_ENV=file:/config/reference-config.yaml
Expand Down
4 changes: 2 additions & 2 deletions helm-charts/reference-server/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ data:
custodyEnabled: false

auth:
type: NONE
type: {{ .Values.config.auth.type | default "NONE" }}

data:
database: postgres
database: postgres
4 changes: 3 additions & 1 deletion helm-charts/reference-server/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ config:
rpcEndpoint: https://soroban-testnet.stellar.org
platformApiEndpoint: http://anchor-platform-svc-platform:8085
rpcEnabled: false
auth:
type: NONE
data:
url: postgresql-ref:5432

Expand All @@ -37,4 +39,4 @@ ingress:
host: reference-server.local
className: nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/rewrite-target: /
10 changes: 6 additions & 4 deletions helm-charts/secret-store/templates/secretstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ spec:
"SEP10_SIGNING_SEED": "{{ .Values.sep10_signing_seed }}",
"EVENTS_QUEUE_KAFKA_USERNAME": "user1",
"EVENTS_QUEUE_KAFKA_PASSWORD": "123456789",
"SENTRY_AUTH_TOKEN": {{ default "\"\"" .Values.sentry_auth_token }}
"SEP45_JWT_SECRET": "1e5ba4a1da18dc6462b21bb720a5aceddb34a421e732e0f6615ad30b4a4aa50f"
"SENTRY_AUTH_TOKEN": {{ default "\"\"" .Values.sentry_auth_token }},
"SEP45_JWT_SECRET": "1e5ba4a1da18dc6462b21bb720a5aceddb34a421e732e0f6615ad30b4a4aa50f",
"CALLBACK_API_AUTH_SECRET": "myPlatformToAnchorSecret",
"PLATFORM_API_AUTH_SECRET": "myAnchorToPlatformSecret"
}
- key: {{ .Values.namespace }}/reference-server-secrets
value: |
Expand All @@ -32,5 +34,5 @@ spec:
"PAYMENT_SIGNING_SEED": "{{ .Values.payment_signing_seed }}",
"SEP24_INTERACTIVE_JWT_KEY": "c5457e3a349df9002117543efa7e316dd89e666a5ce6f33a0deb13e90f3f1e9d",
"PLATFORM_ANCHOR_SECRET": "myPlatformToAnchorSecret",
"ANCHOR_PLATFORM_SECRET": "myAnchorToPlatformSecret",
}
"ANCHOR_PLATFORM_SECRET": "myAnchorToPlatformSecret"
}
10 changes: 10 additions & 0 deletions helm-charts/sep-service/templates/eventprocessor-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ spec:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: SEP6_MORE_INFO_URL_JWT_SECRET
- name: SECRET_CALLBACK_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: CALLBACK_API_AUTH_SECRET
- name: SECRET_PLATFORM_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: PLATFORM_API_AUTH_SECRET
- name: SECRET_EVENTS_QUEUE_KAFKA_USERNAME
valueFrom:
secretKeyRef:
Expand Down
8 changes: 8 additions & 0 deletions helm-charts/sep-service/templates/externalsecrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,11 @@ spec:
remoteRef:
key: {{ .Values.namespace }}/{{ .Values.fullName }}-secrets
property: SEP45_JWT_SECRET
- secretKey: CALLBACK_API_AUTH_SECRET
remoteRef:
key: {{ .Values.namespace }}/{{ .Values.fullName }}-secrets
property: CALLBACK_API_AUTH_SECRET
- secretKey: PLATFORM_API_AUTH_SECRET
remoteRef:
key: {{ .Values.namespace }}/{{ .Values.fullName }}-secrets
property: PLATFORM_API_AUTH_SECRET
12 changes: 11 additions & 1 deletion helm-charts/sep-service/templates/observer-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ spec:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: SEP6_MORE_INFO_URL_JWT_SECRET
- name: SECRET_CALLBACK_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: CALLBACK_API_AUTH_SECRET
- name: SECRET_PLATFORM_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: PLATFORM_API_AUTH_SECRET
- name: SENTRY_AUTH_TOKEN
valueFrom:
secretKeyRef:
Expand All @@ -103,4 +113,4 @@ spec:
volumes:
- name: config-volume
configMap:
name: anchor-config
name: anchor-config
10 changes: 10 additions & 0 deletions helm-charts/sep-service/templates/platform-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ spec:
name: {{ .Values.fullName }}-secrets
key: SEP45_JWT_SECRET
optional: true
- name: SECRET_CALLBACK_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: CALLBACK_API_AUTH_SECRET
- name: SECRET_PLATFORM_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: PLATFORM_API_AUTH_SECRET
resources:
requests:
memory: {{ .Values.services.platform.deployment.resources.requests.memory }}
Expand Down
10 changes: 10 additions & 0 deletions helm-charts/sep-service/templates/sepserver-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ spec:
name: {{ .Values.fullName }}-secrets
key: SEP45_JWT_SECRET
optional: true
- name: SECRET_CALLBACK_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: CALLBACK_API_AUTH_SECRET
- name: SECRET_PLATFORM_API_AUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.fullName }}-secrets
key: PLATFORM_API_AUTH_SECRET
resources:
requests:
memory: {{ .Values.services.sep.deployment.resources.requests.memory }}
Expand Down
Loading
Loading