Skip to content

Prepare 1.5.0#84

Open
nilsbehlen wants to merge 3 commits intomasterfrom
prepare-1.5.0
Open

Prepare 1.5.0#84
nilsbehlen wants to merge 3 commits intomasterfrom
prepare-1.5.0

Conversation

@nilsbehlen
Copy link
Member

No description provided.

@nilsbehlen nilsbehlen requested a review from Copilot March 5, 2026 13:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prepares the privacyidea-java-client for the 1.5.0 release by extending challenge/passkey handling, adjusting client-mode based logic, improving async response body handling/logging, and bumping the Maven version.

Changes:

  • Update PIResponse challenge helpers (pushAvailable, otpMessage, hasChallenges) and customize Gson deserialization for Challenge.
  • Extend JSONParser to recognize passkey challenges inside multi_challenge.
  • Refactor OkHttp async response consumption to close ResponseBody and include HTTP status in logs; bump project version to 1.5.0.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
src/main/java/org/privacyidea/PIResponse.java Adds challenge helpers and new filtering logic; introduces a custom Gson deserializer for Challenge.
src/main/java/org/privacyidea/JSONParser.java Adds handling for passkey challenges found in the multi_challenge array.
src/main/java/org/privacyidea/AsyncRequestCallable.java Ensures response bodies are closed and adjusts logging behavior/format.
pom.xml Bumps artifact version to 1.5.0 and changes test execution configuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

public boolean pushAvailable()
{
return multiChallenge.stream().anyMatch(c -> isPushOrSmartphoneContainer(c.getType()));
return multiChallenge.stream().anyMatch(c -> isPushOrSmartphoneContainer(c.getType()) && "poll".equals(c.getClientMode()));
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushAvailable() now requires clientMode to be exactly "poll". Many server responses don’t include client_mode per challenge (it parses as an empty string), so this can incorrectly return false even when a push challenge is present. Consider detecting push based on token type alone or falling back to the response’s preferredClientMode when clientMode is missing.

Suggested change
return multiChallenge.stream().anyMatch(c -> isPushOrSmartphoneContainer(c.getType()) && "poll".equals(c.getClientMode()));
if (multiChallenge == null || multiChallenge.isEmpty())
{
return false;
}
return multiChallenge.stream().anyMatch(c -> {
if (!isPushOrSmartphoneContainer(c.getType()))
{
return false;
}
String clientMode = c.getClientMode();
if (clientMode == null || clientMode.isEmpty())
{
// Fall back to the response's preferred client mode when per-challenge clientMode is missing
return "poll".equals(preferredClientMode);
}
return "poll".equals(clientMode);
});

Copilot uses AI. Check for mistakes.
Comment on lines +80 to 82
// 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.
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment mentions errorBody(), but okhttp3.Response doesn’t have an errorBody() API (that’s Retrofit). This is misleading documentation; either adjust the comment to OkHttp semantics (body is available regardless of status) or implement the intended behavior in the appropriate layer.

Suggested change
// 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.
// 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.

Copilot uses AI. Check for mistakes.
{
String s = responseBody.string();
if (!privacyIDEA.logExcludedEndpoints().contains(path) && !ENDPOINT_AUTH.equals(path))
if (!privacyIDEA.logExcludedEndpoints().contains(path))
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change will log the full response body for all endpoints not in logExcludedEndpoints(). Since /auth is not excluded by default (and returns JWT/token material), this can leak sensitive credentials into logs. Please re-add an explicit /auth exclusion (or add it to the default excluded list) and/or redact tokens before logging.

Suggested change
if (!privacyIDEA.logExcludedEndpoints().contains(path))
if (!privacyIDEA.logExcludedEndpoints().contains(path) && !ENDPOINT_AUTH.equals(path))

Copilot uses AI. Check for mistakes.
Comment on lines +21 to 22
<skipTests>true</skipTests>
</configuration>
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting Surefire’s <skipTests> to true disables unit tests for all builds, which makes it easy to ship regressions (especially for a release bump). If the intent is only to speed up local packaging, consider removing this change or gating it behind a Maven profile / CI property instead of committing it as the default.

Copilot uses AI. Check for mistakes.
.reduce("", (a, s) -> a + s + ", ")
.trim());

if (!sb.isEmpty())
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringBuilder in Java 14 (per pom.xml) does not have an isEmpty() method, so this will not compile. Use sb.length() > 0 (or check the appended string) before deleting the trailing separator.

Suggested change
if (!sb.isEmpty())
if (sb.length() > 0)

Copilot uses AI. Check for mistakes.
Comment on lines +154 to +158
String cm = c.getClientMode();
System.out.println(
"challenge for " + c.getType() + " " + c.getSerial() + " with mode: " + cm);
boolean yes = "interactive".equals(cm);
return yes;
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otpMessage() now filters challenges by clientMode == "interactive". In existing responses/fixtures, client_mode is often absent for OTP challenges (parsed as empty string), which would make otpMessage() return an empty message even when OTP challenges exist. Consider keeping the previous logic (exclude push/smartphone/webauthn) or falling back to preferredClientMode / treating missing client_mode as interactive for OTP challenges.

Suggested change
String cm = c.getClientMode();
System.out.println(
"challenge for " + c.getType() + " " + c.getSerial() + " with mode: " + cm);
boolean yes = "interactive".equals(cm);
return yes;
String clientMode = c.getClientMode();
String type = c.getType();
// If client_mode is explicitly "interactive", this is an OTP-style interactive challenge.
if ("interactive".equals(clientMode))
{
return true;
}
// For legacy responses where client_mode is missing or empty, fall back to the
// previous behavior: include all non-push / non-smartphone / non-webauthn challenges.
if (clientMode == null || clientMode.trim().isEmpty())
{
if (isPushOrSmartphoneContainer(type) || TOKEN_TYPE_WEBAUTHN.equals(type))
{
return false;
}
return true;
}
// Any other explicit client_mode is not considered an OTP-input challenge.
return false;

Copilot uses AI. Check for mistakes.
Comment on lines +152 to +159
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;
});
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Library code should not write directly to stdout. The System.out.println(...) debug output in otpMessage() will spam application logs and may leak token/challenge details; please remove it or route it through the configured logger behind a debug flag.

Suggested change
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;
});
return reduceChallengeMessagesWhere(c -> "interactive".equals(c.getClientMode()));

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants