Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanded Parser method argument support #844

Merged
merged 5 commits into from
Sep 30, 2023
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: 1 addition & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ The Apache Software Foundation (https://www.apache.org/).
```

Also, the following classes were copied from the Apache Commons-IO project, with further JJWT-specific modifications:
* io.jsonwebtoken.impl.io.CharSequenceReader
* io.jsonwebtoken.impl.io.FilteredInputStream
* io.jsonwebtoken.impl.io.FilteredOutputStream
* io.jsonwebtoken.impl.io.ClosedInputStream
Expand Down
149 changes: 75 additions & 74 deletions api/src/main/java/io/jsonwebtoken/JwtParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package io.jsonwebtoken;

import io.jsonwebtoken.io.Parser;
import io.jsonwebtoken.security.SecurityException;
import io.jsonwebtoken.security.SignatureException;

Expand All @@ -25,7 +26,7 @@
*
* @since 0.1
*/
public interface JwtParser {
public interface JwtParser extends Parser<Jwt<?, ?>> {

/**
* Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
Expand All @@ -38,15 +39,15 @@ public interface JwtParser {
* @return {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
* otherwise.
*/
boolean isSigned(String compact);
boolean isSigned(CharSequence compact);

/**
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
* returns the resulting JWT, JWS, or JWE instance.
*
* <p>This method returns a JWT, JWS, or JWE based on the parsed string. Because it may be cumbersome to
* determine if it is a JWT, JWS or JWE, or if the payload is a Claims or byte array with {@code instanceof} checks,
* the {@link #parse(String, JwtHandler) parse(String,JwtHandler)} method allows for a type-safe callback approach
* the {@link #parse(CharSequence, JwtHandler) parse(String,JwtHandler)} method allows for a type-safe callback approach
* that may help reduce code or instanceof checks.</p>
*
* @param jwt the compact serialized JWT to parse
Expand All @@ -59,15 +60,15 @@ public interface JwtParser {
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
* before the time this method is invoked.
* @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace.
* @see #parse(String, JwtHandler)
* @see #parseContentJwt(String)
* @see #parseClaimsJwt(String)
* @see #parseContentJws(String)
* @see #parseClaimsJws(String)
* @see #parseContentJwe(String)
* @see #parseClaimsJwe(String)
* @see #parse(CharSequence, JwtHandler)
* @see #parseContentJwt(CharSequence)
* @see #parseClaimsJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parseContentJwe(CharSequence)
* @see #parseClaimsJwe(CharSequence)
*/
Jwt<?, ?> parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException,
Jwt<?, ?> parse(CharSequence jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException,
SecurityException, IllegalArgumentException;

/**
Expand All @@ -93,12 +94,12 @@ public interface JwtParser {
* following convenience methods instead of this one:</p>
*
* <ul>
* <li>{@link #parseContentJwt(String)}</li>
* <li>{@link #parseClaimsJwt(String)}</li>
* <li>{@link #parseContentJws(String)}</li>
* <li>{@link #parseClaimsJws(String)}</li>
* <li>{@link #parseContentJwe(String)}</li>
* <li>{@link #parseClaimsJwe(String)}</li>
* <li>{@link #parseContentJwt(CharSequence)}</li>
* <li>{@link #parseClaimsJwt(CharSequence)}</li>
* <li>{@link #parseContentJws(CharSequence)}</li>
* <li>{@link #parseClaimsJws(CharSequence)}</li>
* <li>{@link #parseContentJwe(CharSequence)}</li>
* <li>{@link #parseClaimsJwe(CharSequence)}</li>
* </ul>
*
* @param jwt the compact serialized JWT to parse
Expand All @@ -114,16 +115,16 @@ public interface JwtParser {
* before the time this method is invoked.
* @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace, or if the
* {@code handler} is {@code null}.
* @see #parseContentJwt(String)
* @see #parseClaimsJwt(String)
* @see #parseContentJws(String)
* @see #parseClaimsJws(String)
* @see #parseContentJwe(String)
* @see #parseClaimsJwe(String)
* @see #parse(String)
* @see #parseContentJwt(CharSequence)
* @see #parseClaimsJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parseContentJwe(CharSequence)
* @see #parseClaimsJwe(CharSequence)
* @see #parse(CharSequence)
* @since 0.2
*/
<T> T parse(String jwt, JwtHandler<T> handler) throws ExpiredJwtException, UnsupportedJwtException,
<T> T parse(CharSequence jwt, JwtHandler<T> handler) throws ExpiredJwtException, UnsupportedJwtException,
MalformedJwtException, SignatureException, SecurityException, IllegalArgumentException;

/**
Expand All @@ -148,14 +149,14 @@ <T> T parse(String jwt, JwtHandler<T> handler) throws ExpiredJwtException, Unsup
* @throws SignatureException if the {@code jwt} string is actually a JWS and signature validation fails
* @throws SecurityException if the {@code jwt} string is actually a JWE and decryption fails
* @throws IllegalArgumentException if the {@code jwt} string is {@code null} or empty or only whitespace
* @see #parseClaimsJwt(String)
* @see #parseContentJws(String)
* @see #parseClaimsJws(String)
* @see #parse(String, JwtHandler)
* @see #parse(String)
* @see #parseClaimsJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parse(CharSequence, JwtHandler)
* @see #parse(CharSequence)
* @since 0.2
*/
Jwt<Header, byte[]> parseContentJwt(String jwt) throws UnsupportedJwtException, MalformedJwtException,
Jwt<Header, byte[]> parseContentJwt(CharSequence jwt) throws UnsupportedJwtException, MalformedJwtException,
SignatureException, SecurityException, IllegalArgumentException;

/**
Expand All @@ -178,14 +179,14 @@ Jwt<Header, byte[]> parseContentJwt(String jwt) throws UnsupportedJwtException,
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
* before the time this method is invoked.
* @throws IllegalArgumentException if the {@code jwt} string is {@code null} or empty or only whitespace
* @see #parseContentJwt(String)
* @see #parseContentJws(String)
* @see #parseClaimsJws(String)
* @see #parse(String, JwtHandler)
* @see #parse(String)
* @see #parseContentJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parse(CharSequence, JwtHandler)
* @see #parse(CharSequence)
* @since 0.2
*/
Jwt<Header, Claims> parseClaimsJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException,
Jwt<Header, Claims> parseClaimsJwt(CharSequence jwt) throws ExpiredJwtException, UnsupportedJwtException,
MalformedJwtException, SignatureException, SecurityException, IllegalArgumentException;

/**
Expand All @@ -207,16 +208,16 @@ Jwt<Header, Claims> parseClaimsJwt(String jwt) throws ExpiredJwtException, Unsup
* @throws SignatureException if the {@code jws} JWS signature validation fails
* @throws SecurityException if the {@code jws} string is actually a JWE and decryption fails
* @throws IllegalArgumentException if the {@code jws} string is {@code null} or empty or only whitespace
* @see #parseContentJwt(String)
* @see #parseContentJwe(String)
* @see #parseClaimsJwt(String)
* @see #parseClaimsJws(String)
* @see #parseClaimsJwe(String)
* @see #parse(String, JwtHandler)
* @see #parse(String)
* @see #parseContentJwt(CharSequence)
* @see #parseContentJwe(CharSequence)
* @see #parseClaimsJwt(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parseClaimsJwe(CharSequence)
* @see #parse(CharSequence, JwtHandler)
* @see #parse(CharSequence)
* @since 0.2
*/
Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, MalformedJwtException, SignatureException,
Jws<byte[]> parseContentJws(CharSequence jws) throws UnsupportedJwtException, MalformedJwtException, SignatureException,
SecurityException, IllegalArgumentException;

/**
Expand All @@ -234,7 +235,7 @@ Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, Malforme
* @param unencodedPayload the JWS's associated required unencoded payload used for signature verification.
* @return the parsed Unencoded Payload.
*/
Jws<byte[]> parseContentJws(String jws, byte[] unencodedPayload);
Jws<byte[]> parseContentJws(CharSequence jws, byte[] unencodedPayload);

/**
* Parses a JWS known to use the
Expand All @@ -251,7 +252,7 @@ Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, Malforme
* @param unencodedPayload the JWS's associated required unencoded payload used for signature verification.
* @return the parsed Unencoded Payload.
*/
Jws<Claims> parseClaimsJws(String jws, byte[] unencodedPayload);
Jws<Claims> parseClaimsJws(CharSequence jws, byte[] unencodedPayload);

/**
* Parses a JWS known to use the
Expand All @@ -274,7 +275,7 @@ Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, Malforme
* @param unencodedPayload the JWS's associated required unencoded payload used for signature verification.
* @return the parsed Unencoded Payload.
*/
Jws<byte[]> parseContentJws(String jws, InputStream unencodedPayload);
Jws<byte[]> parseContentJws(CharSequence jws, InputStream unencodedPayload);

/**
* Parses a JWS known to use the
Expand All @@ -285,7 +286,7 @@ Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, Malforme
* <p><b>NOTE:</b> however, because calling this method indicates a completed
* {@link Claims} instance is desired, the specified {@code unencodedPayload} JSON stream will be fully
* read into a Claims instance. If this will be problematic for your application (perhaps if you expect extremely
* large Claims), it is recommended to use the {@link #parseContentJws(String, InputStream)} method instead.</p>
* large Claims), it is recommended to use the {@link #parseContentJws(CharSequence, InputStream)} method instead.</p>
*
* <p><b>Unencoded Non-Detached Payload</b></p>
* <p>Note that if the JWS contains a valid unencoded Payload string (what RFC 7797 calls an
Expand All @@ -297,7 +298,7 @@ Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, Malforme
* @param unencodedPayload the JWS's associated required unencoded payload used for signature verification.
* @return the parsed Unencoded Payload.
*/
Jws<Claims> parseClaimsJws(String jws, InputStream unencodedPayload);
Jws<Claims> parseClaimsJws(CharSequence jws, InputStream unencodedPayload);

/**
* Parses the specified compact serialized JWS string based on the builder's current configuration state and
Expand All @@ -318,16 +319,16 @@ Jws<byte[]> parseContentJws(String jws) throws UnsupportedJwtException, Malforme
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
* before the time this method is invoked.
* @throws IllegalArgumentException if the {@code claimsJws} string is {@code null} or empty or only whitespace
* @see #parseContentJwt(String)
* @see #parseContentJws(String)
* @see #parseContentJwe(String)
* @see #parseClaimsJwt(String)
* @see #parseClaimsJwe(String)
* @see #parse(String, JwtHandler)
* @see #parse(String)
* @see #parseContentJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseContentJwe(CharSequence)
* @see #parseClaimsJwt(CharSequence)
* @see #parseClaimsJwe(CharSequence)
* @see #parse(CharSequence, JwtHandler)
* @see #parse(CharSequence)
* @since 0.2
*/
Jws<Claims> parseClaimsJws(String jws) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
Jws<Claims> parseClaimsJws(CharSequence jws) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
SignatureException, SecurityException, IllegalArgumentException;

/**
Expand All @@ -348,16 +349,16 @@ Jws<Claims> parseClaimsJws(String jws) throws ExpiredJwtException, UnsupportedJw
* @throws MalformedJwtException if the {@code jwe} string is not a valid JWE
* @throws SecurityException if the {@code jwe} JWE decryption fails
* @throws IllegalArgumentException if the {@code jwe} string is {@code null} or empty or only whitespace
* @see #parseContentJwt(String)
* @see #parseContentJws(String)
* @see #parseClaimsJwt(String)
* @see #parseClaimsJws(String)
* @see #parseClaimsJwe(String)
* @see #parse(String, JwtHandler)
* @see #parse(String)
* @see #parseContentJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseClaimsJwt(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parseClaimsJwe(CharSequence)
* @see #parse(CharSequence, JwtHandler)
* @see #parse(CharSequence)
* @since JJWT_RELEASE_VERSION
*/
Jwe<byte[]> parseContentJwe(String jwe) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
Jwe<byte[]> parseContentJwe(CharSequence jwe) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
SecurityException, IllegalArgumentException;

/**
Expand All @@ -378,15 +379,15 @@ Jwe<byte[]> parseContentJwe(String jwe) throws ExpiredJwtException, UnsupportedJ
* @throws ExpiredJwtException if the specified JWT is a Claims JWE and the Claims has an expiration time
* before the time this method is invoked.
* @throws IllegalArgumentException if the {@code claimsJwe} string is {@code null} or empty or only whitespace
* @see #parseContentJwt(String)
* @see #parseContentJws(String)
* @see #parseContentJwe(String)
* @see #parseClaimsJwt(String)
* @see #parseClaimsJws(String)
* @see #parse(String, JwtHandler)
* @see #parse(String)
* @see #parseContentJwt(CharSequence)
* @see #parseContentJws(CharSequence)
* @see #parseContentJwe(CharSequence)
* @see #parseClaimsJwt(CharSequence)
* @see #parseClaimsJws(CharSequence)
* @see #parse(CharSequence, JwtHandler)
* @see #parse(CharSequence)
* @since JJWT_RELEASE_VERSION
*/
Jwe<Claims> parseClaimsJwe(String jwe) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
Jwe<Claims> parseClaimsJwe(CharSequence jwe) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
SecurityException, IllegalArgumentException;
}
21 changes: 13 additions & 8 deletions api/src/main/java/io/jsonwebtoken/io/AbstractDeserializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;

/**
* Convenient base class to use to implement {@link Deserializer}s, with subclasses only needing to implement
* {@link #doDeserialize(InputStream)}.
* {@link #doDeserialize(Reader)}.
*
* @param <T> the type of object returned after deserialization
* @since JJWT_RELEASE_VERSION
Expand All @@ -48,17 +51,19 @@ protected AbstractDeserializer() {
@Override
public final T deserialize(byte[] bytes) throws DeserializationException {
bytes = bytes == null ? EMPTY_BYTES : bytes; // null safe
return deserialize(new ByteArrayInputStream(bytes));
InputStream in = new ByteArrayInputStream(bytes);
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
return deserialize(reader);
}

/**
* {@inheritDoc}
*/
@Override
public final T deserialize(InputStream in) throws DeserializationException {
Assert.notNull(in, "InputStream argument cannot be null.");
public final T deserialize(Reader reader) throws DeserializationException {
Assert.notNull(reader, "Reader argument cannot be null.");
try {
return doDeserialize(in);
return doDeserialize(reader);
} catch (Throwable t) {
if (t instanceof DeserializationException) {
throw (DeserializationException) t;
Expand All @@ -69,11 +74,11 @@ public final T deserialize(InputStream in) throws DeserializationException {
}

/**
* Reads the specified {@code InputStream} and returns the corresponding Java object.
* Reads the specified character stream and returns the corresponding Java object.
*
* @param in the input stream to read
* @param reader the reader to use to read the character stream
* @return the deserialized Java object
* @throws Exception if there is a problem reading the stream or creating the expected Java object
*/
protected abstract T doDeserialize(InputStream in) throws Exception;
protected abstract T doDeserialize(Reader reader) throws Exception;
}
10 changes: 5 additions & 5 deletions api/src/main/java/io/jsonwebtoken/io/Deserializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package io.jsonwebtoken.io;

import java.io.InputStream;
import java.io.Reader;

/**
* A {@code Deserializer} is able to convert serialized byte streams into Java objects.
Expand All @@ -31,18 +31,18 @@ public interface Deserializer<T> {
* @param bytes the formatted data byte array to convert
* @return the reconstituted Java object
* @throws DeserializationException if there is a problem converting the byte array to an object.
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #deserialize(InputStream)}
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #deserialize(Reader)}
*/
@Deprecated
T deserialize(byte[] bytes) throws DeserializationException;

/**
* Reads the specified {@code InputStream} and returns the corresponding Java object.
* Reads the specified character stream and returns the corresponding Java object.
*
* @param in the input stream to read
* @param reader the reader to use to read the character stream
* @return the deserialized Java object
* @throws DeserializationException if there is a problem reading the stream or creating the expected Java object
* @since JJWT_RELEASE_VERSION
*/
T deserialize(InputStream in) throws DeserializationException;
T deserialize(Reader reader) throws DeserializationException;
}
Loading