Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d6d1011

Browse files
committed
Merge branch 'develop'
2 parents cf17485 + 7b355a0 commit d6d1011

File tree

2 files changed

+40
-34
lines changed

2 files changed

+40
-34
lines changed

‎pom.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<modelVersion>4.0.0</modelVersion>
1717
<artifactId>http-server</artifactId>
18-
<version>0.3.18</version>
18+
<version>0.3.19</version>
1919
<name>HttpServer</name>
2020
<packaging>jar</packaging>
2121

‎src/main/java/info/unterrainer/commons/httpserver/accessmanager/HttpAccessManager.java‎

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
package info.unterrainer.commons.httpserver.accessmanager;
22

33
import java.io.IOException;
4-
import java.io.UncheckedIOException;
4+
import java.math.BigInteger;
55
import java.net.URI;
6-
import java.net.URISyntaxException;
76
import java.net.http.HttpClient;
87
import java.net.http.HttpRequest;
9-
import java.net.http.HttpResponse.BodyHandlers;
8+
import java.net.http.HttpResponse;
9+
import java.security.KeyFactory;
1010
import java.security.PublicKey;
11+
import java.security.spec.RSAPublicKeySpec;
12+
import java.util.Base64;
1113
import java.util.HashSet;
1214
import java.util.Set;
1315

1416
import org.eclipse.jetty.http.HttpHeader;
1517
import org.keycloak.TokenVerifier;
1618
import org.keycloak.common.VerificationException;
1719
import org.keycloak.representations.AccessToken;
18-
import org.keycloak.representations.idm.PublishedRealmRepresentation;
1920

21+
import com.fasterxml.jackson.databind.JsonNode;
2022
import com.fasterxml.jackson.databind.ObjectMapper;
2123

2224
import info.unterrainer.commons.httpserver.HttpServer;
2325
import info.unterrainer.commons.httpserver.enums.Attribute;
2426
import info.unterrainer.commons.httpserver.exceptions.ForbiddenException;
25-
import info.unterrainer.commons.httpserver.exceptions.GatewayTimeoutException;
2627
import info.unterrainer.commons.httpserver.exceptions.UnauthorizedException;
2728
import info.unterrainer.commons.httpserver.jsons.UserDataJson;
2829
import io.javalin.core.security.AccessManager;
@@ -56,6 +57,35 @@ public void manage(final Handler handler, final Context ctx, final Set<Role> per
5657
handler.handle(ctx);
5758
}
5859

60+
private PublicKey fetchPublicKey(String jwksUrl) throws Exception {
61+
ObjectMapper objectMapper = new ObjectMapper();
62+
HttpClient client = HttpClient.newHttpClient();
63+
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(jwksUrl)).GET().build();
64+
65+
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
66+
67+
if (response.statusCode() >= 300) {
68+
throw new IOException("Failed to fetch JWKS: HTTP " + response.statusCode());
69+
}
70+
71+
JsonNode jwks = objectMapper.readTree(response.body());
72+
// Just take the first key for now.
73+
JsonNode key = jwks.get("keys").get(0);
74+
75+
String modulusBase64 = key.get("n").asText();
76+
String exponentBase64 = key.get("e").asText();
77+
78+
byte[] modulusBytes = Base64.getUrlDecoder().decode(modulusBase64);
79+
byte[] exponentBytes = Base64.getUrlDecoder().decode(exponentBase64);
80+
81+
BigInteger modulus = new BigInteger(1, modulusBytes);
82+
BigInteger exponent = new BigInteger(1, exponentBytes);
83+
84+
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
85+
KeyFactory factory = KeyFactory.getInstance("RSA");
86+
return factory.generatePublic(spec);
87+
}
88+
5989
private void initPublicKey() {
6090
if (publicKey != null)
6191
return;
@@ -66,36 +96,12 @@ private void initPublicKey() {
6696
if (!realm.startsWith("/"))
6797
realm = "/" + realm;
6898

69-
authUrl = host + "realms" + realm;
99+
authUrl = host + "realms" + realm + "/protocol/openid-connect/certs";
70100
try {
71101
log.info("Getting public key from: [{}]", authUrl);
72-
HttpClient client = HttpClient.newHttpClient();
73-
HttpRequest request = HttpRequest.newBuilder().uri(new URI(authUrl)).build();
74-
ObjectMapper objectMapper = new ObjectMapper();
75-
76-
client.sendAsync(request, BodyHandlers.ofString()).thenApply(response -> {
77-
if (response.statusCode() >= 300) {
78-
log.error("HTTP status [{}] getting public key from keycloak instance [{}].", response.statusCode(),
79-
authUrl);
80-
throw new GatewayTimeoutException(String
81-
.format("The keycloak instance returned an error (status: %d).", response.statusCode()));
82-
}
83-
return response.body();
84-
}).thenAccept(body -> {
85-
if (body == null) {
86-
log.warn("Received empty body.");
87-
return;
88-
}
89-
try {
90-
publicKey = objectMapper.readValue(body, PublishedRealmRepresentation.class).getPublicKey();
91-
log.info("Public key received.");
92-
} catch (IOException e) {
93-
log.error("Error parsing answer from keycloak.");
94-
throw new UncheckedIOException(e);
95-
}
96-
}).join();
97-
} catch (URISyntaxException e) {
98-
log.error("The keycloak URL was illegal [{}].", authUrl);
102+
publicKey = fetchPublicKey(authUrl);
103+
} catch (Exception e) {
104+
log.error("There was an error fetching the PublicKey from the openIdConnect-server [{}].", authUrl);
99105
throw new IllegalStateException(e);
100106
}
101107
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /