Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/badges/branches.svg

This file was deleted.

1 change: 0 additions & 1 deletion .github/badges/coverage-summary.json

This file was deleted.

1 change: 0 additions & 1 deletion .github/badges/jacoco.svg

This file was deleted.

54 changes: 2 additions & 52 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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 }}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
<version>4.5.1</version>
</dependency>
</dependencies>
</project>
5 changes: 3 additions & 2 deletions src/main/java/org/privacyidea/AsyncRequestCallable.java
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
37 changes: 30 additions & 7 deletions src/main/java/org/privacyidea/PIResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -113,7 +119,8 @@ public String otpTransactionId()
return null;
}

public String pushTransactionId() {
public String pushTransactionId()
{
for (Challenge challenge : multiChallenge)
{
if (isPushOrSmartphoneContainer(challenge.getType()))
Expand Down Expand Up @@ -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<Challenge> 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)
{
Expand Down Expand Up @@ -198,7 +209,19 @@ public String toJSON()

public static PIResponse fromJSON(String json)
{
return new Gson().fromJson(json, PIResponse.class);
JsonDeserializer<Challenge> 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
Expand Down
Loading