From d8d9e3ec7fbea769ce98bfcb7a307938c4a69645 Mon Sep 17 00:00:00 2001 From: Oliver Wolff <23139298+cuioss@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:00:53 +0100 Subject: [PATCH] Updating Documentation --- .../token/ParsedRefreshToken.java | 35 +++++++++++++++---- .../util/NonValidatingJwtTokenParser.java | 13 +++++-- .../token/ParsedRefreshTokenTest.java | 10 ++++-- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/ParsedRefreshToken.java b/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/ParsedRefreshToken.java index e9322b71..6564d51a 100644 --- a/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/ParsedRefreshToken.java +++ b/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/ParsedRefreshToken.java @@ -15,22 +15,34 @@ */ package de.cuioss.portal.authentication.token; +import de.cuioss.tools.logging.CuiLogger; import de.cuioss.tools.string.MoreStrings; import lombok.Getter; import lombok.ToString; +import java.io.Serial; import java.io.Serializable; /** - * Variant of {@link ParsedToken} representing a refresh-token + * Variant of {@link ParsedToken} representing a refresh-token. + *

* Caution: This is only tested for keycloak. * The usage of JWTs for a refresh-token is not from the oauth spec. + *

+ * This class provides a simple wrapper around refresh tokens with basic validation + * and type information. + * It is immutable and thread-safe. * * @author Oliver Wolff */ @ToString public class ParsedRefreshToken implements Serializable { + private static final CuiLogger LOGGER = new CuiLogger(ParsedRefreshToken.class); + + @Serial + private static final long serialVersionUID = 1L; + @Getter private final String tokenString; @@ -39,23 +51,34 @@ private ParsedRefreshToken(String tokenString) { } /** - * @param tokenString to be passed - * @return an {@link ParsedRefreshToken} if given Token can be parsed correctly, - * otherwise {@link ParsedAccessToken#EMPTY_WEB_TOKEN}} + * Creates a new {@link ParsedRefreshToken} from the given token string. + *

+ * Note: This method does not validate the token's signature or format. + * It only wraps the string for type-safety purposes. + * + * @param tokenString The raw refresh token string, may be null or empty + * @return a new {@link ParsedRefreshToken} instance wrapping the given token */ public static ParsedRefreshToken fromTokenString(String tokenString) { + if (MoreStrings.isEmpty(tokenString)) { + LOGGER.debug("Creating empty refresh token"); + } return new ParsedRefreshToken(tokenString); } /** - * Indicates, whether the token is (not) present + * Indicates whether the token is empty (null or blank string). + * + * @return {@code true} if the token is null or empty, {@code false} otherwise */ public boolean isEmpty() { return MoreStrings.isEmpty(tokenString); } /** - * The type o contained token. + * Returns the type of this token. + * + * @return always {@link TokenType#REFRESH_TOKEN} */ public TokenType getType() { return TokenType.REFRESH_TOKEN; diff --git a/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/util/NonValidatingJwtTokenParser.java b/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/util/NonValidatingJwtTokenParser.java index a95c4b3c..4ecc7a4d 100644 --- a/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/util/NonValidatingJwtTokenParser.java +++ b/modules/authentication/portal-authentication-token/src/main/java/de/cuioss/portal/authentication/token/util/NonValidatingJwtTokenParser.java @@ -51,10 +51,17 @@ public class NonValidatingJwtTokenParser { /** * Parses a JWT token without validating its signature and returns a JsonWebToken. + *

+ * Security considerations: + *

* - * @param token the JWT token string to parse + * @param token the JWT token string to parse, must not be null * @return an Optional containing the JsonWebToken if parsing is successful, - * or empty if the token is invalid or cannot be parsed + * or empty if the token is invalid or cannot be parsed */ public Optional unsecured(String token) { if (MoreStrings.isEmpty(token)) { @@ -66,6 +73,7 @@ public Optional unsecured(String token) { LOGGER.warn(LogMessages.TOKEN_SIZE_EXCEEDED.format(MAX_TOKEN_SIZE)); return Optional.empty(); } + var parts = Splitter.on('.').splitToList(token); if (parts.size() != 3) { LOGGER.info(LogMessages.INVALID_TOKEN_FORMAT.format(parts.size())); @@ -77,7 +85,6 @@ public Optional unsecured(String token) { return Optional.of(new NotValidatedJsonWebToken(claims)); } catch (Exception e) { LOGGER.info(e, LogMessages.TOKEN_PARSE_FAILED.format(e.getMessage())); - LOGGER.debug(e, "Detailed parse error"); return Optional.empty(); } } diff --git a/modules/authentication/portal-authentication-token/src/test/java/de/cuioss/portal/authentication/token/ParsedRefreshTokenTest.java b/modules/authentication/portal-authentication-token/src/test/java/de/cuioss/portal/authentication/token/ParsedRefreshTokenTest.java index fefc99f2..55d72c45 100644 --- a/modules/authentication/portal-authentication-token/src/test/java/de/cuioss/portal/authentication/token/ParsedRefreshTokenTest.java +++ b/modules/authentication/portal-authentication-token/src/test/java/de/cuioss/portal/authentication/token/ParsedRefreshTokenTest.java @@ -15,6 +15,7 @@ */ package de.cuioss.portal.authentication.token; +import de.cuioss.test.valueobjects.junit5.contracts.ShouldBeSerializable; import org.junit.jupiter.api.Test; import static de.cuioss.portal.authentication.token.TestTokenProducer.REFRESH_TOKEN; @@ -22,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -class ParsedRefreshTokenTest { +class ParsedRefreshTokenTest implements ShouldBeSerializable { @Test void shouldHandleHappyCase() { @@ -33,6 +34,11 @@ void shouldHandleHappyCase() { assertEquals(initialToken, parsedRefreshToken.getTokenString()); assertFalse(parsedRefreshToken.isEmpty()); - assertEquals(TokenType.REFRESH_TOKEN, parsedRefreshToken.getType() ); + assertEquals(TokenType.REFRESH_TOKEN, parsedRefreshToken.getType()); + } + + @Override + public ParsedRefreshToken getUnderTest() { + return ParsedRefreshToken.fromTokenString(validSignedJWTWithClaims(REFRESH_TOKEN)); } } \ No newline at end of file