diff --git a/pom.xml b/pom.xml index 70794c5..2af6fcd 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ maven-surefire-plugin 3.5.3 - false + true diff --git a/src/main/java/org/privacyidea/AsyncRequestCallable.java b/src/main/java/org/privacyidea/AsyncRequestCallable.java index 21a0961..1388e4b 100644 --- a/src/main/java/org/privacyidea/AsyncRequestCallable.java +++ b/src/main/java/org/privacyidea/AsyncRequestCallable.java @@ -77,14 +77,15 @@ public void onFailure(@NotNull Call call, @NotNull IOException e) @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - // Only response.body() is available in OkHttp; ensure it is closed and consumed only once to prevent resource leaks. + // The body of the response can be in `body()` for success cases or in `errorBody()` for error cases. + // We need to handle both and ensure the body is closed to prevent resource leaks. // The body can only be consumed once. try (ResponseBody responseBody = response.body()) { if (responseBody != null) { String s = responseBody.string(); - if (!privacyIDEA.logExcludedEndpoints().contains(path) && !ENDPOINT_AUTH.equals(path)) + if (!privacyIDEA.logExcludedEndpoints().contains(path)) { privacyIDEA.log(path + " (" + response.code() + "):\n" + privacyIDEA.parser.formatJson(s)); } diff --git a/src/main/java/org/privacyidea/PIResponse.java b/src/main/java/org/privacyidea/PIResponse.java index 8b277f7..481a116 100644 --- a/src/main/java/org/privacyidea/PIResponse.java +++ b/src/main/java/org/privacyidea/PIResponse.java @@ -18,6 +18,11 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; @@ -84,10 +89,11 @@ public boolean authenticationSuccessful() */ public boolean pushAvailable() { - return multiChallenge.stream().anyMatch(c -> isPushOrSmartphoneContainer(c.getType())); + return multiChallenge.stream().anyMatch(c -> isPushOrSmartphoneContainer(c.getType()) && "poll".equals(c.getClientMode())); } - private boolean isPushOrSmartphoneContainer(String type) { + private boolean isPushOrSmartphoneContainer(String type) + { return TOKEN_TYPE_PUSH.equals(type) || CONTAINER_TYPE_SMARTPHONE.equals(type); } @@ -113,7 +119,8 @@ public String otpTransactionId() return null; } - public String pushTransactionId() { + public String pushTransactionId() + { for (Challenge challenge : multiChallenge) { if (isPushOrSmartphoneContainer(challenge.getType())) @@ -142,16 +149,27 @@ private boolean isNotBlank(String str) { */ public String otpMessage() { - return reduceChallengeMessagesWhere(c -> !(isPushOrSmartphoneContainer(c.getType()))); + return reduceChallengeMessagesWhere(c -> + { + String cm = c.getClientMode(); + System.out.println( + "challenge for " + c.getType() + " " + c.getSerial() + " with mode: " + cm); + boolean yes = "interactive".equals(cm); + return yes; + }); } private String reduceChallengeMessagesWhere(Predicate predicate) { StringBuilder sb = new StringBuilder(); - sb.append( - multiChallenge.stream().filter(predicate).map(Challenge::getMessage).distinct().reduce("", (a, s) -> a + s + ", ").trim()); - - if (sb.length() > 0) + sb.append(this.multiChallenge.stream() + .filter(predicate) + .map(Challenge::getMessage) + .distinct() + .reduce("", (a, s) -> a + s + ", ") + .trim()); + + if (!sb.isEmpty()) { sb.deleteCharAt(sb.length() - 1); } @@ -198,7 +216,19 @@ public String toJSON() public static PIResponse fromJSON(String json) { - return new Gson().fromJson(json, PIResponse.class); + JsonDeserializer challengeDeserializer = (jsonElement, type, ctx) -> + { + JsonObject obj = jsonElement.getAsJsonObject(); + String serial = obj.has("serial") && !obj.get("serial").isJsonNull() ? obj.get("serial").getAsString() : ""; + String message = obj.has("message") && !obj.get("message").isJsonNull() ? obj.get("message").getAsString() : ""; + String clientMode = obj.has("clientMode") && !obj.get("clientMode").isJsonNull() ? obj.get("clientMode").getAsString() : ""; + String image = obj.has("image") && !obj.get("image").isJsonNull() ? obj.get("image").getAsString() : ""; + String transactionID = obj.has("transactionID") && !obj.get("transactionID").isJsonNull() ? obj.get("transactionID").getAsString() : ""; + String tokenType = obj.has("type") && !obj.get("type").isJsonNull() ? obj.get("type").getAsString() : ""; + return new Challenge(serial, message, clientMode, image, transactionID, tokenType); + }; + Gson gson = new GsonBuilder().registerTypeAdapter(Challenge.class, challengeDeserializer).create(); + return gson.fromJson(json, PIResponse.class); } @Override