diff --git a/.github/badges/branches.svg b/.github/badges/branches.svg
deleted file mode 100644
index 28be886..0000000
--- a/.github/badges/branches.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/.github/badges/coverage-summary.json b/.github/badges/coverage-summary.json
deleted file mode 100644
index 92e8263..0000000
--- a/.github/badges/coverage-summary.json
+++ /dev/null
@@ -1 +0,0 @@
-{"branches": 54.109589041095894, "coverage": 74.64907355418305}
\ No newline at end of file
diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg
deleted file mode 100644
index 8db44d9..0000000
--- a/.github/badges/jacoco.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 979bab4..8cb1782 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,6 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
-name: Java CI with Maven, Run Tests, Coverage Report and Badge
+name: Build
on:
push:
@@ -15,56 +15,6 @@ jobs:
steps:
- uses: actions/checkout@v4
-
- - name: Setup Java Development Kits
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: microsoft
- cache: maven
-
+
- name: Build with Maven
run: mvn -B package --file pom.xml
-
- - name: Generate JavaCodeCoverage badge
- id: jacoco
- uses: cicirello/jacoco-badge-generator@v2
- with:
- badges-directory: .github/badges
- generate-branches-badge: true
- generate-summary: true
-
- - name: Log coverage percentages to workflow output
- run: |
- echo "coverage = ${{ steps.jacoco.outputs.coverage }}"
- echo "branches = ${{ steps.jacoco.outputs.branches }}"
-
- - name: Upload JaCoCo coverage report as a workflow artifact
- uses: actions/upload-artifact@v4
- with:
- name: jacoco-report
- path: target/site/jacoco/
-
- - name: Commit and push the coverage badges and summary file
- if: ${{ github.event_name != 'pull_request' }}
- run: |
- cd .github/badges
- if [[ `git status --porcelain *.svg *.json` ]]; then
- git config --global user.name 'github-actions'
- git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
- git add *.svg *.json
- git commit -m "Autogenerated JaCoCo coverage badges" *.svg *.json
- git push
- fi
-
-# - name: Comment on PR with coverage percentages
-# if: ${{ github.event_name == 'pull_request' }}
-# run: |
-# REPORT=$(<.github/badges/coverage-summary.json)
-# COVERAGE=$(jq -r '.coverage' <<< "$REPORT")%
-# BRANCHES=$(jq -r '.branches' <<< "$REPORT")%
-# NEWLINE=$'\n'
-# BODY="## JaCoCo Test Coverage Summary Statistics${NEWLINE}* __Coverage:__ ${COVERAGE}${NEWLINE}* __Branches:__ ${BRANCHES}"
-# gh pr comment ${{github.event.pull_request.number}} -b "${BODY}"
-# env:
-# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 70794c5..0f04fd3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,7 +118,7 @@
com.auth0
java-jwt
- 4.4.0
+ 4.5.1
diff --git a/src/main/java/org/privacyidea/AsyncRequestCallable.java b/src/main/java/org/privacyidea/AsyncRequestCallable.java
index 21a0961..ba44831 100644
--- a/src/main/java/org/privacyidea/AsyncRequestCallable.java
+++ b/src/main/java/org/privacyidea/AsyncRequestCallable.java
@@ -77,8 +77,9 @@ 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 can only be consumed once.
+ // For OkHttp, the response body is always available via `body()`, regardless of HTTP status.
+ // We must ensure the body is closed to prevent resource leaks, and it can only be consumed once.
+ // Using try-with-resources guarantees the body is properly closed after reading.
try (ResponseBody responseBody = response.body())
{
if (responseBody != null)
diff --git a/src/main/java/org/privacyidea/PIResponse.java b/src/main/java/org/privacyidea/PIResponse.java
index 8b277f7..5b06b4f 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,14 +149,18 @@ private boolean isNotBlank(String str) {
*/
public String otpMessage()
{
- return reduceChallengeMessagesWhere(c -> !(isPushOrSmartphoneContainer(c.getType())));
+ return reduceChallengeMessagesWhere(c -> "interactive".equals(c.getClientMode()));
}
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());
+ sb.append(this.multiChallenge.stream()
+ .filter(predicate)
+ .map(Challenge::getMessage)
+ .distinct()
+ .reduce("", (a, s) -> a + s + ", ")
+ .trim());
if (sb.length() > 0)
{
@@ -198,7 +209,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