If this method is not called, JJWT will use whatever serializer it can find at runtime, checking for the
+ * presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
+ * in the runtime classpath, an exception will be thrown when the {@link #compact()} method is invoked.
+ *
+ * @param serializer the serializer to use when converting Map objects to JSON strings.
+ * @return the builder for method chaining.
+ * @since 0.10.0
+ */
+ JwtBuilder serializeToJsonWith(Serializer> serializer);
+
+ /**
* Actually builds the JWT and serializes it to a compact, URL-safe string according to the
* JWT Compact Serialization
* rules.
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParser.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParser.java (.../JwtParser.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParser.java (.../JwtParser.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,10 +15,13 @@
*/
package io.jsonwebtoken;
-import io.jsonwebtoken.impl.DefaultClock;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Deserializer;
+import io.jsonwebtoken.security.SignatureException;
import java.security.Key;
import java.util.Date;
+import java.util.Map;
/**
* A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
@@ -38,7 +41,12 @@
* @return the parser method for chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireId(String)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ * NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireId(String id);
/**
@@ -50,7 +58,12 @@
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireSubject(String)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireSubject(String subject);
/**
@@ -62,7 +75,12 @@
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireAudience(String)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireAudience(String audience);
/**
@@ -74,7 +92,12 @@
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireIssuer(String)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireIssuer(String issuer);
/**
@@ -86,7 +109,12 @@
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireIssuedAt(Date)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireIssuedAt(Date issuedAt);
/**
@@ -98,7 +126,12 @@
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireExpiration(Date)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireExpiration(Date expiration);
/**
@@ -110,7 +143,12 @@
* @return the parser for method chaining
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#requireNotBefore(Date)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser requireNotBefore(Date notBefore);
/**
@@ -123,17 +161,27 @@
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
+ * @deprecated see {@link JwtParserBuilder#require(String, Object)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser require(String claimName, Object value);
/**
* Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
- * The parser uses a {@link DefaultClock DefaultClock} instance by default.
+ * The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
*
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
* @return the parser for method chaining.
* @since 0.7.0
+ * @deprecated see {@link JwtParserBuilder#setClock(Clock)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser setClock(Clock clock);
/**
@@ -143,8 +191,15 @@
* @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
* @return the parser for method chaining.
* @since 0.7.0
+ * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
+ * any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
+ * @deprecated see {@link JwtParserBuilder#setAllowedClockSkewSeconds(long)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
- JwtParser setAllowedClockSkewSeconds(long seconds);
+ @Deprecated
+ JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
@@ -158,26 +213,59 @@
* @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
* signature.
* @return the parser for method chaining.
+ * @deprecated see {@link JwtParserBuilder#setSigningKey(byte[])}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser setSigningKey(byte[] key);
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
* a JWS (no signature), this key is not used.
- *
+ *
*
Note that this key MUST be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).
- *
+ *
*
This method overwrites any previously set key.
- *
+ *
*
This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #setSigningKey(byte[])}.
*
- * @param base64EncodedKeyBytes the BASE64-encoded algorithm-specific signature verification key to use to validate
- * any discovered JWS digital signature.
+ * Deprecation Notice: Deprecated as of 0.10.0, will be removed in 1.0.0
+ *
+ * This method has been deprecated because the {@code key} argument for this method can be confusing: keys for
+ * cryptographic operations are always binary (byte arrays), and many people were confused as to how bytes were
+ * obtained from the String argument.
+ *
+ * This method always expected a String argument that was effectively the same as the result of the following
+ * (pseudocode):
+ *
+ * {@code String base64EncodedSecretKey = base64Encode(secretKeyBytes);}
+ *
+ * However, a non-trivial number of JJWT users were confused by the method signature and attempted to
+ * use raw password strings as the key argument - for example {@code setSigningKey(myPassword)} - which is
+ * almost always incorrect for cryptographic hashes and can produce erroneous or insecure results.
+ *
+ * See this
+ *
+ * StackOverflow answer explaining why raw (non-base64-encoded) strings are almost always incorrect for
+ * signature operations.
+ *
+ * Finally, please use the {@link #setSigningKey(Key) setSigningKey(Key)} instead, as this method and the
+ * {@code byte[]} variant will be removed before the 1.0.0 release.
+ *
+ * @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signature verification key to use to validate
+ * any discovered JWS digital signature.
* @return the parser for method chaining.
+ * @deprecated see {@link JwtParserBuilder#setSigningKey(String)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ * NOTE: this method will be removed before version 1.0
*/
- JwtParser setSigningKey(String base64EncodedKeyBytes);
+ @Deprecated
+ JwtParser setSigningKey(String base64EncodedSecretKey);
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
@@ -191,7 +279,12 @@
* @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
* signature.
* @return the parser for method chaining.
+ * @deprecated see {@link JwtParserBuilder#setSigningKey(Key)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser setSigningKey(Key key);
/**
@@ -221,7 +314,12 @@
* @param signingKeyResolver the signing key resolver used to retrieve the signing key.
* @return the parser for method chaining.
* @since 0.4
+ * @deprecated see {@link JwtParserBuilder#setSigningKeyResolver(SigningKeyResolver)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
/**
@@ -233,8 +331,8 @@
* the same behavior.
* Default Support
* JJWT's default {@link JwtParser} implementation supports both the
- * {@link io.jsonwebtoken.impl.compression.DeflateCompressionCodec DEFLATE}
- * and {@link io.jsonwebtoken.impl.compression.GzipCompressionCodec GZIP} algorithms by default - you do not need to
+ * {@link CompressionCodecs#DEFLATE DEFLATE}
+ * and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.
* However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement
* your own {@link CompressionCodecResolver} and specify that via this method and also when
@@ -243,10 +341,53 @@
* @param compressionCodecResolver the compression codec resolver used to decompress the JWT body.
* @return the parser for method chaining.
* @since 0.6.0
+ * @deprecated see {@link JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ *
NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
/**
+ * Perform Base64Url decoding with the specified Decoder
+ *
+ *
JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method
+ * to specify a different decoder if you desire.
+ *
+ * @param base64UrlDecoder the decoder to use when Base64Url-decoding
+ * @return the parser for method chaining.
+ * @since 0.10.0
+ * @deprecated see {@link JwtParserBuilder#base64UrlDecodeWith(Decoder)}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ * NOTE: this method will be removed before version 1.0
+ */
+ @Deprecated
+ JwtParser base64UrlDecodeWith(Decoder base64UrlDecoder);
+
+ /**
+ * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is
+ * used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map
+ * objects.
+ *
+ * If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the
+ * presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
+ * in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is
+ * invoked.
+ *
+ * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
+ * @return the parser for method chaining.
+ * @since 0.10.0
+ * @deprecated see {@link JwtParserBuilder#deserializeJsonWith(Deserializer)} )}.
+ * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
+ * immutable JwtParser.
+ * NOTE: this method will be removed before version 1.0
+ */
+ @Deprecated
+ JwtParser deserializeJsonWith(Deserializer> deserializer);
+
+ /**
* Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
* otherwise.
*
@@ -333,7 +474,7 @@
* @since 0.2
*/
T parse(String jwt, JwtHandler handler)
- throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
+ throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
/**
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
@@ -363,7 +504,7 @@
* @since 0.2
*/
Jwt parsePlaintextJwt(String plaintextJwt)
- throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
+ throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
/**
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
@@ -394,7 +535,7 @@
* @since 0.2
*/
Jwt parseClaimsJwt(String claimsJwt)
- throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
+ throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
/**
* Parses the specified compact serialized JWS string based on the builder's current configuration state and
@@ -422,7 +563,7 @@
* @since 0.2
*/
Jws parsePlaintextJws(String plaintextJws)
- throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
+ throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
/**
* Parses the specified compact serialized JWS string based on the builder's current configuration state and
@@ -451,5 +592,5 @@
* @since 0.2
*/
Jws parseClaimsJws(String claimsJws)
- throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
+ throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParserBuilder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParserBuilder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParserBuilder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2019 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken;
+
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Deserializer;
+
+import java.security.Key;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * A builder to construct a {@link JwtParser}. Example usage:
+ * {@code
+ * Jwts.parserBuilder()
+ * .setSigningKey(...)
+ * .requireIssuer("https://issuer.example.com")
+ * .build()
+ * .parse(jwtString)
+ * }
+ * @since 0.11.0
+ */
+public interface JwtParserBuilder {
+
+ /**
+ * Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param id
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireId(String id);
+
+ /**
+ * Ensures that the specified {@code sub} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param subject
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireSubject(String subject);
+
+ /**
+ * Ensures that the specified {@code aud} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param audience
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireAudience(String audience);
+
+ /**
+ * Ensures that the specified {@code iss} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param issuer
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireIssuer(String issuer);
+
+ /**
+ * Ensures that the specified {@code iat} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param issuedAt
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireIssuedAt(Date issuedAt);
+
+ /**
+ * Ensures that the specified {@code exp} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param expiration
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireExpiration(Date expiration);
+
+ /**
+ * Ensures that the specified {@code nbf} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param notBefore
+ * @return the parser builder for method chaining
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder requireNotBefore(Date notBefore);
+
+ /**
+ * Ensures that the specified {@code claimName} exists in the parsed JWT. If missing or if the parsed
+ * value does not equal the specified value, an exception will be thrown indicating that the
+ * JWT is invalid and may not be used.
+ *
+ * @param claimName
+ * @param value
+ * @return the parser builder for method chaining.
+ * @see MissingClaimException
+ * @see IncorrectClaimException
+ */
+ JwtParserBuilder require(String claimName, Object value);
+
+ /**
+ * Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
+ * The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
+ *
+ * @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder setClock(Clock clock);
+
+ /**
+ * Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp}
+ * and {@code nbf} claims.
+ *
+ * @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
+ * @return the parser builder for method chaining.
+ * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
+ * any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
+ */
+ JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
+
+ /**
+ * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
+ * a JWS (no signature), this key is not used.
+ *
+ *
Note that this key MUST be a valid key for the signature algorithm found in the JWT header
+ * (as the {@code alg} header parameter).
+ *
+ *
This method overwrites any previously set key.
+ *
+ * @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
+ * signature.
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder setSigningKey(byte[] key);
+
+ /**
+ * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
+ * a JWS (no signature), this key is not used.
+ *
+ * Note that this key MUST be a valid key for the signature algorithm found in the JWT header
+ * (as the {@code alg} header parameter).
+ *
+ * This method overwrites any previously set key.
+ *
+ * This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
+ * byte array is used to invoke {@link #setSigningKey(byte[])}.
+ *
+ * Deprecation Notice: Deprecated as of 0.10.0, will be removed in 1.0.0
+ *
+ * This method has been deprecated because the {@code key} argument for this method can be confusing: keys for
+ * cryptographic operations are always binary (byte arrays), and many people were confused as to how bytes were
+ * obtained from the String argument.
+ *
+ * This method always expected a String argument that was effectively the same as the result of the following
+ * (pseudocode):
+ *
+ * {@code String base64EncodedSecretKey = base64Encode(secretKeyBytes);}
+ *
+ * However, a non-trivial number of JJWT users were confused by the method signature and attempted to
+ * use raw password strings as the key argument - for example {@code setSigningKey(myPassword)} - which is
+ * almost always incorrect for cryptographic hashes and can produce erroneous or insecure results.
+ *
+ * See this
+ *
+ * StackOverflow answer explaining why raw (non-base64-encoded) strings are almost always incorrect for
+ * signature operations.
+ *
+ * Finally, please use the {@link #setSigningKey(Key) setSigningKey(Key)} instead, as this method and the
+ * {@code byte[]} variant will be removed before the 1.0.0 release.
+ *
+ * @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signature verification key to use to validate
+ * any discovered JWS digital signature.
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder setSigningKey(String base64EncodedSecretKey);
+
+ /**
+ * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
+ * a JWS (no signature), this key is not used.
+ *
+ *
Note that this key MUST be a valid key for the signature algorithm found in the JWT header
+ * (as the {@code alg} header parameter).
+ *
+ *
This method overwrites any previously set key.
+ *
+ * @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
+ * signature.
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder setSigningKey(Key key);
+
+ /**
+ * Sets the {@link SigningKeyResolver} used to acquire the signing key
that should be used to verify
+ * a JWS's signature. If the parsed String is not a JWS (no signature), this resolver is not used.
+ *
+ *
Specifying a {@code SigningKeyResolver} is necessary when the signing key is not already known before parsing
+ * the JWT and the JWT header or payload (plaintext body or Claims) must be inspected first to determine how to
+ * look up the signing key. Once returned by the resolver, the JwtParser will then verify the JWS signature with the
+ * returned key. For example:
+ *
+ *
+ * Jws<Claims> jws = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
+ * @Override
+ * public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
+ * //inspect the header or claims, lookup and return the signing key
+ * return getSigningKey(header, claims); //implement me
+ * }})
+ * .parseClaimsJws(compact);
+ *
+ *
+ *
A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.
+ *
+ *
This method should only be used if a signing key is not provided by the other {@code setSigningKey*} builder
+ * methods.
+ *
+ * @param signingKeyResolver the signing key resolver used to retrieve the signing key.
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
+
+ /**
+ * Sets the {@link CompressionCodecResolver} used to acquire the {@link CompressionCodec} that should be used to
+ * decompress the JWT body. If the parsed JWT is not compressed, this resolver is not used.
+ * NOTE: Compression is not defined by the JWT Specification, and it is not expected that other libraries
+ * (including JJWT versions < 0.6.0) are able to consume a compressed JWT body correctly. This method is only
+ * useful if the compact JWT was compressed with JJWT >= 0.6.0 or another library that you know implements
+ * the same behavior.
+ * Default Support
+ * JJWT's default {@link JwtParser} implementation supports both the
+ * {@link CompressionCodecs#DEFLATE DEFLATE}
+ * and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
+ * specify a {@code CompressionCodecResolver} in these cases.
+ * However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement
+ * your own {@link CompressionCodecResolver} and specify that via this method and also when
+ * {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} JWTs.
+ *
+ * @param compressionCodecResolver the compression codec resolver used to decompress the JWT body.
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
+
+ /**
+ * Perform Base64Url decoding with the specified Decoder
+ *
+ * JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method
+ * to specify a different decoder if you desire.
+ *
+ * @param base64UrlDecoder the decoder to use when Base64Url-decoding
+ * @return the parser builder for method chaining.
+ */
+ JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder);
+
+ /**
+ * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is
+ * used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map
+ * objects.
+ *
+ * If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the
+ * presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
+ * in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is
+ * invoked.
+ *
+ * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
+ * @return the builder for method chaining.
+ */
+ JwtParserBuilder deserializeJsonWith(Deserializer> deserializer);
+
+ /**
+ * Returns an immutable/thread-safe {@link JwtParser} created from the configuration from this JwtParserBuilder.
+ * @return an immutable/thread-safe JwtParser created from the configuration from this JwtParserBuilder.
+ */
+ JwtParser build();
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwts.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwts.java (.../Jwts.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwts.java (.../Jwts.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,11 +15,7 @@
*/
package io.jsonwebtoken;
-import io.jsonwebtoken.impl.DefaultClaims;
-import io.jsonwebtoken.impl.DefaultHeader;
-import io.jsonwebtoken.impl.DefaultJwsHeader;
-import io.jsonwebtoken.impl.DefaultJwtBuilder;
-import io.jsonwebtoken.impl.DefaultJwtParser;
+import io.jsonwebtoken.lang.Classes;
import java.util.Map;
@@ -31,8 +27,11 @@
*/
public final class Jwts {
- private Jwts(){}
+ private static final Class[] MAP_ARG = new Class[]{Map.class};
+ private Jwts() {
+ }
+
/**
* Creates a new {@link Header} instance suitable for plaintext (not digitally signed) JWTs. As this
* is a less common use of JWTs, consider using the {@link #jwsHeader()} factory method instead if you will later
@@ -41,7 +40,7 @@
* @return a new {@link Header} instance suitable for plaintext (not digitally signed) JWTs.
*/
public static Header header() {
- return new DefaultHeader();
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultHeader");
}
/**
@@ -52,7 +51,7 @@
* @return a new {@link Header} instance suitable for plaintext (not digitally signed) JWTs.
*/
public static Header header(Map header) {
- return new DefaultHeader(header);
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultHeader", MAP_ARG, header);
}
/**
@@ -62,7 +61,7 @@
* @see JwtBuilder#setHeader(Header)
*/
public static JwsHeader jwsHeader() {
- return new DefaultJwsHeader();
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwsHeader");
}
/**
@@ -74,7 +73,7 @@
* @see JwtBuilder#setHeader(Header)
*/
public static JwsHeader jwsHeader(Map header) {
- return new DefaultJwsHeader(header);
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwsHeader", MAP_ARG, header);
}
/**
@@ -83,7 +82,7 @@
* @return a new {@link Claims} instance to be used as a JWT body.
*/
public static Claims claims() {
- return new DefaultClaims();
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultClaims");
}
/**
@@ -93,26 +92,52 @@
* @return a new {@link Claims} instance populated with the specified name/value pairs.
*/
public static Claims claims(Map claims) {
- return new DefaultClaims(claims);
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultClaims", MAP_ARG, claims);
}
/**
* Returns a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
*
* @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
+ * @deprecated use {@link Jwts#parserBuilder()} instead. See {@link JwtParserBuilder} for usage details.
+ * Migration to new method structure is minimal, for example:
+ *
Old code:
+ *
{@code
+ * Jwts.parser()
+ * .requireAudience("string")
+ * .parse(jwtString)
+ * }
+ * New code:
+ *
{@code
+ * Jwts.parserBuilder()
+ * .requireAudience("string")
+ * .build()
+ * .parse(jwtString)
+ * }
+ * NOTE: this method will be removed before version 1.0
*/
+ @Deprecated
public static JwtParser parser() {
- return new DefaultJwtParser();
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParser");
}
/**
+ * Returns a new {@link JwtParserBuilder} instance that can be configured to create an immutable/thread-safe {@link JwtParser).
+ *
+ * @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser).
+ */
+ public static JwtParserBuilder parserBuilder() {
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder");
+ }
+
+ /**
* Returns a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.
*
* @return a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.
*/
public static JwtBuilder builder() {
- return new DefaultJwtBuilder();
+ return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder");
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureAlgorithm.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureAlgorithm.java (.../SignatureAlgorithm.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureAlgorithm.java (.../SignatureAlgorithm.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,8 +15,20 @@
*/
package io.jsonwebtoken;
-import io.jsonwebtoken.lang.RuntimeEnvironment;
+import io.jsonwebtoken.security.InvalidKeyException;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SignatureException;
+import io.jsonwebtoken.security.WeakKeyException;
+import javax.crypto.SecretKey;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* Type-safe representation of standard JWT signature algorithm names as defined in the
* JSON Web Algorithms specification.
@@ -25,85 +37,114 @@
*/
public enum SignatureAlgorithm {
- /** JWA name for {@code No digital signature or MAC performed} */
- NONE("none", "No digital signature or MAC performed", "None", null, false),
+ /**
+ * JWA name for {@code No digital signature or MAC performed}
+ */
+ NONE("none", "No digital signature or MAC performed", "None", null, false, 0, 0),
- /** JWA algorithm name for {@code HMAC using SHA-256} */
- HS256("HS256", "HMAC using SHA-256", "HMAC", "HmacSHA256", true),
+ /**
+ * JWA algorithm name for {@code HMAC using SHA-256}
+ */
+ HS256("HS256", "HMAC using SHA-256", "HMAC", "HmacSHA256", true, 256, 256, "1.2.840.113549.2.9"),
- /** JWA algorithm name for {@code HMAC using SHA-384} */
- HS384("HS384", "HMAC using SHA-384", "HMAC", "HmacSHA384", true),
+ /**
+ * JWA algorithm name for {@code HMAC using SHA-384}
+ */
+ HS384("HS384", "HMAC using SHA-384", "HMAC", "HmacSHA384", true, 384, 384, "1.2.840.113549.2.10"),
- /** JWA algorithm name for {@code HMAC using SHA-512} */
- HS512("HS512", "HMAC using SHA-512", "HMAC", "HmacSHA512", true),
+ /**
+ * JWA algorithm name for {@code HMAC using SHA-512}
+ */
+ HS512("HS512", "HMAC using SHA-512", "HMAC", "HmacSHA512", true, 512, 512, "1.2.840.113549.2.11"),
- /** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-256} */
- RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "RSA", "SHA256withRSA", true),
+ /**
+ * JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-256}
+ */
+ RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "RSA", "SHA256withRSA", true, 256, 2048),
- /** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-384} */
- RS384("RS384", "RSASSA-PKCS-v1_5 using SHA-384", "RSA", "SHA384withRSA", true),
+ /**
+ * JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-384}
+ */
+ RS384("RS384", "RSASSA-PKCS-v1_5 using SHA-384", "RSA", "SHA384withRSA", true, 384, 2048),
- /** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-512} */
- RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "RSA", "SHA512withRSA", true),
+ /**
+ * JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-512}
+ */
+ RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "RSA", "SHA512withRSA", true, 512, 2048),
/**
- * JWA algorithm name for {@code ECDSA using P-256 and SHA-256}. This is not a JDK standard algorithm and
- * requires that a JCA provider like BouncyCastle be in the runtime classpath. BouncyCastle will be used
- * automatically if found in the runtime classpath.
+ * JWA algorithm name for {@code ECDSA using P-256 and SHA-256}
*/
- ES256("ES256", "ECDSA using P-256 and SHA-256", "Elliptic Curve", "SHA256withECDSA", false),
+ ES256("ES256", "ECDSA using P-256 and SHA-256", "ECDSA", "SHA256withECDSA", true, 256, 256),
/**
- * JWA algorithm name for {@code ECDSA using P-384 and SHA-384}. This is not a JDK standard algorithm and
- * requires that a JCA provider like BouncyCastle be in the runtime classpath. BouncyCastle will be used
- * automatically if found in the runtime classpath.
+ * JWA algorithm name for {@code ECDSA using P-384 and SHA-384}
*/
- ES384("ES384", "ECDSA using P-384 and SHA-384", "Elliptic Curve", "SHA384withECDSA", false),
+ ES384("ES384", "ECDSA using P-384 and SHA-384", "ECDSA", "SHA384withECDSA", true, 384, 384),
/**
- * JWA algorithm name for {@code ECDSA using P-512 and SHA-512}. This is not a JDK standard algorithm and
- * requires that a JCA provider like BouncyCastle be in the runtime classpath. BouncyCastle will be used
- * automatically if found in the runtime classpath.
+ * JWA algorithm name for {@code ECDSA using P-521 and SHA-512}
*/
- ES512("ES512", "ECDSA using P-512 and SHA-512", "Elliptic Curve", "SHA512withECDSA", false),
+ ES512("ES512", "ECDSA using P-521 and SHA-512", "ECDSA", "SHA512withECDSA", true, 512, 521),
/**
- * JWA algorithm name for {@code RSASSA-PSS using SHA-256 and MGF1 with SHA-256}. This is not a JDK standard
- * algorithm and requires that a JCA provider like BouncyCastle be in the runtime classpath. BouncyCastle
- * will be used automatically if found in the runtime classpath.
+ * JWA algorithm name for {@code RSASSA-PSS using SHA-256 and MGF1 with SHA-256}. This algorithm requires
+ * Java 11 or later or a JCA provider like BouncyCastle to be in the runtime classpath. If on Java 10 or
+ * earlier, BouncyCastle will be used automatically if found in the runtime classpath.
*/
- PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "RSA", "SHA256withRSAandMGF1", false),
+ PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "RSA", "RSASSA-PSS", false, 256, 2048),
/**
- * JWA algorithm name for {@code RSASSA-PSS using SHA-384 and MGF1 with SHA-384}. This is not a JDK standard
- * algorithm and requires that a JCA provider like BouncyCastle be in the runtime classpath. BouncyCastle
- * will be used automatically if found in the runtime classpath.
+ * JWA algorithm name for {@code RSASSA-PSS using SHA-384 and MGF1 with SHA-384}. This algorithm requires
+ * Java 11 or later or a JCA provider like BouncyCastle to be in the runtime classpath. If on Java 10 or
+ * earlier, BouncyCastle will be used automatically if found in the runtime classpath.
*/
- PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "RSA", "SHA384withRSAandMGF1", false),
+ PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "RSA", "RSASSA-PSS", false, 384, 2048),
/**
- * JWA algorithm name for {@code RSASSA-PSS using SHA-512 and MGF1 with SHA-512}. This is not a JDK standard
- * algorithm and requires that a JCA provider like BouncyCastle be in the classpath. BouncyCastle will be used
- * automatically if found in the runtime classpath.
+ * JWA algorithm name for {@code RSASSA-PSS using SHA-512 and MGF1 with SHA-512}. This algorithm requires
+ * Java 11 or later or a JCA provider like BouncyCastle to be in the runtime classpath. If on Java 10 or
+ * earlier, BouncyCastle will be used automatically if found in the runtime classpath.
*/
- PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "RSA", "SHA512withRSAandMGF1", false);
+ PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "RSA", "RSASSA-PSS", false, 512, 2048);
- static {
- RuntimeEnvironment.enableBouncyCastleIfPossible();
- }
+ //purposefully ordered higher to lower:
+ private static final List PREFERRED_HMAC_ALGS = Collections.unmodifiableList(Arrays.asList(
+ SignatureAlgorithm.HS512, SignatureAlgorithm.HS384, SignatureAlgorithm.HS256));
+ //purposefully ordered higher to lower:
+ private static final List PREFERRED_EC_ALGS = Collections.unmodifiableList(Arrays.asList(
+ SignatureAlgorithm.ES512, SignatureAlgorithm.ES384, SignatureAlgorithm.ES256));
- private final String value;
- private final String description;
- private final String familyName;
- private final String jcaName;
+ private final String value;
+ private final String description;
+ private final String familyName;
+ private final String jcaName;
private final boolean jdkStandard;
+ private final int digestLength;
+ private final int minKeyLength;
+ /**
+ * Algorithm name as given by {@link Key#getAlgorithm()} if the key was loaded from a pkcs12 Keystore.
+ *
+ * @deprecated This is just a workaround for https://bugs.openjdk.java.net/browse/JDK-8243551
+ */
+ @Deprecated
+ private final String pkcs12Name;
- SignatureAlgorithm(String value, String description, String familyName, String jcaName, boolean jdkStandard) {
+ SignatureAlgorithm(String value, String description, String familyName, String jcaName, boolean jdkStandard,
+ int digestLength, int minKeyLength) {
+ this(value, description,familyName, jcaName, jdkStandard, digestLength, minKeyLength, jcaName);
+ }
+
+ SignatureAlgorithm(String value, String description, String familyName, String jcaName, boolean jdkStandard,
+ int digestLength, int minKeyLength, String pkcs12Name) {
this.value = value;
this.description = description;
this.familyName = familyName;
this.jcaName = jcaName;
this.jdkStandard = jdkStandard;
+ this.digestLength = digestLength;
+ this.minKeyLength = minKeyLength;
+ this.pkcs12Name = pkcs12Name;
}
/**
@@ -130,67 +171,66 @@
* following table:
*
*
- * Crypto Family
- *
- *
- * SignatureAlgorithm
- * Family Name
- *
- *
- *
- *
- * HS256
- * HMAC
- *
- *
- * HS384
- * HMAC
- *
- *
- * HS512
- * HMAC
- *
- *
- * RS256
- * RSA
- *
- *
- * RS384
- * RSA
- *
- *
- * RS512
- * RSA
- *
- *
- * PS256
- * RSA
- *
- *
- * PS384
- * RSA
- *
- *
- * PS512
- * RSA
- *
- *
- * ES256
- * Elliptic Curve
- *
- *
- * ES384
- * Elliptic Curve
- *
- *
- * ES512
- * Elliptic Curve
- *
- *
+ * Crypto Family
+ *
+ *
+ * SignatureAlgorithm
+ * Family Name
+ *
+ *
+ *
+ *
+ * HS256
+ * HMAC
+ *
+ *
+ * HS384
+ * HMAC
+ *
+ *
+ * HS512
+ * HMAC
+ *
+ *
+ * RS256
+ * RSA
+ *
+ *
+ * RS384
+ * RSA
+ *
+ *
+ * RS512
+ * RSA
+ *
+ *
+ * PS256
+ * RSA
+ *
+ *
+ * PS384
+ * RSA
+ *
+ *
+ * PS512
+ * RSA
+ *
+ *
+ * ES256
+ * ECDSA
+ *
+ *
+ * ES384
+ * ECDSA
+ *
+ *
+ * ES512
+ * ECDSA
+ *
+ *
*
*
* @return Returns the cryptographic family name of the signature algorithm.
- *
* @since 0.5
*/
public String getFamilyName() {
@@ -225,7 +265,7 @@
* @return {@code true} if the enum instance represents an HMAC signature algorithm, {@code false} otherwise.
*/
public boolean isHmac() {
- return name().startsWith("HS");
+ return familyName.equals("HMAC");
}
/**
@@ -236,21 +276,364 @@
* {@code false} otherwise.
*/
public boolean isRsa() {
- return getDescription().startsWith("RSASSA");
+ return familyName.equals("RSA");
}
/**
- * Returns {@code true} if the enum instance represents an Elliptic Curve signature algorithm, {@code false}
+ * Returns {@code true} if the enum instance represents an Elliptic Curve ECDSA signature algorithm, {@code false}
* otherwise.
*
- * @return {@code true} if the enum instance represents an Elliptic Curve signature algorithm, {@code false}
+ * @return {@code true} if the enum instance represents an Elliptic Curve ECDSA signature algorithm, {@code false}
* otherwise.
*/
public boolean isEllipticCurve() {
- return name().startsWith("ES");
+ return familyName.equals("ECDSA");
}
/**
+ * Returns the minimum key length in bits (not bytes) that may be used with this algorithm according to the
+ * JWT JWA Specification (RFC 7518) .
+ *
+ * @return the minimum key length in bits (not bytes) that may be used with this algorithm according to the
+ * JWT JWA Specification (RFC 7518) .
+ * @since 0.10.0
+ */
+ public int getMinKeyLength() {
+ return this.minKeyLength;
+ }
+
+ /**
+ * Returns quietly if the specified key is allowed to create signatures using this algorithm
+ * according to the JWT JWA Specification (RFC 7518) or throws an
+ * {@link InvalidKeyException} if the key is not allowed or not secure enough for this algorithm.
+ *
+ * @param key the key to check for validity.
+ * @throws InvalidKeyException if the key is not allowed or not secure enough for this algorithm.
+ * @since 0.10.0
+ */
+ public void assertValidSigningKey(Key key) throws InvalidKeyException {
+ assertValid(key, true);
+ }
+
+ /**
+ * Returns quietly if the specified key is allowed to verify signatures using this algorithm
+ * according to the JWT JWA Specification (RFC 7518) or throws an
+ * {@link InvalidKeyException} if the key is not allowed or not secure enough for this algorithm.
+ *
+ * @param key the key to check for validity.
+ * @throws InvalidKeyException if the key is not allowed or not secure enough for this algorithm.
+ * @since 0.10.0
+ */
+ public void assertValidVerificationKey(Key key) throws InvalidKeyException {
+ assertValid(key, false);
+ }
+
+ /**
+ * @since 0.10.0 to support assertValid(Key, boolean)
+ */
+ private static String keyType(boolean signing) {
+ return signing ? "signing" : "verification";
+ }
+
+ /**
+ * @since 0.10.0
+ */
+ private void assertValid(Key key, boolean signing) throws InvalidKeyException {
+
+ if (this == NONE) {
+
+ String msg = "The 'NONE' signature algorithm does not support cryptographic keys.";
+ throw new InvalidKeyException(msg);
+
+ } else if (isHmac()) {
+
+ if (!(key instanceof SecretKey)) {
+ String msg = this.familyName + " " + keyType(signing) + " keys must be SecretKey instances.";
+ throw new InvalidKeyException(msg);
+ }
+ SecretKey secretKey = (SecretKey) key;
+
+ byte[] encoded = secretKey.getEncoded();
+ if (encoded == null) {
+ throw new InvalidKeyException("The " + keyType(signing) + " key's encoded bytes cannot be null.");
+ }
+
+ String alg = secretKey.getAlgorithm();
+ if (alg == null) {
+ throw new InvalidKeyException("The " + keyType(signing) + " key's algorithm cannot be null.");
+ }
+
+ // These next checks use equalsIgnoreCase per https://github.com/jwtk/jjwt/issues/381#issuecomment-412912272
+ if (!HS256.jcaName.equalsIgnoreCase(alg) &&
+ !HS384.jcaName.equalsIgnoreCase(alg) &&
+ !HS512.jcaName.equalsIgnoreCase(alg) &&
+ !HS256.pkcs12Name.equals(alg) &&
+ !HS384.pkcs12Name.equals(alg) &&
+ !HS512.pkcs12Name.equals(alg)) {
+ throw new InvalidKeyException("The " + keyType(signing) + " key's algorithm '" + alg +
+ "' does not equal a valid HmacSHA* algorithm name and cannot be used with " + name() + ".");
+ }
+
+ int size = encoded.length * 8; //size in bits
+ if (size < this.minKeyLength) {
+ String msg = "The " + keyType(signing) + " key's size is " + size + " bits which " +
+ "is not secure enough for the " + name() + " algorithm. The JWT " +
+ "JWA Specification (RFC 7518, Section 3.2) states that keys used with " + name() + " MUST have a " +
+ "size >= " + minKeyLength + " bits (the key size must be greater than or equal to the hash " +
+ "output size). Consider using the " + Keys.class.getName() + " class's " +
+ "'secretKeyFor(SignatureAlgorithm." + name() + ")' method to create a key guaranteed to be " +
+ "secure enough for " + name() + ". See " +
+ "https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
+ throw new WeakKeyException(msg);
+ }
+
+ } else { //EC or RSA
+
+ if (signing) {
+ if (!(key instanceof PrivateKey)) {
+ String msg = familyName + " signing keys must be PrivateKey instances.";
+ throw new InvalidKeyException(msg);
+ }
+ }
+
+ if (isEllipticCurve()) {
+
+ if (!(key instanceof ECKey)) {
+ String msg = familyName + " " + keyType(signing) + " keys must be ECKey instances.";
+ throw new InvalidKeyException(msg);
+ }
+
+ ECKey ecKey = (ECKey) key;
+ int size = ecKey.getParams().getOrder().bitLength();
+ if (size < this.minKeyLength) {
+ String msg = "The " + keyType(signing) + " key's size (ECParameterSpec order) is " + size +
+ " bits which is not secure enough for the " + name() + " algorithm. The JWT " +
+ "JWA Specification (RFC 7518, Section 3.4) states that keys used with " +
+ name() + " MUST have a size >= " + this.minKeyLength +
+ " bits. Consider using the " + Keys.class.getName() + " class's " +
+ "'keyPairFor(SignatureAlgorithm." + name() + ")' method to create a key pair guaranteed " +
+ "to be secure enough for " + name() + ". See " +
+ "https://tools.ietf.org/html/rfc7518#section-3.4 for more information.";
+ throw new WeakKeyException(msg);
+ }
+
+ } else { //RSA
+
+ if (!(key instanceof RSAKey)) {
+ String msg = familyName + " " + keyType(signing) + " keys must be RSAKey instances.";
+ throw new InvalidKeyException(msg);
+ }
+
+ RSAKey rsaKey = (RSAKey) key;
+ int size = rsaKey.getModulus().bitLength();
+ if (size < this.minKeyLength) {
+
+ String section = name().startsWith("P") ? "3.5" : "3.3";
+
+ String msg = "The " + keyType(signing) + " key's size is " + size + " bits which is not secure " +
+ "enough for the " + name() + " algorithm. The JWT JWA Specification (RFC 7518, Section " +
+ section + ") states that keys used with " + name() + " MUST have a size >= " +
+ this.minKeyLength + " bits. Consider using the " + Keys.class.getName() + " class's " +
+ "'keyPairFor(SignatureAlgorithm." + name() + ")' method to create a key pair guaranteed " +
+ "to be secure enough for " + name() + ". See " +
+ "https://tools.ietf.org/html/rfc7518#section-" + section + " for more information.";
+ throw new WeakKeyException(msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the recommended signature algorithm to be used with the specified key according to the following
+ * heuristics:
+ *
+ *
+ * Key Signature Algorithm
+ *
+ *
+ * If the Key is a:
+ * And:
+ * With a key size of:
+ * The returned SignatureAlgorithm will be:
+ *
+ *
+ *
+ *
+ * {@link SecretKey}
+ * {@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA256")
1
+ * 256 <= size <= 383 2
+ * {@link SignatureAlgorithm#HS256 HS256}
+ *
+ *
+ * {@link SecretKey}
+ * {@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA384")
1
+ * 384 <= size <= 511
+ * {@link SignatureAlgorithm#HS384 HS384}
+ *
+ *
+ * {@link SecretKey}
+ * {@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA512")
1
+ * 512 <= size
+ * {@link SignatureAlgorithm#HS512 HS512}
+ *
+ *
+ * {@link ECKey}
+ * instanceof {@link PrivateKey}
+ * 256 <= size <= 383 3
+ * {@link SignatureAlgorithm#ES256 ES256}
+ *
+ *
+ * {@link ECKey}
+ * instanceof {@link PrivateKey}
+ * 384 <= size <= 511
+ * {@link SignatureAlgorithm#ES384 ES384}
+ *
+ *
+ * {@link ECKey}
+ * instanceof {@link PrivateKey}
+ * 4096 <= size
+ * {@link SignatureAlgorithm#ES512 ES512}
+ *
+ *
+ * {@link RSAKey}
+ * instanceof {@link PrivateKey}
+ * 2048 <= size <= 3071 4,5
+ * {@link SignatureAlgorithm#RS256 RS256}
+ *
+ *
+ * {@link RSAKey}
+ * instanceof {@link PrivateKey}
+ * 3072 <= size <= 4095 5
+ * {@link SignatureAlgorithm#RS384 RS384}
+ *
+ *
+ * {@link RSAKey}
+ * instanceof {@link PrivateKey}
+ * 4096 <= size 5
+ * {@link SignatureAlgorithm#RS512 RS512}
+ *
+ *
+ *
+ * Notes:
+ *
+ * {@code SecretKey} instances must have an {@link Key#getAlgorithm() algorithm} name equal
+ * to {@code HmacSHA256}, {@code HmacSHA384} or {@code HmacSHA512}. If not, the key bytes might not be
+ * suitable for HMAC signatures will be rejected with a {@link InvalidKeyException}.
+ * The JWT JWA Specification (RFC 7518,
+ * Section 3.2) mandates that HMAC-SHA-* signing keys MUST be 256 bits or greater.
+ * {@code SecretKey}s with key lengths less than 256 bits will be rejected with an
+ * {@link WeakKeyException}.
+ * The JWT JWA Specification (RFC 7518,
+ * Section 3.4) mandates that ECDSA signing key lengths MUST be 256 bits or greater.
+ * {@code ECKey}s with key lengths less than 256 bits will be rejected with a
+ * {@link WeakKeyException}.
+ * The JWT JWA Specification (RFC 7518,
+ * Section 3.3) mandates that RSA signing key lengths MUST be 2048 bits or greater.
+ * {@code RSAKey}s with key lengths less than 2048 bits will be rejected with a
+ * {@link WeakKeyException}.
+ * Technically any RSA key of length >= 2048 bits may be used with the {@link #RS256}, {@link #RS384}, and
+ * {@link #RS512} algorithms, so we assume an RSA signature algorithm based on the key length to
+ * parallel similar decisions in the JWT specification for HMAC and ECDSA signature algorithms.
+ * This is not required - just a convenience.
+ *
+ * This implementation does not return the {@link #PS256}, {@link #PS256}, {@link #PS256} RSA variant for any
+ * specified {@link RSAKey} because:
+ *
+ * The JWT JWA Specification (RFC 7518,
+ * Section 3.1) indicates that {@link #RS256}, {@link #RS384}, and {@link #RS512} are
+ * recommended algorithms while the {@code PS}* variants are simply marked as optional.
+ * The {@link #RS256}, {@link #RS384}, and {@link #RS512} algorithms are available in the JDK by default
+ * while the {@code PS}* variants require an additional JCA Provider (like BouncyCastle).
+ *
+ *
+ *
+ * Finally, this method will throw an {@link InvalidKeyException} for any key that does not match the
+ * heuristics and requirements documented above, since that inevitably means the Key is either insufficient or
+ * explicitly disallowed by the JWT specification.
+ *
+ * @param key the key to inspect
+ * @return the recommended signature algorithm to be used with the specified key
+ * @throws InvalidKeyException for any key that does not match the heuristics and requirements documented above,
+ * since that inevitably means the Key is either insufficient or explicitly disallowed by the JWT specification.
+ * @since 0.10.0
+ */
+ public static SignatureAlgorithm forSigningKey(Key key) throws InvalidKeyException {
+
+ if (key == null) {
+ throw new InvalidKeyException("Key argument cannot be null.");
+ }
+
+ if (!(key instanceof SecretKey ||
+ (key instanceof PrivateKey && (key instanceof ECKey || key instanceof RSAKey)))) {
+ String msg = "JWT standard signing algorithms require either 1) a SecretKey for HMAC-SHA algorithms or " +
+ "2) a private RSAKey for RSA algorithms or 3) a private ECKey for Elliptic Curve algorithms. " +
+ "The specified key is of type " + key.getClass().getName();
+ throw new InvalidKeyException(msg);
+ }
+
+ if (key instanceof SecretKey) {
+
+ SecretKey secretKey = (SecretKey)key;
+ int bitLength = io.jsonwebtoken.lang.Arrays.length(secretKey.getEncoded()) * Byte.SIZE;
+
+ for(SignatureAlgorithm alg : PREFERRED_HMAC_ALGS) {
+ // ensure compatibility check is based on key length. See https://github.com/jwtk/jjwt/issues/381
+ if (bitLength >= alg.minKeyLength) {
+ return alg;
+ }
+ }
+
+ String msg = "The specified SecretKey is not strong enough to be used with JWT HMAC signature " +
+ "algorithms. The JWT specification requires HMAC keys to be >= 256 bits long. The specified " +
+ "key is " + bitLength + " bits. See https://tools.ietf.org/html/rfc7518#section-3.2 for more " +
+ "information.";
+ throw new WeakKeyException(msg);
+ }
+
+ if (key instanceof RSAKey) {
+
+ RSAKey rsaKey = (RSAKey) key;
+ int bitLength = rsaKey.getModulus().bitLength();
+
+ if (bitLength >= 4096) {
+ RS512.assertValidSigningKey(key);
+ return RS512;
+ } else if (bitLength >= 3072) {
+ RS384.assertValidSigningKey(key);
+ return RS384;
+ } else if (bitLength >= RS256.minKeyLength) {
+ RS256.assertValidSigningKey(key);
+ return RS256;
+ }
+
+ String msg = "The specified RSA signing key is not strong enough to be used with JWT RSA signature " +
+ "algorithms. The JWT specification requires RSA keys to be >= 2048 bits long. The specified RSA " +
+ "key is " + bitLength + " bits. See https://tools.ietf.org/html/rfc7518#section-3.3 for more " +
+ "information.";
+ throw new WeakKeyException(msg);
+ }
+
+ // if we've made it this far in the method, the key is an ECKey due to the instanceof assertions at the
+ // top of the method
+
+ ECKey ecKey = (ECKey) key;
+ int bitLength = ecKey.getParams().getOrder().bitLength();
+
+ for (SignatureAlgorithm alg : PREFERRED_EC_ALGS) {
+ if (bitLength >= alg.minKeyLength) {
+ alg.assertValidSigningKey(key);
+ return alg;
+ }
+ }
+
+ String msg = "The specified Elliptic Curve signing key is not strong enough to be used with JWT ECDSA " +
+ "signature algorithms. The JWT specification requires ECDSA keys to be >= 256 bits long. " +
+ "The specified ECDSA key is " + bitLength + " bits. See " +
+ "https://tools.ietf.org/html/rfc7518#section-3.4 for more information.";
+ throw new WeakKeyException(msg);
+ }
+
+ /**
* Looks up and returns the corresponding {@code SignatureAlgorithm} enum instance based on a
* case-insensitive name comparison.
*
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureException.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureException.java (.../SignatureException.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureException.java (.../SignatureException.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,12 +15,16 @@
*/
package io.jsonwebtoken;
+import io.jsonwebtoken.security.SecurityException;
+
/**
* Exception indicating that either calculating a signature or verifying an existing signature of a JWT failed.
*
* @since 0.1
+ * @deprecated in favor of {@link io.jsonwebtoken.security.SecurityException}; this class will be removed before 1.0
*/
-public class SignatureException extends JwtException {
+@Deprecated
+public class SignatureException extends SecurityException {
public SignatureException(String message) {
super(message);
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AbstractTextCodec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AbstractTextCodec.java (.../AbstractTextCodec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AbstractTextCodec.java (.../AbstractTextCodec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,13 +15,19 @@
*/
package io.jsonwebtoken.impl;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Encoder;
import io.jsonwebtoken.lang.Assert;
import java.nio.charset.Charset;
+/**
+ * @deprecated since 0.10.0 - will be removed before 1.0.0. Use {@link Encoder} orr {@link Decoder} instead.
+ */
+@Deprecated
public abstract class AbstractTextCodec implements TextCodec {
- protected static final Charset UTF8 = Charset.forName("UTF-8");
+ protected static final Charset UTF8 = Charset.forName("UTF-8");
protected static final Charset US_ASCII = Charset.forName("US-ASCII");
@Override
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AndroidBase64Codec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AndroidBase64Codec.java (.../AndroidBase64Codec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AndroidBase64Codec.java (.../AndroidBase64Codec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,16 +15,23 @@
*/
package io.jsonwebtoken.impl;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.Encoders;
+
+/**
+ * @deprecated since 0.10.0 - will be removed before 1.0.0. Use {@code io.jsonwebtoken.io.Encoders#BASE64}
+ * or {@code io.jsonwebtoken.io.Decoders#BASE64} instead.
+ */
+@Deprecated
public class AndroidBase64Codec extends AbstractTextCodec {
@Override
public String encode(byte[] data) {
- int flags = android.util.Base64.NO_PADDING | android.util.Base64.NO_WRAP;
- return android.util.Base64.encodeToString(data, flags);
+ return Encoders.BASE64.encode(data);
}
@Override
public byte[] decode(String encoded) {
- return android.util.Base64.decode(encoded, android.util.Base64.DEFAULT);
+ return Decoders.BASE64.decode(encoded);
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64Codec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64Codec.java (.../Base64Codec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64Codec.java (.../Base64Codec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,14 +15,22 @@
*/
package io.jsonwebtoken.impl;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.Encoders;
+
+/**
+ * @deprecated since 0.10.0 - will be removed before 1.0.0. Use {@code io.jsonwebtoken.io.Encoders#BASE64}
+ * or {@code io.jsonwebtoken.io.Decoders#BASE64}
+ */
+@Deprecated
public class Base64Codec extends AbstractTextCodec {
public String encode(byte[] data) {
- return javax.xml.bind.DatatypeConverter.printBase64Binary(data);
+ return Encoders.BASE64.encode(data);
}
@Override
public byte[] decode(String encoded) {
- return javax.xml.bind.DatatypeConverter.parseBase64Binary(encoded);
+ return Decoders.BASE64.decode(encoded);
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64UrlCodec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64UrlCodec.java (.../Base64UrlCodec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64UrlCodec.java (.../Base64UrlCodec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,90 +15,23 @@
*/
package io.jsonwebtoken.impl;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.Encoders;
+
+/**
+ * @deprecated since 0.10.0 - will be removed before 1.0.0. Use {@link Encoders#BASE64URL Encoder.BASE64URL}
+ * or {@link Decoders#BASE64URL Decoder.BASE64URL} instead.
+ */
+@Deprecated
public class Base64UrlCodec extends AbstractTextCodec {
@Override
public String encode(byte[] data) {
- String base64Text = TextCodec.BASE64.encode(data);
- byte[] bytes = base64Text.getBytes(US_ASCII);
-
- //base64url encoding doesn't use padding chars:
- bytes = removePadding(bytes);
-
- //replace URL-unfriendly Base64 chars to url-friendly ones:
- for (int i = 0; i < bytes.length; i++) {
- if (bytes[i] == '+') {
- bytes[i] = '-';
- } else if (bytes[i] == '/') {
- bytes[i] = '_';
- }
- }
-
- return new String(bytes, US_ASCII);
+ return Encoders.BASE64URL.encode(data);
}
- protected byte[] removePadding(byte[] bytes) {
-
- byte[] result = bytes;
-
- int paddingCount = 0;
- for (int i = bytes.length - 1; i > 0; i--) {
- if (bytes[i] == '=') {
- paddingCount++;
- } else {
- break;
- }
- }
- if (paddingCount > 0) {
- result = new byte[bytes.length - paddingCount];
- System.arraycopy(bytes, 0, result, 0, bytes.length - paddingCount);
- }
-
- return result;
- }
-
@Override
public byte[] decode(String encoded) {
- char[] chars = encoded.toCharArray(); //always ASCII - one char == 1 byte
-
- //Base64 requires padding to be in place before decoding, so add it if necessary:
- chars = ensurePadding(chars);
-
- //Replace url-friendly chars back to normal Base64 chars:
- for (int i = 0; i < chars.length; i++) {
- if (chars[i] == '-') {
- chars[i] = '+';
- } else if (chars[i] == '_') {
- chars[i] = '/';
- }
- }
-
- String base64Text = new String(chars);
-
- return TextCodec.BASE64.decode(base64Text);
+ return Decoders.BASE64URL.decode(encoded);
}
-
- protected char[] ensurePadding(char[] chars) {
-
- char[] result = chars; //assume argument in case no padding is necessary
-
- int paddingCount = 0;
-
- //fix for https://github.com/jwtk/jjwt/issues/31
- int remainder = chars.length % 4;
- if (remainder == 2 || remainder == 3) {
- paddingCount = 4 - remainder;
- }
-
- if (paddingCount > 0) {
- result = new char[chars.length + paddingCount];
- System.arraycopy(chars, 0, result, 0, chars.length);
- for (int i = 0; i < paddingCount; i++) {
- result[chars.length + i] = '=';
- }
- }
-
- return result;
- }
-
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClaims.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClaims.java (.../DefaultClaims.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClaims.java (.../DefaultClaims.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -17,17 +17,24 @@
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.RequiredTypeException;
-
import java.util.Date;
import java.util.Map;
public class DefaultClaims extends JwtMap implements Claims {
+ private static final String CONVERSION_ERROR_MSG = "Cannot convert existing claim value of type '%s' to desired type " +
+ "'%s'. JJWT only converts simple String, Date, Long, Integer, Short and Byte types automatically. " +
+ "Anything more complex is expected to be already converted to your desired type by the JSON Deserializer " +
+ "implementation. You may specify a custom Deserializer for a JwtParser with the desired conversion " +
+ "configuration via the JwtParserBuilder.deserializeJsonWith() method. " +
+ "See https://github.com/jwtk/jjwt#custom-json-processor for more information. If using Jackson, you can " +
+ "specify custom claim POJO types as described in https://github.com/jwtk/jjwt#json-jackson-custom-types";
+
public DefaultClaims() {
super();
}
- public DefaultClaims(Map map) {
+ public DefaultClaims(Map map) {
super(map);
}
@@ -71,7 +78,7 @@
@Override
public Claims setExpiration(Date exp) {
- setDate(Claims.EXPIRATION, exp);
+ setDateAsSeconds(Claims.EXPIRATION, exp);
return this;
}
@@ -82,7 +89,7 @@
@Override
public Claims setNotBefore(Date nbf) {
- setDate(Claims.NOT_BEFORE, nbf);
+ setDateAsSeconds(Claims.NOT_BEFORE, nbf);
return this;
}
@@ -93,7 +100,7 @@
@Override
public Claims setIssuedAt(Date iat) {
- setDate(Claims.ISSUED_AT, iat);
+ setDateAsSeconds(Claims.ISSUED_AT, iat);
return this;
}
@@ -108,25 +115,44 @@
return this;
}
+ /**
+ * @since 0.10.0
+ */
+ private static boolean isSpecDate(String claimName) {
+ return Claims.EXPIRATION.equals(claimName) ||
+ Claims.ISSUED_AT.equals(claimName) ||
+ Claims.NOT_BEFORE.equals(claimName);
+ }
+
@Override
+ public Object put(String s, Object o) {
+ if (o instanceof Date && isSpecDate(s)) { //since 0.10.0
+ Date date = (Date)o;
+ return setDateAsSeconds(s, date);
+ }
+ return super.put(s, o);
+ }
+
+ @Override
public T get(String claimName, Class requiredType) {
+
Object value = get(claimName);
- if (value == null) { return null; }
+ if (value == null) {
+ return null;
+ }
- if (Claims.EXPIRATION.equals(claimName) ||
- Claims.ISSUED_AT.equals(claimName) ||
- Claims.NOT_BEFORE.equals(claimName)
- ) {
- value = getDate(claimName);
+ if (Date.class.equals(requiredType)) {
+ if (isSpecDate(claimName)) {
+ value = toSpecDate(value, claimName);
+ } else {
+ value = toDate(value, claimName);
+ }
}
return castClaimValue(value, requiredType);
}
private T castClaimValue(Object value, Class requiredType) {
- if (requiredType == Date.class && value instanceof Long) {
- value = new Date((Long)value);
- }
if (value instanceof Integer) {
int intValue = (Integer) value;
@@ -140,7 +166,7 @@
}
if (!requiredType.isInstance(value)) {
- throw new RequiredTypeException("Expected value to be of type: " + requiredType + ", but was " + value.getClass());
+ throw new RequiredTypeException(String.format(CONVERSION_ERROR_MSG, value.getClass(), requiredType));
}
return requiredType.cast(value);
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClock.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClock.java (.../DefaultClock.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClock.java (.../DefaultClock.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package io.jsonwebtoken.impl;
import io.jsonwebtoken.Clock;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtBuilder.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtBuilder.java (.../DefaultJwtBuilder.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtBuilder.java (.../DefaultJwtBuilder.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,36 +15,62 @@
*/
package io.jsonwebtoken.impl;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.jsonwebtoken.*;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.CompressionCodec;
+import io.jsonwebtoken.Header;
+import io.jsonwebtoken.JwsHeader;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.JwtParser;
+import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.crypto.DefaultJwtSigner;
import io.jsonwebtoken.impl.crypto.JwtSigner;
+import io.jsonwebtoken.impl.lang.LegacyServices;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.Encoder;
+import io.jsonwebtoken.io.Encoders;
+import io.jsonwebtoken.io.SerializationException;
+import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections;
-import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
+import io.jsonwebtoken.security.InvalidKeyException;
+import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.Map;
public class DefaultJwtBuilder implements JwtBuilder {
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
-
private Header header;
private Claims claims;
private String payload;
private SignatureAlgorithm algorithm;
- private Key key;
- private byte[] keyBytes;
+ private Key key;
+ private Serializer> serializer;
+
+ private Encoder base64UrlEncoder = Encoders.BASE64URL;
+
private CompressionCodec compressionCodec;
@Override
+ public JwtBuilder serializeToJsonWith(Serializer> serializer) {
+ Assert.notNull(serializer, "Serializer cannot be null.");
+ this.serializer = serializer;
+ return this;
+ }
+
+ @Override
+ public JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder) {
+ Assert.notNull(base64UrlEncoder, "base64UrlEncoder cannot be null.");
+ this.base64UrlEncoder = base64UrlEncoder;
+ return this;
+ }
+
+ @Override
public JwtBuilder setHeader(Header header) {
this.header = header;
return this;
@@ -83,30 +109,42 @@
}
@Override
- public JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey) {
+ public JwtBuilder signWith(Key key) throws InvalidKeyException {
+ Assert.notNull(key, "Key argument cannot be null.");
+ SignatureAlgorithm alg = SignatureAlgorithm.forSigningKey(key);
+ return signWith(key, alg);
+ }
+
+ @Override
+ public JwtBuilder signWith(Key key, SignatureAlgorithm alg) throws InvalidKeyException {
+ Assert.notNull(key, "Key argument cannot be null.");
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
- Assert.notEmpty(secretKey, "secret key byte array cannot be null or empty.");
- Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.");
+ alg.assertValidSigningKey(key); //since 0.10.0 for https://github.com/jwtk/jjwt/issues/334
this.algorithm = alg;
- this.keyBytes = secretKey;
+ this.key = key;
return this;
}
@Override
- public JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) {
+ public JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKeyBytes) throws InvalidKeyException {
+ Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
+ Assert.notEmpty(secretKeyBytes, "secret key byte array cannot be null or empty.");
+ Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.");
+ SecretKey key = new SecretKeySpec(secretKeyBytes, alg.getJcaName());
+ return signWith(key, alg);
+ }
+
+ @Override
+ public JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) throws InvalidKeyException {
Assert.hasText(base64EncodedSecretKey, "base64-encoded secret key cannot be null or empty.");
Assert.isTrue(alg.isHmac(), "Base64-encoded key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.");
- byte[] bytes = TextCodec.BASE64.decode(base64EncodedSecretKey);
+ byte[] bytes = Decoders.BASE64.decode(base64EncodedSecretKey);
return signWith(alg, bytes);
}
@Override
public JwtBuilder signWith(SignatureAlgorithm alg, Key key) {
- Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
- Assert.notNull(key, "Key argument cannot be null.");
- this.algorithm = alg;
- this.key = key;
- return this;
+ return signWith(key, alg);
}
@Override
@@ -136,8 +174,8 @@
}
@Override
- public JwtBuilder setClaims(Map claims) {
- this.claims = Jwts.claims(claims);
+ public JwtBuilder setClaims(Map claims) {
+ this.claims = new DefaultClaims(claims);
return this;
}
@@ -254,30 +292,29 @@
@Override
public String compact() {
+
+ if (this.serializer == null) {
+ // try to find one based on the services available
+ // TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0
+ // use the previous commented out line instead
+ this.serializer = LegacyServices.loadFirst(Serializer.class);
+ }
+
if (payload == null && Collections.isEmpty(claims)) {
- throw new IllegalStateException("Either 'payload' or 'claims' must be specified.");
+ payload = "";
}
if (payload != null && !Collections.isEmpty(claims)) {
throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one.");
}
- if (key != null && keyBytes != null) {
- throw new IllegalStateException("A key object and key bytes cannot both be specified. Choose either one.");
- }
-
Header header = ensureHeader();
- Key key = this.key;
- if (key == null && !Objects.isEmpty(keyBytes)) {
- key = new SecretKeySpec(keyBytes, algorithm.getJcaName());
- }
-
JwsHeader jwsHeader;
-
if (header instanceof JwsHeader) {
- jwsHeader = (JwsHeader)header;
+ jwsHeader = (JwsHeader) header;
} else {
+ //noinspection unchecked
jwsHeader = new DefaultJwsHeader(header);
}
@@ -294,25 +331,19 @@
String base64UrlEncodedHeader = base64UrlEncode(jwsHeader, "Unable to serialize header to json.");
- String base64UrlEncodedBody;
+ byte[] bytes;
+ try {
+ bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);
+ } catch (SerializationException e) {
+ throw new IllegalArgumentException("Unable to serialize claims object to json: " + e.getMessage(), e);
+ }
if (compressionCodec != null) {
-
- byte[] bytes;
- try {
- bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);
- } catch (JsonProcessingException e) {
- throw new IllegalArgumentException("Unable to serialize claims object to json.");
- }
-
- base64UrlEncodedBody = TextCodec.BASE64URL.encode(compressionCodec.compress(bytes));
-
- } else {
- base64UrlEncodedBody = this.payload != null ?
- TextCodec.BASE64URL.encode(this.payload) :
- base64UrlEncode(claims, "Unable to serialize claims object to json.");
+ bytes = compressionCodec.compress(bytes);
}
+ String base64UrlEncodedBody = base64UrlEncoder.encode(bytes);
+
String jwt = base64UrlEncodedHeader + JwtParser.SEPARATOR_CHAR + base64UrlEncodedBody;
if (key != null) { //jwt must be signed:
@@ -335,22 +366,28 @@
* @since 0.5 mostly to allow testing overrides
*/
protected JwtSigner createSigner(SignatureAlgorithm alg, Key key) {
- return new DefaultJwtSigner(alg, key);
+ return new DefaultJwtSigner(alg, key, base64UrlEncoder);
}
+ @Deprecated // remove before 1.0 - call the serializer and base64UrlEncoder directly
protected String base64UrlEncode(Object o, String errMsg) {
+ Assert.isInstanceOf(Map.class, o, "object argument must be a map.");
+ Map m = (Map)o;
byte[] bytes;
try {
- bytes = toJson(o);
- } catch (JsonProcessingException e) {
+ bytes = toJson(m);
+ } catch (SerializationException e) {
throw new IllegalStateException(errMsg, e);
}
- return TextCodec.BASE64URL.encode(bytes);
+ return base64UrlEncoder.encode(bytes);
}
-
- protected byte[] toJson(Object object) throws JsonProcessingException {
- return OBJECT_MAPPER.writeValueAsBytes(object);
+ @SuppressWarnings("unchecked")
+ @Deprecated //remove before 1.0 - call the serializer directly
+ protected byte[] toJson(Object object) throws SerializationException {
+ Assert.isInstanceOf(Map.class, object, "object argument must be a map.");
+ Map m = (Map)object;
+ return serializer.serialize(m);
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParser.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParser.java (.../DefaultJwtParser.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParser.java (.../DefaultJwtParser.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,7 +15,6 @@
*/
package io.jsonwebtoken.impl;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.ClaimJwtException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Clock;
@@ -35,32 +34,35 @@
import io.jsonwebtoken.MissingClaimException;
import io.jsonwebtoken.PrematureJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.SigningKeyResolver;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
import io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator;
import io.jsonwebtoken.impl.crypto.JwtSignatureValidator;
+import io.jsonwebtoken.impl.lang.LegacyServices;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.DeserializationException;
+import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.lang.DateFormats;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
+import io.jsonwebtoken.security.InvalidKeyException;
+import io.jsonwebtoken.security.SignatureException;
+import io.jsonwebtoken.security.WeakKeyException;
import javax.crypto.spec.SecretKeySpec;
-import java.io.IOException;
import java.security.Key;
-import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
@SuppressWarnings("unchecked")
public class DefaultJwtParser implements JwtParser {
- //don't need millis since JWT date fields are only second granularity:
- private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final int MILLISECONDS_PER_SECOND = 1000;
- private ObjectMapper objectMapper = new ObjectMapper();
-
+ // TODO: make the folling fields final for v1.0
private byte[] keyBytes;
private Key key;
@@ -69,13 +71,58 @@
private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver();
- Claims expectedClaims = new DefaultClaims();
+ private Decoder base64UrlDecoder = Decoders.BASE64URL;
+ private Deserializer> deserializer;
+
+ private Claims expectedClaims = new DefaultClaims();
+
private Clock clock = DefaultClock.INSTANCE;
private long allowedClockSkewMillis = 0;
+ /**
+ * TODO: remove this constructor before 1.0
+ * @deprecated for backward compatibility only, see other constructors.
+ */
+ @Deprecated
+ public DefaultJwtParser() { }
+
+ DefaultJwtParser(SigningKeyResolver signingKeyResolver,
+ Key key,
+ byte[] keyBytes,
+ Clock clock,
+ long allowedClockSkewMillis,
+ Claims expectedClaims,
+ Decoder base64UrlDecoder,
+ Deserializer> deserializer,
+ CompressionCodecResolver compressionCodecResolver) {
+ this.signingKeyResolver = signingKeyResolver;
+ this.key = key;
+ this.keyBytes = keyBytes;
+ this.clock = clock;
+ this.allowedClockSkewMillis = allowedClockSkewMillis;
+ this.expectedClaims = expectedClaims;
+ this.base64UrlDecoder = base64UrlDecoder;
+ this.deserializer = deserializer;
+ this.compressionCodecResolver = compressionCodecResolver;
+ }
+
@Override
+ public JwtParser deserializeJsonWith(Deserializer> deserializer) {
+ Assert.notNull(deserializer, "deserializer cannot be null.");
+ this.deserializer = deserializer;
+ return this;
+ }
+
+ @Override
+ public JwtParser base64UrlDecodeWith(Decoder base64UrlDecoder) {
+ Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null.");
+ this.base64UrlDecoder = base64UrlDecoder;
+ return this;
+ }
+
+ @Override
public JwtParser requireIssuedAt(Date issuedAt) {
expectedClaims.setIssuedAt(issuedAt);
return this;
@@ -133,7 +180,8 @@
}
@Override
- public JwtParser setAllowedClockSkewSeconds(long seconds) {
+ public JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException {
+ Assert.isTrue(seconds <= DefaultJwtParserBuilder.MAX_CLOCK_SKEW_MILLIS, DefaultJwtParserBuilder.MAX_CLOCK_SKEW_ILLEGAL_MSG);
this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND);
return this;
}
@@ -146,9 +194,9 @@
}
@Override
- public JwtParser setSigningKey(String base64EncodedKeyBytes) {
- Assert.hasText(base64EncodedKeyBytes, "signing key cannot be null or empty.");
- this.keyBytes = TextCodec.BASE64.decode(base64EncodedKeyBytes);
+ public JwtParser setSigningKey(String base64EncodedSecretKey) {
+ Assert.hasText(base64EncodedSecretKey, "signing key cannot be null or empty.");
+ this.keyBytes = Decoders.BASE64.decode(base64EncodedSecretKey);
return this;
}
@@ -200,8 +248,21 @@
@Override
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
+ // TODO, this logic is only need for a now deprecated code path
+ // remove this block in v1.0 (the equivalent is already in DefaultJwtParserBuilder)
+ if (this.deserializer == null) {
+ // try to find one based on the services available
+ // TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0
+ this.deserializer = LegacyServices.loadFirst(Deserializer.class);
+ }
+
Assert.hasText(jwt, "JWT String argument cannot be null or empty.");
+ if ("..".equals(jwt)) {
+ String msg = "JWT string '..' is missing a header.";
+ throw new MalformedJwtException(msg);
+ }
+
String base64UrlEncodedHeader = null;
String base64UrlEncodedPayload = null;
String base64UrlEncodedDigest = null;
@@ -215,7 +276,7 @@
if (c == SEPARATOR_CHAR) {
CharSequence tokenSeq = Strings.clean(sb);
- String token = tokenSeq!=null?tokenSeq.toString():null;
+ String token = tokenSeq != null ? tokenSeq.toString() : null;
if (delimiterCount == 0) {
base64UrlEncodedHeader = token;
@@ -238,18 +299,16 @@
base64UrlEncodedDigest = sb.toString();
}
- if (base64UrlEncodedPayload == null) {
- throw new MalformedJwtException("JWT string '" + jwt + "' is missing a body/payload.");
- }
// =============== Header =================
Header header = null;
CompressionCodec compressionCodec = null;
if (base64UrlEncodedHeader != null) {
- String origValue = TextCodec.BASE64URL.decodeToString(base64UrlEncodedHeader);
- Map m = readValue(origValue);
+ byte[] bytes = base64UrlDecoder.decode(base64UrlEncodedHeader);
+ String origValue = new String(bytes, Strings.UTF_8);
+ Map m = (Map) readValue(origValue);
if (base64UrlEncodedDigest != null) {
header = new DefaultJwsHeader(m);
@@ -261,18 +320,19 @@
}
// =============== Body =================
- String payload;
- if (compressionCodec != null) {
- byte[] decompressed = compressionCodec.decompress(TextCodec.BASE64URL.decode(base64UrlEncodedPayload));
- payload = new String(decompressed, Strings.UTF_8);
- } else {
- payload = TextCodec.BASE64URL.decodeToString(base64UrlEncodedPayload);
+ String payload = ""; // https://github.com/jwtk/jjwt/pull/540
+ if (base64UrlEncodedPayload != null) {
+ byte[] bytes = base64UrlDecoder.decode(base64UrlEncodedPayload);
+ if (compressionCodec != null) {
+ bytes = compressionCodec.decompress(bytes);
+ }
+ payload = new String(bytes, Strings.UTF_8);
}
Claims claims = null;
- if (payload.charAt(0) == '{' && payload.charAt(payload.length() - 1) == '}') { //likely to be json, parse it:
- Map claimsMap = readValue(payload);
+ if (!payload.isEmpty() && payload.charAt(0) == '{' && payload.charAt(payload.length() - 1) == '}') { //likely to be json, parse it:
+ Map claimsMap = (Map) readValue(payload);
claims = new DefaultClaims(claimsMap);
}
@@ -293,7 +353,7 @@
if (algorithm == null || algorithm == SignatureAlgorithm.NONE) {
//it is plaintext, but it has a signature. This is invalid:
String msg = "JWT string has a digest/signature, but the header does not reference a valid signature " +
- "algorithm.";
+ "algorithm.";
throw new MalformedJwtException(msg);
}
@@ -322,7 +382,7 @@
if (!Objects.isEmpty(keyBytes)) {
Assert.isTrue(algorithm.isHmac(),
- "Key bytes can only be specified for HMAC signatures. Please specify a PublicKey or PrivateKey instance.");
+ "Key bytes can only be specified for HMAC signatures. Please specify a PublicKey or PrivateKey instance.");
key = new SecretKeySpec(keyBytes, algorithm.getJcaName());
}
@@ -331,26 +391,32 @@
Assert.notNull(key, "A signing key must be specified if the specified JWT is digitally signed.");
//re-create the jwt part without the signature. This is what needs to be signed for verification:
- String jwtWithoutSignature = base64UrlEncodedHeader + SEPARATOR_CHAR + base64UrlEncodedPayload;
+ String jwtWithoutSignature = base64UrlEncodedHeader + SEPARATOR_CHAR;
+ if (base64UrlEncodedPayload != null) {
+ jwtWithoutSignature += base64UrlEncodedPayload;
+ }
JwtSignatureValidator validator;
try {
+ algorithm.assertValidVerificationKey(key); //since 0.10.0: https://github.com/jwtk/jjwt/issues/334
validator = createSignatureValidator(algorithm, key);
- } catch (IllegalArgumentException e) {
+ } catch (WeakKeyException e) {
+ throw e;
+ } catch (InvalidKeyException | IllegalArgumentException e) {
String algName = algorithm.getValue();
- String msg = "The parsed JWT indicates it was signed with the " + algName + " signature " +
- "algorithm, but the specified signing key of type " + key.getClass().getName() +
- " may not be used to validate " + algName + " signatures. Because the specified " +
- "signing key reflects a specific and expected algorithm, and the JWT does not reflect " +
- "this algorithm, it is likely that the JWT was not expected and therefore should not be " +
- "trusted. Another possibility is that the parser was configured with the incorrect " +
- "signing key, but this cannot be assumed for security reasons.";
+ String msg = "The parsed JWT indicates it was signed with the " + algName + " signature " +
+ "algorithm, but the specified signing key of type " + key.getClass().getName() +
+ " may not be used to validate " + algName + " signatures. Because the specified " +
+ "signing key reflects a specific and expected algorithm, and the JWT does not reflect " +
+ "this algorithm, it is likely that the JWT was not expected and therefore should not be " +
+ "trusted. Another possibility is that the parser was configured with the incorrect " +
+ "signing key, but this cannot be assumed for security reasons.";
throw new UnsupportedJwtException(msg, e);
}
if (!validator.isValid(jwtWithoutSignature, base64UrlEncodedDigest)) {
String msg = "JWT signature does not match locally computed signature. JWT validity cannot be " +
- "asserted and should not be trusted.";
+ "asserted and should not be trusted.";
throw new SignatureException(msg);
}
}
@@ -360,8 +426,6 @@
//since 0.3:
if (claims != null) {
- SimpleDateFormat sdf;
-
final Date now = this.clock.now();
long nowTime = now.getTime();
@@ -373,9 +437,8 @@
long maxTime = nowTime - this.allowedClockSkewMillis;
Date max = allowSkew ? new Date(maxTime) : now;
if (max.after(exp)) {
- sdf = new SimpleDateFormat(ISO_8601_FORMAT);
- String expVal = sdf.format(exp);
- String nowVal = sdf.format(now);
+ String expVal = DateFormats.formatIso8601(exp, false);
+ String nowVal = DateFormats.formatIso8601(now, false);
long differenceMillis = maxTime - exp.getTime();
@@ -394,9 +457,8 @@
long minTime = nowTime + this.allowedClockSkewMillis;
Date min = allowSkew ? new Date(minTime) : now;
if (min.before(nbf)) {
- sdf = new SimpleDateFormat(ISO_8601_FORMAT);
- String nbfVal = sdf.format(nbf);
- String nowVal = sdf.format(now);
+ String nbfVal = DateFormats.formatIso8601(nbf, false);
+ String nowVal = DateFormats.formatIso8601(now, false);
long differenceMillis = nbf.getTime() - minTime;
@@ -414,46 +476,53 @@
Object body = claims != null ? claims : payload;
if (base64UrlEncodedDigest != null) {
- return new DefaultJws((JwsHeader) header, body, base64UrlEncodedDigest);
+ return new DefaultJws<>((JwsHeader) header, body, base64UrlEncodedDigest);
} else {
- return new DefaultJwt(header, body);
+ return new DefaultJwt<>(header, body);
}
}
+ /**
+ * @since 0.10.0
+ */
+ private static Object normalize(Object o) {
+ if (o instanceof Integer) {
+ o = ((Integer) o).longValue();
+ }
+ return o;
+ }
+
private void validateExpectedClaims(Header header, Claims claims) {
+
for (String expectedClaimName : expectedClaims.keySet()) {
- Object expectedClaimValue = expectedClaims.get(expectedClaimName);
- Object actualClaimValue = claims.get(expectedClaimName);
+ Object expectedClaimValue = normalize(expectedClaims.get(expectedClaimName));
+ Object actualClaimValue = normalize(claims.get(expectedClaimName));
- if (
- Claims.ISSUED_AT.equals(expectedClaimName) ||
- Claims.EXPIRATION.equals(expectedClaimName) ||
- Claims.NOT_BEFORE.equals(expectedClaimName)
- ) {
- expectedClaimValue = expectedClaims.get(expectedClaimName, Date.class);
- actualClaimValue = claims.get(expectedClaimName, Date.class);
- } else if (
- expectedClaimValue instanceof Date &&
- actualClaimValue != null &&
- actualClaimValue instanceof Long
- ) {
- actualClaimValue = new Date((Long)actualClaimValue);
+ if (expectedClaimValue instanceof Date) {
+ try {
+ actualClaimValue = claims.get(expectedClaimName, Date.class);
+ } catch (Exception e) {
+ String msg = "JWT Claim '" + expectedClaimName + "' was expected to be a Date, but its value " +
+ "cannot be converted to a Date using current heuristics. Value: " + actualClaimValue;
+ throw new IncorrectClaimException(header, claims, msg);
+ }
}
InvalidClaimException invalidClaimException = null;
if (actualClaimValue == null) {
- String msg = String.format(
- ClaimJwtException.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
- expectedClaimName, expectedClaimValue
- );
+
+ String msg = String.format(ClaimJwtException.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
+ expectedClaimName, expectedClaimValue);
+
invalidClaimException = new MissingClaimException(header, claims, msg);
+
} else if (!expectedClaimValue.equals(actualClaimValue)) {
- String msg = String.format(
- ClaimJwtException.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
- expectedClaimName, expectedClaimValue, actualClaimValue
- );
+
+ String msg = String.format(ClaimJwtException.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
+ expectedClaimName, expectedClaimValue, actualClaimValue);
+
invalidClaimException = new IncorrectClaimException(header, claims, msg);
}
@@ -469,7 +538,7 @@
* @since 0.5 mostly to allow testing overrides
*/
protected JwtSignatureValidator createSignatureValidator(SignatureAlgorithm alg, Key key) {
- return new DefaultJwtSignatureValidator(alg, key);
+ return new DefaultJwtSignatureValidator(alg, key, base64UrlDecoder);
}
@Override
@@ -547,10 +616,11 @@
}
@SuppressWarnings("unchecked")
- protected Map readValue(String val) {
+ protected Map readValue(String val) {
try {
- return objectMapper.readValue(val, Map.class);
- } catch (IOException e) {
+ byte[] bytes = val.getBytes(Strings.UTF_8);
+ return deserializer.deserialize(bytes);
+ } catch (DeserializationException e) {
throw new MalformedJwtException("Unable to read JSON value: " + val, e);
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2019 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.impl;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Clock;
+import io.jsonwebtoken.CompressionCodecResolver;
+import io.jsonwebtoken.JwtParser;
+import io.jsonwebtoken.JwtParserBuilder;
+import io.jsonwebtoken.SigningKeyResolver;
+import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.io.Deserializer;
+import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.impl.lang.Services;
+
+import java.security.Key;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @since 0.11.0
+ */
+public class DefaultJwtParserBuilder implements JwtParserBuilder {
+
+ private static final int MILLISECONDS_PER_SECOND = 1000;
+
+ /**
+ * To prevent overflow per Issue 583 .
+ *
+ * Package-protected on purpose to allow use in backwards-compatible {@link DefaultJwtParser} implementation.
+ * TODO: enable private modifier on these two variables when deleting DefaultJwtParser
+ */
+ static final long MAX_CLOCK_SKEW_MILLIS = Long.MAX_VALUE / MILLISECONDS_PER_SECOND;
+ static final String MAX_CLOCK_SKEW_ILLEGAL_MSG = "Illegal allowedClockSkewMillis value: multiplying this " +
+ "value by 1000 to obtain the number of milliseconds would cause a numeric overflow.";
+
+ private byte[] keyBytes;
+
+ private Key key;
+
+ private SigningKeyResolver signingKeyResolver;
+
+ private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver();
+
+ private Decoder base64UrlDecoder = Decoders.BASE64URL;
+
+ private Deserializer> deserializer;
+
+ private Claims expectedClaims = new DefaultClaims();
+
+ private Clock clock = DefaultClock.INSTANCE;
+
+ private long allowedClockSkewMillis = 0;
+
+
+ @Override
+ public JwtParserBuilder deserializeJsonWith(Deserializer> deserializer) {
+ Assert.notNull(deserializer, "deserializer cannot be null.");
+ this.deserializer = deserializer;
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder) {
+ Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null.");
+ this.base64UrlDecoder = base64UrlDecoder;
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireIssuedAt(Date issuedAt) {
+ expectedClaims.setIssuedAt(issuedAt);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireIssuer(String issuer) {
+ expectedClaims.setIssuer(issuer);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireAudience(String audience) {
+ expectedClaims.setAudience(audience);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireSubject(String subject) {
+ expectedClaims.setSubject(subject);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireId(String id) {
+ expectedClaims.setId(id);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireExpiration(Date expiration) {
+ expectedClaims.setExpiration(expiration);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder requireNotBefore(Date notBefore) {
+ expectedClaims.setNotBefore(notBefore);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder require(String claimName, Object value) {
+ Assert.hasText(claimName, "claim name cannot be null or empty.");
+ Assert.notNull(value, "The value cannot be null for claim name: " + claimName);
+ expectedClaims.put(claimName, value);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setClock(Clock clock) {
+ Assert.notNull(clock, "Clock instance cannot be null.");
+ this.clock = clock;
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException {
+ Assert.isTrue(seconds <= MAX_CLOCK_SKEW_MILLIS, MAX_CLOCK_SKEW_ILLEGAL_MSG);
+ this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setSigningKey(byte[] key) {
+ Assert.notEmpty(key, "signing key cannot be null or empty.");
+ this.keyBytes = key;
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setSigningKey(String base64EncodedSecretKey) {
+ Assert.hasText(base64EncodedSecretKey, "signing key cannot be null or empty.");
+ this.keyBytes = Decoders.BASE64.decode(base64EncodedSecretKey);
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setSigningKey(Key key) {
+ Assert.notNull(key, "signing key cannot be null.");
+ this.key = key;
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver) {
+ Assert.notNull(signingKeyResolver, "SigningKeyResolver cannot be null.");
+ this.signingKeyResolver = signingKeyResolver;
+ return this;
+ }
+
+ @Override
+ public JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) {
+ Assert.notNull(compressionCodecResolver, "compressionCodecResolver cannot be null.");
+ this.compressionCodecResolver = compressionCodecResolver;
+ return this;
+ }
+
+ @Override
+ public JwtParser build() {
+
+ // Only lookup the deserializer IF it is null. It is possible a Deserializer implementation was set
+ // that is NOT exposed as a service and no other implementations are available for lookup.
+ if (this.deserializer == null) {
+ // try to find one based on the services available:
+ this.deserializer = Services.loadFirst(Deserializer.class);
+ }
+
+ return new ImmutableJwtParser(
+ new DefaultJwtParser(signingKeyResolver,
+ key,
+ keyBytes,
+ clock,
+ allowedClockSkewMillis,
+ expectedClaims,
+ base64UrlDecoder,
+ deserializer,
+ compressionCodecResolver));
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultTextCodecFactory.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultTextCodecFactory.java (.../DefaultTextCodecFactory.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultTextCodecFactory.java (.../DefaultTextCodecFactory.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,6 +15,10 @@
*/
package io.jsonwebtoken.impl;
+/**
+ * @deprecated since 0.10.0
+ */
+@Deprecated //remove just before 1.0.0 release
public class DefaultTextCodecFactory implements TextCodecFactory {
protected String getSystemProperty(String key) {
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/FixedClock.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/FixedClock.java (.../FixedClock.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/FixedClock.java (.../FixedClock.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package io.jsonwebtoken.impl;
import io.jsonwebtoken.Clock;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/ImmutableJwtParser.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/ImmutableJwtParser.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/ImmutableJwtParser.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2019 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.impl;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Clock;
+import io.jsonwebtoken.CompressionCodecResolver;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Header;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwt;
+import io.jsonwebtoken.JwtHandler;
+import io.jsonwebtoken.JwtParser;
+import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.SigningKeyResolver;
+import io.jsonwebtoken.UnsupportedJwtException;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Deserializer;
+import io.jsonwebtoken.security.SignatureException;
+
+import java.security.Key;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * This JwtParser implementation exists as a stop gap until the mutable methods are removed from JwtParser.
+ * TODO: remove this class BEFORE 1.0
+ * @since 0.11.0
+ */
+class ImmutableJwtParser implements JwtParser {
+
+ private final JwtParser jwtParser;
+
+ ImmutableJwtParser(JwtParser jwtParser) {
+ this.jwtParser = jwtParser;
+ }
+
+ private IllegalStateException doNotMutate() {
+ return new IllegalStateException("Cannot mutate a JwtParser created from JwtParserBuilder.build(), " +
+ "the mutable methods in JwtParser will be removed before version 1.0");
+ }
+
+ @Override
+ public JwtParser requireId(String id) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser requireSubject(String subject) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser requireAudience(String audience) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser requireIssuer(String issuer) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser requireIssuedAt(Date issuedAt) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser requireExpiration(Date expiration) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser requireNotBefore(Date notBefore) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser require(String claimName, Object value) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setClock(Clock clock) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setAllowedClockSkewSeconds(long seconds) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setSigningKey(byte[] key) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setSigningKey(String base64EncodedSecretKey) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setSigningKey(Key key) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser base64UrlDecodeWith(Decoder base64UrlDecoder) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public JwtParser deserializeJsonWith(Deserializer> deserializer) {
+ throw doNotMutate();
+ }
+
+ @Override
+ public boolean isSigned(String jwt) {
+ return this.jwtParser.isSigned(jwt);
+ }
+
+ @Override
+ public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
+ return this.jwtParser.parse(jwt);
+ }
+
+ @Override
+ public T parse(String jwt, JwtHandler handler) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
+ return this.jwtParser.parse(jwt, handler);
+ }
+
+ @Override
+ public Jwt parsePlaintextJwt(String plaintextJwt) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
+ return this.jwtParser.parsePlaintextJwt(plaintextJwt);
+ }
+
+ @Override
+ public Jwt parseClaimsJwt(String claimsJwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
+ return this.jwtParser.parseClaimsJwt(claimsJwt);
+ }
+
+ @Override
+ public Jws parsePlaintextJws(String plaintextJws) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
+ return this.jwtParser.parsePlaintextJws(plaintextJws);
+ }
+
+ @Override
+ public Jws parseClaimsJws(String claimsJws) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
+ return this.jwtParser.parseClaimsJws(claimsJws);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/JwtMap.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/JwtMap.java (.../JwtMap.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/JwtMap.java (.../JwtMap.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,24 +16,27 @@
package io.jsonwebtoken.impl;
import io.jsonwebtoken.lang.Assert;
-
+import io.jsonwebtoken.lang.DateFormats;
+import java.text.ParseException;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
-public class JwtMap implements Map {
+public class JwtMap implements Map {
private final Map map;
public JwtMap() {
- this(new LinkedHashMap());
+ this.map = new LinkedHashMap<>();
}
- public JwtMap(Map map) {
+ public JwtMap(Map map) {
+ this();
Assert.notNull(map, "Map argument cannot be null.");
- this.map = map;
+ putAll(map);
}
protected String getString(String name) {
@@ -46,23 +49,55 @@
return null;
} else if (v instanceof Date) {
return (Date) v;
+ } else if (v instanceof Calendar) { //since 0.10.0
+ return ((Calendar) v).getTime();
} else if (v instanceof Number) {
+ //assume millis:
+ long millis = ((Number) v).longValue();
+ return new Date(millis);
+ } else if (v instanceof String) {
+ return parseIso8601Date((String) v, name); //ISO-8601 parsing since 0.10.0
+ } else {
+ throw new IllegalStateException("Cannot create Date from '" + name + "' value '" + v + "'.");
+ }
+ }
+
+ /**
+ * @since 0.10.0
+ */
+ private static Date parseIso8601Date(String s, String name) throws IllegalArgumentException {
+ try {
+ return DateFormats.parseIso8601Date(s);
+ } catch (ParseException e) {
+ String msg = "'" + name + "' value does not appear to be ISO-8601-formatted: " + s;
+ throw new IllegalArgumentException(msg, e);
+ }
+ }
+
+ /**
+ * @since 0.10.0
+ */
+ protected static Date toSpecDate(Object v, String name) {
+ if (v == null) {
+ return null;
+ } else if (v instanceof Number) {
// https://github.com/jwtk/jjwt/issues/122:
// The JWT RFC *mandates* NumericDate values are represented as seconds.
// Because Because java.util.Date requires milliseconds, we need to multiply by 1000:
long seconds = ((Number) v).longValue();
- long millis = seconds * 1000;
- return new Date(millis);
+ v = seconds * 1000;
} else if (v instanceof String) {
// https://github.com/jwtk/jjwt/issues/122
// The JWT RFC *mandates* NumericDate values are represented as seconds.
// Because Because java.util.Date requires milliseconds, we need to multiply by 1000:
- long seconds = Long.parseLong((String) v);
- long millis = seconds * 1000;
- return new Date(millis);
- } else {
- throw new IllegalStateException("Cannot convert '" + name + "' value [" + v + "] to Date instance.");
+ try {
+ long seconds = Long.parseLong((String) v);
+ v = seconds * 1000;
+ } catch (NumberFormatException ignored) {
+ }
}
+ //v would have been normalized to milliseconds if it was a number value, so perform normal date conversion:
+ return toDate(v, name);
}
protected void setValue(String name, Object v) {
@@ -73,11 +108,7 @@
}
}
- protected Date getDate(String name) {
- Object v = map.get(name);
- return toDate(v, name);
- }
-
+ @Deprecated //remove just before 1.0.0
protected void setDate(String name, Date d) {
if (d == null) {
map.remove(name);
@@ -87,6 +118,15 @@
}
}
+ protected Object setDateAsSeconds(String name, Date d) {
+ if (d == null) {
+ return map.remove(name);
+ } else {
+ long seconds = d.getTime() / 1000;
+ return map.put(name, seconds);
+ }
+ }
+
@Override
public int size() {
return map.size();
@@ -133,7 +173,7 @@
return;
}
for (String s : m.keySet()) {
- map.put(s, m.get(s));
+ put(s, m.get(s));
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodec.java (.../TextCodec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodec.java (.../TextCodec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,11 +15,30 @@
*/
package io.jsonwebtoken.impl;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Encoder;
+
+/**
+ * @deprecated since 0.10.0. Use an {@link Encoder} or {@link Decoder}
+ * as needed. This class will be removed before 1.0.0
+ */
+@Deprecated
public interface TextCodec {
- public static final TextCodec BASE64 = new DefaultTextCodecFactory().getTextCodec();
- public static final TextCodec BASE64URL = new Base64UrlCodec();
+ /**
+ * @deprecated since 0.10.0. Use {@code io.jsonwebtoken.io.Encoders#BASE64} or
+ * {@code io.jsonwebtoken.io.Decoders#BASE64} instead. This class will be removed before 1.0.0
+ */
+ @Deprecated
+ TextCodec BASE64 = new Base64Codec();
+ /**
+ * @deprecated since 0.10.0. Use {@code io.jsonwebtoken.io.Encoders#BASE64URL} or
+ * {@code io.jsonwebtoken.io.Decoders#BASE64URL} instead. This class will be removed before 1.0.0
+ */
+ @Deprecated
+ TextCodec BASE64URL = new Base64UrlCodec();
+
String encode(String data);
String encode(byte[] data);
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodecFactory.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodecFactory.java (.../TextCodecFactory.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodecFactory.java (.../TextCodecFactory.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,6 +15,10 @@
*/
package io.jsonwebtoken.impl;
+/**
+ * @deprecated since 0.10.0
+ */
+@Deprecated
public interface TextCodecFactory {
TextCodec getTextCodec();
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/AbstractCompressionCodec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/AbstractCompressionCodec.java (.../AbstractCompressionCodec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/AbstractCompressionCodec.java (.../AbstractCompressionCodec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -18,8 +18,12 @@
import io.jsonwebtoken.CompressionCodec;
import io.jsonwebtoken.CompressionException;
import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.lang.Objects;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/**
* Abstract class that asserts arguments and wraps IOException with CompressionException.
@@ -28,6 +32,44 @@
*/
public abstract class AbstractCompressionCodec implements CompressionCodec {
+ //package-protected for a point release. This can be made protected on a minor release (0.11.0, 0.12.0, 1.0, etc).
+ //TODO: make protected on a minor release
+ interface StreamWrapper {
+ OutputStream wrap(OutputStream out) throws IOException;
+ }
+
+ //package-protected for a point release. This can be made protected on a minor release (0.11.0, 0.12.0, 1.0, etc).
+ //TODO: make protected on a minor release
+ byte[] readAndClose(InputStream input) throws IOException {
+ byte[] buffer = new byte[512];
+ ByteArrayOutputStream out = new ByteArrayOutputStream(buffer.length);
+ int read;
+ try {
+ read = input.read(buffer); //assignment separate from loop invariant check for code coverage checks
+ while (read != -1) {
+ out.write(buffer, 0, read);
+ read = input.read(buffer);
+ }
+ } finally {
+ Objects.nullSafeClose(input);
+ }
+ return out.toByteArray();
+ }
+
+ //package-protected for a point release. This can be made protected on a minor release (0.11.0, 0.12.0, 1.0, etc).
+ //TODO: make protected on a minor release
+ byte[] writeAndClose(byte[] payload, StreamWrapper wrapper) throws IOException {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(512);
+ OutputStream compressionStream = wrapper.wrap(outputStream);
+ try {
+ compressionStream.write(payload);
+ compressionStream.flush();
+ } finally {
+ Objects.nullSafeClose(compressionStream);
+ }
+ return outputStream.toByteArray();
+ }
+
/**
* Implement this method to do the actual work of compressing the payload
*
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DefaultCompressionCodecResolver.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DefaultCompressionCodecResolver.java (.../DefaultCompressionCodecResolver.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DefaultCompressionCodecResolver.java (.../DefaultCompressionCodecResolver.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -17,20 +17,26 @@
import io.jsonwebtoken.CompressionCodec;
import io.jsonwebtoken.CompressionCodecResolver;
+import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.CompressionException;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.impl.lang.Services;
import io.jsonwebtoken.lang.Strings;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* Default implementation of {@link CompressionCodecResolver} that supports the following:
*
*
- * If the specified JWT {@link Header} does not have a {@code calg} header, this implementation does
+ * If the specified JWT {@link Header} does not have a {@code zip} header, this implementation does
* nothing and returns {@code null} to the caller, indicating no compression was used.
- * If the header has a {@code calg} value of {@code DEF}, a {@link DeflateCompressionCodec} will be returned.
- * If the header has a {@code calg} value of {@code GZIP}, a {@link GzipCompressionCodec} will be returned.
- * If the header has any other {@code calg} value, a {@link CompressionException} is thrown to reflect an
+ * If the header has a {@code zip} value of {@code DEF}, a {@link DeflateCompressionCodec} will be returned.
+ * If the header has a {@code zip} value of {@code GZIP}, a {@link GzipCompressionCodec} will be returned.
+ * If the header has any other {@code zip} value, a {@link CompressionException} is thrown to reflect an
* unrecognized algorithm.
*
*
@@ -45,6 +51,22 @@
*/
public class DefaultCompressionCodecResolver implements CompressionCodecResolver {
+ private static final String MISSING_COMPRESSION_MESSAGE = "Unable to find an implementation for compression algorithm [%s] using java.util.ServiceLoader. Ensure you include a backing implementation .jar in the classpath, for example jjwt-impl.jar, or your own .jar for custom implementations.";
+
+ private final Map codecs;
+
+ public DefaultCompressionCodecResolver() {
+ Map codecMap = new HashMap<>();
+ for (CompressionCodec codec : Services.loadAll(CompressionCodec.class)) {
+ codecMap.put(codec.getAlgorithmName().toUpperCase(), codec);
+ }
+
+ codecMap.put(CompressionCodecs.DEFLATE.getAlgorithmName().toUpperCase(), CompressionCodecs.DEFLATE);
+ codecMap.put(CompressionCodecs.GZIP.getAlgorithmName().toUpperCase(), CompressionCodecs.GZIP);
+
+ codecs = Collections.unmodifiableMap(codecMap);
+ }
+
@Override
public CompressionCodec resolveCompressionCodec(Header header) {
String cmpAlg = getAlgorithmFromHeader(header);
@@ -54,19 +76,23 @@
if (!hasCompressionAlgorithm) {
return null;
}
- if (CompressionCodecs.DEFLATE.getAlgorithmName().equalsIgnoreCase(cmpAlg)) {
- return CompressionCodecs.DEFLATE;
- }
- if (CompressionCodecs.GZIP.getAlgorithmName().equalsIgnoreCase(cmpAlg)) {
- return CompressionCodecs.GZIP;
- }
-
- throw new CompressionException("Unsupported compression algorithm '" + cmpAlg + "'");
+ return byName(cmpAlg);
}
private String getAlgorithmFromHeader(Header header) {
Assert.notNull(header, "header cannot be null.");
return header.getCompressionAlgorithm();
}
+
+ private CompressionCodec byName(String name) {
+ Assert.hasText(name, "'name' must not be empty");
+
+ CompressionCodec codec = codecs.get(name.toUpperCase());
+ if (codec == null) {
+ throw new CompressionException(String.format(MISSING_COMPRESSION_MESSAGE, name));
+ }
+
+ return codec;
+ }
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DeflateCompressionCodec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DeflateCompressionCodec.java (.../DeflateCompressionCodec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DeflateCompressionCodec.java (.../DeflateCompressionCodec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -17,10 +17,13 @@
import io.jsonwebtoken.lang.Objects;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.util.zip.Deflater;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
import java.util.zip.InflaterOutputStream;
/**
@@ -32,32 +35,47 @@
private static final String DEFLATE = "DEF";
+ private static final StreamWrapper WRAPPER = new StreamWrapper() {
+ @Override
+ public OutputStream wrap(OutputStream out) {
+ return new DeflaterOutputStream(out);
+ }
+ };
+
@Override
public String getAlgorithmName() {
return DEFLATE;
}
@Override
- public byte[] doCompress(byte[] payload) throws IOException {
+ protected byte[] doCompress(byte[] payload) throws IOException {
+ return writeAndClose(payload, WRAPPER);
+ }
- Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
-
- ByteArrayOutputStream outputStream = null;
- DeflaterOutputStream deflaterOutputStream = null;
+ @Override
+ protected byte[] doDecompress(final byte[] compressed) throws IOException {
try {
- outputStream = new ByteArrayOutputStream();
- deflaterOutputStream = new DeflaterOutputStream(outputStream, deflater, true);
-
- deflaterOutputStream.write(payload, 0, payload.length);
- deflaterOutputStream.flush();
- return outputStream.toByteArray();
- } finally {
- Objects.nullSafeClose(outputStream, deflaterOutputStream);
+ return readAndClose(new InflaterInputStream(new ByteArrayInputStream(compressed)));
+ } catch (IOException e1) {
+ try {
+ return doDecompressBackCompat(compressed);
+ } catch (IOException e2) {
+ throw e1; //retain/report original exception
+ }
}
}
- @Override
- public byte[] doDecompress(byte[] compressed) throws IOException {
+ /**
+ * This implementation was in 0.10.6 and earlier - it will be used as a fallback for backwards compatibility if
+ * {@link #readAndClose(InputStream)} fails per Issue 536 .
+ *
+ * @param compressed the compressed byte array
+ * @return decompressed bytes
+ * @throws IOException if unable to decompress using the 0.10.6 and earlier logic
+ * @since 0.10.8
+ */
+ // package protected on purpose
+ byte[] doDecompressBackCompat(byte[] compressed) throws IOException {
InflaterOutputStream inflaterOutputStream = null;
ByteArrayOutputStream decompressedOutputStream = null;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/GzipCompressionCodec.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/GzipCompressionCodec.java (.../GzipCompressionCodec.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/GzipCompressionCodec.java (.../GzipCompressionCodec.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,11 +16,10 @@
package io.jsonwebtoken.impl.compression;
import io.jsonwebtoken.CompressionCodec;
-import io.jsonwebtoken.lang.Objects;
import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -33,43 +32,25 @@
private static final String GZIP = "GZIP";
+ private static final StreamWrapper WRAPPER = new StreamWrapper() {
+ @Override
+ public OutputStream wrap(OutputStream out) throws IOException {
+ return new GZIPOutputStream(out);
+ }
+ };
+
@Override
public String getAlgorithmName() {
return GZIP;
}
@Override
- protected byte[] doDecompress(byte[] compressed) throws IOException {
- byte[] buffer = new byte[512];
-
- ByteArrayOutputStream outputStream = null;
- GZIPInputStream gzipInputStream = null;
- ByteArrayInputStream inputStream = null;
-
- try {
- inputStream = new ByteArrayInputStream(compressed);
- gzipInputStream = new GZIPInputStream(inputStream);
- outputStream = new ByteArrayOutputStream();
- int read = gzipInputStream.read(buffer);
- while (read != -1) {
- outputStream.write(buffer, 0, read);
- read = gzipInputStream.read(buffer);
- }
- return outputStream.toByteArray();
- } finally {
- Objects.nullSafeClose(inputStream, gzipInputStream, outputStream);
- }
+ protected byte[] doCompress(byte[] payload) throws IOException {
+ return writeAndClose(payload, WRAPPER);
}
- protected byte[] doCompress(byte[] payload) throws IOException {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- GZIPOutputStream compressorOutputStream = new GZIPOutputStream(outputStream, true);
- try {
- compressorOutputStream.write(payload, 0, payload.length);
- compressorOutputStream.finish();
- return outputStream.toByteArray();
- } finally {
- Objects.nullSafeClose(compressorOutputStream, outputStream);
- }
+ @Override
+ protected byte[] doDecompress(byte[] compressed) throws IOException {
+ return readAndClose(new GZIPInputStream(new ByteArrayInputStream(compressed)));
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSignatureValidator.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSignatureValidator.java (.../DefaultJwtSignatureValidator.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSignatureValidator.java (.../DefaultJwtSignatureValidator.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,7 +16,8 @@
package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.impl.TextCodec;
+import io.jsonwebtoken.io.Decoder;
+import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.lang.Assert;
import java.nio.charset.Charset;
@@ -27,22 +28,35 @@
private static final Charset US_ASCII = Charset.forName("US-ASCII");
private final SignatureValidator signatureValidator;
+ private final Decoder base64UrlDecoder;
+ @Deprecated
public DefaultJwtSignatureValidator(SignatureAlgorithm alg, Key key) {
- this(DefaultSignatureValidatorFactory.INSTANCE, alg, key);
+ this(DefaultSignatureValidatorFactory.INSTANCE, alg, key, Decoders.BASE64URL);
}
+ public DefaultJwtSignatureValidator(SignatureAlgorithm alg, Key key, Decoder base64UrlDecoder) {
+ this(DefaultSignatureValidatorFactory.INSTANCE, alg, key, base64UrlDecoder);
+ }
+
+ @Deprecated
public DefaultJwtSignatureValidator(SignatureValidatorFactory factory, SignatureAlgorithm alg, Key key) {
+ this(factory, alg, key, Decoders.BASE64URL);
+ }
+
+ public DefaultJwtSignatureValidator(SignatureValidatorFactory factory, SignatureAlgorithm alg, Key key, Decoder base64UrlDecoder) {
Assert.notNull(factory, "SignerFactory argument cannot be null.");
+ Assert.notNull(base64UrlDecoder, "Base64Url decoder argument cannot be null.");
this.signatureValidator = factory.createSignatureValidator(alg, key);
+ this.base64UrlDecoder = base64UrlDecoder;
}
@Override
public boolean isValid(String jwtWithoutSignature, String base64UrlEncodedSignature) {
byte[] data = jwtWithoutSignature.getBytes(US_ASCII);
- byte[] signature = TextCodec.BASE64URL.decode(base64UrlEncodedSignature);
+ byte[] signature = base64UrlDecoder.decode(base64UrlEncodedSignature);
return this.signatureValidator.isValid(data, signature);
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSigner.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSigner.java (.../DefaultJwtSigner.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSigner.java (.../DefaultJwtSigner.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,7 +16,8 @@
package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.impl.TextCodec;
+import io.jsonwebtoken.io.Encoder;
+import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.lang.Assert;
import java.nio.charset.Charset;
@@ -27,13 +28,26 @@
private static final Charset US_ASCII = Charset.forName("US-ASCII");
private final Signer signer;
+ private final Encoder base64UrlEncoder;
+ @Deprecated
public DefaultJwtSigner(SignatureAlgorithm alg, Key key) {
- this(DefaultSignerFactory.INSTANCE, alg, key);
+ this(DefaultSignerFactory.INSTANCE, alg, key, Encoders.BASE64URL);
}
+ public DefaultJwtSigner(SignatureAlgorithm alg, Key key, Encoder base64UrlEncoder) {
+ this(DefaultSignerFactory.INSTANCE, alg, key, base64UrlEncoder);
+ }
+
+ @Deprecated
public DefaultJwtSigner(SignerFactory factory, SignatureAlgorithm alg, Key key) {
+ this(factory, alg, key, Encoders.BASE64URL);
+ }
+
+ public DefaultJwtSigner(SignerFactory factory, SignatureAlgorithm alg, Key key, Encoder base64UrlEncoder) {
Assert.notNull(factory, "SignerFactory argument cannot be null.");
+ Assert.notNull(base64UrlEncoder, "Base64Url Encoder cannot be null.");
+ this.base64UrlEncoder = base64UrlEncoder;
this.signer = factory.createSigner(alg, key);
}
@@ -44,6 +58,6 @@
byte[] signature = signer.sign(bytesToSign);
- return TextCodec.BASE64URL.encode(signature);
+ return base64UrlEncoder.encode(signature);
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java (.../EllipticCurveProvider.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java (.../EllipticCurveProvider.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,17 +15,19 @@
*/
package io.jsonwebtoken.impl.crypto;
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.lang.Strings;
+
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
+import java.security.spec.ECGenParameterSpec;
import java.util.HashMap;
import java.util.Map;
-import io.jsonwebtoken.JwtException;
-import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.lang.Assert;
-
/**
* ElliptiCurve crypto provider.
*
@@ -78,17 +80,15 @@
* @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)
*/
public static KeyPair generateKeyPair(SignatureAlgorithm alg) {
- return generateKeyPair(alg, SignatureProvider.DEFAULT_SECURE_RANDOM);
+ return generateKeyPair(alg, DEFAULT_SECURE_RANDOM);
}
/**
* Generates a new secure-random key pair of sufficient strength for the specified Elliptic Curve {@link
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link
* SecureRandom} random number generator. This is a convenience method that immediately delegates to {@link
- * #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)} using {@code "ECDSA"} as the {@code
- * jcaAlgorithmName} and {@code "BC"} as the {@code jcaProviderName} since EllipticCurve requires the use of an
- * external JCA provider ({@code BC stands for BouncyCastle}. This will work as expected as long as the
- * BouncyCastle dependency is in the runtime classpath.
+ * #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)} using {@code "EC"} as the {@code
+ * jcaAlgorithmName}.
*
* @param alg alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or {@code
* ES512}
@@ -101,7 +101,7 @@
* @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)
*/
public static KeyPair generateKeyPair(SignatureAlgorithm alg, SecureRandom random) {
- return generateKeyPair("ECDSA", "BC", alg, random);
+ return generateKeyPair("EC", null, alg, random);
}
/**
@@ -111,8 +111,8 @@
*
* @param jcaAlgorithmName the JCA name of the algorithm to use for key pair generation, for example, {@code
* ECDSA}.
- * @param jcaProviderName the JCA provider name of the algorithm implementation, for example {@code BC} for
- * BouncyCastle.
+ * @param jcaProviderName the JCA provider name of the algorithm implementation (for example {@code "BC"} for
+ * BouncyCastle) or {@code null} if the default provider should be used.
* @param alg alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or
* {@code ES512}
* @param random the SecureRandom generator to use during key generation.
@@ -128,9 +128,17 @@
Assert.notNull(alg, "SignatureAlgorithm argument cannot be null.");
Assert.isTrue(alg.isEllipticCurve(), "SignatureAlgorithm argument must represent an Elliptic Curve algorithm.");
try {
- KeyPairGenerator g = KeyPairGenerator.getInstance(jcaAlgorithmName, jcaProviderName);
+ KeyPairGenerator g;
+
+ if (Strings.hasText(jcaProviderName)) {
+ g = KeyPairGenerator.getInstance(jcaAlgorithmName, jcaProviderName);
+ } else {
+ g = KeyPairGenerator.getInstance(jcaAlgorithmName);
+ }
+
String paramSpecCurveName = EC_CURVE_NAMES.get(alg);
- g.initialize(org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec(paramSpecCurveName), random);
+ ECGenParameterSpec spec = new ECGenParameterSpec(paramSpecCurveName);
+ g.initialize(spec, random);
return g.generateKeyPair();
} catch (Exception e) {
throw new IllegalStateException("Unable to generate Elliptic Curve KeyPair: " + e.getMessage(), e);
@@ -143,18 +151,19 @@
*
* @param alg The ECDSA algorithm. Must be supported and not
* {@code null}.
- *
* @return The expected byte array length for the signature.
- *
* @throws JwtException If the algorithm is not supported.
*/
public static int getSignatureByteArrayLength(final SignatureAlgorithm alg)
- throws JwtException {
+ throws JwtException {
switch (alg) {
- case ES256: return 64;
- case ES384: return 96;
- case ES512: return 132;
+ case ES256:
+ return 64;
+ case ES384:
+ return 96;
+ case ES512:
+ return 132;
default:
throw new JwtException("Unsupported Algorithm: " + alg.name());
}
@@ -167,13 +176,10 @@
*
* @param derSignature The ASN1./DER-encoded. Must not be {@code null}.
* @param outputLength The expected length of the ECDSA JWS signature.
- *
* @return The ECDSA JWS encoded signature.
- *
* @throws JwtException If the ASN.1/DER signature format is invalid.
*/
- public static byte[] transcodeSignatureToConcat(final byte[] derSignature, int outputLength)
- throws JwtException {
+ public static byte[] transcodeSignatureToConcat(final byte[] derSignature, int outputLength) throws JwtException {
if (derSignature.length < 8 || derSignature[0] != 48) {
throw new JwtException("Invalid ECDSA signature format");
@@ -191,24 +197,24 @@
byte rLength = derSignature[offset + 1];
int i = rLength;
- while ((i > 0)
- && (derSignature[(offset + 2 + rLength) - i] == 0))
+ while ((i > 0) && (derSignature[(offset + 2 + rLength) - i] == 0)) {
i--;
+ }
byte sLength = derSignature[offset + 2 + rLength + 1];
int j = sLength;
- while ((j > 0)
- && (derSignature[(offset + 2 + rLength + 2 + sLength) - j] == 0))
+ while ((j > 0) && (derSignature[(offset + 2 + rLength + 2 + sLength) - j] == 0)) {
j--;
+ }
int rawLen = Math.max(i, j);
rawLen = Math.max(rawLen, outputLength / 2);
if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset
- || (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
- || derSignature[offset] != 2
- || derSignature[offset + 2 + rLength] != 2) {
+ || (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
+ || derSignature[offset] != 2
+ || derSignature[offset + 2 + rLength] != 2) {
throw new JwtException("Invalid ECDSA signature format");
}
@@ -221,29 +227,25 @@
}
-
/**
* Transcodes the ECDSA JWS signature into ASN.1/DER format for use by
* the JCA verifier.
*
* @param jwsSignature The JWS signature, consisting of the
* concatenated R and S values. Must not be
* {@code null}.
- *
* @return The ASN.1/DER encoded signature.
- *
* @throws JwtException If the ECDSA JWS signature format is invalid.
*/
- public static byte[] transcodeSignatureToDER(byte[] jwsSignature)
- throws JwtException {
+ public static byte[] transcodeSignatureToDER(byte[] jwsSignature) throws JwtException {
int rawLen = jwsSignature.length / 2;
int i = rawLen;
- while((i > 0)
- && (jwsSignature[rawLen - i] == 0))
+ while ((i > 0) && (jwsSignature[rawLen - i] == 0)) {
i--;
+ }
int j = i;
@@ -253,9 +255,9 @@
int k = rawLen;
- while ((k > 0)
- && (jwsSignature[2 * rawLen - k] == 0))
+ while ((k > 0) && (jwsSignature[2 * rawLen - k] == 0)) {
k--;
+ }
int l = k;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java (.../EllipticCurveSignatureValidator.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java (.../EllipticCurveSignatureValidator.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,16 +15,16 @@
*/
package io.jsonwebtoken.impl.crypto;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.security.SignatureException;
+
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.ECPublicKey;
-import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
-import io.jsonwebtoken.lang.Assert;
-
public class EllipticCurveSignatureValidator extends EllipticCurveProvider implements SignatureValidator {
private static final String EC_PUBLIC_KEY_REQD_MSG =
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java (.../EllipticCurveSigner.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java (.../EllipticCurveSigner.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,17 +15,16 @@
*/
package io.jsonwebtoken.impl.crypto;
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.SignatureException;
+
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.interfaces.ECKey;
-import java.security.interfaces.ECPrivateKey;
-import io.jsonwebtoken.JwtException;
-import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
-
public class EllipticCurveSigner extends EllipticCurveProvider implements Signer {
public EllipticCurveSigner(SignatureAlgorithm alg, Key key) {
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacProvider.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacProvider.java (.../MacProvider.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacProvider.java (.../MacProvider.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -18,9 +18,10 @@
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
+import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
+import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public abstract class MacProvider extends SignatureProvider {
@@ -31,11 +32,11 @@
}
/**
- * Generates a new secure-random 512 bit secret key suitable for creating and verifying HMAC signatures. This is a
- * convenience method that immediately delegates to {@link #generateKey(SignatureAlgorithm)} using {@link
+ * Generates a new secure-random 512 bit secret key suitable for creating and verifying HMAC-SHA signatures. This
+ * is a convenience method that immediately delegates to {@link #generateKey(SignatureAlgorithm)} using {@link
* SignatureAlgorithm#HS512} as the method argument.
*
- * @return a new secure-random 512 bit secret key suitable for creating and verifying HMAC signatures.
+ * @return a new secure-random 512 bit secret key suitable for creating and verifying HMAC-SHA signatures.
* @see #generateKey(SignatureAlgorithm)
* @see #generateKey(SignatureAlgorithm, SecureRandom)
* @since 0.5
@@ -59,7 +60,7 @@
* @since 0.5
*/
public static SecretKey generateKey(SignatureAlgorithm alg) {
- return generateKey(alg, SignatureProvider.DEFAULT_SECURE_RANDOM);
+ return generateKey(alg, DEFAULT_SECURE_RANDOM);
}
/**
@@ -78,26 +79,22 @@
* @see #generateKey()
* @see #generateKey(SignatureAlgorithm)
* @since 0.5
+ * @deprecated since 0.10.0 - use {@link #generateKey(SignatureAlgorithm)} instead.
*/
+ @Deprecated
public static SecretKey generateKey(SignatureAlgorithm alg, SecureRandom random) {
Assert.isTrue(alg.isHmac(), "SignatureAlgorithm argument must represent an HMAC algorithm.");
- byte[] bytes;
+ KeyGenerator gen;
- switch (alg) {
- case HS256:
- bytes = new byte[32];
- break;
- case HS384:
- bytes = new byte[48];
- break;
- default:
- bytes = new byte[64];
+ try {
+ gen = KeyGenerator.getInstance(alg.getJcaName());
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("The " + alg.getJcaName() + " algorithm is not available. " +
+ "This should never happen on JDK 7 or later - please report this to the JJWT developers.", e);
}
- random.nextBytes(bytes);
-
- return new SecretKeySpec(bytes, alg.getJcaName());
+ return gen.generateKey();
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacSigner.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacSigner.java (.../MacSigner.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacSigner.java (.../MacSigner.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,8 +16,8 @@
package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacValidator.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacValidator.java (.../MacValidator.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacValidator.java (.../MacValidator.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -19,7 +19,6 @@
import java.security.Key;
import java.security.MessageDigest;
-import java.util.Arrays;
public class MacValidator implements SignatureValidator {
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaProvider.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaProvider.java (.../RsaProvider.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaProvider.java (.../RsaProvider.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,8 +16,9 @@
package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.lang.RuntimeEnvironment;
+import io.jsonwebtoken.security.SignatureException;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
@@ -54,6 +55,10 @@
return m;
}
+ static {
+ RuntimeEnvironment.enableBouncyCastleIfPossible(); //PS256, PS384, PS512 on <= JDK 10 require BC
+ }
+
protected RsaProvider(SignatureAlgorithm alg, Key key) {
super(alg, key);
Assert.isTrue(alg.isRsa(), "SignatureAlgorithm must be an RSASSA or RSASSA-PSS algorithm.");
@@ -111,10 +116,40 @@
* @since 0.5
*/
public static KeyPair generateKeyPair(int keySizeInBits) {
- return generateKeyPair(keySizeInBits, SignatureProvider.DEFAULT_SECURE_RANDOM);
+ return generateKeyPair(keySizeInBits, DEFAULT_SECURE_RANDOM);
}
/**
+ * Generates a new RSA secure-randomly key pair suitable for the specified SignatureAlgorithm using JJWT's
+ * default {@link SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method
+ * that immediately delegates to {@link #generateKeyPair(int)} based on the relevant key size for the specified
+ * algorithm.
+ *
+ * @param alg the signature algorithm to inspect to determine a size in bits.
+ * @return a new RSA secure-random key pair of the specified size.
+ * @see #generateKeyPair()
+ * @see #generateKeyPair(int, SecureRandom)
+ * @see #generateKeyPair(String, int, SecureRandom)
+ * @since 0.10.0
+ */
+ @SuppressWarnings("unused") //used by io.jsonwebtoken.security.Keys
+ public static KeyPair generateKeyPair(SignatureAlgorithm alg) {
+ Assert.isTrue(alg.isRsa(), "Only RSA algorithms are supported by this method.");
+ int keySizeInBits = 4096;
+ switch (alg) {
+ case RS256:
+ case PS256:
+ keySizeInBits = 2048;
+ break;
+ case RS384:
+ case PS384:
+ keySizeInBits = 3072;
+ break;
+ }
+ return generateKeyPair(keySizeInBits, DEFAULT_SECURE_RANDOM);
+ }
+
+ /**
* Generates a new RSA secure-random key pair of the specified size using the given SecureRandom number generator.
* This is a convenience method that immediately delegates to {@link #generateKeyPair(String, int, SecureRandom)}
* using {@code RSA} as the {@code jcaAlgorithmName} argument.
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSignatureValidator.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSignatureValidator.java (.../RsaSignatureValidator.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSignatureValidator.java (.../RsaSignatureValidator.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,11 +16,12 @@
package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.Key;
+import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
@@ -52,7 +53,7 @@
} else {
Assert.notNull(this.SIGNER, "RSA Signer instance cannot be null. This is a bug. Please report it.");
byte[] computed = this.SIGNER.sign(data);
- return Arrays.equals(computed, signature);
+ return MessageDigest.isEqual(computed, signature);
}
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSigner.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSigner.java (.../RsaSigner.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSigner.java (.../RsaSigner.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -16,7 +16,7 @@
package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
+import io.jsonwebtoken.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.Key;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureProvider.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureProvider.java (.../SignatureProvider.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureProvider.java (.../SignatureProvider.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,16 +15,16 @@
*/
package io.jsonwebtoken.impl.crypto;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.lang.RuntimeEnvironment;
+import io.jsonwebtoken.security.SignatureException;
+
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Signature;
-import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
-import io.jsonwebtoken.lang.Assert;
-import io.jsonwebtoken.lang.RuntimeEnvironment;
-
abstract class SignatureProvider {
/**
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/Signer.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/Signer.java (.../Signer.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/Signer.java (.../Signer.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -15,7 +15,7 @@
*/
package io.jsonwebtoken.impl.crypto;
-import io.jsonwebtoken.SignatureException;
+import io.jsonwebtoken.security.SignatureException;
public interface Signer {
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/LegacyServices.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/LegacyServices.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/LegacyServices.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+package io.jsonwebtoken.impl.lang;
+
+import io.jsonwebtoken.lang.Classes;
+import io.jsonwebtoken.lang.UnknownClassException;
+
+/**
+ * A backward compatibility {@link Services} utility to help migrate away from {@link Classes#newInstance(String)}.
+ * TODO: remove before v1.0
+ * @deprecated use {@link Services} directly
+ */
+@Deprecated
+public final class LegacyServices {
+
+ /**
+ * Wraps {@code Services.loadFirst} and throws a {@link UnknownClassException} instead of a
+ * {@link UnavailableImplementationException} to retain the previous behavior. This method should be used when
+ * to retain the previous behavior of methods that throw an unchecked UnknownClassException.
+ */
+ public static T loadFirst(Class spi) {
+ try {
+ return Services.loadFirst(spi);
+ } catch (UnavailableImplementationException e) {
+ throw new UnknownClassException(e.getMessage(), e);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/Services.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/Services.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/Services.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.impl.lang;
+
+import io.jsonwebtoken.lang.Assert;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import static io.jsonwebtoken.lang.Collections.arrayToList;
+
+/**
+ * Helper class for loading services from the classpath, using a {@link ServiceLoader}. Decouples loading logic for
+ * better separation of concerns and testability.
+ */
+public final class Services {
+
+ private static final List CLASS_LOADER_ACCESSORS = arrayToList(new ClassLoaderAccessor[] {
+ new ClassLoaderAccessor() {
+ @Override
+ public ClassLoader getClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ },
+ new ClassLoaderAccessor() {
+ @Override
+ public ClassLoader getClassLoader() {
+ return Services.class.getClassLoader();
+ }
+ },
+ new ClassLoaderAccessor() {
+ @Override
+ public ClassLoader getClassLoader() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ }
+ });
+
+ private Services() {}
+
+ /**
+ * Loads and instantiates all service implementation of the given SPI class and returns them as a List.
+ *
+ * @param spi The class of the Service Provider Interface
+ * @param The type of the SPI
+ * @return An unmodifiable list with an instance of all available implementations of the SPI. No guarantee is given
+ * on the order of implementations, if more than one.
+ */
+ public static List loadAll(Class spi) {
+ Assert.notNull(spi, "Parameter 'spi' must not be null.");
+
+ for (ClassLoaderAccessor classLoaderAccessor : CLASS_LOADER_ACCESSORS) {
+ List implementations = loadAll(spi, classLoaderAccessor.getClassLoader());
+ if (!implementations.isEmpty()) {
+ return Collections.unmodifiableList(implementations);
+ }
+ }
+
+ throw new UnavailableImplementationException(spi);
+ }
+
+ private static List loadAll(Class spi, ClassLoader classLoader) {
+ ServiceLoader serviceLoader = ServiceLoader.load(spi, classLoader);
+ List implementations = new ArrayList<>();
+ for (T implementation : serviceLoader) {
+ implementations.add(implementation);
+ }
+ return implementations;
+ }
+
+ /**
+ * Loads the first available implementation the given SPI class from the classpath. Uses the {@link ServiceLoader}
+ * to find implementations. When multiple implementations are available it will return the first one that it
+ * encounters. There is no guarantee with regard to ordering.
+ *
+ * @param spi The class of the Service Provider Interface
+ * @param The type of the SPI
+ * @return A new instance of the service.
+ * @throws UnavailableImplementationException When no implementation the SPI is available on the classpath.
+ */
+ public static T loadFirst(Class spi) {
+ Assert.notNull(spi, "Parameter 'spi' must not be null.");
+
+ for (ClassLoaderAccessor classLoaderAccessor : CLASS_LOADER_ACCESSORS) {
+ T result = loadFirst(spi, classLoaderAccessor.getClassLoader());
+ if (result != null) {
+ return result;
+ }
+ }
+ throw new UnavailableImplementationException(spi);
+ }
+
+ private static T loadFirst(Class spi, ClassLoader classLoader) {
+ ServiceLoader serviceLoader = ServiceLoader.load(spi, classLoader);
+ if (serviceLoader.iterator().hasNext()) {
+ return serviceLoader.iterator().next();
+ }
+ return null;
+ }
+
+ private interface ClassLoaderAccessor {
+ ClassLoader getClassLoader();
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/UnavailableImplementationException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/UnavailableImplementationException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/lang/UnavailableImplementationException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.impl.lang;
+
+/**
+ * Exception indicating that no implementation of an jjwt-api SPI was found on the classpath.
+ * @since 0.11.0
+ */
+public final class UnavailableImplementationException extends RuntimeException {
+
+ private static final String DEFAULT_NOT_FOUND_MESSAGE = "Unable to find an implementation for %s using java.util.ServiceLoader. Ensure you include a backing implementation .jar in the classpath, for example jjwt-impl.jar, or your own .jar for custom implementations.";
+
+ UnavailableImplementationException(final Class klass) {
+ super(String.format(DEFAULT_NOT_FOUND_MESSAGE, klass));
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import java.util.Arrays;
+
+/**
+ * A very fast and memory efficient class to encode and decode to and from BASE64 or BASE64URL in full accordance
+ * with RFC 4648 .
+ *
+ * Based initially on MigBase64 with continued modifications for Base64 URL support and JDK-standard code formatting.
+ *
+ * This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
+ * allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
+ * as large as algorithms that create a temporary array.
+ *
+ * There is also a "fast" version of all decode methods that works the same way as the normal ones, but
+ * has a few demands on the decoded input. Normally though, these fast versions should be used if the source if
+ * the input is known and it hasn't bee tampered with.
+ *
+ * @author Mikael Grev
+ * @author Les Hazlewood
+ * @since 0.10.0
+ */
+@SuppressWarnings("Duplicates")
+final class Base64 { //final and package-protected on purpose
+
+ private static final char[] BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
+ private static final char[] BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();
+ private static final int[] BASE64_IALPHABET = new int[256];
+ private static final int[] BASE64URL_IALPHABET = new int[256];
+ private static final int IALPHABET_MAX_INDEX = BASE64_IALPHABET.length - 1;
+
+ static {
+ Arrays.fill(BASE64_IALPHABET, -1);
+ System.arraycopy(BASE64_IALPHABET, 0, BASE64URL_IALPHABET, 0, BASE64_IALPHABET.length);
+ for (int i = 0, iS = BASE64_ALPHABET.length; i < iS; i++) {
+ BASE64_IALPHABET[BASE64_ALPHABET[i]] = i;
+ BASE64URL_IALPHABET[BASE64URL_ALPHABET[i]] = i;
+ }
+ BASE64_IALPHABET['='] = 0;
+ BASE64URL_IALPHABET['='] = 0;
+ }
+
+ static final Base64 DEFAULT = new Base64(false);
+ static final Base64 URL_SAFE = new Base64(true);
+
+ private final boolean urlsafe;
+ private final char[] ALPHABET;
+ private final int[] IALPHABET;
+
+ private Base64(boolean urlsafe) {
+ this.urlsafe = urlsafe;
+ this.ALPHABET = urlsafe ? BASE64URL_ALPHABET : BASE64_ALPHABET;
+ this.IALPHABET = urlsafe ? BASE64URL_IALPHABET : BASE64_IALPHABET;
+ }
+
+ // ****************************************************************************************
+ // * char[] version
+ // ****************************************************************************************
+
+ private String getName() {
+ return urlsafe ? "base64url" : "base64"; // RFC 4648 codec names are all lowercase
+ }
+
+ /**
+ * Encodes a raw byte array into a BASE64 char[]
representation in accordance with RFC 2045.
+ *
+ * @param sArr The bytes to convert. If null
or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null
.
+ */
+ private char[] encodeToChar(byte[] sArr, boolean lineSep) {
+
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0) {
+ return new char[0];
+ }
+
+ int eLen = (sLen / 3) * 3; // # of bytes that can encode evenly into 24-bit chunks
+ int left = sLen - eLen; // # of bytes that remain after 24-bit chunking. Always 0, 1 or 2
+
+ int cCnt = (((sLen - 1) / 3 + 1) << 2); // # of base64-encoded characters including padding
+ int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned char array with padding and any line separators
+
+ int padCount = 0;
+ if (left == 2) {
+ padCount = 1;
+ } else if (left == 1) {
+ padCount = 2;
+ }
+
+ char[] dArr = new char[urlsafe ? (dLen - padCount) : dLen];
+
+ // Encode even 24-bits
+ for (int s = 0, d = 0, cc = 0; s < eLen; ) {
+
+ // Copy next three bytes into lower 24 bits of int, paying attension to sign.
+ int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
+
+ // Encode the int into four chars
+ dArr[d++] = ALPHABET[(i >>> 18) & 0x3f];
+ dArr[d++] = ALPHABET[(i >>> 12) & 0x3f];
+ dArr[d++] = ALPHABET[(i >>> 6) & 0x3f];
+ dArr[d++] = ALPHABET[i & 0x3f];
+
+ // Add optional line separator
+ if (lineSep && ++cc == 19 && d < dLen - 2) {
+ dArr[d++] = '\r';
+ dArr[d++] = '\n';
+ cc = 0;
+ }
+ }
+
+ // Pad and encode last bits if source isn't even 24 bits.
+ if (left > 0) {
+ // Prepare the int
+ int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
+
+ // Set last four chars
+ dArr[dLen - 4] = ALPHABET[i >> 12];
+ dArr[dLen - 3] = ALPHABET[(i >>> 6) & 0x3f];
+ //dArr[dLen - 2] = left == 2 ? ALPHABET[i & 0x3f] : '=';
+ //dArr[dLen - 1] = '=';
+ if (left == 2) {
+ dArr[dLen - 2] = ALPHABET[i & 0x3f];
+ } else if (!urlsafe) { // if not urlsafe, we need to include the padding characters
+ dArr[dLen - 2] = '=';
+ }
+ if (!urlsafe) { // include padding
+ dArr[dLen - 1] = '=';
+ }
+ }
+ return dArr;
+ }
+
+ /*
+ * Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
+ * and without line separators.
+ *
+ * @param sArr The source array. null
or length 0 will return an empty array.
+ * @return The decoded array of bytes. May be of length 0. Will be null
if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ *
+ public final byte[] decode(char[] sArr) {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0) {
+ return new byte[0];
+ }
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) { // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IALPHABET[sArr[i]] < 0) {
+ sepCnt++;
+ }
+ }
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0) {
+ return null;
+ }
+
+ int pad = 0;
+ for (int i = sLen; i > 1 && IALPHABET[sArr[--i]] <= 0; ) {
+ if (sArr[i] == '=') {
+ pad++;
+ }
+ }
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IALPHABET[sArr[s++]];
+ if (c >= 0) {
+ i |= c << (18 - j * 6);
+ } else {
+ j--;
+ }
+ }
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++] = (byte) (i >> 8);
+ if (d < len) {
+ dArr[d++] = (byte) i;
+ }
+ }
+ }
+ return dArr;
+ }
+ */
+
+ private int ctoi(char c) {
+ int i = c > IALPHABET_MAX_INDEX ? -1 : IALPHABET[c];
+ if (i < 0) {
+ String msg = "Illegal " + getName() + " character: '" + c + "'";
+ throw new DecodingException(msg);
+ }
+ return i;
+ }
+
+ /**
+ * Decodes a BASE64 encoded char array that is known to be reasonably well formatted. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ *
+ * @param sArr The source array. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ * @throws DecodingException on illegal input
+ */
+ final byte[] decodeFast(char[] sArr) throws DecodingException {
+
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0) {
+ return new byte[0];
+ }
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IALPHABET[sArr[sIx]] < 0) {
+ sIx++;
+ }
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IALPHABET[sArr[eIx]] < 0) {
+ eIx--;
+ }
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
+
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = ctoi(sArr[sIx++]) << 18 | ctoi(sArr[sIx++]) << 12 | ctoi(sArr[sIx++]) << 6 | ctoi(sArr[sIx++]);
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++) {
+ i |= ctoi(sArr[sIx++]) << (18 - j * 6);
+ }
+
+ for (int r = 16; d < len; r -= 8) {
+ dArr[d++] = (byte) (i >> r);
+ }
+ }
+
+ return dArr;
+ }
+
+ // ****************************************************************************************
+ // * byte[] version
+ // ****************************************************************************************
+
+ /*
+ * Encodes a raw byte array into a BASE64 byte[]
representation i accordance with RFC 2045.
+ *
+ * @param sArr The bytes to convert. If null
or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null
.
+ *
+ public final byte[] encodeToByte(byte[] sArr, boolean lineSep) {
+ return encodeToByte(sArr, 0, sArr != null ? sArr.length : 0, lineSep);
+ }
+
+ /**
+ * Encodes a raw byte array into a BASE64 byte[]
representation i accordance with RFC 2045.
+ *
+ * @param sArr The bytes to convert. If null
an empty array will be returned.
+ * @param sOff The starting position in the bytes to convert.
+ * @param sLen The number of bytes to convert. If 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null
.
+ *
+ public final byte[] encodeToByte(byte[] sArr, int sOff, int sLen, boolean lineSep) {
+
+ // Check special case
+ if (sArr == null || sLen == 0) {
+ return new byte[0];
+ }
+
+ int eLen = (sLen / 3) * 3; // Length of even 24-bits.
+ int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
+ int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
+ byte[] dArr = new byte[dLen];
+
+ // Encode even 24-bits
+ for (int s = sOff, d = 0, cc = 0; s < sOff + eLen; ) {
+
+ // Copy next three bytes into lower 24 bits of int, paying attension to sign.
+ int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
+
+ // Encode the int into four chars
+ dArr[d++] = (byte) ALPHABET[(i >>> 18) & 0x3f];
+ dArr[d++] = (byte) ALPHABET[(i >>> 12) & 0x3f];
+ dArr[d++] = (byte) ALPHABET[(i >>> 6) & 0x3f];
+ dArr[d++] = (byte) ALPHABET[i & 0x3f];
+
+ // Add optional line separator
+ if (lineSep && ++cc == 19 && d < dLen - 2) {
+ dArr[d++] = '\r';
+ dArr[d++] = '\n';
+ cc = 0;
+ }
+ }
+
+ // Pad and encode last bits if source isn't an even 24 bits.
+ int left = sLen - eLen; // 0 - 2.
+ if (left > 0) {
+ // Prepare the int
+ int i = ((sArr[sOff + eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sOff + sLen - 1] & 0xff) << 2) : 0);
+
+ // Set last four chars
+ dArr[dLen - 4] = (byte) ALPHABET[i >> 12];
+ dArr[dLen - 3] = (byte) ALPHABET[(i >>> 6) & 0x3f];
+ dArr[dLen - 2] = left == 2 ? (byte) ALPHABET[i & 0x3f] : (byte) '=';
+ dArr[dLen - 1] = '=';
+ }
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
+ * and without line separators.
+ *
+ * @param sArr The source array. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0. Will be null
if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ *
+ public final byte[] decode(byte[] sArr) {
+ return decode(sArr, 0, sArr.length);
+ }
+
+ /**
+ * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
+ * and without line separators.
+ *
+ * @param sArr The source array. null
will throw an exception.
+ * @param sOff The starting position in the source array.
+ * @param sLen The number of bytes to decode from the source array. Length 0 will return an empty array.
+ * @return The decoded array of bytes. May be of length 0. Will be null
if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ *
+ public final byte[] decode(byte[] sArr, int sOff, int sLen) {
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) { // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IALPHABET[sArr[sOff + i] & 0xff] < 0) {
+ sepCnt++;
+ }
+ }
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0) {
+ return null;
+ }
+
+ int pad = 0;
+ for (int i = sLen; i > 1 && IALPHABET[sArr[sOff + --i] & 0xff] <= 0; ) {
+ if (sArr[sOff + i] == '=') {
+ pad++;
+ }
+ }
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IALPHABET[sArr[sOff + s++] & 0xff];
+ if (c >= 0) {
+ i |= c << (18 - j * 6);
+ } else {
+ j--;
+ }
+ }
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++] = (byte) (i >> 8);
+ if (d < len) {
+ dArr[d++] = (byte) i;
+ }
+ }
+ }
+
+ return dArr;
+ }
+
+
+ /*
+ * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link #decode(byte[])}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ *
+ * @param sArr The source array. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ *
+ public final byte[] decodeFast(byte[] sArr) {
+
+ // Check special case
+ int sLen = sArr.length;
+ if (sLen == 0) {
+ return new byte[0];
+ }
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IALPHABET[sArr[sIx] & 0xff] < 0) {
+ sIx++;
+ }
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IALPHABET[sArr[eIx] & 0xff] < 0) {
+ eIx--;
+ }
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
+
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IALPHABET[sArr[sIx++]] << 18 | IALPHABET[sArr[sIx++]] << 12 | IALPHABET[sArr[sIx++]] << 6 | IALPHABET[sArr[sIx++]];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++) {
+ i |= IALPHABET[sArr[sIx++]] << (18 - j * 6);
+ }
+
+ for (int r = 16; d < len; r -= 8) {
+ dArr[d++] = (byte) (i >> r);
+ }
+ }
+
+ return dArr;
+ }
+ */
+
+ // ****************************************************************************************
+ // * String version
+ // ****************************************************************************************
+
+ /**
+ * Encodes a raw byte array into a BASE64 String
representation i accordance with RFC 2045.
+ *
+ * @param sArr The bytes to convert. If null
or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null
.
+ */
+ final String encodeToString(byte[] sArr, boolean lineSep) {
+ // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
+ return new String(encodeToChar(sArr, lineSep));
+ }
+
+ /*
+ * Decodes a BASE64 encoded String
. All illegal characters will be ignored and can handle both strings with
+ * and without line separators.
+ * Note! It can be up to about 2x the speed to call decode(str.toCharArray())
instead. That
+ * will create a temporary array though. This version will use str.charAt(i)
to iterate the string.
+ *
+ * @param str The source string. null
or length 0 will return an empty array.
+ * @return The decoded array of bytes. May be of length 0. Will be null
if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ *
+ public final byte[] decode(String str) {
+
+ // Check special case
+ int sLen = str != null ? str.length() : 0;
+ if (sLen == 0) {
+ return new byte[0];
+ }
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) { // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IALPHABET[str.charAt(i)] < 0) {
+ sepCnt++;
+ }
+ }
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0) {
+ return null;
+ }
+
+ // Count '=' at end
+ int pad = 0;
+ for (int i = sLen; i > 1 && IALPHABET[str.charAt(--i)] <= 0; ) {
+ if (str.charAt(i) == '=') {
+ pad++;
+ }
+ }
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IALPHABET[str.charAt(s++)];
+ if (c >= 0) {
+ i |= c << (18 - j * 6);
+ } else {
+ j--;
+ }
+ }
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++] = (byte) (i >> 8);
+ if (d < len) {
+ dArr[d++] = (byte) i;
+ }
+ }
+ }
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link #decode(String)}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ *
+ * @param s The source string. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ *
+ public final byte[] decodeFast(String s) {
+
+ // Check special case
+ int sLen = s.length();
+ if (sLen == 0) {
+ return new byte[0];
+ }
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IALPHABET[s.charAt(sIx) & 0xff] < 0) {
+ sIx++;
+ }
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IALPHABET[s.charAt(eIx) & 0xff] < 0) {
+ eIx--;
+ }
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IALPHABET[s.charAt(sIx++)] << 18 | IALPHABET[s.charAt(sIx++)] << 12 | IALPHABET[s.charAt(sIx++)] << 6 | IALPHABET[s.charAt(sIx++)];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++) {
+ i |= IALPHABET[s.charAt(sIx++)] << (18 - j * 6);
+ }
+
+ for (int r = 16; d < len; r -= 8) {
+ dArr[d++] = (byte) (i >> r);
+ }
+ }
+
+ return dArr;
+ }
+ */
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Decoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Decoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Decoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import io.jsonwebtoken.lang.Assert;
+
+/**
+ * @since 0.10.0
+ */
+class Base64Decoder extends Base64Support implements Decoder {
+
+ Base64Decoder() {
+ super(Base64.DEFAULT);
+ }
+
+ Base64Decoder(Base64 base64) {
+ super(base64);
+ }
+
+ @Override
+ public byte[] decode(String s) throws DecodingException {
+ Assert.notNull(s, "String argument cannot be null");
+ return this.base64.decodeFast(s.toCharArray());
+ }
+}
\ No newline at end of file
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Encoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Encoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Encoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import io.jsonwebtoken.lang.Assert;
+
+/**
+ * @since 0.10.0
+ */
+class Base64Encoder extends Base64Support implements Encoder {
+
+ Base64Encoder() {
+ super(Base64.DEFAULT);
+ }
+
+ Base64Encoder(Base64 base64) {
+ super(base64);
+ }
+
+ @Override
+ public String encode(byte[] bytes) throws EncodingException {
+ Assert.notNull(bytes, "byte array argument cannot be null");
+ return this.base64.encodeToString(bytes, false);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Support.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Support.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64Support.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import io.jsonwebtoken.lang.Assert;
+
+/**
+ * @since 0.10.0
+ */
+class Base64Support {
+
+ protected final Base64 base64;
+
+ Base64Support(Base64 base64) {
+ Assert.notNull(base64, "Base64 argument cannot be null");
+ this.base64 = base64;
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64UrlDecoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64UrlDecoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64UrlDecoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+class Base64UrlDecoder extends Base64Decoder {
+
+ Base64UrlDecoder() {
+ super(Base64.URL_SAFE);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64UrlEncoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64UrlEncoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Base64UrlEncoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+class Base64UrlEncoder extends Base64Encoder {
+
+ Base64UrlEncoder() {
+ super(Base64.URL_SAFE);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/CodecException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/CodecException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/CodecException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public class CodecException extends IOException {
+
+ public CodecException(String message) {
+ super(message);
+ }
+
+ public CodecException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Decoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Decoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Decoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public interface Decoder {
+
+ R decode(T t) throws DecodingException;
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Decoders.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Decoders.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Decoders.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public final class Decoders {
+
+ public static final Decoder BASE64 = new ExceptionPropagatingDecoder<>(new Base64Decoder());
+ public static final Decoder BASE64URL = new ExceptionPropagatingDecoder<>(new Base64UrlDecoder());
+
+ private Decoders() { //prevent instantiation
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/DecodingException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/DecodingException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/DecodingException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public class DecodingException extends CodecException {
+
+ public DecodingException(String message) {
+ super(message);
+ }
+
+ public DecodingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/DeserializationException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/DeserializationException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/DeserializationException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public class DeserializationException extends SerialException {
+
+ public DeserializationException(String msg) {
+ super(msg);
+ }
+
+ public DeserializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Deserializer.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Deserializer.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Deserializer.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public interface Deserializer {
+
+ T deserialize(byte[] bytes) throws DeserializationException;
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Encoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Encoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Encoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public interface Encoder {
+
+ R encode(T t) throws EncodingException;
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Encoders.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Encoders.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Encoders.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public final class Encoders {
+
+ public static final Encoder BASE64 = new ExceptionPropagatingEncoder<>(new Base64Encoder());
+ public static final Encoder BASE64URL = new ExceptionPropagatingEncoder<>(new Base64UrlEncoder());
+
+ private Encoders() { //prevent instantiation
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/EncodingException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/EncodingException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/EncodingException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public class EncodingException extends CodecException {
+
+ public EncodingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/ExceptionPropagatingDecoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/ExceptionPropagatingDecoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/ExceptionPropagatingDecoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import io.jsonwebtoken.lang.Assert;
+
+/**
+ * @since 0.10.0
+ */
+class ExceptionPropagatingDecoder implements Decoder {
+
+ private final Decoder decoder;
+
+ ExceptionPropagatingDecoder(Decoder decoder) {
+ Assert.notNull(decoder, "Decoder cannot be null.");
+ this.decoder = decoder;
+ }
+
+ @Override
+ public R decode(T t) throws DecodingException {
+ Assert.notNull(t, "Decode argument cannot be null.");
+ try {
+ return decoder.decode(t);
+ } catch (DecodingException e) {
+ throw e; //propagate
+ } catch (Exception e) {
+ String msg = "Unable to decode input: " + e.getMessage();
+ throw new DecodingException(msg, e);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/ExceptionPropagatingEncoder.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/ExceptionPropagatingEncoder.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/ExceptionPropagatingEncoder.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import io.jsonwebtoken.lang.Assert;
+
+/**
+ * @since 0.10.0
+ */
+class ExceptionPropagatingEncoder implements Encoder {
+
+ private final Encoder encoder;
+
+ ExceptionPropagatingEncoder(Encoder encoder) {
+ Assert.notNull(encoder, "Encoder cannot be null.");
+ this.encoder = encoder;
+ }
+
+ @Override
+ public R encode(T t) throws EncodingException {
+ Assert.notNull(t, "Encode argument cannot be null.");
+ try {
+ return this.encoder.encode(t);
+ } catch (EncodingException e) {
+ throw e; //propagate
+ } catch (Exception e) {
+ String msg = "Unable to encode input: " + e.getMessage();
+ throw new EncodingException(msg, e);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/IOException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/IOException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/IOException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+import io.jsonwebtoken.JwtException;
+
+/**
+ * @since 0.10.0
+ */
+public class IOException extends JwtException {
+
+ public IOException(String msg) {
+ super(msg);
+ }
+
+ public IOException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/SerialException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/SerialException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/SerialException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public class SerialException extends IOException {
+
+ public SerialException(String msg) {
+ super(msg);
+ }
+
+ public SerialException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/SerializationException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/SerializationException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/SerializationException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public class SerializationException extends SerialException {
+
+ public SerializationException(String msg) {
+ super(msg);
+ }
+
+ public SerializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Serializer.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Serializer.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/io/Serializer.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.io;
+
+/**
+ * @since 0.10.0
+ */
+public interface Serializer {
+
+ byte[] serialize(T t) throws SerializationException;
+
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/jackson/io/JacksonDeserializer.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/jackson/io/JacksonDeserializer.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/jackson/io/JacksonDeserializer.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.jackson.io;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import io.jsonwebtoken.io.DeserializationException;
+import io.jsonwebtoken.io.Deserializer;
+import io.jsonwebtoken.lang.Assert;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * @since 0.10.0
+ */
+public class JacksonDeserializer implements Deserializer {
+
+ private final Class returnType;
+ private final ObjectMapper objectMapper;
+
+ @SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
+ public JacksonDeserializer() {
+ this(JacksonSerializer.DEFAULT_OBJECT_MAPPER);
+ }
+
+ /**
+ * Creates a new JacksonDeserializer where the values of the claims can be parsed into given types. A common usage
+ * example is to parse custom User object out of a claim, for example the claims:
+ * {@code
+ * {
+ * "issuer": "https://issuer.example.com",
+ * "user": {
+ * "firstName": "Jill",
+ * "lastName": "Coder"
+ * }
+ * }}
+ * Passing a map of {@code ["user": User.class]} to this constructor would result in the {@code user} claim being
+ * transformed to an instance of your custom {@code User} class, instead of the default of {@code Map}.
+ *
+ * Because custom type parsing requires modifying the state of a Jackson {@code ObjectMapper}, this
+ * constructor creates a new internal {@code ObjectMapper} instance and customizes it to support the
+ * specified {@code claimTypeMap}. This ensures that the JJWT parsing behavior does not unexpectedly
+ * modify the state of another application-specific {@code ObjectMapper}.
+ *
+ * If you would like to use your own {@code ObjectMapper} instance that also supports custom types for
+ * JWT {@code Claims}, you will need to first customize your {@code ObjectMapper} instance by registering
+ * your custom types and then use the {@link #JacksonDeserializer(ObjectMapper)} constructor instead.
+ *
+ * @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
+ */
+ public JacksonDeserializer(Map claimTypeMap) {
+ // DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
+ // between instances
+ this(new ObjectMapper());
+ Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
+ // register a new Deserializer
+ SimpleModule module = new SimpleModule();
+ module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
+ objectMapper.registerModule(module);
+ }
+
+ @SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper
+ public JacksonDeserializer(ObjectMapper objectMapper) {
+ this(objectMapper, (Class) Object.class);
+ }
+
+ private JacksonDeserializer(ObjectMapper objectMapper, Class returnType) {
+ Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
+ Assert.notNull(returnType, "Return type cannot be null.");
+ this.objectMapper = objectMapper;
+ this.returnType = returnType;
+ }
+
+ @Override
+ public T deserialize(byte[] bytes) throws DeserializationException {
+ try {
+ return readValue(bytes);
+ } catch (IOException e) {
+ String msg = "Unable to deserialize bytes into a " + returnType.getName() + " instance: " + e.getMessage();
+ throw new DeserializationException(msg, e);
+ }
+ }
+
+ protected T readValue(byte[] bytes) throws IOException {
+ return objectMapper.readValue(bytes, returnType);
+ }
+
+ /**
+ * A Jackson {@link com.fasterxml.jackson.databind.JsonDeserializer JsonDeserializer}, that will convert claim
+ * values to types based on {@code claimTypeMap}.
+ */
+ private static class MappedTypeDeserializer extends UntypedObjectDeserializer {
+
+ private final Map claimTypeMap;
+
+ private MappedTypeDeserializer(Map claimTypeMap) {
+ super(null, null);
+ this.claimTypeMap = claimTypeMap;
+ }
+
+ @Override
+ public Object deserialize(JsonParser parser, DeserializationContext context) throws IOException {
+ // check if the current claim key is mapped, if so traverse it's value
+ String name = parser.currentName();
+ if (claimTypeMap != null && name != null && claimTypeMap.containsKey(name)) {
+ Class type = claimTypeMap.get(name);
+ return parser.readValueAsTree().traverse(parser.getCodec()).readValueAs(type);
+ }
+ // otherwise default to super
+ return super.deserialize(parser, context);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/jackson/io/JacksonSerializer.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/jackson/io/JacksonSerializer.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/jackson/io/JacksonSerializer.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.jackson.io;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.jsonwebtoken.io.SerializationException;
+import io.jsonwebtoken.io.Serializer;
+import io.jsonwebtoken.lang.Assert;
+
+/**
+ * @since 0.10.0
+ */
+public class JacksonSerializer implements Serializer {
+
+ static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper();
+
+ private final ObjectMapper objectMapper;
+
+ @SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
+ public JacksonSerializer() {
+ this(DEFAULT_OBJECT_MAPPER);
+ }
+
+ @SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom ObjectMapper
+ public JacksonSerializer(ObjectMapper objectMapper) {
+ Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public byte[] serialize(T t) throws SerializationException {
+ Assert.notNull(t, "Object to serialize cannot be null.");
+ try {
+ return writeValueAsBytes(t);
+ } catch (JsonProcessingException e) {
+ String msg = "Unable to serialize object: " + e.getMessage();
+ throw new SerializationException(msg, e);
+ }
+ }
+
+ @SuppressWarnings("WeakerAccess") //for testing
+ protected byte[] writeValueAsBytes(T t) throws JsonProcessingException {
+ return this.objectMapper.writeValueAsBytes(t);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Arrays.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Arrays.java (.../Arrays.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Arrays.java (.../Arrays.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -1,15 +1,27 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package io.jsonwebtoken.lang;
/**
* @since 0.6
*/
public final class Arrays {
- //for code coverage
- private static final Arrays INSTANCE = new Arrays();
+ private Arrays(){} //prevent instantiation
- private Arrays(){}
-
public static int length(byte[] bytes) {
return bytes != null ? bytes.length : 0;
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Assert.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Assert.java (.../Assert.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Assert.java (.../Assert.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -20,11 +20,8 @@
public final class Assert {
- //for code coverage
- private static final Assert INSTANCE = new Assert();
+ private Assert(){} //prevent instantiation
- private Assert(){}
-
/**
* Assert a boolean expression, throwing IllegalArgumentException
* if the test result is false
.
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Classes.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Classes.java (.../Classes.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Classes.java (.../Classes.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -17,16 +17,15 @@
import java.io.InputStream;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
/**
* @since 0.1
*/
public final class Classes {
- private static final Classes INSTANCE = new Classes();
+ private Classes() {} //prevent instantiation
- private Classes() {}
-
/**
* @since 0.1
*/
@@ -69,7 +68,8 @@
* @return the located class
* @throws UnknownClassException if the class cannot be found.
*/
- public static Class forName(String fqcn) throws UnknownClassException {
+ @SuppressWarnings("unchecked")
+ public static Class forName(String fqcn) throws UnknownClassException {
Class clazz = THREAD_CL_ACCESSOR.loadClass(fqcn);
@@ -85,8 +85,8 @@
String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or " +
"system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.";
- if (fqcn != null && fqcn.startsWith("com.stormpath.sdk.impl")) {
- msg += " Have you remembered to include the stormpath-sdk-impl .jar in your runtime classpath?";
+ if (fqcn != null && fqcn.startsWith("io.jsonwebtoken.impl")) {
+ msg += " Have you remembered to include the jjwt-impl.jar in your runtime classpath?";
}
throw new UnknownClassException(msg);
@@ -132,13 +132,19 @@
}
@SuppressWarnings("unchecked")
- public static Object newInstance(String fqcn) {
- return newInstance(forName(fqcn));
+ public static T newInstance(String fqcn) {
+ return (T)newInstance(forName(fqcn));
}
+ public static T newInstance(String fqcn, Class[] ctorArgTypes, Object... args) {
+ Class clazz = forName(fqcn);
+ Constructor ctor = getConstructor(clazz, ctorArgTypes);
+ return instantiate(ctor, args);
+ }
+
@SuppressWarnings("unchecked")
- public static Object newInstance(String fqcn, Object... args) {
- return newInstance(forName(fqcn), args);
+ public static T newInstance(String fqcn, Object... args) {
+ return (T)newInstance(forName(fqcn), args);
}
public static T newInstance(Class clazz) {
@@ -181,6 +187,23 @@
}
/**
+ * @since 0.10.0
+ */
+ @SuppressWarnings("unchecked")
+ public static T invokeStatic(String fqcn, String methodName, Class[] argTypes, Object... args) {
+ try {
+ Class clazz = Classes.forName(fqcn);
+ Method method = clazz.getDeclaredMethod(methodName, argTypes);
+ method.setAccessible(true);
+ return(T)method.invoke(null, args);
+ } catch (Exception e) {
+ String msg = "Unable to invoke class method " + fqcn + "#" + methodName + ". Ensure the necessary " +
+ "implementation is in the runtime classpath.";
+ throw new IllegalStateException(msg, e);
+ }
+ }
+
+ /**
* @since 1.0
*/
private static interface ClassLoaderAccessor {
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Collections.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Collections.java (.../Collections.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Collections.java (.../Collections.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -26,11 +26,8 @@
public final class Collections {
- //for code coverage
- private static final Collections INSTANCE = new Collections();
+ private Collections(){} //prevent instantiation
- private Collections(){}
-
/**
* Return true
if the supplied Collection is null
* or empty. Otherwise, return false
.
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/DateFormats.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/DateFormats.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/DateFormats.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.lang;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @since 0.10.0
+ */
+public class DateFormats {
+
+ private static final String ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+
+ private static final String ISO_8601_MILLIS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+
+ private static final ThreadLocal ISO_8601 = new ThreadLocal() {
+ @Override
+ protected DateFormat initialValue() {
+ SimpleDateFormat format = new SimpleDateFormat(ISO_8601_PATTERN);
+ format.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return format;
+ }
+ };
+
+ private static final ThreadLocal ISO_8601_MILLIS = new ThreadLocal() {
+ @Override
+ protected DateFormat initialValue() {
+ SimpleDateFormat format = new SimpleDateFormat(ISO_8601_MILLIS_PATTERN);
+ format.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return format;
+ }
+ };
+
+ public static String formatIso8601(Date date) {
+ return formatIso8601(date, true);
+ }
+
+ public static String formatIso8601(Date date, boolean includeMillis) {
+ if (includeMillis) {
+ return ISO_8601_MILLIS.get().format(date);
+ }
+ return ISO_8601.get().format(date);
+ }
+
+ public static Date parseIso8601Date(String s) throws ParseException {
+ Assert.notNull(s, "String argument cannot be null.");
+ if (s.lastIndexOf('.') > -1) { //assume ISO-8601 with milliseconds
+ return ISO_8601_MILLIS.get().parse(s);
+ } else { //assume ISO-8601 without millis:
+ return ISO_8601.get().parse(s);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Maps.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Maps.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Maps.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.lang;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class to help with the manipulation of working with Maps.
+ * @since 0.11.0
+ */
+public final class Maps {
+
+ private Maps() {} //prevent instantiation
+
+ /**
+ * Creates a new map builder with a single entry.
+ * Typical usage:
{@code
+ * Map result = Maps.of("key1", value1)
+ * .and("key2", value2)
+ * // ...
+ * .build();
+ * }
+ * @param key the key of an map entry to be added
+ * @param value the value of map entry to be added
+ * @param the maps key type
+ * @param the maps value type
+ * Creates a new map builder with a single entry.
+ */
+ public static MapBuilder of(K key, V value) {
+ return new HashMapBuilder().and(key, value);
+ }
+
+ /**
+ * Utility Builder class for fluently building maps:
+ * Typical usage:
{@code
+ * Map result = Maps.of("key1", value1)
+ * .and("key2", value2)
+ * // ...
+ * .build();
+ * }
+ * @param the maps key type
+ * @param the maps value type
+ */
+ public interface MapBuilder {
+ /**
+ * Add a new entry to this map builder
+ * @param key the key of an map entry to be added
+ * @param value the value of map entry to be added
+ * @return the current MapBuilder to allow for method chaining.
+ */
+ MapBuilder and(K key, V value);
+
+ /**
+ * Returns a the resulting Map object from this MapBuilder.
+ * @return Returns a the resulting Map object from this MapBuilder.
+ */
+ Map build();
+ }
+
+ private static class HashMapBuilder implements MapBuilder {
+
+ private final Map data = new HashMap<>();
+
+ public MapBuilder and(K key, V value) {
+ data.put(key, value);
+ return this;
+ }
+ public Map build() {
+ return Collections.unmodifiableMap(data);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Objects.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Objects.java (.../Objects.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Objects.java (.../Objects.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -22,11 +22,8 @@
public final class Objects {
- //for code coverage
- private static final Objects INSTANCE = new Objects();
+ private Objects(){} //prevent instantiation
- private Objects(){}
-
private static final int INITIAL_HASH = 7;
private static final int MULTIPLIER = 31;
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/RuntimeEnvironment.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/RuntimeEnvironment.java (.../RuntimeEnvironment.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/RuntimeEnvironment.java (.../RuntimeEnvironment.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -21,10 +21,8 @@
public final class RuntimeEnvironment {
- private static final RuntimeEnvironment INSTANCE = new RuntimeEnvironment();
+ private RuntimeEnvironment(){} //prevent instantiation
- private RuntimeEnvironment(){}
-
private static final String BC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider";
private static final AtomicBoolean bcLoaded = new AtomicBoolean(false);
@@ -33,7 +31,7 @@
public static void enableBouncyCastleIfPossible() {
- if (bcLoaded.get()) {
+ if (!BOUNCY_CASTLE_AVAILABLE || bcLoaded.get()) {
return;
}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Strings.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Strings.java (.../Strings.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Strings.java (.../Strings.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -31,8 +31,6 @@
public final class Strings {
- private static final Strings INSTANCE = new Strings(); //for code coverage
-
private static final String FOLDER_SEPARATOR = "/";
private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
@@ -45,7 +43,7 @@
public static final Charset UTF_8 = Charset.forName("UTF-8");
- private Strings(){}
+ private Strings(){} //prevent instantiation
//---------------------------------------------------------------------
// General convenience methods for working with Strings
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/UnknownClassException.java
===================================================================
diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/UnknownClassException.java (.../UnknownClassException.java) (revision dd64f16fdf89f789b8c2179d421290dcabf15835)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/UnknownClassException.java (.../UnknownClassException.java) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -48,16 +48,17 @@
public UnknownClassException(Throwable cause) {
super(cause);
}
+ */
/**
* Constructs a new UnknownClassException.
*
* @param message the reason for the exception
* @param cause the underlying Throwable that caused this exception to be thrown.
- *
+ */
public UnknownClassException(String message, Throwable cause) {
+ // TODO: remove in v1.0, this constructor is only exposed to allow for backward compatible behavior
super(message, cause);
}
- */
}
\ No newline at end of file
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/InvalidKeyException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/InvalidKeyException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/InvalidKeyException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.security;
+
+/**
+ * @since 0.10.0
+ */
+public class InvalidKeyException extends KeyException {
+
+ public InvalidKeyException(String message) {
+ super(message);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/KeyException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/KeyException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/KeyException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.security;
+
+/**
+ * @since 0.10.0
+ */
+public class KeyException extends SecurityException {
+
+ public KeyException(String message) {
+ super(message);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/Keys.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/Keys.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/Keys.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.security;
+
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.lang.Assert;
+import io.jsonwebtoken.lang.Classes;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.KeyPair;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility class for securely generating {@link SecretKey}s and {@link KeyPair}s.
+ *
+ * @since 0.10.0
+ */
+public final class Keys {
+
+ private static final String MAC = "io.jsonwebtoken.impl.crypto.MacProvider";
+ private static final String RSA = "io.jsonwebtoken.impl.crypto.RsaProvider";
+ private static final String EC = "io.jsonwebtoken.impl.crypto.EllipticCurveProvider";
+
+ private static final Class[] SIG_ARG_TYPES = new Class[]{SignatureAlgorithm.class};
+
+ //purposefully ordered higher to lower:
+ private static final List PREFERRED_HMAC_ALGS = Collections.unmodifiableList(Arrays.asList(
+ SignatureAlgorithm.HS512, SignatureAlgorithm.HS384, SignatureAlgorithm.HS256));
+
+ //prevent instantiation
+ private Keys() {
+ }
+
+ /*
+ public static final int bitLength(Key key) throws IllegalArgumentException {
+ Assert.notNull(key, "Key cannot be null.");
+ if (key instanceof SecretKey) {
+ byte[] encoded = key.getEncoded();
+ return Arrays.length(encoded) * 8;
+ } else if (key instanceof RSAKey) {
+ return ((RSAKey)key).getModulus().bitLength();
+ } else if (key instanceof ECKey) {
+ return ((ECKey)key).getParams().getOrder().bitLength();
+ }
+
+ throw new IllegalArgumentException("Unsupported key type: " + key.getClass().getName());
+ }
+ */
+
+ /**
+ * Creates a new SecretKey instance for use with HMAC-SHA algorithms based on the specified key byte array.
+ *
+ * @param bytes the key byte array
+ * @return a new SecretKey instance for use with HMAC-SHA algorithms based on the specified key byte array.
+ * @throws WeakKeyException if the key byte array length is less than 256 bits (32 bytes) as mandated by the
+ * JWT JWA Specification
+ * (RFC 7518, Section 3.2)
+ */
+ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException {
+
+ if (bytes == null) {
+ throw new InvalidKeyException("SecretKey byte array cannot be null.");
+ }
+
+ int bitLength = bytes.length * 8;
+
+ for (SignatureAlgorithm alg : PREFERRED_HMAC_ALGS) {
+ if (bitLength >= alg.getMinKeyLength()) {
+ return new SecretKeySpec(bytes, alg.getJcaName());
+ }
+ }
+
+ String msg = "The specified key byte array is " + bitLength + " bits which " +
+ "is not secure enough for any JWT HMAC-SHA algorithm. The JWT " +
+ "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " +
+ "size >= 256 bits (the key size must be greater than or equal to the hash " +
+ "output size). Consider using the " + Keys.class.getName() + "#secretKeyFor(SignatureAlgorithm) method " +
+ "to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm. See " +
+ "https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
+ throw new WeakKeyException(msg);
+ }
+
+ /**
+ * Returns a new {@link SecretKey} with a key length suitable for use with the specified {@link SignatureAlgorithm}.
+ *
+ * JWA Specification (RFC 7518), Section 3.2
+ * requires minimum key lengths to be used for each respective Signature Algorithm. This method returns a
+ * secure-random generated SecretKey that adheres to the required minimum key length. The lengths are:
+ *
+ *
+ *
+ * Algorithm
+ * Key Length
+ *
+ *
+ * HS256
+ * 256 bits (32 bytes)
+ *
+ *
+ * HS384
+ * 384 bits (48 bytes)
+ *
+ *
+ * HS512
+ * 512 bits (64 bytes)
+ *
+ *
+ *
+ * @param alg the {@code SignatureAlgorithm} to inspect to determine which key length to use.
+ * @return a new {@link SecretKey} instance suitable for use with the specified {@link SignatureAlgorithm}.
+ * @throws IllegalArgumentException for any input value other than {@link SignatureAlgorithm#HS256},
+ * {@link SignatureAlgorithm#HS384}, or {@link SignatureAlgorithm#HS512}
+ */
+ public static SecretKey secretKeyFor(SignatureAlgorithm alg) throws IllegalArgumentException {
+ Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
+ switch (alg) {
+ case HS256:
+ case HS384:
+ case HS512:
+ return Classes.invokeStatic(MAC, "generateKey", SIG_ARG_TYPES, alg);
+ default:
+ String msg = "The " + alg.name() + " algorithm does not support shared secret keys.";
+ throw new IllegalArgumentException(msg);
+ }
+ }
+
+ /**
+ * Returns a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
+ *
+ * If the {@code alg} argument is an RSA algorithm, a KeyPair is generated based on the following:
+ *
+ *
+ *
+ * JWA Algorithm
+ * Key Size
+ *
+ *
+ * RS256
+ * 2048 bits
+ *
+ *
+ * PS256
+ * 2048 bits
+ *
+ *
+ * RS384
+ * 3072 bits
+ *
+ *
+ * PS384
+ * 3072 bits
+ *
+ *
+ * RS512
+ * 4096 bits
+ *
+ *
+ * PS512
+ * 4096 bits
+ *
+ *
+ *
+ * If the {@code alg} argument is an Elliptic Curve algorithm, a KeyPair is generated based on the following:
+ *
+ *
+ *
+ * JWA Algorithm
+ * Key Size
+ * JWA Curve Name
+ * ASN1 OID Curve Name
+ *
+ *
+ * EC256
+ * 256 bits
+ * {@code P-256}
+ * {@code secp256r1}
+ *
+ *
+ * EC384
+ * 384 bits
+ * {@code P-384}
+ * {@code secp384r1}
+ *
+ *
+ * EC512
+ * 512 bits
+ * {@code P-521}
+ * {@code secp521r1}
+ *
+ *
+ *
+ * @param alg the {@code SignatureAlgorithm} to inspect to determine which asymmetric algorithm to use.
+ * @return a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
+ * @throws IllegalArgumentException if {@code alg} is not an asymmetric algorithm
+ */
+ public static KeyPair keyPairFor(SignatureAlgorithm alg) throws IllegalArgumentException {
+ Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
+ switch (alg) {
+ case RS256:
+ case PS256:
+ case RS384:
+ case PS384:
+ case RS512:
+ case PS512:
+ return Classes.invokeStatic(RSA, "generateKeyPair", SIG_ARG_TYPES, alg);
+ case ES256:
+ case ES384:
+ case ES512:
+ return Classes.invokeStatic(EC, "generateKeyPair", SIG_ARG_TYPES, alg);
+ default:
+ String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
+ throw new IllegalArgumentException(msg);
+ }
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/SecurityException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/SecurityException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/SecurityException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.security;
+
+import io.jsonwebtoken.JwtException;
+
+/**
+ * @since 0.10.0
+ */
+public class SecurityException extends JwtException {
+
+ public SecurityException(String message) {
+ super(message);
+ }
+
+ public SecurityException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/SignatureException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/SignatureException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/SignatureException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.security;
+
+/**
+ * @since 0.10.0
+ */
+public class SignatureException extends io.jsonwebtoken.SignatureException {
+
+ public SignatureException(String message) {
+ super(message);
+ }
+
+ public SignatureException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/WeakKeyException.java
===================================================================
diff -u
--- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/WeakKeyException.java (revision 0)
+++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/security/WeakKeyException.java (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.security;
+
+/**
+ * @since 0.10.0
+ */
+public class WeakKeyException extends InvalidKeyException {
+
+ public WeakKeyException(String message) {
+ super(message);
+ }
+}
Index: 3rdParty_sources/versions.txt
===================================================================
diff -u -r22d20e45f4a7cbb2a9477c66f75e2a162b0d3f06 -r0761df64c22d4bca1649836fda23e4526282498b
--- 3rdParty_sources/versions.txt (.../versions.txt) (revision 22d20e45f4a7cbb2a9477c66f75e2a162b0d3f06)
+++ 3rdParty_sources/versions.txt (.../versions.txt) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -39,7 +39,7 @@
jLaTexMath 1.0.6
-jsonwebtoken 0.9.0
+jsonwebtoken 0.11.2
JSP API 2.3 1.0.3
Index: lams_build/3rdParty.userlibraries
===================================================================
diff -u -r8ba50cf0cbd248f016f5827b4dfd2d8a16b3d80e -r0761df64c22d4bca1649836fda23e4526282498b
--- lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 8ba50cf0cbd248f016f5827b4dfd2d8a16b3d80e)
+++ lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -23,7 +23,6 @@
-
@@ -45,5 +44,8 @@
+
+
+
Index: lams_build/lib/json/jjwt-0.9.0.jar
===================================================================
diff -u -r33d7aa31deb6606940bcd51544b17d62387777cf -r0761df64c22d4bca1649836fda23e4526282498b
Binary files differ
Index: lams_build/lib/json/jjwt-api-0.11.2.jar
===================================================================
diff -u
Binary files differ
Index: lams_build/lib/json/jjwt-impl-0.11.2.jar
===================================================================
diff -u
Binary files differ
Index: lams_build/lib/json/jjwt-jackson-0.11.2.jar
===================================================================
diff -u
Binary files differ
Index: lams_build/lib/json/jjwt.module.xml
===================================================================
diff -u -r33d7aa31deb6606940bcd51544b17d62387777cf -r0761df64c22d4bca1649836fda23e4526282498b
--- lams_build/lib/json/jjwt.module.xml (.../jjwt.module.xml) (revision 33d7aa31deb6606940bcd51544b17d62387777cf)
+++ lams_build/lib/json/jjwt.module.xml (.../jjwt.module.xml) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -24,7 +24,9 @@
-
+
+
+
Index: lams_build/liblist.txt
===================================================================
diff -u -r8ba50cf0cbd248f016f5827b4dfd2d8a16b3d80e -r0761df64c22d4bca1649836fda23e4526282498b
--- lams_build/liblist.txt (.../liblist.txt) (revision 8ba50cf0cbd248f016f5827b4dfd2d8a16b3d80e)
+++ lams_build/liblist.txt (.../liblist.txt) (revision 0761df64c22d4bca1649836fda23e4526282498b)
@@ -48,7 +48,9 @@
json-simple json-simple-1.1.1.jar 1.1.1 Apache License 2.0 fangyidong A simple Java toolkit for JSON
-jsonwebtoken jjwt-0.9.0.jar 0.9.0 JWTK Apache
+jsonwebtoken jjwt-api-0.11.2.jar 0.11.2 JWTK Apache
+ jjwt-impl-0.11.2.jar
+ jjwt-jackson-0.11.2.jar
kotlin-stdlib kotlin-stdlib-1.3.11.jar 1.3.11 Apache License 2.0 JetBrains Kotlin runtime