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/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

jobs:
build:
uses: valitydev/java-workflow/.github/workflows/maven-service-build.yml@v3
uses: valitydev/java-workflow/.github/workflows/maven-service-build.yml@v4
Comment thread
echerniak marked this conversation as resolved.
Dismissed
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

jobs:
deploy:
uses: valitydev/java-workflow/.github/workflows/maven-service-deploy.yml@v3
uses: valitydev/java-workflow/.github/workflows/maven-service-deploy.yml@v4
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
mm-webhook-url: ${{ secrets.MATTERMOST_WEBHOOK_URL }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
48 changes: 0 additions & 48 deletions agents.md

This file was deleted.

53 changes: 36 additions & 17 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>dev.vality</groupId>
<artifactId>service-parent-pom</artifactId>
<version>3.1.9</version>
<version>4.0.0</version>
</parent>

<artifactId>wachter</artifactId>
Expand All @@ -16,18 +16,14 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>21</java.version>
<java.version>25</java.version>
<server.port>8022</server.port>
<management.port>8023</management.port>
<exposed.ports>${server.port} ${management.port}</exposed.ports>
</properties>

<dependencies>
<!--vality-->
<dependency>
<groupId>dev.vality.woody</groupId>
<artifactId>woody-api</artifactId>
</dependency>
<dependency>
<groupId>dev.vality.woody</groupId>
<artifactId>woody-thrift</artifactId>
Expand All @@ -36,10 +32,6 @@
<groupId>dev.vality.geck</groupId>
<artifactId>serializer</artifactId>
</dependency>
<dependency>
<groupId>dev.vality</groupId>
<artifactId>woody-http-bridge</artifactId>
</dependency>

<!--spring-->
<dependency>
Expand All @@ -56,7 +48,11 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
<artifactId>spring-boot-starter-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-restclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -68,12 +64,20 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter-webmvc</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
Expand All @@ -90,15 +94,12 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
Expand All @@ -115,6 +116,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
Expand All @@ -136,7 +142,7 @@
<dependency>
<groupId>org.wiremock.integrations</groupId>
<artifactId>wiremock-spring-boot</artifactId>
<version>3.10.0</version>
<version>4.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -162,6 +168,7 @@
<filtering>true</filtering>
<excludes>
<exclude>Dockerfile</exclude>
<exclude>opentelemetry-javaagent.jar</exclude>
</excludes>
</resource>
<resource>
Expand Down Expand Up @@ -200,6 +207,18 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
2 changes: 1 addition & 1 deletion src/main/java/dev/vality/wachter/WachterApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.server.servlet.context.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.vality.wachter.client;

import dev.vality.woody.http.bridge.tracing.TraceHeadersConstants;
import dev.vality.wachter.tracing.TraceHeaders;
import jakarta.servlet.http.HttpServletRequest;
import lombok.experimental.UtilityClass;
import org.springframework.http.HttpHeaders;
Expand Down Expand Up @@ -43,19 +43,19 @@ public class ProxyHeadersExtractor {
"dnt",
"priority",
"service",
TraceHeadersConstants.OTEL_TRACE_PARENT,
TraceHeadersConstants.OTEL_TRACE_STATE,
TraceHeadersConstants.ExternalHeaders.X_REQUEST_ID,
TraceHeadersConstants.ExternalHeaders.X_REQUEST_DEADLINE,
TraceHeadersConstants.ExternalHeaders.X_INVOICE_ID
TraceHeaders.OTEL_TRACE_PARENT,
TraceHeaders.OTEL_TRACE_STATE,
TraceHeaders.ExternalHeaders.X_REQUEST_ID,
TraceHeaders.ExternalHeaders.X_REQUEST_DEADLINE,
TraceHeaders.ExternalHeaders.X_INVOICE_ID
).map(header -> header.toLowerCase(Locale.ROOT)).collect(Collectors.toSet());

private static final List<String> EXCLUDED_PREFIXES = List.of(
"cf-",
"cdn-",
"sec-",
TraceHeadersConstants.WOODY_PREFIX,
TraceHeadersConstants.ExternalHeaders.X_WOODY_PREFIX
TraceHeaders.WOODY_PREFIX,
TraceHeaders.ExternalHeaders.X_WOODY_PREFIX
);

public HttpHeaders extractHeaders(HttpServletRequest request) {
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/dev/vality/wachter/client/WachterClient.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.vality.wachter.client;

import dev.vality.woody.http.bridge.tracing.TraceContextExtractor;
import dev.vality.woody.http.bridge.tracing.TraceContextHeadersNormalizer;
import dev.vality.wachter.tracing.TraceHeaderNormalizer;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -27,11 +26,11 @@ public WachterClientResponse send(HttpServletRequest servletRequest, byte[] cont
var httpMethod = resolveMethod(servletRequest);

var proxyHeaders = ProxyHeadersExtractor.extractHeaders(servletRequest);
var traceHeaders = TraceContextExtractor.extractHeaders();
var traceHeaders = TraceHeaderNormalizer.normalizeRequest(servletRequest);

var httpHeaders = new HttpHeaders();
proxyHeaders.forEach(httpHeaders::addAll);
traceHeaders.forEach(httpHeaders::set);
httpHeaders.addAll(traceHeaders);

log.info("-> Send request to {} {} | headers: {}", httpMethod, url, httpHeaders);

Expand All @@ -48,7 +47,7 @@ public WachterClientResponse send(HttpServletRequest servletRequest, byte[] cont
log.info("<- Receive response from {} {} | status: {}, headers: {}", httpMethod, url, status,
response.getHeaders());
var responseBody = Objects.requireNonNullElse(response.bodyTo(byte[].class), EMPTY_BODY);
var responseHeaders = TraceContextHeadersNormalizer.normalizeResponseHeaders(response.getHeaders());
var responseHeaders = TraceHeaderNormalizer.normalizeResponse(response.getHeaders());
return new WachterClientResponse(status, responseHeaders, responseBody);
});
}
Expand Down
26 changes: 7 additions & 19 deletions src/main/java/dev/vality/wachter/config/RestClientConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.vality.wachter.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;
import dev.vality.wachter.config.properties.HttpProperties;
import lombok.RequiredArgsConstructor;
import org.apache.hc.client5.http.classic.HttpClient;
Expand All @@ -21,13 +21,10 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.web.client.RestClient;

import javax.net.ssl.SSLContext;
import java.time.Duration;
import java.util.List;

@Configuration
@RequiredArgsConstructor
Expand Down Expand Up @@ -85,25 +82,16 @@ public CloseableHttpClient httpClient(

@Bean
public HttpComponentsClientHttpRequestFactory requestFactory(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setConnectTimeout(Duration.ofMillis(httpProperties.getConnectionTimeout()));
factory.setConnectionRequestTimeout(Duration.ofMillis(httpProperties.getPoolTimeout()));
factory.setReadTimeout(Duration.ofMillis(httpProperties.getRequestTimeout()));
return factory;
return new HttpComponentsClientHttpRequestFactory(httpClient);
}

@Bean
public RestClient restClient(ClientHttpRequestFactory requestFactory, ObjectMapper objectMapper) {
public RestClient restClient(ClientHttpRequestFactory requestFactory, JsonMapper jsonMapper) {
return RestClient.builder()
.requestFactory(requestFactory)
.messageConverters(converters -> updateObjectMapper(converters, objectMapper))
.configureMessageConverters(converters -> converters
.registerDefaults()
.withJsonConverter(new JacksonJsonHttpMessageConverter(jsonMapper)))
.build();
}

private void updateObjectMapper(List<HttpMessageConverter<?>> converters, ObjectMapper objectMapper) {
converters.stream()
.filter(MappingJackson2HttpMessageConverter.class::isInstance)
.map(MappingJackson2HttpMessageConverter.class::cast)
.forEach(converter -> converter.setObjectMapper(objectMapper));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dev.vality.wachter.security;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;

import java.util.List;
import java.util.Optional;

public final class JwtTokenDetailsExtractor {

private JwtTokenDetailsExtractor() {
}

public static Optional<JwtTokenDetails> extract(Authentication authentication) {
if (!(authentication instanceof JwtAuthenticationToken jwtAuthentication)) {
return Optional.empty();
}
var token = jwtAuthentication.getToken();
return Optional.of(new JwtTokenDetails(
token.getSubject(),
token.getClaimAsString("preferred_username"),
token.getClaimAsString("email"),
extractRealm(token),
jwtAuthentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList()));
}

private static String extractRealm(Jwt token) {
var issuer = token.getClaimAsString(JwtClaimNames.ISS);
if (issuer == null || issuer.isBlank()) {
return null;
}
var normalized = issuer.replaceAll("/+$", "");
var lastSlash = normalized.lastIndexOf('/');
var realm = lastSlash >= 0 ? normalized.substring(lastSlash + 1) : normalized;
return realm.isBlank() ? null : realm;
}

public record JwtTokenDetails(
String subject,
String preferredUsername,
String email,
String realm,
List<String> roles) {
}
}
Loading
Loading