Skip to content

Commit

Permalink
chore: sync from gitlab
Browse files Browse the repository at this point in the history
  • Loading branch information
ron96G committed Aug 14, 2024
1 parent 9b0738d commit 630f7ec
Show file tree
Hide file tree
Showing 20 changed files with 749 additions and 105 deletions.
77 changes: 77 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,82 @@
# Changelog

## [3.16.0](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/compare/3.15.2...3.16.0) (2024-07-04)


### 🧪 Tests

* added loadbalancing test ([ca1940f](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/ca1940ffd9c00408ffa4e61a5186c1386aee5aad))
* fix no header test ([5236a03](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/5236a03dda2a2d272a6b4ddf6f11a39e8ec4f1ae))


### 🚀 Features

* loadbalancing draft ([f89ecec](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/f89ecec6131a57b9f8f5b3413068cac0574cc4b1))


### 🛠 Fixes

* pass spectre info as header ([98de0fb](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/98de0fbbc8a28e526b333c23dcb4cbd84f864fbc))

## [3.15.2](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/compare/3.15.1...3.15.2) (2024-06-25)


### 💈 Style

* fix formatting ([8e9c1af](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/8e9c1afbba9ca788f8fd0715556845080252b3dc))


### 🦊 CI/CD

* fix pipeline ([32ccb34](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/32ccb346b07e78b81695283b6b97f877eb1856ed))


### Other

* update to new Gherkin KeyWords ([9c01cfb](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/9c01cfb2b1385b10c131b644f1e3cb3ffdeed7af))

## [3.15.1](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/compare/3.15.0...3.15.1) (2024-06-25)


### 🛠 Fixes

* **dhei-12175:** added logic to handle default-key in jc-oauth-config ([efeb289](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/efeb289fcb6776a2c0e27646e6a834a5b3a09417))


### Other

* **release:** 3.15.0 ([8356342](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/83563429c391e35aa0019fd6842a62f69da3f615))

## [3.15.0](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/compare/3.14.4...3.15.0) (2024-06-25)


### 🚀 Features

* enhance-Jumper-error-handling ([d1387ec](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/d1387ec80d089616663f48f93df3e18a672f2dfe))
* enhanced error handling for external IDP responses to consumer ([94852e4](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/94852e4efde19516ca6f6d5148e6fd76ca7f1adb))


### Other

* **release:** 3.14.4 ([22add44](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/22add443d09fe29a37f066081c04578c835b80f2))

## [3.14.4](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/compare/3.14.3...3.14.4) (2024-06-05)


### 🦊 CI/CD

* **dhei-00000:** pass headers for secondary failover ([fc50cb4](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/fc50cb4e0a6953794be193905647ce85451ee376))


### 🛠 Fixes

* pass headers for secondary failover ([da06f74](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/da06f7462b72c621aa553acc7c8df7f8d81697d5))


### Other

* **release:** 3.14.3 ([583d339](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/commit/583d339a4780a6202501956979fb6efd038a081d))

## [3.14.3](https://gitlab.devops.telekom.de/dhei/teams/hyperion/dev/src/jumper-sse/compare/3.14.2...3.14.3) (2024-05-30)


Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SPDX-License-Identifier: Apache-2.0

<groupId>de.telekom.ei.jumper</groupId>
<artifactId>jumper-sse</artifactId>
<version>3.14.3</version>
<version>3.16.0</version>

<parent>
<groupId>org.springframework.boot</groupId>
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/jumper/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public class Constants {
public static final String HEADER_X_FORWARDED_PORT_PORT = "443";
public static final String HEADER_X_FORWARDED_PROTO_HTTPS = "https";

public static final String HEADER_X_SPECTRE_ISSUE = "x-spectre-issue";
public static final String HEADER_X_SPECTRE_PROVIDER = "x-spectre-provider";
public static final String HEADER_X_SPECTRE_CONSUMER = "x-spectre-consumer";

public static final String HEADER_X_FAILOVER_SKIP_ZONE = "x-failover-skip-zone";

public static final String QUERY_PARAM_LISTENER = "listener";
Expand Down Expand Up @@ -93,6 +97,7 @@ public class Constants {
public static final List<String> SPACE_ZONES = List.of("space", "canis", "aries");

public static final String BASIC_AUTH_PROVIDER_KEY = "default";
public static final String OAUTH_PROVIDER_KEY = "default";

public static final String ENVIRONMENT_PLACEHOLDER = "ENVIRONMENT_PLACEHOLDER";
}
18 changes: 9 additions & 9 deletions src/main/java/jumper/filter/RequestFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,6 @@ public GatewayFilter apply(Config config) {

// no failover
else {
// checking to prevent later nullPointer on inconsistent state from Kong
if (!request.getHeaders().containsKey(Constants.HEADER_REMOTE_API_URL)) {
throw new RuntimeException(
"missing mandatory header " + Constants.HEADER_REMOTE_API_URL);
}

// Prepare and extract JumperConfigValues
jumperConfig = JumperConfig.parseAndFillJumperConfigFrom(request);
log.debug("JumperConfig decoded: {}", jumperConfig);
Expand All @@ -129,9 +123,15 @@ public GatewayFilter apply(Config config) {
.put(Constants.HEADER_JUMPER_CONFIG, JumperConfig.toBase64(jumperConfig));
}

// write audit log if needed
if (jumperConfig.getAuditLog()) {
if (jumperConfig.getSecondaryFailover()) {
// write audit log if needed
AuditLogService.writeFailoverAuditLog(jumperConfig);

// pass headers from config to provider
HeaderUtil.addHeader(
exchange, Constants.HEADER_REALM, jumperConfig.getRealmName());
HeaderUtil.addHeader(
exchange, Constants.HEADER_ENVIRONMENT, jumperConfig.getEnvName());
}

// handle request
Expand Down Expand Up @@ -466,7 +466,7 @@ private JumperConfig evaluateTargetZone(
for (JumperConfig jc : jumperConfigList) {
// secondary route, failover in place => audit logs
if (StringUtils.isEmpty(jc.getTargetZoneName())) {
jc.setAuditLog(true);
jc.setSecondaryFailover(true);
return jc;
}
// targetZoneName present, check it against force skip header and zones state
Expand Down
57 changes: 51 additions & 6 deletions src/main/java/jumper/model/config/JumperConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
import java.util.*;
import javax.validation.constraints.NotNull;
import jumper.Constants;
import jumper.service.HeaderUtil;
import jumper.service.OauthTokenUtil;
Expand All @@ -31,6 +32,7 @@ public class JumperConfig {
private HashMap<String, BasicAuthCredentials> basicAuth;
private HashMap<String, RouteListener> routeListener;
private GatewayClient gatewayClient;
private LoadBalancing loadBalancing;

String targetZoneName;
String scopes;
Expand Down Expand Up @@ -65,7 +67,7 @@ public class JumperConfig {
String routingPath;
String finalApiUrl;

Boolean auditLog = false;
Boolean secondaryFailover = false;

@JsonIgnore
public static String toBase64(Object o) {
Expand Down Expand Up @@ -103,10 +105,18 @@ private static JumperConfig fromBase64(String jsonConfigBase64) {
@JsonIgnore
private void fillWithLegacyHeaders(ServerHttpRequest request) {

// proxy & real
if (request.getHeaders().containsKey(Constants.HEADER_REMOTE_API_URL)) {
setRemoteApiUrl(
HeaderUtil.getLastValueFromHeaderField(request, Constants.HEADER_REMOTE_API_URL));
} else if (Objects.nonNull(loadBalancing) && !loadBalancing.getServers().isEmpty()) {
setRemoteApiUrl(calculateUpstream(loadBalancing.getServers()));
} else {
throw new RuntimeException(
"missing routing information " + Constants.HEADER_REMOTE_API_URL + " / jc.loadBalancing");
}

// proxy
setRemoteApiUrl(
HeaderUtil.getLastValueFromHeaderField(
request, Constants.HEADER_REMOTE_API_URL)); // also real
setInternalTokenEndpoint(
HeaderUtil.getLastValueFromHeaderField(request, Constants.HEADER_ISSUER));
setClientId(
Expand Down Expand Up @@ -174,6 +184,13 @@ public void fillProcessingInfo(ServerHttpRequest request) {
HeaderUtil.getLastValueFromHeaderField(request, Constants.HEADER_JUMPER_CONFIG));
this.setRouteListener(jc.getRouteListener());
this.setGatewayClient(jc.getGatewayClient());

// check loadBalancing
if (Objects.nonNull(loadBalancing) && !loadBalancing.getServers().isEmpty()) {
setRemoteApiUrl(calculateUpstream(loadBalancing.getServers()));
} else if (Objects.isNull(remoteApiUrl)) {
throw new RuntimeException("missing routing information jc.remoteApiUrl / jc.loadBalancing");
}
}

public static List<JumperConfig> parseJumperConfigListFrom(ServerHttpRequest request) {
Expand Down Expand Up @@ -228,8 +245,14 @@ public Optional<BasicAuthCredentials> getBasicAuthCredentials() {
}

public Optional<OauthCredentials> getOauthCredentials() {
if (Objects.nonNull(getOauth()) && getOauth().containsKey(getConsumer())) {
return Optional.of(getOauth().get(getConsumer()));
if (Objects.nonNull(getOauth())) {
if (getOauth().containsKey(getConsumer())) {
return Optional.of(getOauth().get(getConsumer()));
}

if (getOauth().containsKey(Constants.OAUTH_PROVIDER_KEY)) {
return Optional.of(getOauth().get(Constants.OAUTH_PROVIDER_KEY));
}
}

return Optional.empty();
Expand All @@ -239,4 +262,26 @@ public String getSecurityScopes() {
Optional<OauthCredentials> oauthCredentials = getOauthCredentials();
return oauthCredentials.map(OauthCredentials::getScopes).orElse(null);
}

private static String calculateUpstream(@NotNull List<Server> servers) {
// Sum total of weights
double total = 0;
for (Server server : servers) {
total += server.getWeight();
}

// Random a number between [1, total]
double random = Math.ceil(Math.random() * total);

// Seek cursor to find which area the random is in
double cursor = 0;
for (Server server : servers) {
cursor += server.getWeight();
if (cursor >= random) {
return server.getUpstream();
}
}

throw new RuntimeException("can not calculate upstream");
}
}
17 changes: 17 additions & 0 deletions src/main/java/jumper/model/config/LoadBalancing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2023 Deutsche Telekom AG
//
// SPDX-License-Identifier: Apache-2.0

package jumper.model.config;

import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class LoadBalancing {
List<Server> servers;
}
17 changes: 17 additions & 0 deletions src/main/java/jumper/model/config/Server.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2023 Deutsche Telekom AG
//
// SPDX-License-Identifier: Apache-2.0

package jumper.model.config;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Server {
private String upstream;
private Double weight;
}
33 changes: 31 additions & 2 deletions src/main/java/jumper/service/OauthTokenUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.UnsupportedMediaTypeException;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ResponseStatusException;
Expand Down Expand Up @@ -356,6 +357,18 @@ private TokenInfo getAccessTokenQuery(
+ ", original status: "
+ response.statusCode()));
})
.onStatus(
HttpStatus::is5xxServerError,
response -> {
logClientErrorResponse(response, tokenKey);
return Mono.error(
new ResponseStatusException(
HttpStatus.UNAUTHORIZED,
"Failed to retrieve token from "
+ tokenEndpoint
+ ", original status: "
+ response.statusCode()));
})
.bodyToMono(TokenInfo.class)
.doOnError(
throwable ->
Expand All @@ -372,7 +385,8 @@ private TokenInfo getAccessTokenQuery(
|| throwable.getCause() instanceof PrematureCloseException)
.onRetryExhaustedThrow(
(retryBackoffSpec, retrySignal) -> {
throw new RuntimeException(
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED,
"Failed to connect to "
+ tokenEndpoint
+ ", cause: "
Expand All @@ -391,7 +405,8 @@ private TokenInfo getAccessTokenQuery(
String msg = e.getCause().getMessage();

if (e.getCause() instanceof ResponseStatusException) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, msg);
var statusCode = ((ResponseStatusException) e.getCause()).getStatus();
throw new ResponseStatusException(statusCode, msg);
}

if (e.getCause() instanceof TimeoutException) {
Expand All @@ -400,6 +415,15 @@ private TokenInfo getAccessTokenQuery(
"Timeout occurred while fetching token from " + tokenEndpoint);
}

if (e.getCause().getCause() instanceof UnsupportedMediaTypeException) {
throw new ResponseStatusException(
HttpStatus.NOT_ACCEPTABLE,
"Failed while fetching token from "
+ tokenEndpoint
+ ": "
+ e.getCause().getCause().getMessage().replace("bodyType=jumper.model.", ""));
}

throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, msg);

} catch (InterruptedException e) {
Expand All @@ -408,6 +432,11 @@ private TokenInfo getAccessTokenQuery(
"Error occurred while fetching token from " + tokenEndpoint);
}

if (accessToken == null) {
throw new ResponseStatusException(
HttpStatus.NOT_ACCEPTABLE, "Empty response while fetching token from " + tokenEndpoint);
}

tokenCache.saveToken(tokenKey, accessToken);
return accessToken;
}
Expand Down
Loading

0 comments on commit 630f7ec

Please sign in to comment.