Skip to content

Commit

Permalink
[ANCHOR-687] Upgrade to JDK-17 (#1367)
Browse files Browse the repository at this point in the history
### Description

- Upgrade JDK from 11 to 17.
- Fix Jwt Json serialization

### Context

- JDK 11 is expected to sunset in 10/2024. 

### Testing

- `./gradlew test`

### Documentation

Update `How to Contribute` doc.


### Known limitations

N/A
  • Loading branch information
lijamie98 authored May 24, 2024
1 parent 778d3bd commit eba522b
Show file tree
Hide file tree
Showing 20 changed files with 129 additions and 54 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/sub_essential_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ jobs:
runs-on: ubuntu-latest-8-cores
steps:
#############################################
# Setup JDK 11
# Setup JDK 17
# Download, and Extract java-stellar-anchor-sdk.tar
# Setup hostnames (/etc/hosts)
#############################################
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'

- name: Download java-stellar-anchor-sdk.tar
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/sub_extended_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ jobs:
runs-on: ubuntu-latest-16-cores
steps:
#############################################
# Setup JDK 11
# Setup JDK 17
# Download, and Extract java-stellar-anchor-sdk.tar
# Setup hostnames (/etc/hosts)
#############################################
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'

- name: Download java-stellar-anchor-sdk.tar
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sub_gradle_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
with:
show-progress: false

- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'

- name: Gradle Build with unit tests only
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/sub_jacoco_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ jobs:
runs-on: ubuntu-latest
steps:
#############################################
# Setup JDK 11
# Setup JDK 17
# Download, and Extract java-stellar-anchor-sdk.tar
# Setup hostnames (/etc/hosts)
#############################################
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'

- name: Download java-stellar-anchor-sdk.tar
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG BASE_IMAGE=gradle:7.6.4-jdk11-alpine
ARG BASE_IMAGE=gradle:7.6.4-jdk17-alpine

FROM ${BASE_IMAGE} AS build
WORKDIR /code
Expand All @@ -9,7 +9,7 @@ RUN gradle clean bootJar --stacktrace -x test
FROM ubuntu:22.04

RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jre
apt-get install -y --no-install-recommends openjdk-17-jre

COPY --from=build /code/service-runner/build/libs/anchor-platform-runner*.jar /app/anchor-platform-runner.jar
COPY --from=build /code/scripts/docker-start.sh /app/start.sh
Expand Down
19 changes: 2 additions & 17 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,10 @@ subprojects {
maven { url = uri("https://jitpack.io") }
}

/** Specifies JDK-11 */
java { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) } }
/** Specifies JDK-17 */
java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } }

spotless {
val javaVersion = System.getProperty("java.version")
if (javaVersion >= "17") {
logger.warn("!!! WARNING !!!")
logger.warn("=================")
logger.warn(
" You are running Java version:[{}]. Spotless may not work well with JDK 17.",
javaVersion)
logger.warn(
" In IntelliJ, go to [File -> Build -> Execution, Build, Deployment -> Gradle] and check Gradle JVM")
}

if (javaVersion < "11") {
throw GradleException("Java 11 or greater is required for spotless Gradle plugin.")
}

java {
importOrder("java", "javax", "org.stellar")
removeUnusedImports()
Expand Down
2 changes: 2 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ dependencies {
// Lombok should be used by all subprojects to reduce Java verbosity
annotationProcessor(libs.lombok)

implementation("io.jsonwebtoken:jjwt-gson:0.12.5")

implementation(libs.spring.kafka)
implementation(libs.spring.data.commons)

Expand Down
11 changes: 11 additions & 0 deletions core/src/main/java/org/stellar/anchor/auth/AuthHelper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.stellar.anchor.auth;

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParserBuilder;
import io.jsonwebtoken.Jwts;
import java.util.Calendar;
import javax.annotation.Nullable;
import org.stellar.anchor.api.exception.InvalidConfigException;
Expand Down Expand Up @@ -66,6 +69,14 @@ public AuthHeader<String, String> createCustodyAuthHeader() throws InvalidConfig
return createAuthHeader(CustodyAuthJwt.class);
}

public static JwtBuilder jwtsBuilder() {
return Jwts.builder().json(JwtsGsonSerializer.newInstance());
}

public static JwtParserBuilder jwtsParser() {
return Jwts.parser().json(JwtsGsonDeserializer.newInstance());
}

@Nullable
private <T extends ApiAuthJwt> AuthHeader<String, String> createAuthHeader(Class<T> jwtClass)
throws InvalidConfigException {
Expand Down
18 changes: 12 additions & 6 deletions core/src/main/java/org/stellar/anchor/auth/JwtService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.stellar.anchor.auth;

import static java.util.Date.from;
import static org.stellar.anchor.auth.AuthHelper.jwtsBuilder;

import io.jsonwebtoken.*;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -81,8 +82,9 @@ public JwtService(
public String encode(Sep10Jwt token) {
Instant timeExp = Instant.ofEpochSecond(token.getExp());
Instant timeIat = Instant.ofEpochSecond(token.getIat());

JwtBuilder builder =
Jwts.builder()
jwtsBuilder()
.id(token.getJti())
.issuer(token.getIss())
.subject(token.getSub())
Expand All @@ -106,7 +108,7 @@ public String encode(MoreInfoUrlJwt token) throws InvalidConfigException {

Instant timeExp = Instant.ofEpochSecond(token.getExp());
JwtBuilder builder =
Jwts.builder().id(token.getJti()).expiration(from(timeExp)).subject(token.getSub());
jwtsBuilder().id(token.getJti()).expiration(from(timeExp)).subject(token.getSub());
for (Map.Entry<String, Object> claim : token.claims.entrySet()) {
builder.claim(claim.getKey(), claim.getValue());
}
Expand All @@ -132,7 +134,7 @@ public String encode(Sep24InteractiveUrlJwt token) throws InvalidConfigException
}
Instant timeExp = Instant.ofEpochSecond(token.getExp());
JwtBuilder builder =
Jwts.builder().id(token.getJti()).expiration(from(timeExp)).subject(token.getSub());
jwtsBuilder().id(token.getJti()).expiration(from(timeExp)).subject(token.getSub());
for (Map.Entry<String, Object> claim : token.claims.entrySet()) {
builder.claim(claim.getKey(), claim.getValue());
}
Expand Down Expand Up @@ -164,7 +166,7 @@ private String encode(ApiAuthJwt token, String secret) throws InvalidConfigExcep

Instant timeExp = Instant.ofEpochSecond(token.getExp());
Instant timeIat = Instant.ofEpochSecond(token.getIat());
JwtBuilder builder = Jwts.builder().issuedAt(from(timeIat)).expiration(from(timeExp));
JwtBuilder builder = jwtsBuilder().issuedAt(from(timeIat)).expiration(from(timeExp));

return builder.signWith(KeyUtil.toSecretKeySpecOrNull(secret), Jwts.SIG.HS256).compact();
}
Expand Down Expand Up @@ -193,7 +195,11 @@ public <T extends AbstractJwt> T decode(String cipher, Class<T> cls)
String.format("The Jwt class:[%s] is not supported", cls.getName()));
}

Jwt jwt = Jwts.parser().verifyWith(KeyUtil.toSecretKeySpecOrNull(secret)).build().parse(cipher);
Jwt jwt =
AuthHelper.jwtsParser()
.verifyWith(KeyUtil.toSecretKeySpecOrNull(secret))
.build()
.parse(cipher);

if (cls.equals(Sep6MoreInfoUrlJwt.class)) {
return (T) Sep6MoreInfoUrlJwt.class.getConstructor(Jwt.class).newInstance(jwt);
Expand Down Expand Up @@ -223,7 +229,7 @@ public Jws<Claims> getHeaderJwt(String signingKey, String cipher) {
var jcaPublicKey = factory.generatePublic(x509KeySpec);

try {
return Jwts.parser().verifyWith(jcaPublicKey).build().parseSignedClaims(cipher);
return AuthHelper.jwtsParser().verifyWith(jcaPublicKey).build().parseSignedClaims(cipher);
} catch (Exception e) {
Log.debugF("Invalid header signature {}", e.getMessage());
throw new SepValidationException("Invalid header signature");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.stellar.anchor.auth;

import com.google.gson.Gson;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.Deserializer;
import java.io.Reader;
import java.util.Map;
import org.stellar.anchor.util.GsonUtils;

public class JwtsGsonDeserializer implements Deserializer<Map<String, ?>> {
private static final Gson gson = GsonUtils.getInstance();

public static JwtsGsonDeserializer newInstance() {
return new JwtsGsonDeserializer();
}

@Override
public Map<String, ?> deserialize(byte[] bytes) throws DeserializationException {
return gson.fromJson(new String(bytes), Map.class);
}

@Override
public Map<String, ?> deserialize(Reader reader) throws DeserializationException {
return gson.fromJson(reader, Map.class);
}
}
30 changes: 30 additions & 0 deletions core/src/main/java/org/stellar/anchor/auth/JwtsGsonSerializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.stellar.anchor.auth;

import com.google.gson.Gson;
import io.jsonwebtoken.io.SerializationException;
import io.jsonwebtoken.io.Serializer;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import lombok.SneakyThrows;
import org.stellar.anchor.util.GsonUtils;

public class JwtsGsonSerializer implements Serializer<Map<String, ?>> {
private static final Gson gson = GsonUtils.getInstance();

public static JwtsGsonSerializer newInstance() {
return new JwtsGsonSerializer();
}

@Override
public byte[] serialize(Map<String, ?> stringMap) throws SerializationException {
return gson.toJson(stringMap).getBytes(StandardCharsets.UTF_8);
}

@SneakyThrows
@Override
public void serialize(Map<String, ?> stringMap, OutputStream outputStream)
throws SerializationException {
outputStream.write(serialize(stringMap));
}
}
16 changes: 15 additions & 1 deletion core/src/main/java/org/stellar/anchor/util/Log.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -81,7 +83,19 @@ public static void error(final String msg) {
* @param detail The additional object to be logged.
*/
public static void error(final String message, final Object detail) {
logMessageWithJson(message, detail, getLogger()::error);
if (detail instanceof Exception) {
Exception ex = (Exception) detail;

logMessageWithJson(
message,
Arrays.stream(ex.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n")),
getLogger()::error);
return;
} else {
logMessageWithJson(message, detail, getLogger()::error);
}
Metrics.counter("logger", "type", "error").increment();
}

Expand Down
6 changes: 3 additions & 3 deletions docs/01 - Contributing/A - Development Environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- TOC -->

* [How to set up the development environment](#how-to-set-up-the-development-environment)
* [Install JDK 11](#install-jdk-11)
* [Install JDK 17](#install-jdk-17)
* [Checkout the Project](#checkout-the-project)
* [Set up `docker`](#set-up-docker)
* [Set up your hosts file](#set-up-your-hosts-file)
Expand All @@ -27,10 +27,10 @@

<!-- TOC -->

## Install JDK 11
## Install JDK 17

Before you start, please make sure you
have [JDK-11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html) installed on your machine.
have [JDK-17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) installed on your machine.

To check if you have it installed, run:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class Sep24Tests : AbstractIntegrationTests(TestConfig()) {
val jwt = jwtService.decode(cipher, Sep24InteractiveUrlJwt::class.java)
assertEquals(response.id, jwt.jti)
assertNotNull(jwt.claims["data"])
assertNotNull((jwt.claims["data"] as HashMap<*, *>)["asset"])
assertNotNull((jwt.claims["data"] as Map<*, *>)["asset"])
}

/*
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dotenv = "2.3.2"
exposed = "0.49.0"
findbugs-jsr305 = "3.0.2"
flyway-core = "8.5.13"
google-gson = "2.8.9"
google-gson = "2.10.1"
httpclient = "4.5.13"
h2database = "2.2.224"
hibernate-types = "2.18.0"
Expand Down
2 changes: 1 addition & 1 deletion kotlin-reference-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ dependencies {
tasks {
compileKotlin {
dependsOn("spotlessKotlinApply")
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "17"
}

test { useJUnitPlatform() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.stellar.anchor.platform.custody.fireblocks;

import static org.stellar.anchor.auth.AuthHelper.jwtsBuilder;
import static org.stellar.anchor.util.OkHttpUtil.TYPE_JSON;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.io.IOException;
import java.math.BigInteger;
Expand Down Expand Up @@ -117,7 +117,7 @@ private String signJwt(String path, String dataJSONString) {
Instant now = Instant.now();
Instant expirationTime = now.plusSeconds(TOKEN_EXPIRATION_SECONDS);

return Jwts.builder()
return jwtsBuilder()
.setSubject(apiKey)
.setIssuedAt(Date.from(now))
.setExpiration(Date.from(expirationTime))
Expand Down
Loading

0 comments on commit eba522b

Please sign in to comment.