diff --git a/pom.xml b/pom.xml
index a5ce3c7..70794c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
org.privacyidea
privacyidea-java-client
- 1.4.0
+ 1.5.0
jar
UTF-8
@@ -83,16 +83,16 @@
4.13.2
test
-
- com.squareup.okhttp3
- okhttp
- 4.12.0
-
org.jetbrains.kotlin
kotlin-stdlib
1.9.0
+
+ com.squareup.okhttp3
+ okhttp
+ 4.12.0
+
com.squareup.okio
okio
diff --git a/src/main/java/org/privacyidea/AsyncRequestCallable.java b/src/main/java/org/privacyidea/AsyncRequestCallable.java
index 46495a0..21a0961 100644
--- a/src/main/java/org/privacyidea/AsyncRequestCallable.java
+++ b/src/main/java/org/privacyidea/AsyncRequestCallable.java
@@ -24,6 +24,7 @@
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
+import okhttp3.ResponseBody;
import org.jetbrains.annotations.NotNull;
import static org.privacyidea.PIConstants.ENDPOINT_AUTH;
@@ -76,15 +77,22 @@ public void onFailure(@NotNull Call call, @NotNull IOException e)
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException
{
- if (response.body() != null)
+ // Only response.body() is available in OkHttp; ensure it is closed and consumed only once to prevent resource leaks.
+ // The body can only be consumed once.
+ try (ResponseBody responseBody = response.body())
{
- String s = response.body().string();
- if (!privacyIDEA.logExcludedEndpoints().contains(path) && !ENDPOINT_AUTH.equals(path))
+ if (responseBody != null)
{
- privacyIDEA.log(path + ":\n" + privacyIDEA.parser.formatJson(s));
+ String s = responseBody.string();
+ if (!privacyIDEA.logExcludedEndpoints().contains(path) && !ENDPOINT_AUTH.equals(path))
+ {
+ privacyIDEA.log(path + " (" + response.code() + "):\n" + privacyIDEA.parser.formatJson(s));
+ }
+ callbackResult[0] = s;
}
- callbackResult[0] = s;
}
- latch.countDown();
+ finally {
+ latch.countDown();
+ }
}
}
\ No newline at end of file
diff --git a/src/main/java/org/privacyidea/JSONParser.java b/src/main/java/org/privacyidea/JSONParser.java
index f67ea71..e065ea7 100644
--- a/src/main/java/org/privacyidea/JSONParser.java
+++ b/src/main/java/org/privacyidea/JSONParser.java
@@ -73,6 +73,7 @@
import static org.privacyidea.PIConstants.TIME;
import static org.privacyidea.PIConstants.TOKEN;
import static org.privacyidea.PIConstants.TOKENS;
+import static org.privacyidea.PIConstants.TOKEN_TYPE_PASSKEY;
import static org.privacyidea.PIConstants.TOKEN_TYPE_WEBAUTHN;
import static org.privacyidea.PIConstants.TRANSACTION_ID;
import static org.privacyidea.PIConstants.TYPE;
@@ -277,6 +278,7 @@ else if ("interactive".equals(modeFromResponse))
});
}
+ // Multichallenge
JsonArray arrChallenges = detail.getAsJsonArray(MULTI_CHALLENGE);
if (arrChallenges != null)
{
@@ -311,6 +313,10 @@ else if ("interactive".equals(modeFromResponse))
webauthnSignRequests.add(webauthnSignRequest);
}
}
+ else if (TOKEN_TYPE_PASSKEY.equals(type))
+ {
+ response.passkeyChallenge = challenge.toString();
+ }
else
{
response.multiChallenge.add(new Challenge(serial, message, clientMode, image, transactionID, type));
diff --git a/src/main/java/org/privacyidea/PIResponse.java b/src/main/java/org/privacyidea/PIResponse.java
index 534ac74..8b277f7 100644
--- a/src/main/java/org/privacyidea/PIResponse.java
+++ b/src/main/java/org/privacyidea/PIResponse.java
@@ -124,6 +124,17 @@ public String pushTransactionId() {
return null;
}
+ public boolean hasChallenges()
+ {
+ return (multiChallenge != null && !multiChallenge.isEmpty()) ||
+ isNotBlank(mergedSignRequest()) ||
+ isNotBlank(passkeyChallenge);
+ }
+
+ private boolean isNotBlank(String str) {
+ return str != null && !str.trim().isEmpty();
+ }
+
/**
* Get the messages of all token that require an input field (HOTP, TOTP, SMS, Email...) reduced to a single string.
*