Skip to content

feat: implement JWT utility class with configurable properties and to…#293

Merged
lhpqaq merged 3 commits intoapache:mainfrom
timyuer:fix_auth_vulnerability
Mar 30, 2026
Merged

feat: implement JWT utility class with configurable properties and to…#293
lhpqaq merged 3 commits intoapache:mainfrom
timyuer:fix_auth_vulnerability

Conversation

@timyuer
Copy link
Copy Markdown
Member

@timyuer timyuer commented Jan 20, 2026

…ken management

Copy link
Copy Markdown

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

This PR introduces a configurable JWT utility (secret/issuer/audience/expiration) and wires it into login/auth flows, with accompanying config and test updates.

Changes:

  • Add JwtProperties configuration and enable it in the Spring Boot application.
  • Refactor JWTUtils from static helpers to a Spring component using configurable signing/verification parameters (plus stricter verification).
  • Update login/auth code paths and tests; add dev-support container wiring for JWT secret env var.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
dev-support/docker/containers/build.sh Sets/passes JWT secret into dev Docker containers and attempts to inject it into server config.
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/JWTUtils.java New Spring-managed JWT utility using JwtProperties, stricter verification, configurable secret.
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/config/JwtProperties.java Adds bindable JWT configuration properties.
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/BigtopManagerServer.java Enables configuration properties binding for JwtProperties.
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/LoginServiceImpl.java Switches token generation to injected JWTUtils.
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/AuthInterceptor.java Switches token verification to injected JWTUtils.
bigtop-manager-server/src/main/resources/application.yml Adds JWT configuration section and env-var secret placeholder.
bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/utils/JWTUtilsTest.java Updates tests for instance-based JWTUtils and new verification rules.
bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/service/LoginServiceTest.java Mocks JWTUtils to keep login unit test isolated from signing config.

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

Comment on lines +134 to +135
docker exec ${container} bash -c "grep -q '^\s*secret:' /opt/bigtop-manager-server/conf/application.yml || true"
docker exec ${container} bash -c "sed -i 's/^\(\s*secret:\).*/\1 \${BIGTOP_MANAGER_JWT_SECRET}/' /opt/bigtop-manager-server/conf/application.yml || true"
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

The grep/sed patterns use \s to match whitespace, but POSIX grep/sed don’t treat \s as whitespace. As a result, these commands won’t match secret: lines and the “inject JWT secret” step is effectively a no-op. Use a portable whitespace class (e.g., [[:space:]]) and make the logic actually update/ensure the intended YAML key.

Suggested change
docker exec ${container} bash -c "grep -q '^\s*secret:' /opt/bigtop-manager-server/conf/application.yml || true"
docker exec ${container} bash -c "sed -i 's/^\(\s*secret:\).*/\1 \${BIGTOP_MANAGER_JWT_SECRET}/' /opt/bigtop-manager-server/conf/application.yml || true"
docker exec ${container} bash -c "if grep -q '^[[:space:]]*secret:' /opt/bigtop-manager-server/conf/application.yml; then sed -i 's/^\([[:space:]]*secret:\).*/\1 \${BIGTOP_MANAGER_JWT_SECRET}/' /opt/bigtop-manager-server/conf/application.yml; else printf '\nsecret: %s\n' \"\${BIGTOP_MANAGER_JWT_SECRET}\" >> /opt/bigtop-manager-server/conf/application.yml; fi || true"

Copilot uses AI. Check for mistakes.
Comment on lines +106 to 108
throw new IllegalStateException(
"JWT secret is not configured. Please set bigtop-manager.security.jwt.secret (or enable allowDefaultSecret for dev only).");
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

getSigningSecret() throws IllegalStateException when the secret is missing, which will be handled by the global exception handler as a generic 500. That makes a common misconfiguration hard to diagnose and can surface as an opaque runtime failure on login/auth. Consider failing fast at startup (validation) or throwing/handling a domain-specific exception that returns a clearer configuration error response.

Suggested change
throw new IllegalStateException(
"JWT secret is not configured. Please set bigtop-manager.security.jwt.secret (or enable allowDefaultSecret for dev only).");
}
throw new JwtConfigurationException(
"JWT secret is not configured. Please set bigtop-manager.security.jwt.secret (or enable allowDefaultSecret for dev only).");
}
/**
* Exception indicating that the JWT subsystem is misconfigured, for example
* when the signing secret is missing in a non-development environment.
*/
static class JwtConfigurationException extends RuntimeException {
JwtConfigurationException(String message) {
super(message);
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +85
public DecodedJWT resolveToken(String token) throws JWTVerificationException {
Algorithm algorithm = Algorithm.HMAC256(getSigningSecret());
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer(jwtProperties.getIssuer())
.withAudience(jwtProperties.getAudience())
.build();

DecodedJWT decodedJWT = verifier.verify(token);

// Enforce issued-at to mitigate tokens without freshness metadata.
Date issuedAt = decodedJWT.getIssuedAt();
if (issuedAt == null) {
throw new JWTVerificationException("Missing iat");
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

resolveToken() now requires issuer/audience and enforces presence of iat. Tokens minted by the previous implementation (no issuer/audience/iat) will start failing verification immediately after upgrade, forcing all clients to re-authenticate. If that’s intended, it should be explicitly documented as a breaking change; otherwise consider a compatibility mode/migration window (e.g., optionally accept missing fields for a period).

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +81
# IMPORTANT: Set a strong, random secret in production (e.g. via env var BIGTOP_MANAGER_JWT_SECRET)
secret: ${BIGTOP_MANAGER_JWT_SECRET:}
issuer: bigtop-manager
audience: bigtop-manager
expiration-days: 7
# Dev-only compatibility switch. Keep false in production.
allow-default-secret: false
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

With secret: ${BIGTOP_MANAGER_JWT_SECRET:} and allow-default-secret: false, a default install where the env var isn’t set will allow the app to start but will later fail token generation/verification at runtime (typically as 500s). If the intention is to require an explicit secret everywhere, consider failing fast during startup or providing a clear dev/default profile so contributors don’t hit opaque runtime errors.

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +40
# Generate a random JWT secret for local dev if user didn't provide one.
init_jwt_secret() {
if [ -z "${BIGTOP_MANAGER_JWT_SECRET}" ]; then
# Dev-support default. Override by exporting BIGTOP_MANAGER_JWT_SECRET before running this script.
BIGTOP_MANAGER_JWT_SECRET="r0PGVyvjKOxUBwGt"
export BIGTOP_MANAGER_JWT_SECRET
log "Defaulted BIGTOP_MANAGER_JWT_SECRET for dev-support"
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

init_jwt_secret says it "Generate[s] a random JWT secret", but it actually sets a hard-coded, well-known value. This is misleading and also makes local environments share the same signing key, which weakens token integrity even in dev. Either generate a per-run/per-dev random secret (and optionally persist it) or update the comment/behavior to clearly indicate it’s a fixed dev default.

Suggested change
# Generate a random JWT secret for local dev if user didn't provide one.
init_jwt_secret() {
if [ -z "${BIGTOP_MANAGER_JWT_SECRET}" ]; then
# Dev-support default. Override by exporting BIGTOP_MANAGER_JWT_SECRET before running this script.
BIGTOP_MANAGER_JWT_SECRET="r0PGVyvjKOxUBwGt"
export BIGTOP_MANAGER_JWT_SECRET
log "Defaulted BIGTOP_MANAGER_JWT_SECRET for dev-support"
# Set a fixed default JWT secret for local dev if user didn't provide one.
init_jwt_secret() {
if [ -z "${BIGTOP_MANAGER_JWT_SECRET}" ]; then
# Fixed dev-support default. Override by exporting BIGTOP_MANAGER_JWT_SECRET before running this script.
BIGTOP_MANAGER_JWT_SECRET="r0PGVyvjKOxUBwGt"
export BIGTOP_MANAGER_JWT_SECRET
log "Using fixed default BIGTOP_MANAGER_JWT_SECRET for dev-support"

Copilot uses AI. Check for mistakes.
@lhpqaq lhpqaq merged commit ff82a89 into apache:main Mar 30, 2026
15 checks passed
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.

3 participants