Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ClaimJwtException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ClaimJwtException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ClaimJwtException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,51 @@ +/* + * 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; + +/** + * ClaimJwtException is a subclass of the {@link JwtException} that is thrown after a validation of an JTW claim failed. + * + * @since 0.5 + */ +public abstract class ClaimJwtException extends JwtException { + + public static final String INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was: %s."; + public static final String MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was not present in the JWT claims."; + + private final Header header; + + private final Claims claims; + + protected ClaimJwtException(Header header, Claims claims, String message) { + super(message); + this.header = header; + this.claims = claims; + } + + protected ClaimJwtException(Header header, Claims claims, String message, Throwable cause) { + super(message, cause); + this.header = header; + this.claims = claims; + } + + public Claims getClaims() { + return claims; + } + + public Header getHeader() { + return header; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Claims.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Claims.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Claims.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,174 @@ +/* + * 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; + +import java.util.Date; +import java.util.Map; + +/** + * A JWT Claims set. + * + *

This is ultimately a JSON map and any values can be added to it, but JWT standard names are provided as + * type-safe getters and setters for convenience.

+ * + *

Because this interface extends {@code Map<String, Object>}, if you would like to add your own properties, + * you simply use map methods, for example:

+ * + *
+ * claims.{@link Map#put(Object, Object) put}("someKey", "someValue");
+ * 
+ * + *

Creation

+ * + *

It is easiest to create a {@code Claims} instance by calling one of the + * {@link Jwts#claims() JWTs.claims()} factory methods.

+ * + * @since 0.1 + */ +public interface Claims extends Map, ClaimsMutator { + + /** JWT {@code Issuer} claims parameter name: "iss" */ + public static final String ISSUER = "iss"; + + /** JWT {@code Subject} claims parameter name: "sub" */ + public static final String SUBJECT = "sub"; + + /** JWT {@code Audience} claims parameter name: "aud" */ + public static final String AUDIENCE = "aud"; + + /** JWT {@code Expiration} claims parameter name: "exp" */ + public static final String EXPIRATION = "exp"; + + /** JWT {@code Not Before} claims parameter name: "nbf" */ + public static final String NOT_BEFORE = "nbf"; + + /** JWT {@code Issued At} claims parameter name: "iat" */ + public static final String ISSUED_AT = "iat"; + + /** JWT {@code JWT ID} claims parameter name: "jti" */ + public static final String ID = "jti"; + + /** + * Returns the JWT + * iss (issuer) value or {@code null} if not present. + * + * @return the JWT {@code iss} value or {@code null} if not present. + */ + String getIssuer(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setIssuer(String iss); + + /** + * Returns the JWT + * sub (subject) value or {@code null} if not present. + * + * @return the JWT {@code sub} value or {@code null} if not present. + */ + String getSubject(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setSubject(String sub); + + /** + * Returns the JWT + * aud (audience) value or {@code null} if not present. + * + * @return the JWT {@code aud} value or {@code null} if not present. + */ + String getAudience(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setAudience(String aud); + + /** + * Returns the JWT + * exp (expiration) timestamp or {@code null} if not present. + * + *

A JWT obtained after this timestamp should not be used.

+ * + * @return the JWT {@code exp} value or {@code null} if not present. + */ + Date getExpiration(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setExpiration(Date exp); + + /** + * Returns the JWT + * nbf (not before) timestamp or {@code null} if not present. + * + *

A JWT obtained before this timestamp should not be used.

+ * + * @return the JWT {@code nbf} value or {@code null} if not present. + */ + Date getNotBefore(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setNotBefore(Date nbf); + + /** + * Returns the JWT + * iat (issued at) timestamp or {@code null} if not present. + * + *

If present, this value is the timestamp when the JWT was created.

+ * + * @return the JWT {@code nbf} value or {@code null} if not present. + */ + Date getIssuedAt(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setIssuedAt(Date iat); + + /** + * Returns the JWTs + * jti (JWT ID) value or {@code null} if not present. + * + *

This value is a CaSe-SenSiTiVe unique identifier for the JWT. If available, this value is expected to be + * assigned in a manner that ensures that there is a negligible probability that the same value will be + * accidentally + * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

+ * + * @return the JWT {@code jti} value or {@code null} if not present. + */ + String getId(); + + /** + * {@inheritDoc} + */ + @Override //only for better/targeted JavaDoc + Claims setId(String jti); + + T get(String claimName, Class requiredType); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ClaimsMutator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ClaimsMutator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ClaimsMutator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,102 @@ +/* + * 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; + +import java.util.Date; + +/** + * Mutation (modifications) to a {@link io.jsonwebtoken.Claims Claims} instance. + * + * @param the type of mutator + * @see io.jsonwebtoken.JwtBuilder + * @see io.jsonwebtoken.Claims + * @since 0.2 + */ +public interface ClaimsMutator { + + /** + * Sets the JWT + * iss (issuer) value. A {@code null} value will remove the property from the JSON map. + * + * @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setIssuer(String iss); + + /** + * Sets the JWT + * sub (subject) value. A {@code null} value will remove the property from the JSON map. + * + * @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setSubject(String sub); + + /** + * Sets the JWT + * aud (audience) value. A {@code null} value will remove the property from the JSON map. + * + * @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setAudience(String aud); + + /** + * Sets the JWT + * exp (expiration) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

A JWT obtained after this timestamp should not be used.

+ * + * @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setExpiration(Date exp); + + /** + * Sets the JWT + * nbf (not before) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

A JWT obtained before this timestamp should not be used.

+ * + * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setNotBefore(Date nbf); + + /** + * Sets the JWT + * iat (issued at) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

The value is the timestamp when the JWT was created.

+ * + * @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setIssuedAt(Date iat); + + /** + * Sets the JWT + * jti (JWT ID) value. A {@code null} value will remove the property from the JSON map. + * + *

This value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a + * manner that ensures that there is a negligible probability that the same value will be accidentally + * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

+ * + * @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + */ + T setId(String jti); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Clock.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Clock.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Clock.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,18 @@ +package io.jsonwebtoken; + +import java.util.Date; + +/** + * A clock represents a time source that can be used when creating and verifying JWTs. + * + * @since 0.7.0 + */ +public interface Clock { + + /** + * Returns the clock's current timestamp at the instant the method is invoked. + * + * @return the clock's current timestamp at the instant the method is invoked. + */ + Date now(); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 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; + +/** + * Compresses and decompresses byte arrays according to a compression algorithm. + * + * @see io.jsonwebtoken.impl.compression.DeflateCompressionCodec + * @see io.jsonwebtoken.impl.compression.GzipCompressionCodec + * @since 0.6.0 + */ +public interface CompressionCodec { + + /** + * The algorithm name to use as the JWT's {@code calg} header value. + * + * @return the algorithm name to use as the JWT's {@code calg} header value. + */ + String getAlgorithmName(); + + /** + * Compresses the specified byte array according to the compression {@link #getAlgorithmName() algorithm}. + * + * @param payload bytes to compress + * @return compressed bytes + * @throws CompressionException if the specified byte array cannot be compressed according to the compression + * {@link #getAlgorithmName() algorithm}. + */ + byte[] compress(byte[] payload) throws CompressionException; + + /** + * Decompresses the specified compressed byte array according to the compression + * {@link #getAlgorithmName() algorithm}. The specified byte array must already be in compressed form + * according to the {@link #getAlgorithmName() algorithm}. + * + * @param compressed compressed bytes + * @return decompressed bytes + * @throws CompressionException if the specified byte array cannot be decompressed according to the compression + * {@link #getAlgorithmName() algorithm}. + */ + byte[] decompress(byte[] compressed) throws CompressionException; +} \ No newline at end of file Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodecResolver.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodecResolver.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodecResolver.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 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; + +/** + * Looks for a JWT {@code calg} header, and if found, returns the corresponding {@link CompressionCodec} the parser + * can use to decompress the JWT body. + * + *

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 + * 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 when + * {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} and + * {@link io.jsonwebtoken.JwtParser#setCompressionCodecResolver(CompressionCodecResolver) parsing} JWTs.

+ * + * @since 0.6.0 + */ +public interface CompressionCodecResolver { + + /** + * Looks for a JWT {@code calg} header, and if found, returns the corresponding {@link CompressionCodec} the parser + * can use to decompress the JWT body. + * + * @param header of the JWT + * @return CompressionCodec matching the {@code calg} header, or null if there is no {@code calg} header. + * @throws CompressionException if a {@code calg} header value is found and not supported. + */ + CompressionCodec resolveCompressionCodec(Header header) throws CompressionException; + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodecs.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodecs.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionCodecs.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,34 @@ +package io.jsonwebtoken; + +import io.jsonwebtoken.impl.compression.DeflateCompressionCodec; +import io.jsonwebtoken.impl.compression.GzipCompressionCodec; + +/** + * Provides default implementations of the {@link CompressionCodec} interface. + * + * @see #DEFLATE + * @see #GZIP + * @since 0.7.0 + */ +public final class CompressionCodecs { + + private static final CompressionCodecs INSTANCE = new CompressionCodecs(); + + private CompressionCodecs() {} //prevent external instantiation + + /** + * Codec implementing the JWA standard + * deflate compression algorithm + */ + public static final CompressionCodec DEFLATE = new DeflateCompressionCodec(); + + /** + * Codec implementing the gzip compression algorithm. + *

Compatibility Warning

+ *

This is not a standard JWA compression algorithm. Be sure to use this only when you are confident + * that all parties accessing the token support the gzip algorithm.

+ *

If you're concerned about compatibility, the {@link #DEFLATE DEFLATE} code is JWA standards-compliant.

+ */ + public static final CompressionCodec GZIP = new GzipCompressionCodec(); + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/CompressionException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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; + +/** + * Exception indicating that either compressing or decompressing an JWT body failed. + * + * @since 0.6.0 + */ +public class CompressionException extends JwtException { + + public CompressionException(String message) { + super(message); + } + + public CompressionException(String message, Throwable cause) { + super(message, cause); + } + +} \ No newline at end of file Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ExpiredJwtException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ExpiredJwtException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/ExpiredJwtException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,39 @@ +/* + * 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; + +/** + * Exception indicating that a JWT was accepted after it expired and must be rejected. + * + * @since 0.3 + */ +public class ExpiredJwtException extends ClaimJwtException { + + public ExpiredJwtException(Header header, Claims claims, String message) { + super(header, claims, message); + } + + /** + * @param header jwt header + * @param claims jwt claims (body) + * @param message exception message + * @param cause cause + * @since 0.5 + */ + public ExpiredJwtException(Header header, Claims claims, String message, Throwable cause) { + super(header, claims, message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Header.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Header.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Header.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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; + +import java.util.Map; + +/** + * A JWT JOSE header. + * + *

This is ultimately a JSON map and any values can be added to it, but JWT JOSE standard names are provided as + * type-safe getters and setters for convenience.

+ * + *

Because this interface extends {@code Map<String, Object>}, if you would like to add your own properties, + * you simply use map methods, for example:

+ * + *
+ * header.{@link Map#put(Object, Object) put}("headerParamName", "headerParamValue");
+ * 
+ * + *

Creation

+ * + *

It is easiest to create a {@code Header} instance by calling one of the + * {@link Jwts#header() JWTs.header()} factory methods.

+ * + * @since 0.1 + */ +public interface Header> extends Map { + + /** JWT {@code Type} (typ) value: "JWT" */ + public static final String JWT_TYPE = "JWT"; + + /** JWT {@code Type} header parameter name: "typ" */ + public static final String TYPE = "typ"; + + /** JWT {@code Content Type} header parameter name: "cty" */ + public static final String CONTENT_TYPE = "cty"; + + /** JWT {@code Compression Algorithm} header parameter name: "zip" */ + public static final String COMPRESSION_ALGORITHM = "zip"; + + /** JJWT legacy/deprecated compression algorithm header parameter name: "calg" + * @deprecated use {@link #COMPRESSION_ALGORITHM} instead. */ + @Deprecated + public static final String DEPRECATED_COMPRESSION_ALGORITHM = "calg"; + + /** + * Returns the + * typ (type) header value or {@code null} if not present. + * + * @return the {@code typ} header value or {@code null} if not present. + */ + String getType(); + + /** + * Sets the JWT + * typ (Type) header value. A {@code null} value will remove the property from the JSON map. + * + * @param typ the JWT JOSE {@code typ} header value or {@code null} to remove the property from the JSON map. + * @return the {@code Header} instance for method chaining. + */ + T setType(String typ); + + /** + * Returns the + * cty (Content Type) header value or {@code null} if not present. + * + *

In the normal case where nested signing or encryption operations are not employed (i.e. a compact + * serialization JWT), the use of this header parameter is NOT RECOMMENDED. In the case that nested + * signing or encryption is employed, this Header Parameter MUST be present; in this case, the value MUST be + * {@code JWT}, to indicate that a Nested JWT is carried in this JWT. While media type names are not + * case-sensitive, it is RECOMMENDED that {@code JWT} always be spelled using uppercase characters for + * compatibility with legacy implementations. See + * JWT Appendix A.2 for + * an example of a Nested JWT.

+ * + * @return the {@code typ} header parameter value or {@code null} if not present. + */ + String getContentType(); + + /** + * Sets the JWT + * cty (Content Type) header parameter value. A {@code null} value will remove the property from + * the JSON map. + * + *

In the normal case where nested signing or encryption operations are not employed (i.e. a compact + * serialization JWT), the use of this header parameter is NOT RECOMMENDED. In the case that nested + * signing or encryption is employed, this Header Parameter MUST be present; in this case, the value MUST be + * {@code JWT}, to indicate that a Nested JWT is carried in this JWT. While media type names are not + * case-sensitive, it is RECOMMENDED that {@code JWT} always be spelled using uppercase characters for + * compatibility with legacy implementations. See + * JWT Appendix A.2 for + * an example of a Nested JWT.

+ * + * @param cty the JWT JOSE {@code cty} header value or {@code null} to remove the property from the JSON map. + */ + T setContentType(String cty); + + /** + * Returns the JWT calg (Compression Algorithm) header value or {@code null} if not present. + * + * @return the {@code calg} header parameter value or {@code null} if not present. + * @since 0.6.0 + */ + String getCompressionAlgorithm(); + + /** + * Sets the JWT calg (Compression Algorithm) header parameter value. A {@code null} value will remove + * the property from the JSON map. + *

+ *

The compression algorithm is NOT part of the JWT specification + * and must be used carefully since, is not expected that other libraries (including previous versions of this one) + * be able to deserialize a compressed JTW body correctly.

+ * + * @param calg the JWT compression algorithm {@code calg} value or {@code null} to remove the property from the JSON map. + * @since 0.6.0 + */ + T setCompressionAlgorithm(String calg); + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/IncorrectClaimException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/IncorrectClaimException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/IncorrectClaimException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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; + +/** + * Exception thrown when discovering that a required claim does not equal the required value, indicating the JWT is + * invalid and may not be used. + * + * @since 0.6 + */ +public class IncorrectClaimException extends InvalidClaimException { + public IncorrectClaimException(Header header, Claims claims, String message) { + super(header, claims, message); + } + + public IncorrectClaimException(Header header, Claims claims, String message, Throwable cause) { + super(header, claims, message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/InvalidClaimException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/InvalidClaimException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/InvalidClaimException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 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; + +/** + * Exception indicating a parsed claim is invalid in some way. Subclasses reflect the specific + * reason the claim is invalid. + * + * @see IncorrectClaimException + * @see MissingClaimException + * + * @since 0.6 + */ +public class InvalidClaimException extends ClaimJwtException { + private String claimName; + private Object claimValue; + + protected InvalidClaimException(Header header, Claims claims, String message) { + super(header, claims, message); + } + + protected InvalidClaimException(Header header, Claims claims, String message, Throwable cause) { + super(header, claims, message, cause); + } + + public String getClaimName() { + return claimName; + } + + public void setClaimName(String claimName) { + this.claimName = claimName; + } + + public Object getClaimValue() { + return claimValue; + } + + public void setClaimValue(Object claimValue) { + this.claimValue = claimValue; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jws.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jws.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jws.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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; + +/** + * An expanded (not compact/serialized) Signed JSON Web Token. + * + * @param the type of the JWS body contents, either a String or a {@link Claims} instance. + * + * @since 0.1 + */ +public interface Jws extends Jwt { + + String getSignature(); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwsHeader.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwsHeader.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwsHeader.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,107 @@ +/* + * 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; + +/** + * A JWS header. + * + * @param header type + * @since 0.1 + */ +public interface JwsHeader> extends Header { + + /** JWS {@code Algorithm} header parameter name: "alg" */ + public static final String ALGORITHM = "alg"; + + /** JWS {@code JWT Set URL} header parameter name: "jku" */ + public static final String JWK_SET_URL = "jku"; + + /** JWS {@code JSON Web Key} header parameter name: "jwk" */ + public static final String JSON_WEB_KEY = "jwk"; + + /** JWS {@code Key ID} header parameter name: "kid" */ + public static final String KEY_ID = "kid"; + + /** JWS {@code X.509 URL} header parameter name: "x5u" */ + public static final String X509_URL = "x5u"; + + /** JWS {@code X.509 Certificate Chain} header parameter name: "x5c" */ + public static final String X509_CERT_CHAIN = "x5c"; + + /** JWS {@code X.509 Certificate SHA-1 Thumbprint} header parameter name: "x5t" */ + public static final String X509_CERT_SHA1_THUMBPRINT = "x5t"; + + /** JWS {@code X.509 Certificate SHA-256 Thumbprint} header parameter name: "x5t#S256" */ + public static final String X509_CERT_SHA256_THUMBPRINT = "x5t#S256"; + + /** JWS {@code Critical} header parameter name: "crit" */ + public static final String CRITICAL = "crit"; + + /** + * Returns the JWS + * alg (algorithm) header value or {@code null} if not present. + * + *

The algorithm header parameter identifies the cryptographic algorithm used to secure the JWS. Consider + * using {@link io.jsonwebtoken.SignatureAlgorithm#forName(String) SignatureAlgorithm.forName} to convert this + * string value to a type-safe enum instance.

+ * + * @return the JWS {@code alg} header value or {@code null} if not present. This will always be + * {@code non-null} on validly constructed JWS instances, but could be {@code null} during construction. + */ + String getAlgorithm(); + + /** + * Sets the JWT + * alg (Algorithm) header value. A {@code null} value will remove the property from the JSON map. + * + *

The algorithm header parameter identifies the cryptographic algorithm used to secure the JWS. Consider + * using a type-safe {@link io.jsonwebtoken.SignatureAlgorithm SignatureAlgorithm} instance and using its + * {@link io.jsonwebtoken.SignatureAlgorithm#getValue() value} as the argument to this method.

+ * + * @param alg the JWS {@code alg} header value or {@code null} to remove the property from the JSON map. + * @return the {@code Header} instance for method chaining. + */ + T setAlgorithm(String alg); + + /** + * Returns the JWS + * kid (Key ID) header value or {@code null} if not present. + * + *

The keyId header parameter is a hint indicating which key was used to secure the JWS. This parameter allows + * originators to explicitly signal a change of key to recipients. The structure of the keyId value is + * unspecified.

+ * + *

When used with a JWK, the keyId value is used to match a JWK {@code keyId} parameter value.

+ * + * @return the JWS {@code kid} header value or {@code null} if not present. + */ + String getKeyId(); + + /** + * Sets the JWT + * kid (Key ID) header value. A {@code null} value will remove the property from the JSON map. + * + *

The keyId header parameter is a hint indicating which key was used to secure the JWS. This parameter allows + * originators to explicitly signal a change of key to recipients. The structure of the keyId value is + * unspecified.

+ * + *

When used with a JWK, the keyId value is used to match a JWK {@code keyId} parameter value.

+ * + * @param kid the JWS {@code kid} header value or {@code null} to remove the property from the JSON map. + * @return the {@code Header} instance for method chaining. + */ + T setKeyId(String kid); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwt.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwt.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwt.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,40 @@ +/* + * 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; + +/** + * An expanded (not compact/serialized) JSON Web Token. + * + * @param the type of the JWT body contents, either a String or a {@link Claims} instance. + * + * @since 0.1 + */ +public interface Jwt { + + /** + * Returns the JWT {@link Header} or {@code null} if not present. + * + * @return the JWT {@link Header} or {@code null} if not present. + */ + H getHeader(); + + /** + * Returns the JWT body, either a {@code String} or a {@code Claims} instance. + * + * @return the JWT body, either a {@code String} or a {@code Claims} instance. + */ + B getBody(); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtBuilder.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtBuilder.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtBuilder.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,398 @@ +/* + * 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; + +import java.security.Key; +import java.util.Date; +import java.util.Map; + +/** + * A builder for constructing JWTs. + * + * @since 0.1 + */ +public interface JwtBuilder extends ClaimsMutator { + + //replaces any existing header with the specified header. + + /** + * Sets (and replaces) any existing header with the specified header. If you do not want to replace the existing + * header and only want to append to it, use the {@link #setHeaderParams(java.util.Map)} method instead. + * + * @param header the header to set (and potentially replace any existing header). + * @return the builder for method chaining. + */ + JwtBuilder setHeader(Header header); + + /** + * Sets (and replaces) any existing header with the specified header. If you do not want to replace the existing + * header and only want to append to it, use the {@link #setHeaderParams(java.util.Map)} method instead. + * + * @param header the header to set (and potentially replace any existing header). + * @return the builder for method chaining. + */ + JwtBuilder setHeader(Map header); + + /** + * Applies the specified name/value pairs to the header. If a header does not yet exist at the time this method + * is called, one will be created automatically before applying the name/value pairs. + * + * @param params the header name/value pairs to append to the header. + * @return the builder for method chaining. + */ + JwtBuilder setHeaderParams(Map params); + + //sets the specified header parameter, overwriting any previous value under the same name. + + /** + * Applies the specified name/value pair to the header. If a header does not yet exist at the time this method + * is called, one will be created automatically before applying the name/value pair. + * + * @param name the header parameter name + * @param value the header parameter value + * @return the builder for method chaining. + */ + JwtBuilder setHeaderParam(String name, Object value); + + /** + * Sets the JWT's payload to be a plaintext (non-JSON) string. If you want the JWT body to be JSON, use the + * {@link #setClaims(Claims)} or {@link #setClaims(java.util.Map)} methods instead. + * + *

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ * + * @param payload the plaintext (non-JSON) string that will be the body of the JWT. + * @return the builder for method chaining. + */ + JwtBuilder setPayload(String payload); + + /** + * Sets the JWT payload to be a JSON Claims instance. If you do not want the JWT body to be JSON and instead want + * it to be a plaintext string, use the {@link #setPayload(String)} method instead. + * + *

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ * + * @param claims the JWT claims to be set as the JWT body. + * @return the builder for method chaining. + */ + JwtBuilder setClaims(Claims claims); + + /** + * Sets the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. If you do not + * want the JWT body to be JSON and instead want it to be a plaintext string, use the {@link #setPayload(String)} + * method instead. + * + *

The payload* and claims* properties are mutually exclusive - only one of the two may be used.

+ * + * @param claims the JWT claims to be set as the JWT body. + * @return the builder for method chaining. + */ + JwtBuilder setClaims(Map claims); + + /** + * Adds all given name/value pairs to the JSON Claims in the payload. If a Claims instance does not yet exist at the + * time this method is called, one will be created automatically before applying the name/value pairs. + * + *

The payload and claims properties are mutually exclusive - only one of the two may be used.

+ * + * @param claims the JWT claims to be added to the JWT body. + * @return the builder for method chaining. + * @since 0.8 + */ + JwtBuilder addClaims(Map claims); + + /** + * Sets the JWT Claims + * iss (issuer) value. A {@code null} value will remove the property from the Claims. + * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setIssuer(String) issuer} field with the specified value. This allows you to write + * code like this:

+ * + *
+     * String jwt = Jwts.builder().setIssuer("Joe").compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setIssuer("Joe");
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param iss the JWT {@code iss} value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setIssuer(String iss); + + /** + * Sets the JWT Claims + * sub (subject) value. A {@code null} value will remove the property from the Claims. + * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setSubject(String) subject} field with the specified value. This allows you to write + * code like this:

+ * + *
+     * String jwt = Jwts.builder().setSubject("Me").compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setSubject("Me");
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param sub the JWT {@code sub} value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setSubject(String sub); + + /** + * Sets the JWT Claims + * aud (audience) value. A {@code null} value will remove the property from the Claims. + * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setAudience(String) audience} field with the specified value. This allows you to write + * code like this:

+ * + *
+     * String jwt = Jwts.builder().setAudience("You").compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setSubject("You");
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param aud the JWT {@code aud} value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setAudience(String aud); + + /** + * Sets the JWT Claims + * exp (expiration) value. A {@code null} value will remove the property from the Claims. + * + *

A JWT obtained after this timestamp should not be used.

+ * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setExpiration(java.util.Date) expiration} field with the specified value. This allows + * you to write code like this:

+ * + *
+     * String jwt = Jwts.builder().setExpiration(new Date(System.currentTimeMillis() + 3600000)).compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setExpiration(new Date(System.currentTimeMillis() + 3600000));
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param exp the JWT {@code exp} value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setExpiration(Date exp); + + /** + * Sets the JWT Claims + * nbf (not before) value. A {@code null} value will remove the property from the Claims. + * + *

A JWT obtained before this timestamp should not be used.

+ * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setNotBefore(java.util.Date) notBefore} field with the specified value. This allows + * you to write code like this:

+ * + *
+     * String jwt = Jwts.builder().setNotBefore(new Date()).compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setNotBefore(new Date());
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setNotBefore(Date nbf); + + /** + * Sets the JWT Claims + * iat (issued at) value. A {@code null} value will remove the property from the Claims. + * + *

The value is the timestamp when the JWT was created.

+ * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setIssuedAt(java.util.Date) issuedAt} field with the specified value. This allows + * you to write code like this:

+ * + *
+     * String jwt = Jwts.builder().setIssuedAt(new Date()).compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setIssuedAt(new Date());
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param iat the JWT {@code iat} value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setIssuedAt(Date iat); + + /** + * Sets the JWT Claims + * jti (JWT ID) value. A {@code null} value will remove the property from the Claims. + * + *

The value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a + * manner that ensures that there is a negligible probability that the same value will be accidentally + * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

+ * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set + * the Claims {@link Claims#setId(String) id} field with the specified value. This allows + * you to write code like this:

+ * + *
+     * String jwt = Jwts.builder().setId(UUID.randomUUID().toString()).compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().setIssuedAt(UUID.randomUUID().toString());
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param jti the JWT {@code jti} (id) value or {@code null} to remove the property from the Claims map. + * @return the builder instance for method chaining. + * @since 0.2 + */ + @Override //only for better/targeted JavaDoc + JwtBuilder setId(String jti); + + /** + * Sets a custom JWT Claims parameter value. A {@code null} value will remove the property from the Claims. + * + *

This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set the + * named property on the Claims instance using the Claims {@link Claims#put(Object, Object) put} method. This allows + * you to write code like this:

+ * + *
+     * String jwt = Jwts.builder().claim("aName", "aValue").compact();
+     * 
+ * + *

instead of this:

+ *
+     * Claims claims = Jwts.claims().put("aName", "aValue");
+     * String jwt = Jwts.builder().setClaims(claims).compact();
+     * 
+ *

if desired.

+ * + * @param name the JWT Claims property name + * @param value the value to set for the specified Claims property name + * @return the builder instance for method chaining. + * @since 0.2 + */ + JwtBuilder claim(String name, Object value); + + /** + * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS. + * + * @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS. + * @param secretKey the algorithm-specific signing key to use to digitally sign the JWT. + * @return the builder for method chaining. + */ + JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey); + + /** + * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS. + * + *

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 #signWith(SignatureAlgorithm, byte[])}.

+ * + * @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS. + * @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the + * JWT. + * @return the builder for method chaining. + */ + JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey); + + /** + * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS. + * + * @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS. + * @param key the algorithm-specific signing key to use to digitally sign the JWT. + * @return the builder for method chaining. + */ + JwtBuilder signWith(SignatureAlgorithm alg, Key key); + + /** + * Compresses the JWT body using the specified {@link CompressionCodec}. + * + *

If your compact JWTs are large, and you want to reduce their total size during network transmission, this + * can be useful. For example, when embedding JWTs in URLs, some browsers may not support URLs longer than a + * certain length. Using compression can help ensure the compact JWT fits within that length. However, NOTE:

+ * + *

Compatibility Warning

+ * + *

The JWT family of specifications defines compression only for JWE (Json Web Encryption) + * tokens. Even so, JJWT will also support compression for JWS tokens as well if you choose to use it. + * However, be aware that if you use compression when creating a JWS token, other libraries may not be able to + * parse that JWS token. When using compression for JWS tokens, be sure that that all parties accessing the + * JWS token support compression for JWS.

+ * + *

Compression when creating JWE tokens however should be universally accepted for any + * library that supports JWE.

+ * + * @see io.jsonwebtoken.CompressionCodecs + * + * @param codec implementation of the {@link CompressionCodec} to be used. + * @return the builder for method chaining. + * @since 0.6.0 + */ + JwtBuilder compressWith(CompressionCodec codec); + + /** + * Actually builds the JWT and serializes it to a compact, URL-safe string according to the + * JWT Compact Serialization + * rules. + * + * @return A compact URL-safe JWT string. + */ + String compact(); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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; + +/** + * Base class for JWT-related runtime exceptions. + * + * @since 0.1 + */ +public class JwtException extends RuntimeException { + + public JwtException(String message) { + super(message); + } + + public JwtException(String message, Throwable cause) { + super(message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtHandler.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtHandler.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtHandler.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,68 @@ +/* + * 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; + +/** + * A JwtHandler is invoked by a {@link io.jsonwebtoken.JwtParser JwtParser} after parsing a JWT to indicate the exact + * type of JWT or JWS parsed. + * + * @param the type of object to return to the parser caller after handling the parsed JWT. + * @since 0.2 + */ +public interface JwtHandler { + + /** + * This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is + * a plaintext JWT. A plaintext JWT has a String (non-JSON) body payload and it is not cryptographically signed. + * + * @param jwt the parsed plaintext JWT + * @return any object to be used after inspecting the JWT, or {@code null} if no return value is necessary. + */ + T onPlaintextJwt(Jwt jwt); + + /** + * This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is + * a Claims JWT. A Claims JWT has a {@link Claims} body and it is not cryptographically signed. + * + * @param jwt the parsed claims JWT + * @return any object to be used after inspecting the JWT, or {@code null} if no return value is necessary. + */ + T onClaimsJwt(Jwt jwt); + + /** + * This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is + * a plaintext JWS. A plaintext JWS is a JWT with a String (non-JSON) body (payload) that has been + * cryptographically signed. + * + *

This method will only be invoked if the cryptographic signature can be successfully verified.

+ * + * @param jws the parsed plaintext JWS + * @return any object to be used after inspecting the JWS, or {@code null} if no return value is necessary. + */ + T onPlaintextJws(Jws jws); + + /** + * This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is + * a valid Claims JWS. A Claims JWS is a JWT with a {@link Claims} body that has been cryptographically signed. + * + *

This method will only be invoked if the cryptographic signature can be successfully verified.

+ * + * @param jws the parsed claims JWS + * @return any object to be used after inspecting the JWS, or {@code null} if no return value is necessary. + */ + T onClaimsJws(Jws jws); + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtHandlerAdapter.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtHandlerAdapter.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtHandlerAdapter.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,52 @@ +/* + * 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; + +/** + * An Adapter implementation of the + * {@link JwtHandler} interface that allows for anonymous subclasses to process only the JWT results that are + * known/expected for a particular use case. + * + *

All of the methods in this implementation throw exceptions: overridden methods represent + * scenarios expected by calling code in known situations. It would be unexpected to receive a JWS or JWT that did + * not match parsing expectations, so all non-overridden methods throw exceptions to indicate that the JWT + * input was unexpected.

+ * + * @param the type of object to return to the parser caller after handling the parsed JWT. + * @since 0.2 + */ +public class JwtHandlerAdapter implements JwtHandler { + + @Override + public T onPlaintextJwt(Jwt jwt) { + throw new UnsupportedJwtException("Unsigned plaintext JWTs are not supported."); + } + + @Override + public T onClaimsJwt(Jwt jwt) { + throw new UnsupportedJwtException("Unsigned Claims JWTs are not supported."); + } + + @Override + public T onPlaintextJws(Jws jws) { + throw new UnsupportedJwtException("Signed plaintext JWSs are not supported."); + } + + @Override + public T onClaimsJws(Jws jws) { + throw new UnsupportedJwtException("Signed Claims JWSs are not supported."); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParser.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParser.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/JwtParser.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,455 @@ +/* + * 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; + +import io.jsonwebtoken.impl.DefaultClock; + +import java.security.Key; +import java.util.Date; + +/** + * A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT. + * + * @since 0.1 + */ +public interface JwtParser { + + public static final char SEPARATOR_CHAR = '.'; + + /** + * 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 method for chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining + * @see MissingClaimException + * @see IncorrectClaimException + */ + JwtParser 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 for method chaining. + * @see MissingClaimException + * @see IncorrectClaimException + */ + 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. + * + * @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 + */ + JwtParser 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 for method chaining. + * @since 0.7.0 + */ + JwtParser setAllowedClockSkewSeconds(long seconds); + + /** + * 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 for method chaining. + */ + 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. + * @return the parser for method chaining. + */ + JwtParser setSigningKey(String base64EncodedKeyBytes); + + /** + * 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 for method chaining. + */ + JwtParser 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 for method chaining. + * @since 0.4 + */ + JwtParser 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 io.jsonwebtoken.impl.compression.DeflateCompressionCodec DEFLATE} + * and {@link io.jsonwebtoken.impl.compression.GzipCompressionCodec 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 for method chaining. + * @since 0.6.0 + */ + JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver); + + /** + * Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false} + * otherwise. + *

+ *

Note that if you are reasonably sure that the token is signed, it is more efficient to attempt to + * parse the token (and catching exceptions if necessary) instead of calling this method first before parsing.

+ * + * @param jwt the compact serialized JWT to check + * @return {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false} + * otherwise. + */ + boolean isSigned(String jwt); + + /** + * Parses the specified compact serialized JWT string based on the builder's current configuration state and + * returns the resulting JWT or JWS instance. + *

+ *

This method returns a JWT or JWS based on the parsed string. Because it may be cumbersome to determine if it + * is a JWT or JWS, or if the body/payload is a Claims or String with {@code instanceof} checks, the + * {@link #parse(String, JwtHandler) parse(String,JwtHandler)} method allows for a type-safe callback approach that + * may help reduce code or instanceof checks.

+ * + * @param jwt the compact serialized JWT to parse + * @return the specified compact serialized JWT string based on the builder's current configuration state. + * @throws MalformedJwtException if the specified JWT was incorrectly constructed (and therefore invalid). + * Invalid + * JWTs should not be trusted and should be discarded. + * @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail + * signature validation should not be trusted and should be discarded. + * @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time + * before the time this method is invoked. + * @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace. + * @see #parse(String, JwtHandler) + * @see #parsePlaintextJwt(String) + * @see #parseClaimsJwt(String) + * @see #parsePlaintextJws(String) + * @see #parseClaimsJws(String) + */ + Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException; + + /** + * Parses the specified compact serialized JWT string based on the builder's current configuration state and + * invokes the specified {@code handler} with the resulting JWT or JWS instance. + *

+ *

If you are confident of the format of the JWT before parsing, you can create an anonymous subclass using the + * {@link io.jsonwebtoken.JwtHandlerAdapter JwtHandlerAdapter} and override only the methods you know are relevant + * for your use case(s), for example:

+ *

+ *

+     * String compactJwt = request.getParameter("jwt"); //we are confident this is a signed JWS
+     *
+     * String subject = Jwts.parser().setSigningKey(key).parse(compactJwt, new JwtHandlerAdapter<String>() {
+     *     @Override
+     *     public String onClaimsJws(Jws<Claims> jws) {
+     *         return jws.getBody().getSubject();
+     *     }
+     * });
+     * 
+ *

+ *

If you know the JWT string can be only one type of JWT, then it is even easier to invoke one of the + * following convenience methods instead of this one:

+ *

+ *

    + *
  • {@link #parsePlaintextJwt(String)}
  • + *
  • {@link #parseClaimsJwt(String)}
  • + *
  • {@link #parsePlaintextJws(String)}
  • + *
  • {@link #parseClaimsJws(String)}
  • + *
+ * + * @param jwt the compact serialized JWT to parse + * @return the result returned by the {@code JwtHandler} + * @throws MalformedJwtException if the specified JWT was incorrectly constructed (and therefore invalid). + * Invalid JWTs should not be trusted and should be discarded. + * @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail + * signature validation should not be trusted and should be discarded. + * @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time + * before the time this method is invoked. + * @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace, or if the + * {@code handler} is {@code null}. + * @see #parsePlaintextJwt(String) + * @see #parseClaimsJwt(String) + * @see #parsePlaintextJws(String) + * @see #parseClaimsJws(String) + * @see #parse(String) + * @since 0.2 + */ + T parse(String jwt, JwtHandler handler) + throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException; + + /** + * Parses the specified compact serialized JWT string based on the builder's current configuration state and + * returns + * the resulting unsigned plaintext JWT instance. + *

+ *

This is a convenience method that is usable if you are confident that the compact string argument reflects an + * unsigned plaintext JWT. An unsigned plaintext JWT has a String (non-JSON) body payload and it is not + * cryptographically signed.

+ *

+ *

If the compact string presented does not reflect an unsigned plaintext JWT with non-JSON string body, + * an {@link UnsupportedJwtException} will be thrown.

+ * + * @param plaintextJwt a compact serialized unsigned plaintext JWT string. + * @return the {@link Jwt Jwt} instance that reflects the specified compact JWT string. + * @throws UnsupportedJwtException if the {@code plaintextJwt} argument does not represent an unsigned plaintext + * JWT + * @throws MalformedJwtException if the {@code plaintextJwt} string is not a valid JWT + * @throws SignatureException if the {@code plaintextJwt} string is actually a JWS and signature validation + * fails + * @throws IllegalArgumentException if the {@code plaintextJwt} string is {@code null} or empty or only whitespace + * @see #parseClaimsJwt(String) + * @see #parsePlaintextJws(String) + * @see #parseClaimsJws(String) + * @see #parse(String, JwtHandler) + * @see #parse(String) + * @since 0.2 + */ + Jwt parsePlaintextJwt(String plaintextJwt) + throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException; + + /** + * Parses the specified compact serialized JWT string based on the builder's current configuration state and + * returns + * the resulting unsigned plaintext JWT instance. + *

+ *

This is a convenience method that is usable if you are confident that the compact string argument reflects an + * unsigned Claims JWT. An unsigned Claims JWT has a {@link Claims} body and it is not cryptographically + * signed.

+ *

+ *

If the compact string presented does not reflect an unsigned Claims JWT, an + * {@link UnsupportedJwtException} will be thrown.

+ * + * @param claimsJwt a compact serialized unsigned Claims JWT string. + * @return the {@link Jwt Jwt} instance that reflects the specified compact JWT string. + * @throws UnsupportedJwtException if the {@code claimsJwt} argument does not represent an unsigned Claims JWT + * @throws MalformedJwtException if the {@code claimsJwt} string is not a valid JWT + * @throws SignatureException if the {@code claimsJwt} string is actually a JWS and signature validation + * fails + * @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time + * before the time this method is invoked. + * @throws IllegalArgumentException if the {@code claimsJwt} string is {@code null} or empty or only whitespace + * @see #parsePlaintextJwt(String) + * @see #parsePlaintextJws(String) + * @see #parseClaimsJws(String) + * @see #parse(String, JwtHandler) + * @see #parse(String) + * @since 0.2 + */ + Jwt parseClaimsJwt(String claimsJwt) + throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException; + + /** + * Parses the specified compact serialized JWS string based on the builder's current configuration state and + * returns + * the resulting plaintext JWS instance. + *

+ *

This is a convenience method that is usable if you are confident that the compact string argument reflects a + * plaintext JWS. A plaintext JWS is a JWT with a String (non-JSON) body (payload) that has been + * cryptographically signed.

+ *

+ *

If the compact string presented does not reflect a plaintext JWS, an {@link UnsupportedJwtException} + * will be thrown.

+ * + * @param plaintextJws a compact serialized JWS string. + * @return the {@link Jws Jws} instance that reflects the specified compact JWS string. + * @throws UnsupportedJwtException if the {@code plaintextJws} argument does not represent an plaintext JWS + * @throws MalformedJwtException if the {@code plaintextJws} string is not a valid JWS + * @throws SignatureException if the {@code plaintextJws} JWS signature validation fails + * @throws IllegalArgumentException if the {@code plaintextJws} string is {@code null} or empty or only whitespace + * @see #parsePlaintextJwt(String) + * @see #parseClaimsJwt(String) + * @see #parseClaimsJws(String) + * @see #parse(String, JwtHandler) + * @see #parse(String) + * @since 0.2 + */ + Jws parsePlaintextJws(String plaintextJws) + throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException; + + /** + * Parses the specified compact serialized JWS string based on the builder's current configuration state and + * returns + * the resulting Claims JWS instance. + *

+ *

This is a convenience method that is usable if you are confident that the compact string argument reflects a + * Claims JWS. A Claims JWS is a JWT with a {@link Claims} body that has been cryptographically signed.

+ *

+ *

If the compact string presented does not reflect a Claims JWS, an {@link UnsupportedJwtException} will be + * thrown.

+ * + * @param claimsJws a compact serialized Claims JWS string. + * @return the {@link Jws Jws} instance that reflects the specified compact Claims JWS string. + * @throws UnsupportedJwtException if the {@code claimsJws} argument does not represent an Claims JWS + * @throws MalformedJwtException if the {@code claimsJws} string is not a valid JWS + * @throws SignatureException if the {@code claimsJws} JWS signature validation fails + * @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time + * before the time this method is invoked. + * @throws IllegalArgumentException if the {@code claimsJws} string is {@code null} or empty or only whitespace + * @see #parsePlaintextJwt(String) + * @see #parseClaimsJwt(String) + * @see #parsePlaintextJws(String) + * @see #parse(String, JwtHandler) + * @see #parse(String) + * @since 0.2 + */ + Jws parseClaimsJws(String claimsJws) + throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException; +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwts.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwts.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/Jwts.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,118 @@ +/* + * 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; + +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 java.util.Map; + +/** + * Factory class useful for creating instances of JWT interfaces. Using this factory class can be a good + * alternative to tightly coupling your code to implementation classes. + * + * @since 0.1 + */ +public final class Jwts { + + 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 + * digitally sign the JWT. + * + * @return a new {@link Header} instance suitable for plaintext (not digitally signed) JWTs. + */ + public static Header header() { + return new DefaultHeader(); + } + + /** + * Creates a new {@link Header} instance suitable for plaintext (not digitally signed) JWTs, populated + * with the specified name/value pairs. As this is a less common use of JWTs, consider using the + * {@link #jwsHeader(java.util.Map)} factory method instead if you will later digitally sign the JWT. + * + * @return a new {@link Header} instance suitable for plaintext (not digitally signed) JWTs. + */ + public static Header header(Map header) { + return new DefaultHeader(header); + } + + /** + * Returns a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's). + * + * @return a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's). + * @see JwtBuilder#setHeader(Header) + */ + public static JwsHeader jwsHeader() { + return new DefaultJwsHeader(); + } + + /** + * Returns a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's), populated with the + * specified name/value pairs. + * + * @return a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's), populated with the + * specified name/value pairs. + * @see JwtBuilder#setHeader(Header) + */ + public static JwsHeader jwsHeader(Map header) { + return new DefaultJwsHeader(header); + } + + /** + * Returns a new {@link Claims} instance to be used as a JWT body. + * + * @return a new {@link Claims} instance to be used as a JWT body. + */ + public static Claims claims() { + return new DefaultClaims(); + } + + /** + * Returns a new {@link Claims} instance populated with the specified name/value pairs. + * + * @param claims the name/value pairs to populate the new Claims instance. + * @return a new {@link Claims} instance populated with the specified name/value pairs. + */ + public static Claims claims(Map claims) { + return new DefaultClaims(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. + */ + public static JwtParser parser() { + return new DefaultJwtParser(); + } + + /** + * 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(); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/MalformedJwtException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/MalformedJwtException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/MalformedJwtException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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; + +/** + * Exception indicating that a JWT was not correctly constructed and should be rejected. + * + * @since 0.2 + */ +public class MalformedJwtException extends JwtException { + + public MalformedJwtException(String message) { + super(message); + } + + public MalformedJwtException(String message, Throwable cause) { + super(message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/MissingClaimException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/MissingClaimException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/MissingClaimException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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; + +/** + * Exception thrown when discovering that a required claim is not present, indicating the JWT is + * invalid and may not be used. + * + * @since 0.6 + */ +public class MissingClaimException extends InvalidClaimException { + public MissingClaimException(Header header, Claims claims, String message) { + super(header, claims, message); + } + + public MissingClaimException(Header header, Claims claims, String message, Throwable cause) { + super(header, claims, message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/PrematureJwtException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/PrematureJwtException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/PrematureJwtException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,39 @@ +/* + * 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; + +/** + * Exception indicating that a JWT was accepted before it is allowed to be accessed and must be rejected. + * + * @since 0.3 + */ +public class PrematureJwtException extends ClaimJwtException { + + public PrematureJwtException(Header header, Claims claims, String message) { + super(header, claims, message); + } + + /** + * @param header jwt header + * @param claims jwt claims (body) + * @param message exception message + * @param cause cause + * @since 0.5 + */ + public PrematureJwtException(Header header, Claims claims, String message, Throwable cause) { + super(header, claims, message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/RequiredTypeException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/RequiredTypeException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/RequiredTypeException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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; + +/** + * Exception thrown when {@link Claims#get(String, Class)} is called and the value does not match the type of the + * {@code Class} argument. + * + * @since 0.6 + */ +public class RequiredTypeException extends JwtException { + public RequiredTypeException(String message) { + super(message); + } + + public RequiredTypeException(String message, Throwable cause) { + super(message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureAlgorithm.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureAlgorithm.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureAlgorithm.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,272 @@ +/* + * 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; + +import io.jsonwebtoken.lang.RuntimeEnvironment; + +/** + * Type-safe representation of standard JWT signature algorithm names as defined in the + * JSON Web Algorithms specification. + * + * @since 0.1 + */ +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 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-384} */ + HS384("HS384", "HMAC using SHA-384", "HMAC", "HmacSHA384", true), + + /** JWA algorithm name for {@code HMAC using SHA-512} */ + HS512("HS512", "HMAC using SHA-512", "HMAC", "HmacSHA512", 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), + + /** 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-512} */ + RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "RSA", "SHA512withRSA", true), + + /** + * 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. + */ + ES256("ES256", "ECDSA using P-256 and SHA-256", "Elliptic Curve", "SHA256withECDSA", false), + + /** + * 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. + */ + ES384("ES384", "ECDSA using P-384 and SHA-384", "Elliptic Curve", "SHA384withECDSA", false), + + /** + * 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. + */ + ES512("ES512", "ECDSA using P-512 and SHA-512", "Elliptic Curve", "SHA512withECDSA", false), + + /** + * 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. + */ + PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "RSA", "SHA256withRSAandMGF1", false), + + /** + * 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. + */ + PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "RSA", "SHA384withRSAandMGF1", false), + + /** + * 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. + */ + PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "RSA", "SHA512withRSAandMGF1", false); + + static { + RuntimeEnvironment.enableBouncyCastleIfPossible(); + } + + private final String value; + private final String description; + private final String familyName; + private final String jcaName; + private final boolean jdkStandard; + + SignatureAlgorithm(String value, String description, String familyName, String jcaName, boolean jdkStandard) { + this.value = value; + this.description = description; + this.familyName = familyName; + this.jcaName = jcaName; + this.jdkStandard = jdkStandard; + } + + /** + * Returns the JWA algorithm name constant. + * + * @return the JWA algorithm name constant. + */ + public String getValue() { + return value; + } + + /** + * Returns the JWA algorithm description. + * + * @return the JWA algorithm description. + */ + public String getDescription() { + return description; + } + + + /** + * Returns the cryptographic family name of the signature algorithm. The value returned is according to the + * following table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Crypto Family
SignatureAlgorithmFamily Name
HS256HMAC
HS384HMAC
HS512HMAC
RS256RSA
RS384RSA
RS512RSA
PS256RSA
PS384RSA
PS512RSA
ES256Elliptic Curve
ES384Elliptic Curve
ES512Elliptic Curve
+ * + * @return Returns the cryptographic family name of the signature algorithm. + * + * @since 0.5 + */ + public String getFamilyName() { + return familyName; + } + + /** + * Returns the name of the JCA algorithm used to compute the signature. + * + * @return the name of the JCA algorithm used to compute the signature. + */ + public String getJcaName() { + return jcaName; + } + + /** + * Returns {@code true} if the algorithm is supported by standard JDK distributions or {@code false} if the + * algorithm implementation is not in the JDK and must be provided by a separate runtime JCA Provider (like + * BouncyCastle for example). + * + * @return {@code true} if the algorithm is supported by standard JDK distributions or {@code false} if the + * algorithm implementation is not in the JDK and must be provided by a separate runtime JCA Provider (like + * BouncyCastle for example). + */ + public boolean isJdkStandard() { + return jdkStandard; + } + + /** + * Returns {@code true} if the enum instance represents an HMAC signature algorithm, {@code false} otherwise. + * + * @return {@code true} if the enum instance represents an HMAC signature algorithm, {@code false} otherwise. + */ + public boolean isHmac() { + return name().startsWith("HS"); + } + + /** + * Returns {@code true} if the enum instance represents an RSA public/private key pair signature algorithm, + * {@code false} otherwise. + * + * @return {@code true} if the enum instance represents an RSA public/private key pair signature algorithm, + * {@code false} otherwise. + */ + public boolean isRsa() { + return getDescription().startsWith("RSASSA"); + } + + /** + * Returns {@code true} if the enum instance represents an Elliptic Curve signature algorithm, {@code false} + * otherwise. + * + * @return {@code true} if the enum instance represents an Elliptic Curve signature algorithm, {@code false} + * otherwise. + */ + public boolean isEllipticCurve() { + return name().startsWith("ES"); + } + + /** + * Looks up and returns the corresponding {@code SignatureAlgorithm} enum instance based on a + * case-insensitive name comparison. + * + * @param value The case-insensitive name of the {@code SignatureAlgorithm} instance to return + * @return the corresponding {@code SignatureAlgorithm} enum instance based on a + * case-insensitive name comparison. + * @throws SignatureException if the specified value does not match any {@code SignatureAlgorithm} + * name. + */ + public static SignatureAlgorithm forName(String value) throws SignatureException { + for (SignatureAlgorithm alg : values()) { + if (alg.getValue().equalsIgnoreCase(value)) { + return alg; + } + } + + throw new SignatureException("Unsupported signature algorithm '" + value + "'"); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SignatureException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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; + +/** + * Exception indicating that either calculating a signature or verifying an existing signature of a JWT failed. + * + * @since 0.1 + */ +public class SignatureException extends JwtException { + + public SignatureException(String message) { + super(message); + } + + public SignatureException(String message, Throwable cause) { + super(message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SigningKeyResolver.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SigningKeyResolver.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SigningKeyResolver.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,73 @@ +/* + * 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; + +import java.security.Key; + +/** + * A {@code SigningKeyResolver} can be used by a {@link io.jsonwebtoken.JwtParser JwtParser} to find a signing key that + * should be used to verify a JWS signature. + * + *

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 getSigningKeyBytes(header, claims); //implement me
+ *         }})
+ *     .parseClaimsJws(compact);
+ * 
+ * + *

A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.

+ * + *

SigningKeyResolverAdapter

+ * + *

If you only need to resolve a signing key for a particular JWS (either a plaintext or Claims JWS), consider using + * the {@link io.jsonwebtoken.SigningKeyResolverAdapter} and overriding only the method you need to support instead of + * implementing this interface directly.

+ * + * @see io.jsonwebtoken.SigningKeyResolverAdapter + * @since 0.4 + */ +public interface SigningKeyResolver { + + /** + * Returns the signing key that should be used to validate a digital signature for the Claims JWS with the specified + * header and claims. + * + * @param header the header of the JWS to validate + * @param claims the claims (body) of the JWS to validate + * @return the signing key that should be used to validate a digital signature for the Claims JWS with the specified + * header and claims. + */ + Key resolveSigningKey(JwsHeader header, Claims claims); + + /** + * Returns the signing key that should be used to validate a digital signature for the Plaintext JWS with the + * specified header and plaintext payload. + * + * @param header the header of the JWS to validate + * @param plaintext the plaintext body of the JWS to validate + * @return the signing key that should be used to validate a digital signature for the Plaintext JWS with the + * specified header and plaintext payload. + */ + Key resolveSigningKey(JwsHeader header, String plaintext); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SigningKeyResolverAdapter.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SigningKeyResolverAdapter.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/SigningKeyResolverAdapter.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,99 @@ +/* + * 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; + +import io.jsonwebtoken.lang.Assert; + +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; + +/** + * An Adapter implementation of the + * {@link SigningKeyResolver} interface that allows subclasses to process only the type of JWS body that + * is known/expected for a particular case. + * + *

The {@link #resolveSigningKey(JwsHeader, Claims)} and {@link #resolveSigningKey(JwsHeader, String)} method + * implementations delegate to the + * {@link #resolveSigningKeyBytes(JwsHeader, Claims)} and {@link #resolveSigningKeyBytes(JwsHeader, String)} methods + * respectively. The latter two methods simply throw exceptions: they represent scenarios expected by + * calling code in known situations, and it is expected that you override the implementation in those known situations; + * non-overridden *KeyBytes methods indicates that the JWS input was unexpected.

+ * + *

If either {@link #resolveSigningKey(JwsHeader, String)} or {@link #resolveSigningKey(JwsHeader, Claims)} + * are not overridden, one (or both) of the *KeyBytes variants must be overridden depending on your expected + * use case. You do not have to override any method that does not represent an expected condition.

+ * + * @since 0.4 + */ +public class SigningKeyResolverAdapter implements SigningKeyResolver { + + @Override + public Key resolveSigningKey(JwsHeader header, Claims claims) { + SignatureAlgorithm alg = SignatureAlgorithm.forName(header.getAlgorithm()); + Assert.isTrue(alg.isHmac(), "The default resolveSigningKey(JwsHeader, Claims) implementation cannot be " + + "used for asymmetric key algorithms (RSA, Elliptic Curve). " + + "Override the resolveSigningKey(JwsHeader, Claims) method instead and return a " + + "Key instance appropriate for the " + alg.name() + " algorithm."); + byte[] keyBytes = resolveSigningKeyBytes(header, claims); + return new SecretKeySpec(keyBytes, alg.getJcaName()); + } + + @Override + public Key resolveSigningKey(JwsHeader header, String plaintext) { + SignatureAlgorithm alg = SignatureAlgorithm.forName(header.getAlgorithm()); + Assert.isTrue(alg.isHmac(), "The default resolveSigningKey(JwsHeader, String) implementation cannot be " + + "used for asymmetric key algorithms (RSA, Elliptic Curve). " + + "Override the resolveSigningKey(JwsHeader, String) method instead and return a " + + "Key instance appropriate for the " + alg.name() + " algorithm."); + byte[] keyBytes = resolveSigningKeyBytes(header, plaintext); + return new SecretKeySpec(keyBytes, alg.getJcaName()); + } + + /** + * Convenience method invoked by {@link #resolveSigningKey(JwsHeader, Claims)} that obtains the necessary signing + * key bytes. This implementation simply throws an exception: if the JWS parsed is a Claims JWS, you must + * override this method or the {@link #resolveSigningKey(JwsHeader, Claims)} method instead. + * + *

NOTE: You cannot override this method when validating RSA signatures. If you expect RSA signatures, + * you must override the {@link #resolveSigningKey(JwsHeader, Claims)} method instead.

+ * + * @param header the parsed {@link JwsHeader} + * @param claims the parsed {@link Claims} + * @return the signing key bytes to use to verify the JWS signature. + */ + public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) { + throw new UnsupportedJwtException("The specified SigningKeyResolver implementation does not support " + + "Claims JWS signing key resolution. Consider overriding either the " + + "resolveSigningKey(JwsHeader, Claims) method or, for HMAC algorithms, the " + + "resolveSigningKeyBytes(JwsHeader, Claims) method."); + } + + /** + * Convenience method invoked by {@link #resolveSigningKey(JwsHeader, String)} that obtains the necessary signing + * key bytes. This implementation simply throws an exception: if the JWS parsed is a plaintext JWS, you must + * override this method or the {@link #resolveSigningKey(JwsHeader, String)} method instead. + * + * @param header the parsed {@link JwsHeader} + * @param payload the parsed String plaintext payload + * @return the signing key bytes to use to verify the JWS signature. + */ + public byte[] resolveSigningKeyBytes(JwsHeader header, String payload) { + throw new UnsupportedJwtException("The specified SigningKeyResolver implementation does not support " + + "plaintext JWS signing key resolution. Consider overriding either the " + + "resolveSigningKey(JwsHeader, String) method or, for HMAC algorithms, the " + + "resolveSigningKeyBytes(JwsHeader, String) method."); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/UnsupportedJwtException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/UnsupportedJwtException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/UnsupportedJwtException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,36 @@ +/* + * 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; + +/** + * Exception thrown when receiving a JWT in a particular format/configuration that does not match the format expected + * by the application. + * + *

For example, this exception would be thrown if parsing an unsigned plaintext JWT when the application + * requires a cryptographically signed Claims JWS instead.

+ * + * @since 0.2 + */ +public class UnsupportedJwtException extends JwtException { + + public UnsupportedJwtException(String message) { + super(message); + } + + public UnsupportedJwtException(String message, Throwable cause) { + super(message, cause); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AbstractTextCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AbstractTextCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AbstractTextCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,39 @@ +/* + * 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.lang.Assert; + +import java.nio.charset.Charset; + +public abstract class AbstractTextCodec implements TextCodec { + + protected static final Charset UTF8 = Charset.forName("UTF-8"); + protected static final Charset US_ASCII = Charset.forName("US-ASCII"); + + @Override + public String encode(String data) { + Assert.hasText(data, "String argument to encode cannot be null or empty."); + byte[] bytes = data.getBytes(UTF8); + return encode(bytes); + } + + @Override + public String decodeToString(String encoded) { + byte[] bytes = decode(encoded); + return new String(bytes, UTF8); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AndroidBase64Codec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AndroidBase64Codec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/AndroidBase64Codec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 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; + +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); + } + + @Override + public byte[] decode(String encoded) { + return android.util.Base64.decode(encoded, android.util.Base64.DEFAULT); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64Codec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64Codec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64Codec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.impl; + +public class Base64Codec extends AbstractTextCodec { + + public String encode(byte[] data) { + return javax.xml.bind.DatatypeConverter.printBase64Binary(data); + } + + @Override + public byte[] decode(String encoded) { + return javax.xml.bind.DatatypeConverter.parseBase64Binary(encoded); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64UrlCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64UrlCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/Base64UrlCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,104 @@ +/* + * 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; + +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); + } + + 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); + } + + 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 --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClaims.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClaims.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,148 @@ +/* + * 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.Claims; +import io.jsonwebtoken.RequiredTypeException; + +import java.util.Date; +import java.util.Map; + +public class DefaultClaims extends JwtMap implements Claims { + + public DefaultClaims() { + super(); + } + + public DefaultClaims(Map map) { + super(map); + } + + @Override + public String getIssuer() { + return getString(ISSUER); + } + + @Override + public Claims setIssuer(String iss) { + setValue(ISSUER, iss); + return this; + } + + @Override + public String getSubject() { + return getString(SUBJECT); + } + + @Override + public Claims setSubject(String sub) { + setValue(SUBJECT, sub); + return this; + } + + @Override + public String getAudience() { + return getString(AUDIENCE); + } + + @Override + public Claims setAudience(String aud) { + setValue(AUDIENCE, aud); + return this; + } + + @Override + public Date getExpiration() { + return get(Claims.EXPIRATION, Date.class); + } + + @Override + public Claims setExpiration(Date exp) { + setDate(Claims.EXPIRATION, exp); + return this; + } + + @Override + public Date getNotBefore() { + return get(Claims.NOT_BEFORE, Date.class); + } + + @Override + public Claims setNotBefore(Date nbf) { + setDate(Claims.NOT_BEFORE, nbf); + return this; + } + + @Override + public Date getIssuedAt() { + return get(Claims.ISSUED_AT, Date.class); + } + + @Override + public Claims setIssuedAt(Date iat) { + setDate(Claims.ISSUED_AT, iat); + return this; + } + + @Override + public String getId() { + return getString(ID); + } + + @Override + public Claims setId(String jti) { + setValue(Claims.ID, jti); + return this; + } + + @Override + public T get(String claimName, Class requiredType) { + Object value = get(claimName); + if (value == null) { return null; } + + if (Claims.EXPIRATION.equals(claimName) || + Claims.ISSUED_AT.equals(claimName) || + Claims.NOT_BEFORE.equals(claimName) + ) { + value = getDate(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; + if (requiredType == Long.class) { + value = (long) intValue; + } else if (requiredType == Short.class && Short.MIN_VALUE <= intValue && intValue <= Short.MAX_VALUE) { + value = (short) intValue; + } else if (requiredType == Byte.class && Byte.MIN_VALUE <= intValue && intValue <= Byte.MAX_VALUE) { + value = (byte) intValue; + } + } + + if (!requiredType.isInstance(value)) { + throw new RequiredTypeException("Expected value to be of type: " + requiredType + ", but was " + value.getClass()); + } + + return requiredType.cast(value); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClock.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClock.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultClock.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,28 @@ +package io.jsonwebtoken.impl; + +import io.jsonwebtoken.Clock; + +import java.util.Date; + +/** + * Default {@link Clock} implementation. + * + * @since 0.7.0 + */ +public class DefaultClock implements Clock { + + /** + * Default static instance that may be shared. It is thread-safe. + */ + public static final Clock INSTANCE = new DefaultClock(); + + /** + * Simply returns new {@link Date}(). + * + * @return a new {@link Date} instance. + */ + @Override + public Date now() { + return new Date(); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultHeader.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultHeader.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultHeader.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,72 @@ +/* + * 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.Header; +import io.jsonwebtoken.lang.Strings; + +import java.util.Map; + +@SuppressWarnings("unchecked") +public class DefaultHeader> extends JwtMap implements Header { + + public DefaultHeader() { + super(); + } + + public DefaultHeader(Map map) { + super(map); + } + + @Override + public String getType() { + return getString(TYPE); + } + + @Override + public T setType(String typ) { + setValue(TYPE, typ); + return (T)this; + } + + @Override + public String getContentType() { + return getString(CONTENT_TYPE); + } + + @Override + public T setContentType(String cty) { + setValue(CONTENT_TYPE, cty); + return (T)this; + } + + @SuppressWarnings("deprecation") + @Override + public String getCompressionAlgorithm() { + String alg = getString(COMPRESSION_ALGORITHM); + if (!Strings.hasText(alg)) { + alg = getString(DEPRECATED_COMPRESSION_ALGORITHM); + } + return alg; + } + + @Override + public T setCompressionAlgorithm(String compressionAlgorithm) { + setValue(COMPRESSION_ALGORITHM, compressionAlgorithm); + return (T) this; + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJws.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJws.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJws.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,52 @@ +/* + * 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.Jws; +import io.jsonwebtoken.JwsHeader; + +public class DefaultJws implements Jws { + + private final JwsHeader header; + private final B body; + private final String signature; + + public DefaultJws(JwsHeader header, B body, String signature) { + this.header = header; + this.body = body; + this.signature = signature; + } + + @Override + public JwsHeader getHeader() { + return this.header; + } + + @Override + public B getBody() { + return this.body; + } + + @Override + public String getSignature() { + return this.signature; + } + + @Override + public String toString() { + return "header=" + header + ",body=" + body + ",signature=" + signature; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwsHeader.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwsHeader.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwsHeader.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,54 @@ +/* + * 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.JwsHeader; + +import java.util.Map; + +public class DefaultJwsHeader extends DefaultHeader implements JwsHeader { + + public DefaultJwsHeader() { + super(); + } + + public DefaultJwsHeader(Map map) { + super(map); + } + + @Override + public String getAlgorithm() { + return getString(ALGORITHM); + } + + @Override + public JwsHeader setAlgorithm(String alg) { + setValue(ALGORITHM, alg); + return this; + } + + @Override + public String getKeyId() { + return getString(KEY_ID); + } + + @Override + public JwsHeader setKeyId(String kid) { + setValue(KEY_ID, kid); + return this; + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwt.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwt.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwt.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,45 @@ +/* + * 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.Header; +import io.jsonwebtoken.Jwt; + +public class DefaultJwt implements Jwt { + + private final Header header; + private final B body; + + public DefaultJwt(Header header, B body) { + this.header = header; + this.body = body; + } + + @Override + public Header getHeader() { + return header; + } + + @Override + public B getBody() { + return body; + } + + @Override + public String toString() { + return "header=" + header + ",body=" + body; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtBuilder.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtBuilder.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtBuilder.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,356 @@ +/* + * 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 com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.*; +import io.jsonwebtoken.impl.crypto.DefaultJwtSigner; +import io.jsonwebtoken.impl.crypto.JwtSigner; +import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Collections; +import io.jsonwebtoken.lang.Objects; +import io.jsonwebtoken.lang.Strings; + +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 CompressionCodec compressionCodec; + + @Override + public JwtBuilder setHeader(Header header) { + this.header = header; + return this; + } + + @Override + public JwtBuilder setHeader(Map header) { + this.header = new DefaultHeader(header); + return this; + } + + @Override + public JwtBuilder setHeaderParams(Map params) { + if (!Collections.isEmpty(params)) { + + Header header = ensureHeader(); + + for (Map.Entry entry : params.entrySet()) { + header.put(entry.getKey(), entry.getValue()); + } + } + return this; + } + + protected Header ensureHeader() { + if (this.header == null) { + this.header = new DefaultHeader(); + } + return this.header; + } + + @Override + public JwtBuilder setHeaderParam(String name, Object value) { + ensureHeader().put(name, value); + return this; + } + + @Override + public JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey) { + 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."); + this.algorithm = alg; + this.keyBytes = secretKey; + return this; + } + + @Override + public JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) { + 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); + 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; + } + + @Override + public JwtBuilder compressWith(CompressionCodec compressionCodec) { + Assert.notNull(compressionCodec, "compressionCodec cannot be null"); + this.compressionCodec = compressionCodec; + return this; + } + + @Override + public JwtBuilder setPayload(String payload) { + this.payload = payload; + return this; + } + + protected Claims ensureClaims() { + if (this.claims == null) { + this.claims = new DefaultClaims(); + } + return this.claims; + } + + @Override + public JwtBuilder setClaims(Claims claims) { + this.claims = claims; + return this; + } + + @Override + public JwtBuilder setClaims(Map claims) { + this.claims = Jwts.claims(claims); + return this; + } + + @Override + public JwtBuilder addClaims(Map claims) { + ensureClaims().putAll(claims); + return this; + } + + @Override + public JwtBuilder setIssuer(String iss) { + if (Strings.hasText(iss)) { + ensureClaims().setIssuer(iss); + } else { + if (this.claims != null) { + claims.setIssuer(iss); + } + } + return this; + } + + @Override + public JwtBuilder setSubject(String sub) { + if (Strings.hasText(sub)) { + ensureClaims().setSubject(sub); + } else { + if (this.claims != null) { + claims.setSubject(sub); + } + } + return this; + } + + @Override + public JwtBuilder setAudience(String aud) { + if (Strings.hasText(aud)) { + ensureClaims().setAudience(aud); + } else { + if (this.claims != null) { + claims.setAudience(aud); + } + } + return this; + } + + @Override + public JwtBuilder setExpiration(Date exp) { + if (exp != null) { + ensureClaims().setExpiration(exp); + } else { + if (this.claims != null) { + //noinspection ConstantConditions + this.claims.setExpiration(exp); + } + } + return this; + } + + @Override + public JwtBuilder setNotBefore(Date nbf) { + if (nbf != null) { + ensureClaims().setNotBefore(nbf); + } else { + if (this.claims != null) { + //noinspection ConstantConditions + this.claims.setNotBefore(nbf); + } + } + return this; + } + + @Override + public JwtBuilder setIssuedAt(Date iat) { + if (iat != null) { + ensureClaims().setIssuedAt(iat); + } else { + if (this.claims != null) { + //noinspection ConstantConditions + this.claims.setIssuedAt(iat); + } + } + return this; + } + + @Override + public JwtBuilder setId(String jti) { + if (Strings.hasText(jti)) { + ensureClaims().setId(jti); + } else { + if (this.claims != null) { + claims.setId(jti); + } + } + return this; + } + + @Override + public JwtBuilder claim(String name, Object value) { + Assert.hasText(name, "Claim property name cannot be null or empty."); + if (this.claims == null) { + if (value != null) { + ensureClaims().put(name, value); + } + } else { + if (value == null) { + this.claims.remove(name); + } else { + this.claims.put(name, value); + } + } + + return this; + } + + @Override + public String compact() { + if (payload == null && Collections.isEmpty(claims)) { + throw new IllegalStateException("Either 'payload' or 'claims' must be specified."); + } + + 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; + } else { + jwsHeader = new DefaultJwsHeader(header); + } + + if (key != null) { + jwsHeader.setAlgorithm(algorithm.getValue()); + } else { + //no signature - plaintext JWT: + jwsHeader.setAlgorithm(SignatureAlgorithm.NONE.getValue()); + } + + if (compressionCodec != null) { + jwsHeader.setCompressionAlgorithm(compressionCodec.getAlgorithmName()); + } + + String base64UrlEncodedHeader = base64UrlEncode(jwsHeader, "Unable to serialize header to json."); + + String base64UrlEncodedBody; + + 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."); + } + + String jwt = base64UrlEncodedHeader + JwtParser.SEPARATOR_CHAR + base64UrlEncodedBody; + + if (key != null) { //jwt must be signed: + + JwtSigner signer = createSigner(algorithm, key); + + String base64UrlSignature = signer.sign(jwt); + + jwt += JwtParser.SEPARATOR_CHAR + base64UrlSignature; + } else { + // no signature (plaintext), but must terminate w/ a period, see + // https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-6.1 + jwt += JwtParser.SEPARATOR_CHAR; + } + + return jwt; + } + + /* + * @since 0.5 mostly to allow testing overrides + */ + protected JwtSigner createSigner(SignatureAlgorithm alg, Key key) { + return new DefaultJwtSigner(alg, key); + } + + protected String base64UrlEncode(Object o, String errMsg) { + byte[] bytes; + try { + bytes = toJson(o); + } catch (JsonProcessingException e) { + throw new IllegalStateException(errMsg, e); + } + + return TextCodec.BASE64URL.encode(bytes); + } + + + protected byte[] toJson(Object object) throws JsonProcessingException { + return OBJECT_MAPPER.writeValueAsBytes(object); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParser.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParser.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultJwtParser.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,557 @@ +/* + * 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 com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.ClaimJwtException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Clock; +import io.jsonwebtoken.CompressionCodec; +import io.jsonwebtoken.CompressionCodecResolver; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Header; +import io.jsonwebtoken.IncorrectClaimException; +import io.jsonwebtoken.InvalidClaimException; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwsHeader; +import io.jsonwebtoken.Jwt; +import io.jsonwebtoken.JwtHandler; +import io.jsonwebtoken.JwtHandlerAdapter; +import io.jsonwebtoken.JwtParser; +import io.jsonwebtoken.MalformedJwtException; +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.lang.Assert; +import io.jsonwebtoken.lang.Objects; +import io.jsonwebtoken.lang.Strings; + +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(); + + private byte[] keyBytes; + + private Key key; + + private SigningKeyResolver signingKeyResolver; + + private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver(); + + Claims expectedClaims = new DefaultClaims(); + + private Clock clock = DefaultClock.INSTANCE; + + private long allowedClockSkewMillis = 0; + + @Override + public JwtParser requireIssuedAt(Date issuedAt) { + expectedClaims.setIssuedAt(issuedAt); + return this; + } + + @Override + public JwtParser requireIssuer(String issuer) { + expectedClaims.setIssuer(issuer); + return this; + } + + @Override + public JwtParser requireAudience(String audience) { + expectedClaims.setAudience(audience); + return this; + } + + @Override + public JwtParser requireSubject(String subject) { + expectedClaims.setSubject(subject); + return this; + } + + @Override + public JwtParser requireId(String id) { + expectedClaims.setId(id); + return this; + } + + @Override + public JwtParser requireExpiration(Date expiration) { + expectedClaims.setExpiration(expiration); + return this; + } + + @Override + public JwtParser requireNotBefore(Date notBefore) { + expectedClaims.setNotBefore(notBefore); + return this; + } + + @Override + public JwtParser 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 JwtParser setClock(Clock clock) { + Assert.notNull(clock, "Clock instance cannot be null."); + this.clock = clock; + return this; + } + + @Override + public JwtParser setAllowedClockSkewSeconds(long seconds) { + this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND); + return this; + } + + @Override + public JwtParser setSigningKey(byte[] key) { + Assert.notEmpty(key, "signing key cannot be null or empty."); + this.keyBytes = key; + return this; + } + + @Override + public JwtParser setSigningKey(String base64EncodedKeyBytes) { + Assert.hasText(base64EncodedKeyBytes, "signing key cannot be null or empty."); + this.keyBytes = TextCodec.BASE64.decode(base64EncodedKeyBytes); + return this; + } + + @Override + public JwtParser setSigningKey(Key key) { + Assert.notNull(key, "signing key cannot be null."); + this.key = key; + return this; + } + + @Override + public JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver) { + Assert.notNull(signingKeyResolver, "SigningKeyResolver cannot be null."); + this.signingKeyResolver = signingKeyResolver; + return this; + } + + @Override + public JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) { + Assert.notNull(compressionCodecResolver, "compressionCodecResolver cannot be null."); + this.compressionCodecResolver = compressionCodecResolver; + return this; + } + + @Override + public boolean isSigned(String jwt) { + + if (jwt == null) { + return false; + } + + int delimiterCount = 0; + + for (int i = 0; i < jwt.length(); i++) { + char c = jwt.charAt(i); + + if (delimiterCount == 2) { + return !Character.isWhitespace(c) && c != SEPARATOR_CHAR; + } + + if (c == SEPARATOR_CHAR) { + delimiterCount++; + } + } + + return false; + } + + @Override + public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException { + + Assert.hasText(jwt, "JWT String argument cannot be null or empty."); + + String base64UrlEncodedHeader = null; + String base64UrlEncodedPayload = null; + String base64UrlEncodedDigest = null; + + int delimiterCount = 0; + + StringBuilder sb = new StringBuilder(128); + + for (char c : jwt.toCharArray()) { + + if (c == SEPARATOR_CHAR) { + + CharSequence tokenSeq = Strings.clean(sb); + String token = tokenSeq!=null?tokenSeq.toString():null; + + if (delimiterCount == 0) { + base64UrlEncodedHeader = token; + } else if (delimiterCount == 1) { + base64UrlEncodedPayload = token; + } + + delimiterCount++; + sb.setLength(0); + } else { + sb.append(c); + } + } + + if (delimiterCount != 2) { + String msg = "JWT strings must contain exactly 2 period characters. Found: " + delimiterCount; + throw new MalformedJwtException(msg); + } + if (sb.length() > 0) { + 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); + + if (base64UrlEncodedDigest != null) { + header = new DefaultJwsHeader(m); + } else { + header = new DefaultHeader(m); + } + + compressionCodec = compressionCodecResolver.resolveCompressionCodec(header); + } + + // =============== 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); + } + + Claims claims = null; + + if (payload.charAt(0) == '{' && payload.charAt(payload.length() - 1) == '}') { //likely to be json, parse it: + Map claimsMap = readValue(payload); + claims = new DefaultClaims(claimsMap); + } + + // =============== Signature ================= + if (base64UrlEncodedDigest != null) { //it is signed - validate the signature + + JwsHeader jwsHeader = (JwsHeader) header; + + SignatureAlgorithm algorithm = null; + + if (header != null) { + String alg = jwsHeader.getAlgorithm(); + if (Strings.hasText(alg)) { + algorithm = SignatureAlgorithm.forName(alg); + } + } + + 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."; + throw new MalformedJwtException(msg); + } + + if (key != null && keyBytes != null) { + throw new IllegalStateException("A key object and key bytes cannot both be specified. Choose either."); + } else if ((key != null || keyBytes != null) && signingKeyResolver != null) { + String object = key != null ? "a key object" : "key bytes"; + throw new IllegalStateException("A signing key resolver and " + object + " cannot both be specified. Choose either."); + } + + //digitally signed, let's assert the signature: + Key key = this.key; + + if (key == null) { //fall back to keyBytes + + byte[] keyBytes = this.keyBytes; + + if (Objects.isEmpty(keyBytes) && signingKeyResolver != null) { //use the signingKeyResolver + if (claims != null) { + key = signingKeyResolver.resolveSigningKey(jwsHeader, claims); + } else { + key = signingKeyResolver.resolveSigningKey(jwsHeader, payload); + } + } + + 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 = new SecretKeySpec(keyBytes, algorithm.getJcaName()); + } + } + + 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; + + JwtSignatureValidator validator; + try { + validator = createSignatureValidator(algorithm, key); + } catch (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."; + 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."; + throw new SignatureException(msg); + } + } + + final boolean allowSkew = this.allowedClockSkewMillis > 0; + + //since 0.3: + if (claims != null) { + + SimpleDateFormat sdf; + + final Date now = this.clock.now(); + long nowTime = now.getTime(); + + //https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.4 + //token MUST NOT be accepted on or after any specified exp time: + Date exp = claims.getExpiration(); + if (exp != null) { + + 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); + + long differenceMillis = maxTime - exp.getTime(); + + String msg = "JWT expired at " + expVal + ". Current time: " + nowVal + ", a difference of " + + differenceMillis + " milliseconds. Allowed clock skew: " + + this.allowedClockSkewMillis + " milliseconds."; + throw new ExpiredJwtException(header, claims, msg); + } + } + + //https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.5 + //token MUST NOT be accepted before any specified nbf time: + Date nbf = claims.getNotBefore(); + if (nbf != null) { + + 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); + + long differenceMillis = nbf.getTime() - minTime; + + String msg = "JWT must not be accepted before " + nbfVal + ". Current time: " + nowVal + + ", a difference of " + + differenceMillis + " milliseconds. Allowed clock skew: " + + this.allowedClockSkewMillis + " milliseconds."; + throw new PrematureJwtException(header, claims, msg); + } + } + + validateExpectedClaims(header, claims); + } + + Object body = claims != null ? claims : payload; + + if (base64UrlEncodedDigest != null) { + return new DefaultJws((JwsHeader) header, body, base64UrlEncodedDigest); + } else { + return new DefaultJwt(header, body); + } + } + + private void validateExpectedClaims(Header header, Claims claims) { + for (String expectedClaimName : expectedClaims.keySet()) { + + Object expectedClaimValue = expectedClaims.get(expectedClaimName); + Object actualClaimValue = 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); + } + + InvalidClaimException invalidClaimException = null; + + if (actualClaimValue == null) { + 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 + ); + invalidClaimException = new IncorrectClaimException(header, claims, msg); + } + + if (invalidClaimException != null) { + invalidClaimException.setClaimName(expectedClaimName); + invalidClaimException.setClaimValue(expectedClaimValue); + throw invalidClaimException; + } + } + } + + /* + * @since 0.5 mostly to allow testing overrides + */ + protected JwtSignatureValidator createSignatureValidator(SignatureAlgorithm alg, Key key) { + return new DefaultJwtSignatureValidator(alg, key); + } + + @Override + public T parse(String compact, JwtHandler handler) + throws ExpiredJwtException, MalformedJwtException, SignatureException { + Assert.notNull(handler, "JwtHandler argument cannot be null."); + Assert.hasText(compact, "JWT String argument cannot be null or empty."); + + Jwt jwt = parse(compact); + + if (jwt instanceof Jws) { + Jws jws = (Jws) jwt; + Object body = jws.getBody(); + if (body instanceof Claims) { + return handler.onClaimsJws((Jws) jws); + } else { + return handler.onPlaintextJws((Jws) jws); + } + } else { + Object body = jwt.getBody(); + if (body instanceof Claims) { + return handler.onClaimsJwt((Jwt) jwt); + } else { + return handler.onPlaintextJwt((Jwt) jwt); + } + } + } + + @Override + public Jwt parsePlaintextJwt(String plaintextJwt) { + return parse(plaintextJwt, new JwtHandlerAdapter>() { + @Override + public Jwt onPlaintextJwt(Jwt jwt) { + return jwt; + } + }); + } + + @Override + public Jwt parseClaimsJwt(String claimsJwt) { + try { + return parse(claimsJwt, new JwtHandlerAdapter>() { + @Override + public Jwt onClaimsJwt(Jwt jwt) { + return jwt; + } + }); + } catch (IllegalArgumentException iae) { + throw new UnsupportedJwtException("Signed JWSs are not supported.", iae); + } + } + + @Override + public Jws parsePlaintextJws(String plaintextJws) { + try { + return parse(plaintextJws, new JwtHandlerAdapter>() { + @Override + public Jws onPlaintextJws(Jws jws) { + return jws; + } + }); + } catch (IllegalArgumentException iae) { + throw new UnsupportedJwtException("Signed JWSs are not supported.", iae); + } + } + + @Override + public Jws parseClaimsJws(String claimsJws) { + return parse(claimsJws, new JwtHandlerAdapter>() { + @Override + public Jws onClaimsJws(Jws jws) { + return jws; + } + }); + } + + @SuppressWarnings("unchecked") + protected Map readValue(String val) { + try { + return objectMapper.readValue(val, Map.class); + } catch (IOException e) { + throw new MalformedJwtException("Unable to read JSON value: " + val, e); + } + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultTextCodecFactory.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultTextCodecFactory.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/DefaultTextCodecFactory.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 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; + +public class DefaultTextCodecFactory implements TextCodecFactory { + + protected String getSystemProperty(String key) { + return System.getProperty(key); + } + + protected boolean isAndroid() { + + String name = getSystemProperty("java.vm.name"); + if (name != null) { + String lcase = name.toLowerCase(); + return lcase.contains("dalvik"); + } + + name = getSystemProperty("java.vm.vendor"); + if (name != null) { + String lcase = name.toLowerCase(); + return lcase.contains("android"); + } + + return false; + } + + + @Override + public TextCodec getTextCodec() { + + if (isAndroid()) { + return new AndroidBase64Codec(); + } + + return new Base64Codec(); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/FixedClock.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/FixedClock.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/FixedClock.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,39 @@ +package io.jsonwebtoken.impl; + +import io.jsonwebtoken.Clock; + +import java.util.Date; + +/** + * A {@code Clock} implementation that is constructed with a seed timestamp and always reports that same + * timestamp. + * + * @since 0.7.0 + */ +public class FixedClock implements Clock { + + private final Date now; + + /** + * Creates a new fixed clock using new {@link Date Date}() as the seed timestamp. All calls to + * {@link #now now()} will always return this seed Date. + */ + public FixedClock() { + this(new Date()); + } + + /** + * Creates a new fixed clock using the specified seed timestamp. All calls to + * {@link #now now()} will always return this seed Date. + * + * @param now the specified Date to always return from all calls to {@link #now now()}. + */ + public FixedClock(Date now) { + this.now = now; + } + + @Override + public Date now() { + return this.now; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/JwtMap.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/JwtMap.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/JwtMap.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,174 @@ +/* + * 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.lang.Assert; + +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 { + + private final Map map; + + public JwtMap() { + this(new LinkedHashMap()); + } + + public JwtMap(Map map) { + Assert.notNull(map, "Map argument cannot be null."); + this.map = map; + } + + protected String getString(String name) { + Object v = get(name); + return v != null ? String.valueOf(v) : null; + } + + protected static Date toDate(Object v, String name) { + if (v == null) { + return null; + } else if (v instanceof Date) { + return (Date) v; + } 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); + } 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."); + } + } + + protected void setValue(String name, Object v) { + if (v == null) { + map.remove(name); + } else { + map.put(name, v); + } + } + + protected Date getDate(String name) { + Object v = map.get(name); + return toDate(v, name); + } + + protected void setDate(String name, Date d) { + if (d == null) { + map.remove(name); + } else { + long seconds = d.getTime() / 1000; + map.put(name, seconds); + } + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object o) { + return map.containsKey(o); + } + + @Override + public boolean containsValue(Object o) { + return map.containsValue(o); + } + + @Override + public Object get(Object o) { + return map.get(o); + } + + @Override + public Object put(String s, Object o) { + if (o == null) { + return map.remove(s); + } else { + return map.put(s, o); + } + } + + @Override + public Object remove(Object o) { + return map.remove(o); + } + + @SuppressWarnings("NullableProblems") + @Override + public void putAll(Map m) { + if (m == null) { + return; + } + for (String s : m.keySet()) { + map.put(s, m.get(s)); + } + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + + @Override + public String toString() { + return map.toString(); + } + + @Override + public int hashCode() { + return map.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return map.equals(obj); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.impl; + +public interface TextCodec { + + public static final TextCodec BASE64 = new DefaultTextCodecFactory().getTextCodec(); + public static final TextCodec BASE64URL = new Base64UrlCodec(); + + String encode(String data); + + String encode(byte[] data); + + byte[] decode(String encoded); + + String decodeToString(String encoded); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodecFactory.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodecFactory.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/TextCodecFactory.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015 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; + +public interface TextCodecFactory { + + TextCodec getTextCodec(); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/AbstractCompressionCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/AbstractCompressionCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/AbstractCompressionCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 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.compression; + +import io.jsonwebtoken.CompressionCodec; +import io.jsonwebtoken.CompressionException; +import io.jsonwebtoken.lang.Assert; + +import java.io.IOException; + +/** + * Abstract class that asserts arguments and wraps IOException with CompressionException. + * + * @since 0.6.0 + */ +public abstract class AbstractCompressionCodec implements CompressionCodec { + + /** + * Implement this method to do the actual work of compressing the payload + * + * @param payload the bytes to compress + * @return the compressed bytes + * @throws IOException if the compression causes an IOException + */ + protected abstract byte[] doCompress(byte[] payload) throws IOException; + + /** + * Asserts that payload is not null and calls {@link #doCompress(byte[]) doCompress} + * + * @param payload bytes to compress + * @return compressed bytes + * @throws CompressionException if {@link #doCompress(byte[]) doCompress} throws an IOException + */ + @Override + public final byte[] compress(byte[] payload) { + Assert.notNull(payload, "payload cannot be null."); + + try { + return doCompress(payload); + } catch (IOException e) { + throw new CompressionException("Unable to compress payload.", e); + } + } + + /** + * Asserts the compressed bytes is not null and calls {@link #doDecompress(byte[]) doDecompress} + * + * @param compressed compressed bytes + * @return decompressed bytes + * @throws CompressionException if {@link #doDecompress(byte[]) doDecompress} throws an IOException + */ + @Override + public final byte[] decompress(byte[] compressed) { + Assert.notNull(compressed, "compressed bytes cannot be null."); + + try { + return doDecompress(compressed); + } catch (IOException e) { + throw new CompressionException("Unable to decompress bytes.", e); + } + } + + /** + * Implement this method to do the actual work of decompressing the compressed bytes. + * + * @param compressed compressed bytes + * @return decompressed bytes + * @throws IOException if the decompression runs into an IO problem + */ + protected abstract byte[] doDecompress(byte[] compressed) throws IOException; +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/CompressionCodecs.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/CompressionCodecs.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/CompressionCodecs.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 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.compression; + +import io.jsonwebtoken.CompressionCodec; + +/** + * Provides default implementations of the {@link CompressionCodec} interface. + * + * @see #DEFLATE + * @see #GZIP + * + * @since 0.6.0 + * @deprecated use {@link io.jsonwebtoken.CompressionCodecs} instead. + */ +@Deprecated +public final class CompressionCodecs { + + private static final CompressionCodecs I = new CompressionCodecs(); + + private CompressionCodecs(){} //prevent external instantiation + + /** + * Codec implementing the deflate compression algorithm + * @deprecated use {@link io.jsonwebtoken.CompressionCodecs#DEFLATE} instead. + */ + @Deprecated + public static final CompressionCodec DEFLATE = io.jsonwebtoken.CompressionCodecs.DEFLATE; + + /** + * Codec implementing the gzip compression algorithm + * @deprecated use {@link io.jsonwebtoken.CompressionCodecs#GZIP} instead. + */ + @Deprecated + public static final CompressionCodec GZIP = io.jsonwebtoken.CompressionCodecs.GZIP; + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DefaultCompressionCodecResolver.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DefaultCompressionCodecResolver.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DefaultCompressionCodecResolver.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 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.compression; + +import io.jsonwebtoken.CompressionCodec; +import io.jsonwebtoken.CompressionCodecResolver; +import io.jsonwebtoken.CompressionException; +import io.jsonwebtoken.Header; +import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Strings; + +/** + * 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 + * 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 + * unrecognized algorithm.
  • + *
+ * + *

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 when + * {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} and + * {@link io.jsonwebtoken.JwtParser#setCompressionCodecResolver(CompressionCodecResolver) parsing} JWTs.

+ * + * @see DeflateCompressionCodec + * @see GzipCompressionCodec + * @since 0.6.0 + */ +public class DefaultCompressionCodecResolver implements CompressionCodecResolver { + + @Override + public CompressionCodec resolveCompressionCodec(Header header) { + String cmpAlg = getAlgorithmFromHeader(header); + + final boolean hasCompressionAlgorithm = Strings.hasText(cmpAlg); + + 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 + "'"); + } + + private String getAlgorithmFromHeader(Header header) { + Assert.notNull(header, "header cannot be null."); + + return header.getCompressionAlgorithm(); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DeflateCompressionCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DeflateCompressionCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/DeflateCompressionCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 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.compression; + +import io.jsonwebtoken.lang.Objects; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterOutputStream; + +/** + * Codec implementing the deflate compression algorithm. + * + * @since 0.6.0 + */ +public class DeflateCompressionCodec extends AbstractCompressionCodec { + + private static final String DEFLATE = "DEF"; + + @Override + public String getAlgorithmName() { + return DEFLATE; + } + + @Override + public byte[] doCompress(byte[] payload) throws IOException { + + Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); + + ByteArrayOutputStream outputStream = null; + DeflaterOutputStream deflaterOutputStream = null; + 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); + } + } + + @Override + public byte[] doDecompress(byte[] compressed) throws IOException { + InflaterOutputStream inflaterOutputStream = null; + ByteArrayOutputStream decompressedOutputStream = null; + + try { + decompressedOutputStream = new ByteArrayOutputStream(); + inflaterOutputStream = new InflaterOutputStream(decompressedOutputStream); + inflaterOutputStream.write(compressed); + inflaterOutputStream.flush(); + return decompressedOutputStream.toByteArray(); + } finally { + Objects.nullSafeClose(decompressedOutputStream, inflaterOutputStream); + } + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/GzipCompressionCodec.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/GzipCompressionCodec.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/compression/GzipCompressionCodec.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 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.compression; + +import io.jsonwebtoken.CompressionCodec; +import io.jsonwebtoken.lang.Objects; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * Codec implementing the gzip compression algorithm. + * + * @since 0.6.0 + */ +public class GzipCompressionCodec extends AbstractCompressionCodec implements CompressionCodec { + + private static final String GZIP = "GZIP"; + + @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 { + 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); + } + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSignatureValidator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSignatureValidator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSignatureValidator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,49 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.impl.TextCodec; +import io.jsonwebtoken.lang.Assert; + +import java.nio.charset.Charset; +import java.security.Key; + +public class DefaultJwtSignatureValidator implements JwtSignatureValidator { + + private static final Charset US_ASCII = Charset.forName("US-ASCII"); + + private final SignatureValidator signatureValidator; + + public DefaultJwtSignatureValidator(SignatureAlgorithm alg, Key key) { + this(DefaultSignatureValidatorFactory.INSTANCE, alg, key); + } + + public DefaultJwtSignatureValidator(SignatureValidatorFactory factory, SignatureAlgorithm alg, Key key) { + Assert.notNull(factory, "SignerFactory argument cannot be null."); + this.signatureValidator = factory.createSignatureValidator(alg, key); + } + + @Override + public boolean isValid(String jwtWithoutSignature, String base64UrlEncodedSignature) { + + byte[] data = jwtWithoutSignature.getBytes(US_ASCII); + + byte[] signature = TextCodec.BASE64URL.decode(base64UrlEncodedSignature); + + return this.signatureValidator.isValid(data, signature); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSigner.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSigner.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultJwtSigner.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,49 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.impl.TextCodec; +import io.jsonwebtoken.lang.Assert; + +import java.nio.charset.Charset; +import java.security.Key; + +public class DefaultJwtSigner implements JwtSigner { + + private static final Charset US_ASCII = Charset.forName("US-ASCII"); + + private final Signer signer; + + public DefaultJwtSigner(SignatureAlgorithm alg, Key key) { + this(DefaultSignerFactory.INSTANCE, alg, key); + } + + public DefaultJwtSigner(SignerFactory factory, SignatureAlgorithm alg, Key key) { + Assert.notNull(factory, "SignerFactory argument cannot be null."); + this.signer = factory.createSigner(alg, key); + } + + @Override + public String sign(String jwtWithoutSignature) { + + byte[] bytesToSign = jwtWithoutSignature.getBytes(US_ASCII); + + byte[] signature = signer.sign(bytesToSign); + + return TextCodec.BASE64URL.encode(signature); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultSignatureValidatorFactory.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultSignatureValidatorFactory.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultSignatureValidatorFactory.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,52 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.lang.Assert; + +import java.security.Key; + +public class DefaultSignatureValidatorFactory implements SignatureValidatorFactory { + + public static final SignatureValidatorFactory INSTANCE = new DefaultSignatureValidatorFactory(); + + @Override + public SignatureValidator createSignatureValidator(SignatureAlgorithm alg, Key key) { + Assert.notNull(alg, "SignatureAlgorithm cannot be null."); + Assert.notNull(key, "Signing Key cannot be null."); + + switch (alg) { + case HS256: + case HS384: + case HS512: + return new MacValidator(alg, key); + case RS256: + case RS384: + case RS512: + case PS256: + case PS384: + case PS512: + return new RsaSignatureValidator(alg, key); + case ES256: + case ES384: + case ES512: + return new EllipticCurveSignatureValidator(alg, key); + default: + throw new IllegalArgumentException("The '" + alg.name() + "' algorithm cannot be used for signing."); + } + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultSignerFactory.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultSignerFactory.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/DefaultSignerFactory.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,52 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.lang.Assert; + +import java.security.Key; + +public class DefaultSignerFactory implements SignerFactory { + + public static final SignerFactory INSTANCE = new DefaultSignerFactory(); + + @Override + public Signer createSigner(SignatureAlgorithm alg, Key key) { + Assert.notNull(alg, "SignatureAlgorithm cannot be null."); + Assert.notNull(key, "Signing Key cannot be null."); + + switch (alg) { + case HS256: + case HS384: + case HS512: + return new MacSigner(alg, key); + case RS256: + case RS384: + case RS512: + case PS256: + case PS384: + case PS512: + return new RsaSigner(alg, key); + case ES256: + case ES384: + case ES512: + return new EllipticCurveSigner(alg, key); + default: + throw new IllegalArgumentException("The '" + alg.name() + "' algorithm cannot be used for signing."); + } + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2015 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.crypto; + +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.lang.Assert; + +/** + * ElliptiCurve crypto provider. + * + * @since 0.5 + */ +public abstract class EllipticCurveProvider extends SignatureProvider { + + private static final Map EC_CURVE_NAMES = createEcCurveNames(); + + private static Map createEcCurveNames() { + Map m = new HashMap(); //alg to ASN1 OID name + m.put(SignatureAlgorithm.ES256, "secp256r1"); + m.put(SignatureAlgorithm.ES384, "secp384r1"); + m.put(SignatureAlgorithm.ES512, "secp521r1"); + return m; + } + + protected EllipticCurveProvider(SignatureAlgorithm alg, Key key) { + super(alg, key); + Assert.isTrue(alg.isEllipticCurve(), "SignatureAlgorithm must be an Elliptic Curve algorithm."); + } + + /** + * Generates a new secure-random key pair assuming strength enough for the {@link + * SignatureAlgorithm#ES512} algorithm. This is a convenience method that immediately delegates to {@link + * #generateKeyPair(SignatureAlgorithm)} using {@link SignatureAlgorithm#ES512} as the method argument. + * + * @return a new secure-randomly-generated key pair assuming strength enough for the {@link + * SignatureAlgorithm#ES512} algorithm. + * @see #generateKeyPair(SignatureAlgorithm) + * @see #generateKeyPair(SignatureAlgorithm, SecureRandom) + * @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom) + */ + public static KeyPair generateKeyPair() { + return generateKeyPair(SignatureAlgorithm.ES512); + } + + /** + * 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 JJWT's default {@link + * SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method that immediately + * delegates to {@link #generateKeyPair(SignatureAlgorithm, SecureRandom)}. + * + * @param alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or {@code ES512} + * @return a new secure-randomly generated key pair of sufficient strength for the specified {@link + * SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using JJWT's default {@link + * SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. + * @see #generateKeyPair() + * @see #generateKeyPair(SignatureAlgorithm, SecureRandom) + * @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom) + */ + public static KeyPair generateKeyPair(SignatureAlgorithm alg) { + return generateKeyPair(alg, SignatureProvider.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. + * + * @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. + * @return a new secure-randomly generated key pair of sufficient strength for the specified {@link + * SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link + * SecureRandom} random number generator. + * @see #generateKeyPair() + * @see #generateKeyPair(SignatureAlgorithm) + * @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom) + */ + public static KeyPair generateKeyPair(SignatureAlgorithm alg, SecureRandom random) { + return generateKeyPair("ECDSA", "BC", alg, 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 via the specified JCA provider and algorithm name. + * + * @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 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. + * @return a new secure-randomly generated 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 via the specified JCA provider and algorithm name. + * @see #generateKeyPair() + * @see #generateKeyPair(SignatureAlgorithm) + * @see #generateKeyPair(SignatureAlgorithm, SecureRandom) + */ + public static KeyPair generateKeyPair(String jcaAlgorithmName, String jcaProviderName, SignatureAlgorithm alg, + SecureRandom random) { + 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); + String paramSpecCurveName = EC_CURVE_NAMES.get(alg); + g.initialize(org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec(paramSpecCurveName), random); + return g.generateKeyPair(); + } catch (Exception e) { + throw new IllegalStateException("Unable to generate Elliptic Curve KeyPair: " + e.getMessage(), e); + } + } + + /** + * Returns the expected signature byte array length (R + S parts) for + * the specified ECDSA algorithm. + * + * @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 { + + switch (alg) { + case ES256: return 64; + case ES384: return 96; + case ES512: return 132; + default: + throw new JwtException("Unsupported Algorithm: " + alg.name()); + } + } + + + /** + * Transcodes the JCA ASN.1/DER-encoded signature into the concatenated + * R + S format expected by ECDSA JWS. + * + * @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 { + + if (derSignature.length < 8 || derSignature[0] != 48) { + throw new JwtException("Invalid ECDSA signature format"); + } + + int offset; + if (derSignature[1] > 0) { + offset = 2; + } else if (derSignature[1] == (byte) 0x81) { + offset = 3; + } else { + throw new JwtException("Invalid ECDSA signature format"); + } + + byte rLength = derSignature[offset + 1]; + + int i = rLength; + 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)) + 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) { + throw new JwtException("Invalid ECDSA signature format"); + } + + final byte[] concatSignature = new byte[2 * rawLen]; + + System.arraycopy(derSignature, (offset + 2 + rLength) - i, concatSignature, rawLen - i, i); + System.arraycopy(derSignature, (offset + 2 + rLength + 2 + sLength) - j, concatSignature, 2 * rawLen - j, j); + + return concatSignature; + } + + + + /** + * 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 { + + int rawLen = jwsSignature.length / 2; + + int i = rawLen; + + while((i > 0) + && (jwsSignature[rawLen - i] == 0)) + i--; + + int j = i; + + if (jwsSignature[rawLen - i] < 0) { + j += 1; + } + + int k = rawLen; + + while ((k > 0) + && (jwsSignature[2 * rawLen - k] == 0)) + k--; + + int l = k; + + if (jwsSignature[2 * rawLen - k] < 0) { + l += 1; + } + + int len = 2 + j + 2 + l; + + if (len > 255) { + throw new JwtException("Invalid ECDSA signature format"); + } + + int offset; + + final byte derSignature[]; + + if (len < 128) { + derSignature = new byte[2 + 2 + j + 2 + l]; + offset = 1; + } else { + derSignature = new byte[3 + 2 + j + 2 + l]; + derSignature[1] = (byte) 0x81; + offset = 2; + } + + derSignature[0] = 48; + derSignature[offset++] = (byte) len; + derSignature[offset++] = 2; + derSignature[offset++] = (byte) j; + + System.arraycopy(jwsSignature, rawLen - i, derSignature, (offset + j) - i, i); + + offset += j; + + derSignature[offset++] = 2; + derSignature[offset++] = (byte) l; + + System.arraycopy(jwsSignature, 2 * rawLen - k, derSignature, (offset + l) - k, k); + + return derSignature; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 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.crypto; + +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 = + "Elliptic Curve signature validation requires an ECPublicKey instance."; + + public EllipticCurveSignatureValidator(SignatureAlgorithm alg, Key key) { + super(alg, key); + Assert.isTrue(key instanceof ECPublicKey, EC_PUBLIC_KEY_REQD_MSG); + } + + @Override + public boolean isValid(byte[] data, byte[] signature) { + Signature sig = createSignatureInstance(); + PublicKey publicKey = (PublicKey) key; + try { + int expectedSize = getSignatureByteArrayLength(alg); + /** + * + * If the expected size is not valid for JOSE, fall back to ASN.1 DER signature. + * This fallback is for backwards compatibility ONLY (to support tokens generated by previous versions of jjwt) + * and backwards compatibility will possibly be removed in a future version of this library. + * + * **/ + byte[] derSignature = expectedSize != signature.length && signature[0] == 0x30 ? signature : EllipticCurveProvider.transcodeSignatureToDER(signature); + return doVerify(sig, publicKey, data, derSignature); + } catch (Exception e) { + String msg = "Unable to verify Elliptic Curve signature using configured ECPublicKey. " + e.getMessage(); + throw new SignatureException(msg, e); + } + } + + protected boolean doVerify(Signature sig, PublicKey publicKey, byte[] data, byte[] signature) + throws InvalidKeyException, java.security.SignatureException { + sig.initVerify(publicKey); + sig.update(data); + return sig.verify(signature); + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 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.crypto; + +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) { + super(alg, key); + if (!(key instanceof PrivateKey && key instanceof ECKey)) { + String msg = "Elliptic Curve signatures must be computed using an EC PrivateKey. The specified key of " + + "type " + key.getClass().getName() + " is not an EC PrivateKey."; + throw new IllegalArgumentException(msg); + } + } + + @Override + public byte[] sign(byte[] data) { + try { + return doSign(data); + } catch (InvalidKeyException e) { + throw new SignatureException("Invalid Elliptic Curve PrivateKey. " + e.getMessage(), e); + } catch (java.security.SignatureException e) { + throw new SignatureException("Unable to calculate signature using Elliptic Curve PrivateKey. " + e.getMessage(), e); + } catch (JwtException e) { + throw new SignatureException("Unable to convert signature to JOSE format. " + e.getMessage(), e); + } + } + + protected byte[] doSign(byte[] data) throws InvalidKeyException, java.security.SignatureException, JwtException { + PrivateKey privateKey = (PrivateKey)key; + Signature sig = createSignatureInstance(); + sig.initSign(privateKey); + sig.update(data); + return transcodeSignatureToConcat(sig.sign(), getSignatureByteArrayLength(alg)); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/JwtSignatureValidator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/JwtSignatureValidator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/JwtSignatureValidator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,21 @@ +/* + * 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.crypto; + +public interface JwtSignatureValidator { + + boolean isValid(String jwtWithoutSignature, String base64UrlEncodedSignature); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/JwtSigner.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/JwtSigner.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/JwtSigner.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,21 @@ +/* + * 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.crypto; + +public interface JwtSigner { + + String sign(String jwtWithoutSignature); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacProvider.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacProvider.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacProvider.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,103 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.lang.Assert; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; +import java.security.SecureRandom; + +public abstract class MacProvider extends SignatureProvider { + + protected MacProvider(SignatureAlgorithm alg, Key key) { + super(alg, key); + Assert.isTrue(alg.isHmac(), "SignatureAlgorithm must be a HMAC SHA algorithm."); + } + + /** + * 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 + * SignatureAlgorithm#HS512} as the method argument. + * + * @return a new secure-random 512 bit secret key suitable for creating and verifying HMAC signatures. + * @see #generateKey(SignatureAlgorithm) + * @see #generateKey(SignatureAlgorithm, SecureRandom) + * @since 0.5 + */ + public static SecretKey generateKey() { + return generateKey(SignatureAlgorithm.HS512); + } + + /** + * Generates a new secure-random secret key of a length suitable for creating and verifying HMAC signatures + * according to the specified {@code SignatureAlgorithm} using JJWT's default {@link + * SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method that immediately + * delegates to {@link #generateKey(SignatureAlgorithm, SecureRandom)}. + * + * @param alg the desired signature algorithm + * @return a new secure-random secret key of a length suitable for creating and verifying HMAC signatures according + * to the specified {@code SignatureAlgorithm} using JJWT's default {@link SignatureProvider#DEFAULT_SECURE_RANDOM + * SecureRandom instance}. + * @see #generateKey() + * @see #generateKey(SignatureAlgorithm, SecureRandom) + * @since 0.5 + */ + public static SecretKey generateKey(SignatureAlgorithm alg) { + return generateKey(alg, SignatureProvider.DEFAULT_SECURE_RANDOM); + } + + /** + * Generates a new secure-random secret key of a length suitable for creating and verifying HMAC signatures + * according to the specified {@code SignatureAlgorithm} using the specified SecureRandom number generator. This + * implementation returns secure-random key sizes as follows: + * + * + * + *
Key Sizes
Signature Algorithm Generated Key Size
HS256 256 bits (32 bytes)
HS384 384 bits (48 bytes)
HS512 512 bits (64 bytes)
+ * + * @param alg the signature algorithm that will be used with the generated key + * @param random the secure random number generator used during key generation + * @return a new secure-random secret key of a length suitable for creating and verifying HMAC signatures according + * to the specified {@code SignatureAlgorithm} using the specified SecureRandom number generator. + * @see #generateKey() + * @see #generateKey(SignatureAlgorithm) + * @since 0.5 + */ + public static SecretKey generateKey(SignatureAlgorithm alg, SecureRandom random) { + + Assert.isTrue(alg.isHmac(), "SignatureAlgorithm argument must represent an HMAC algorithm."); + + byte[] bytes; + + switch (alg) { + case HS256: + bytes = new byte[32]; + break; + case HS384: + bytes = new byte[48]; + break; + default: + bytes = new byte[64]; + } + + random.nextBytes(bytes); + + return new SecretKeySpec(bytes, alg.getJcaName()); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacSigner.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacSigner.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacSigner.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,68 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.lang.Assert; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; + +public class MacSigner extends MacProvider implements Signer { + + public MacSigner(SignatureAlgorithm alg, byte[] key) { + this(alg, new SecretKeySpec(key, alg.getJcaName())); + } + + public MacSigner(SignatureAlgorithm alg, Key key) { + super(alg, key); + Assert.isTrue(alg.isHmac(), "The MacSigner only supports HMAC signature algorithms."); + if (!(key instanceof SecretKey)) { + String msg = "MAC signatures must be computed and verified using a SecretKey. The specified key of " + + "type " + key.getClass().getName() + " is not a SecretKey."; + throw new IllegalArgumentException(msg); + } + } + + @Override + public byte[] sign(byte[] data) { + Mac mac = getMacInstance(); + return mac.doFinal(data); + } + + protected Mac getMacInstance() throws SignatureException { + try { + return doGetMacInstance(); + } catch (NoSuchAlgorithmException e) { + String msg = "Unable to obtain JCA MAC algorithm '" + alg.getJcaName() + "': " + e.getMessage(); + throw new SignatureException(msg, e); + } catch (InvalidKeyException e) { + String msg = "The specified signing key is not a valid " + alg.name() + " key: " + e.getMessage(); + throw new SignatureException(msg, e); + } + } + + protected Mac doGetMacInstance() throws NoSuchAlgorithmException, InvalidKeyException { + Mac mac = Mac.getInstance(alg.getJcaName()); + mac.init(key); + return mac; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacValidator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacValidator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/MacValidator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,37 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; + +import java.security.Key; +import java.security.MessageDigest; +import java.util.Arrays; + +public class MacValidator implements SignatureValidator { + + private final MacSigner signer; + + public MacValidator(SignatureAlgorithm alg, Key key) { + this.signer = new MacSigner(alg, key); + } + + @Override + public boolean isValid(byte[] data, byte[] signature) { + byte[] computed = this.signer.sign(data); + return MessageDigest.isEqual(computed, signature); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaProvider.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaProvider.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaProvider.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,161 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.lang.Assert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.HashMap; +import java.util.Map; + +public abstract class RsaProvider extends SignatureProvider { + + private static final Map PSS_PARAMETER_SPECS = createPssParameterSpecs(); + + private static Map createPssParameterSpecs() { + + Map m = new HashMap(); + + MGF1ParameterSpec ps = MGF1ParameterSpec.SHA256; + PSSParameterSpec spec = new PSSParameterSpec(ps.getDigestAlgorithm(), "MGF1", ps, 32, 1); + m.put(SignatureAlgorithm.PS256, spec); + + ps = MGF1ParameterSpec.SHA384; + spec = new PSSParameterSpec(ps.getDigestAlgorithm(), "MGF1", ps, 48, 1); + m.put(SignatureAlgorithm.PS384, spec); + + ps = MGF1ParameterSpec.SHA512; + spec = new PSSParameterSpec(ps.getDigestAlgorithm(), "MGF1", ps, 64, 1); + m.put(SignatureAlgorithm.PS512, spec); + + return m; + } + + protected RsaProvider(SignatureAlgorithm alg, Key key) { + super(alg, key); + Assert.isTrue(alg.isRsa(), "SignatureAlgorithm must be an RSASSA or RSASSA-PSS algorithm."); + } + + protected Signature createSignatureInstance() { + + Signature sig = super.createSignatureInstance(); + + PSSParameterSpec spec = PSS_PARAMETER_SPECS.get(alg); + if (spec != null) { + setParameter(sig, spec); + } + return sig; + } + + protected void setParameter(Signature sig, PSSParameterSpec spec) { + try { + doSetParameter(sig, spec); + } catch (InvalidAlgorithmParameterException e) { + String msg = "Unsupported RSASSA-PSS parameter '" + spec + "': " + e.getMessage(); + throw new SignatureException(msg, e); + } + } + + protected void doSetParameter(Signature sig, PSSParameterSpec spec) throws InvalidAlgorithmParameterException { + sig.setParameter(spec); + } + + /** + * Generates a new RSA secure-random 4096 bit key pair. 4096 bits is JJWT's current recommended minimum key size + * for use in modern applications (during or after year 2015). This is a convenience method that immediately + * delegates to {@link #generateKeyPair(int)}. + * + * @return a new RSA secure-random 4096 bit key pair. + * @see #generateKeyPair(int) + * @see #generateKeyPair(int, SecureRandom) + * @see #generateKeyPair(String, int, SecureRandom) + * @since 0.5 + */ + public static KeyPair generateKeyPair() { + return generateKeyPair(4096); + } + + /** + * Generates a new RSA secure-randomly key pair of the specified size using JJWT's default {@link + * SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method that immediately + * delegates to {@link #generateKeyPair(int, SecureRandom)}. + * + * @param keySizeInBits the key size in bits (NOT bytes). + * @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.5 + */ + public static KeyPair generateKeyPair(int keySizeInBits) { + return generateKeyPair(keySizeInBits, SignatureProvider.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. + * + * @param keySizeInBits the key size in bits (NOT bytes) + * @param random the secure random number generator to use during key generation. + * @return a new RSA secure-random key pair of the specified size using the given SecureRandom number generator. + * @see #generateKeyPair() + * @see #generateKeyPair(int) + * @see #generateKeyPair(String, int, SecureRandom) + * @since 0.5 + */ + public static KeyPair generateKeyPair(int keySizeInBits, SecureRandom random) { + return generateKeyPair("RSA", keySizeInBits, random); + } + + /** + * Generates a new secure-random key pair of the specified size using the specified SecureRandom according to the + * specified {@code jcaAlgorithmName}. + * + * @param jcaAlgorithmName the name of the JCA algorithm to use for key pair generation, for example, {@code RSA}. + * @param keySizeInBits the key size in bits (NOT bytes) + * @param random the SecureRandom generator to use during key generation. + * @return a new secure-randomly generated key pair of the specified size using the specified SecureRandom according + * to the specified {@code jcaAlgorithmName}. + * @see #generateKeyPair() + * @see #generateKeyPair(int) + * @see #generateKeyPair(int, SecureRandom) + * @since 0.5 + */ + protected static KeyPair generateKeyPair(String jcaAlgorithmName, int keySizeInBits, SecureRandom random) { + KeyPairGenerator keyGenerator; + try { + keyGenerator = KeyPairGenerator.getInstance(jcaAlgorithmName); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Unable to obtain an RSA KeyPairGenerator: " + e.getMessage(), e); + } + + keyGenerator.initialize(keySizeInBits, random); + + return keyGenerator.genKeyPair(); + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSignatureValidator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSignatureValidator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSignatureValidator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,66 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.lang.Assert; + +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PublicKey; +import java.security.Signature; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +public class RsaSignatureValidator extends RsaProvider implements SignatureValidator { + + private final RsaSigner SIGNER; + + public RsaSignatureValidator(SignatureAlgorithm alg, Key key) { + super(alg, key); + Assert.isTrue(key instanceof RSAPrivateKey || key instanceof RSAPublicKey, + "RSA Signature validation requires either a RSAPublicKey or RSAPrivateKey instance."); + this.SIGNER = key instanceof RSAPrivateKey ? new RsaSigner(alg, key) : null; + } + + @Override + public boolean isValid(byte[] data, byte[] signature) { + if (key instanceof PublicKey) { + Signature sig = createSignatureInstance(); + PublicKey publicKey = (PublicKey) key; + try { + return doVerify(sig, publicKey, data, signature); + } catch (Exception e) { + String msg = "Unable to verify RSA signature using configured PublicKey. " + e.getMessage(); + throw new SignatureException(msg, e); + } + } 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); + } + } + + protected boolean doVerify(Signature sig, PublicKey publicKey, byte[] data, byte[] signature) + throws InvalidKeyException, java.security.SignatureException { + sig.initVerify(publicKey); + sig.update(data); + return sig.verify(signature); + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSigner.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSigner.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/RsaSigner.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.impl.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; + +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.interfaces.RSAKey; + +public class RsaSigner extends RsaProvider implements Signer { + + public RsaSigner(SignatureAlgorithm alg, Key key) { + super(alg, key); + // https://github.com/jwtk/jjwt/issues/68 + // Instead of checking for an instance of RSAPrivateKey, check for PrivateKey and RSAKey: + if (!(key instanceof PrivateKey && key instanceof RSAKey)) { + String msg = "RSA signatures must be computed using an RSA PrivateKey. The specified key of type " + + key.getClass().getName() + " is not an RSA PrivateKey."; + throw new IllegalArgumentException(msg); + } + } + + @Override + public byte[] sign(byte[] data) { + try { + return doSign(data); + } catch (InvalidKeyException e) { + throw new SignatureException("Invalid RSA PrivateKey. " + e.getMessage(), e); + } catch (java.security.SignatureException e) { + throw new SignatureException("Unable to calculate signature using RSA PrivateKey. " + e.getMessage(), e); + } + } + + protected byte[] doSign(byte[] data) throws InvalidKeyException, java.security.SignatureException { + PrivateKey privateKey = (PrivateKey)key; + Signature sig = createSignatureInstance(); + sig.initSign(privateKey); + sig.update(data); + return sig.sign(); + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureProvider.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureProvider.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureProvider.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,79 @@ +/* + * 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.crypto; + +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 { + + /** + * JJWT's default SecureRandom number generator. This RNG is initialized using the JVM default as follows: + * + *

+     * static {
+     *     DEFAULT_SECURE_RANDOM = new SecureRandom();
+     *     DEFAULT_SECURE_RANDOM.nextBytes(new byte[64]);
+     * }
+     * 
+ * + *

nextBytes is called to force the RNG to initialize itself if not already initialized. The + * byte array is not used and discarded immediately for garbage collection.

+ */ + public static final SecureRandom DEFAULT_SECURE_RANDOM; + + static { + DEFAULT_SECURE_RANDOM = new SecureRandom(); + DEFAULT_SECURE_RANDOM.nextBytes(new byte[64]); + } + + protected final SignatureAlgorithm alg; + protected final Key key; + + protected SignatureProvider(SignatureAlgorithm alg, Key key) { + Assert.notNull(alg, "SignatureAlgorithm cannot be null."); + Assert.notNull(key, "Key cannot be null."); + this.alg = alg; + this.key = key; + } + + protected Signature createSignatureInstance() { + try { + return getSignatureInstance(); + } catch (NoSuchAlgorithmException e) { + String msg = "Unavailable " + alg.getFamilyName() + " Signature algorithm '" + alg.getJcaName() + "'."; + if (!alg.isJdkStandard() && !isBouncyCastleAvailable()) { + msg += " This is not a standard JDK algorithm. Try including BouncyCastle in the runtime classpath."; + } + throw new SignatureException(msg, e); + } + } + + protected Signature getSignatureInstance() throws NoSuchAlgorithmException { + return Signature.getInstance(alg.getJcaName()); + } + + protected boolean isBouncyCastleAvailable() { + return RuntimeEnvironment.BOUNCY_CASTLE_AVAILABLE; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureValidator.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureValidator.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureValidator.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,22 @@ +/* + * 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.crypto; + +public interface SignatureValidator { + + boolean isValid(byte[] data, byte[] signature); + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureValidatorFactory.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureValidatorFactory.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignatureValidatorFactory.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.impl.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; + +import java.security.Key; + +public interface SignatureValidatorFactory { + + SignatureValidator createSignatureValidator(SignatureAlgorithm alg, Key key); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/Signer.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/Signer.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/Signer.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,23 @@ +/* + * 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.crypto; + +import io.jsonwebtoken.SignatureException; + +public interface Signer { + + byte[] sign(byte[] data) throws SignatureException; +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignerFactory.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignerFactory.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/impl/crypto/SignerFactory.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.impl.crypto; + +import io.jsonwebtoken.SignatureAlgorithm; + +import java.security.Key; + +public interface SignerFactory { + + Signer createSigner(SignatureAlgorithm alg, Key key); +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Arrays.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Arrays.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Arrays.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,20 @@ +package io.jsonwebtoken.lang; + +/** + * @since 0.6 + */ +public final class Arrays { + + //for code coverage + private static final Arrays INSTANCE = new Arrays(); + + private Arrays(){} + + public static int length(byte[] bytes) { + return bytes != null ? bytes.length : 0; + } + + public static byte[] clean(byte[] bytes) { + return length(bytes) > 0 ? bytes : null; + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Assert.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Assert.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Assert.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,380 @@ +/* + * 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.util.Collection; +import java.util.Map; + +public final class Assert { + + //for code coverage + private static final Assert INSTANCE = new Assert(); + + private Assert(){} + + /** + * Assert a boolean expression, throwing IllegalArgumentException + * if the test result is false. + *
Assert.isTrue(i > 0, "The value must be greater than zero");
+ * @param expression a boolean expression + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(boolean expression, String message) { + if (!expression) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert a boolean expression, throwing IllegalArgumentException + * if the test result is false. + *
Assert.isTrue(i > 0);
+ * @param expression a boolean expression + * @throws IllegalArgumentException if expression is false + */ + public static void isTrue(boolean expression) { + isTrue(expression, "[Assertion failed] - this expression must be true"); + } + + /** + * Assert that an object is null . + *
Assert.isNull(value, "The value must be null");
+ * @param object the object to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object is not null + */ + public static void isNull(Object object, String message) { + if (object != null) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an object is null . + *
Assert.isNull(value);
+ * @param object the object to check + * @throws IllegalArgumentException if the object is not null + */ + public static void isNull(Object object) { + isNull(object, "[Assertion failed] - the object argument must be null"); + } + + /** + * Assert that an object is not null . + *
Assert.notNull(clazz, "The class must not be null");
+ * @param object the object to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object is null + */ + public static void notNull(Object object, String message) { + if (object == null) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an object is not null . + *
Assert.notNull(clazz);
+ * @param object the object to check + * @throws IllegalArgumentException if the object is null + */ + public static void notNull(Object object) { + notNull(object, "[Assertion failed] - this argument is required; it must not be null"); + } + + /** + * Assert that the given String is not empty; that is, + * it must not be null and not the empty String. + *
Assert.hasLength(name, "Name must not be empty");
+ * @param text the String to check + * @param message the exception message to use if the assertion fails + * @see Strings#hasLength + */ + public static void hasLength(String text, String message) { + if (!Strings.hasLength(text)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that the given String is not empty; that is, + * it must not be null and not the empty String. + *
Assert.hasLength(name);
+ * @param text the String to check + * @see Strings#hasLength + */ + public static void hasLength(String text) { + hasLength(text, + "[Assertion failed] - this String argument must have length; it must not be null or empty"); + } + + /** + * Assert that the given String has valid text content; that is, it must not + * be null and must contain at least one non-whitespace character. + *
Assert.hasText(name, "'name' must not be empty");
+ * @param text the String to check + * @param message the exception message to use if the assertion fails + * @see Strings#hasText + */ + public static void hasText(String text, String message) { + if (!Strings.hasText(text)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that the given String has valid text content; that is, it must not + * be null and must contain at least one non-whitespace character. + *
Assert.hasText(name, "'name' must not be empty");
+ * @param text the String to check + * @see Strings#hasText + */ + public static void hasText(String text) { + hasText(text, + "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank"); + } + + /** + * Assert that the given text does not contain the given substring. + *
Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");
+ * @param textToSearch the text to search + * @param substring the substring to find within the text + * @param message the exception message to use if the assertion fails + */ + public static void doesNotContain(String textToSearch, String substring, String message) { + if (Strings.hasLength(textToSearch) && Strings.hasLength(substring) && + textToSearch.indexOf(substring) != -1) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that the given text does not contain the given substring. + *
Assert.doesNotContain(name, "rod");
+ * @param textToSearch the text to search + * @param substring the substring to find within the text + */ + public static void doesNotContain(String textToSearch, String substring) { + doesNotContain(textToSearch, substring, + "[Assertion failed] - this String argument must not contain the substring [" + substring + "]"); + } + + + /** + * Assert that an array has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(array, "The array must have elements");
+ * @param array the array to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object array is null or has no elements + */ + public static void notEmpty(Object[] array, String message) { + if (Objects.isEmpty(array)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an array has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(array);
+ * @param array the array to check + * @throws IllegalArgumentException if the object array is null or has no elements + */ + public static void notEmpty(Object[] array) { + notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element"); + } + + public static void notEmpty(byte[] array, String msg) { + if (Objects.isEmpty(array)) { + throw new IllegalArgumentException(msg); + } + } + + /** + * Assert that an array has no null elements. + * Note: Does not complain if the array is empty! + *
Assert.noNullElements(array, "The array must have non-null elements");
+ * @param array the array to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object array contains a null element + */ + public static void noNullElements(Object[] array, String message) { + if (array != null) { + for (int i = 0; i < array.length; i++) { + if (array[i] == null) { + throw new IllegalArgumentException(message); + } + } + } + } + + /** + * Assert that an array has no null elements. + * Note: Does not complain if the array is empty! + *
Assert.noNullElements(array);
+ * @param array the array to check + * @throws IllegalArgumentException if the object array contains a null element + */ + public static void noNullElements(Object[] array) { + noNullElements(array, "[Assertion failed] - this array must not contain any null elements"); + } + + /** + * Assert that a collection has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(collection, "Collection must have elements");
+ * @param collection the collection to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the collection is null or has no elements + */ + public static void notEmpty(Collection collection, String message) { + if (Collections.isEmpty(collection)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that a collection has elements; that is, it must not be + * null and must have at least one element. + *
Assert.notEmpty(collection, "Collection must have elements");
+ * @param collection the collection to check + * @throws IllegalArgumentException if the collection is null or has no elements + */ + public static void notEmpty(Collection collection) { + notEmpty(collection, + "[Assertion failed] - this collection must not be empty: it must contain at least 1 element"); + } + + /** + * Assert that a Map has entries; that is, it must not be null + * and must have at least one entry. + *
Assert.notEmpty(map, "Map must have entries");
+ * @param map the map to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the map is null or has no entries + */ + public static void notEmpty(Map map, String message) { + if (Collections.isEmpty(map)) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that a Map has entries; that is, it must not be null + * and must have at least one entry. + *
Assert.notEmpty(map);
+ * @param map the map to check + * @throws IllegalArgumentException if the map is null or has no entries + */ + public static void notEmpty(Map map) { + notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry"); + } + + + /** + * Assert that the provided object is an instance of the provided class. + *
Assert.instanceOf(Foo.class, foo);
+ * @param clazz the required class + * @param obj the object to check + * @throws IllegalArgumentException if the object is not an instance of clazz + * @see Class#isInstance + */ + public static void isInstanceOf(Class clazz, Object obj) { + isInstanceOf(clazz, obj, ""); + } + + /** + * Assert that the provided object is an instance of the provided class. + *
Assert.instanceOf(Foo.class, foo);
+ * @param type the type to check against + * @param obj the object to check + * @param message a message which will be prepended to the message produced by + * the function itself, and which may be used to provide context. It should + * normally end in a ": " or ". " so that the function generate message looks + * ok when prepended to it. + * @throws IllegalArgumentException if the object is not an instance of clazz + * @see Class#isInstance + */ + public static void isInstanceOf(Class type, Object obj, String message) { + notNull(type, "Type to check against must not be null"); + if (!type.isInstance(obj)) { + throw new IllegalArgumentException(message + + "Object of class [" + (obj != null ? obj.getClass().getName() : "null") + + "] must be an instance of " + type); + } + } + + /** + * Assert that superType.isAssignableFrom(subType) is true. + *
Assert.isAssignable(Number.class, myClass);
+ * @param superType the super type to check + * @param subType the sub type to check + * @throws IllegalArgumentException if the classes are not assignable + */ + public static void isAssignable(Class superType, Class subType) { + isAssignable(superType, subType, ""); + } + + /** + * Assert that superType.isAssignableFrom(subType) is true. + *
Assert.isAssignable(Number.class, myClass);
+ * @param superType the super type to check against + * @param subType the sub type to check + * @param message a message which will be prepended to the message produced by + * the function itself, and which may be used to provide context. It should + * normally end in a ": " or ". " so that the function generate message looks + * ok when prepended to it. + * @throws IllegalArgumentException if the classes are not assignable + */ + public static void isAssignable(Class superType, Class subType, String message) { + notNull(superType, "Type to check against must not be null"); + if (subType == null || !superType.isAssignableFrom(subType)) { + throw new IllegalArgumentException(message + subType + " is not assignable to " + superType); + } + } + + + /** + * Assert a boolean expression, throwing IllegalStateException + * if the test result is false. Call isTrue if you wish to + * throw IllegalArgumentException on an assertion failure. + *
Assert.state(id == null, "The id property must not already be initialized");
+ * @param expression a boolean expression + * @param message the exception message to use if the assertion fails + * @throws IllegalStateException if expression is false + */ + public static void state(boolean expression, String message) { + if (!expression) { + throw new IllegalStateException(message); + } + } + + /** + * Assert a boolean expression, throwing {@link IllegalStateException} + * if the test result is false. + *

Call {@link #isTrue(boolean)} if you wish to + * throw {@link IllegalArgumentException} on an assertion failure. + *

Assert.state(id == null);
+ * @param expression a boolean expression + * @throws IllegalStateException if the supplied expression is false + */ + public static void state(boolean expression) { + state(expression, "[Assertion failed] - this state invariant must be true"); + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Classes.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Classes.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Classes.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.lang; + +import java.io.InputStream; +import java.lang.reflect.Constructor; + +/** + * @since 0.1 + */ +public final class Classes { + + private static final Classes INSTANCE = new Classes(); + + private Classes() {} + + /** + * @since 0.1 + */ + private static final ClassLoaderAccessor THREAD_CL_ACCESSOR = new ExceptionIgnoringAccessor() { + @Override + protected ClassLoader doGetClassLoader() throws Throwable { + return Thread.currentThread().getContextClassLoader(); + } + }; + + /** + * @since 0.1 + */ + private static final ClassLoaderAccessor CLASS_CL_ACCESSOR = new ExceptionIgnoringAccessor() { + @Override + protected ClassLoader doGetClassLoader() throws Throwable { + return Classes.class.getClassLoader(); + } + }; + + /** + * @since 0.1 + */ + private static final ClassLoaderAccessor SYSTEM_CL_ACCESSOR = new ExceptionIgnoringAccessor() { + @Override + protected ClassLoader doGetClassLoader() throws Throwable { + return ClassLoader.getSystemClassLoader(); + } + }; + + /** + * Attempts to load the specified class name from the current thread's + * {@link Thread#getContextClassLoader() context class loader}, then the + * current ClassLoader (Classes.class.getClassLoader()), then the system/application + * ClassLoader (ClassLoader.getSystemClassLoader(), in that order. If any of them cannot locate + * the specified class, an UnknownClassException is thrown (our RuntimeException equivalent of + * the JRE's ClassNotFoundException. + * + * @param fqcn the fully qualified class name to load + * @return the located class + * @throws UnknownClassException if the class cannot be found. + */ + public static Class forName(String fqcn) throws UnknownClassException { + + Class clazz = THREAD_CL_ACCESSOR.loadClass(fqcn); + + if (clazz == null) { + clazz = CLASS_CL_ACCESSOR.loadClass(fqcn); + } + + if (clazz == null) { + clazz = SYSTEM_CL_ACCESSOR.loadClass(fqcn); + } + + if (clazz == null) { + 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?"; + } + + throw new UnknownClassException(msg); + } + + return clazz; + } + + /** + * Returns the specified resource by checking the current thread's + * {@link Thread#getContextClassLoader() context class loader}, then the + * current ClassLoader (Classes.class.getClassLoader()), then the system/application + * ClassLoader (ClassLoader.getSystemClassLoader(), in that order, using + * {@link ClassLoader#getResourceAsStream(String) getResourceAsStream(name)}. + * + * @param name the name of the resource to acquire from the classloader(s). + * @return the InputStream of the resource found, or null if the resource cannot be found from any + * of the three mentioned ClassLoaders. + * @since 0.8 + */ + public static InputStream getResourceAsStream(String name) { + + InputStream is = THREAD_CL_ACCESSOR.getResourceStream(name); + + if (is == null) { + is = CLASS_CL_ACCESSOR.getResourceStream(name); + } + + if (is == null) { + is = SYSTEM_CL_ACCESSOR.getResourceStream(name); + } + + return is; + } + + public static boolean isAvailable(String fullyQualifiedClassName) { + try { + forName(fullyQualifiedClassName); + return true; + } catch (UnknownClassException e) { + return false; + } + } + + @SuppressWarnings("unchecked") + public static Object newInstance(String fqcn) { + return newInstance(forName(fqcn)); + } + + @SuppressWarnings("unchecked") + public static Object newInstance(String fqcn, Object... args) { + return newInstance(forName(fqcn), args); + } + + public static T newInstance(Class clazz) { + if (clazz == null) { + String msg = "Class method parameter cannot be null."; + throw new IllegalArgumentException(msg); + } + try { + return clazz.newInstance(); + } catch (Exception e) { + throw new InstantiationException("Unable to instantiate class [" + clazz.getName() + "]", e); + } + } + + public static T newInstance(Class clazz, Object... args) { + Class[] argTypes = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + argTypes[i] = args[i].getClass(); + } + Constructor ctor = getConstructor(clazz, argTypes); + return instantiate(ctor, args); + } + + public static Constructor getConstructor(Class clazz, Class... argTypes) { + try { + return clazz.getConstructor(argTypes); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } + + } + + public static T instantiate(Constructor ctor, Object... args) { + try { + return ctor.newInstance(args); + } catch (Exception e) { + String msg = "Unable to instantiate instance with constructor [" + ctor + "]"; + throw new InstantiationException(msg, e); + } + } + + /** + * @since 1.0 + */ + private static interface ClassLoaderAccessor { + Class loadClass(String fqcn); + + InputStream getResourceStream(String name); + } + + /** + * @since 1.0 + */ + private static abstract class ExceptionIgnoringAccessor implements ClassLoaderAccessor { + + public Class loadClass(String fqcn) { + Class clazz = null; + ClassLoader cl = getClassLoader(); + if (cl != null) { + try { + clazz = cl.loadClass(fqcn); + } catch (ClassNotFoundException e) { + //Class couldn't be found by loader + } + } + return clazz; + } + + public InputStream getResourceStream(String name) { + InputStream is = null; + ClassLoader cl = getClassLoader(); + if (cl != null) { + is = cl.getResourceAsStream(name); + } + return is; + } + + protected final ClassLoader getClassLoader() { + try { + return doGetClassLoader(); + } catch (Throwable t) { + //Unable to get ClassLoader + } + return null; + } + + protected abstract ClassLoader doGetClassLoader() throws Throwable; + } +} + Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Collections.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Collections.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Collections.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,368 @@ +/* + * 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.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +public final class Collections { + + //for code coverage + private static final Collections INSTANCE = new Collections(); + + private Collections(){} + + /** + * Return true if the supplied Collection is null + * or empty. Otherwise, return false. + * @param collection the Collection to check + * @return whether the given Collection is empty + */ + public static boolean isEmpty(Collection collection) { + return (collection == null || collection.isEmpty()); + } + + /** + * Returns the collection's size or {@code 0} if the collection is {@code null}. + * + * @param collection the collection to check. + * @return the collection's size or {@code 0} if the collection is {@code null}. + * @since 0.9.2 + */ + public static int size(Collection collection) { + return collection == null ? 0 : collection.size(); + } + + /** + * Returns the map's size or {@code 0} if the map is {@code null}. + * + * @param map the map to check + * @return the map's size or {@code 0} if the map is {@code null}. + * @since 0.9.2 + */ + public static int size(Map map) { + return map == null ? 0 : map.size(); + } + + /** + * Return true if the supplied Map is null + * or empty. Otherwise, return false. + * @param map the Map to check + * @return whether the given Map is empty + */ + public static boolean isEmpty(Map map) { + return (map == null || map.isEmpty()); + } + + /** + * Convert the supplied array into a List. A primitive array gets + * converted into a List of the appropriate wrapper type. + *

A null source value will be converted to an + * empty List. + * @param source the (potentially primitive) array + * @return the converted List result + * @see Objects#toObjectArray(Object) + */ + public static List arrayToList(Object source) { + return Arrays.asList(Objects.toObjectArray(source)); + } + + /** + * Merge the given array into the given Collection. + * @param array the array to merge (may be null) + * @param collection the target Collection to merge the array into + */ + @SuppressWarnings("unchecked") + public static void mergeArrayIntoCollection(Object array, Collection collection) { + if (collection == null) { + throw new IllegalArgumentException("Collection must not be null"); + } + Object[] arr = Objects.toObjectArray(array); + for (Object elem : arr) { + collection.add(elem); + } + } + + /** + * Merge the given Properties instance into the given Map, + * copying all properties (key-value pairs) over. + *

Uses Properties.propertyNames() to even catch + * default properties linked into the original Properties instance. + * @param props the Properties instance to merge (may be null) + * @param map the target Map to merge the properties into + */ + @SuppressWarnings("unchecked") + public static void mergePropertiesIntoMap(Properties props, Map map) { + if (map == null) { + throw new IllegalArgumentException("Map must not be null"); + } + if (props != null) { + for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { + String key = (String) en.nextElement(); + Object value = props.getProperty(key); + if (value == null) { + // Potentially a non-String value... + value = props.get(key); + } + map.put(key, value); + } + } + } + + + /** + * Check whether the given Iterator contains the given element. + * @param iterator the Iterator to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean contains(Iterator iterator, Object element) { + if (iterator != null) { + while (iterator.hasNext()) { + Object candidate = iterator.next(); + if (Objects.nullSafeEquals(candidate, element)) { + return true; + } + } + } + return false; + } + + /** + * Check whether the given Enumeration contains the given element. + * @param enumeration the Enumeration to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean contains(Enumeration enumeration, Object element) { + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + Object candidate = enumeration.nextElement(); + if (Objects.nullSafeEquals(candidate, element)) { + return true; + } + } + } + return false; + } + + /** + * Check whether the given Collection contains the given element instance. + *

Enforces the given instance to be present, rather than returning + * true for an equal element as well. + * @param collection the Collection to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean containsInstance(Collection collection, Object element) { + if (collection != null) { + for (Object candidate : collection) { + if (candidate == element) { + return true; + } + } + } + return false; + } + + /** + * Return true if any element in 'candidates' is + * contained in 'source'; otherwise returns false. + * @param source the source Collection + * @param candidates the candidates to search for + * @return whether any of the candidates has been found + */ + public static boolean containsAny(Collection source, Collection candidates) { + if (isEmpty(source) || isEmpty(candidates)) { + return false; + } + for (Object candidate : candidates) { + if (source.contains(candidate)) { + return true; + } + } + return false; + } + + /** + * Return the first element in 'candidates' that is contained in + * 'source'. If no element in 'candidates' is present in + * 'source' returns null. Iteration order is + * {@link Collection} implementation specific. + * @param source the source Collection + * @param candidates the candidates to search for + * @return the first present object, or null if not found + */ + public static Object findFirstMatch(Collection source, Collection candidates) { + if (isEmpty(source) || isEmpty(candidates)) { + return null; + } + for (Object candidate : candidates) { + if (source.contains(candidate)) { + return candidate; + } + } + return null; + } + + /** + * Find a single value of the given type in the given Collection. + * @param collection the Collection to search + * @param type the type to look for + * @return a value of the given type found if there is a clear match, + * or null if none or more than one such value found + */ + @SuppressWarnings("unchecked") + public static T findValueOfType(Collection collection, Class type) { + if (isEmpty(collection)) { + return null; + } + T value = null; + for (Object element : collection) { + if (type == null || type.isInstance(element)) { + if (value != null) { + // More than one value found... no clear single value. + return null; + } + value = (T) element; + } + } + return value; + } + + /** + * Find a single value of one of the given types in the given Collection: + * searching the Collection for a value of the first type, then + * searching for a value of the second type, etc. + * @param collection the collection to search + * @param types the types to look for, in prioritized order + * @return a value of one of the given types found if there is a clear match, + * or null if none or more than one such value found + */ + public static Object findValueOfType(Collection collection, Class[] types) { + if (isEmpty(collection) || Objects.isEmpty(types)) { + return null; + } + for (Class type : types) { + Object value = findValueOfType(collection, type); + if (value != null) { + return value; + } + } + return null; + } + + /** + * Determine whether the given Collection only contains a single unique object. + * @param collection the Collection to check + * @return true if the collection contains a single reference or + * multiple references to the same instance, false else + */ + public static boolean hasUniqueObject(Collection collection) { + if (isEmpty(collection)) { + return false; + } + boolean hasCandidate = false; + Object candidate = null; + for (Object elem : collection) { + if (!hasCandidate) { + hasCandidate = true; + candidate = elem; + } + else if (candidate != elem) { + return false; + } + } + return true; + } + + /** + * Find the common element type of the given Collection, if any. + * @param collection the Collection to check + * @return the common element type, or null if no clear + * common type has been found (or the collection was empty) + */ + public static Class findCommonElementType(Collection collection) { + if (isEmpty(collection)) { + return null; + } + Class candidate = null; + for (Object val : collection) { + if (val != null) { + if (candidate == null) { + candidate = val.getClass(); + } + else if (candidate != val.getClass()) { + return null; + } + } + } + return candidate; + } + + /** + * Marshal the elements from the given enumeration into an array of the given type. + * Enumeration elements must be assignable to the type of the given array. The array + * returned will be a different instance than the array given. + */ + public static A[] toArray(Enumeration enumeration, A[] array) { + ArrayList elements = new ArrayList(); + while (enumeration.hasMoreElements()) { + elements.add(enumeration.nextElement()); + } + return elements.toArray(array); + } + + /** + * Adapt an enumeration to an iterator. + * @param enumeration the enumeration + * @return the iterator + */ + public static Iterator toIterator(Enumeration enumeration) { + return new EnumerationIterator(enumeration); + } + + /** + * Iterator wrapping an Enumeration. + */ + private static class EnumerationIterator implements Iterator { + + private Enumeration enumeration; + + public EnumerationIterator(Enumeration enumeration) { + this.enumeration = enumeration; + } + + public boolean hasNext() { + return this.enumeration.hasMoreElements(); + } + + public E next() { + return this.enumeration.nextElement(); + } + + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException("Not supported"); + } + } +} + Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/InstantiationException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/InstantiationException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/InstantiationException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -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.lang; + +/** + * @since 0.1 + */ +public class InstantiationException extends RuntimeException { + + public InstantiationException(String s, Throwable t) { + super(s, t); + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Objects.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Objects.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Objects.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,930 @@ +/* + * 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.io.Closeable; +import java.io.IOException; +import java.lang.reflect.Array; +import java.util.Arrays; + +public final class Objects { + + //for code coverage + private static final Objects INSTANCE = new Objects(); + + private Objects(){} + + private static final int INITIAL_HASH = 7; + private static final int MULTIPLIER = 31; + + private static final String EMPTY_STRING = ""; + private static final String NULL_STRING = "null"; + private static final String ARRAY_START = "{"; + private static final String ARRAY_END = "}"; + private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; + private static final String ARRAY_ELEMENT_SEPARATOR = ", "; + + /** + * Return whether the given throwable is a checked exception: + * that is, neither a RuntimeException nor an Error. + * + * @param ex the throwable to check + * @return whether the throwable is a checked exception + * @see java.lang.Exception + * @see java.lang.RuntimeException + * @see java.lang.Error + */ + public static boolean isCheckedException(Throwable ex) { + return !(ex instanceof RuntimeException || ex instanceof Error); + } + + /** + * Check whether the given exception is compatible with the exceptions + * declared in a throws clause. + * + * @param ex the exception to checked + * @param declaredExceptions the exceptions declared in the throws clause + * @return whether the given exception is compatible + */ + public static boolean isCompatibleWithThrowsClause(Throwable ex, Class[] declaredExceptions) { + if (!isCheckedException(ex)) { + return true; + } + if (declaredExceptions != null) { + int i = 0; + while (i < declaredExceptions.length) { + if (declaredExceptions[i].isAssignableFrom(ex.getClass())) { + return true; + } + i++; + } + } + return false; + } + + /** + * Determine whether the given object is an array: + * either an Object array or a primitive array. + * + * @param obj the object to check + */ + public static boolean isArray(Object obj) { + return (obj != null && obj.getClass().isArray()); + } + + /** + * Determine whether the given array is empty: + * i.e. null or of zero length. + * + * @param array the array to check + */ + public static boolean isEmpty(Object[] array) { + return (array == null || array.length == 0); + } + + /** + * Returns {@code true} if the specified byte array is null or of zero length, {@code false} otherwise. + * + * @param array the byte array to check + * @return {@code true} if the specified byte array is null or of zero length, {@code false} otherwise. + */ + public static boolean isEmpty(byte[] array) { + return array == null || array.length == 0; + } + + /** + * Check whether the given array contains the given element. + * + * @param array the array to check (may be null, + * in which case the return value will always be false) + * @param element the element to check for + * @return whether the element has been found in the given array + */ + public static boolean containsElement(Object[] array, Object element) { + if (array == null) { + return false; + } + for (Object arrayEle : array) { + if (nullSafeEquals(arrayEle, element)) { + return true; + } + } + return false; + } + + /** + * Check whether the given array of enum constants contains a constant with the given name, + * ignoring case when determining a match. + * + * @param enumValues the enum values to check, typically the product of a call to MyEnum.values() + * @param constant the constant name to find (must not be null or empty string) + * @return whether the constant has been found in the given array + */ + public static boolean containsConstant(Enum[] enumValues, String constant) { + return containsConstant(enumValues, constant, false); + } + + /** + * Check whether the given array of enum constants contains a constant with the given name. + * + * @param enumValues the enum values to check, typically the product of a call to MyEnum.values() + * @param constant the constant name to find (must not be null or empty string) + * @param caseSensitive whether case is significant in determining a match + * @return whether the constant has been found in the given array + */ + public static boolean containsConstant(Enum[] enumValues, String constant, boolean caseSensitive) { + for (Enum candidate : enumValues) { + if (caseSensitive ? + candidate.toString().equals(constant) : + candidate.toString().equalsIgnoreCase(constant)) { + return true; + } + } + return false; + } + + /** + * Case insensitive alternative to {@link Enum#valueOf(Class, String)}. + * + * @param the concrete Enum type + * @param enumValues the array of all Enum constants in question, usually per Enum.values() + * @param constant the constant to get the enum value of + * @throws IllegalArgumentException if the given constant is not found in the given array + * of enum values. Use {@link #containsConstant(Enum[], String)} as a guard to + * avoid this exception. + */ + public static > E caseInsensitiveValueOf(E[] enumValues, String constant) { + for (E candidate : enumValues) { + if (candidate.toString().equalsIgnoreCase(constant)) { + return candidate; + } + } + throw new IllegalArgumentException( + String.format("constant [%s] does not exist in enum type %s", + constant, enumValues.getClass().getComponentType().getName())); + } + + /** + * Append the given object to the given array, returning a new array + * consisting of the input array contents plus the given object. + * + * @param array the array to append to (can be null) + * @param obj the object to append + * @return the new array (of the same component type; never null) + */ + public static A[] addObjectToArray(A[] array, O obj) { + Class compType = Object.class; + if (array != null) { + compType = array.getClass().getComponentType(); + } else if (obj != null) { + compType = obj.getClass(); + } + int newArrLength = (array != null ? array.length + 1 : 1); + @SuppressWarnings("unchecked") + A[] newArr = (A[]) Array.newInstance(compType, newArrLength); + if (array != null) { + System.arraycopy(array, 0, newArr, 0, array.length); + } + newArr[newArr.length - 1] = obj; + return newArr; + } + + /** + * Convert the given array (which may be a primitive array) to an + * object array (if necessary of primitive wrapper objects). + *

A null source value will be converted to an + * empty Object array. + * + * @param source the (potentially primitive) array + * @return the corresponding object array (never null) + * @throws IllegalArgumentException if the parameter is not an array + */ + public static Object[] toObjectArray(Object source) { + if (source instanceof Object[]) { + return (Object[]) source; + } + if (source == null) { + return new Object[0]; + } + if (!source.getClass().isArray()) { + throw new IllegalArgumentException("Source is not an array: " + source); + } + int length = Array.getLength(source); + if (length == 0) { + return new Object[0]; + } + Class wrapperType = Array.get(source, 0).getClass(); + Object[] newArray = (Object[]) Array.newInstance(wrapperType, length); + for (int i = 0; i < length; i++) { + newArray[i] = Array.get(source, i); + } + return newArray; + } + + + //--------------------------------------------------------------------- + // Convenience methods for content-based equality/hash-code handling + //--------------------------------------------------------------------- + + /** + * Determine if the given objects are equal, returning true + * if both are null or false if only one is + * null. + *

Compares arrays with Arrays.equals, performing an equality + * check based on the array elements rather than the array reference. + * + * @param o1 first Object to compare + * @param o2 second Object to compare + * @return whether the given objects are equal + * @see java.util.Arrays#equals + */ + public static boolean nullSafeEquals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + if (o1.equals(o2)) { + return true; + } + if (o1.getClass().isArray() && o2.getClass().isArray()) { + if (o1 instanceof Object[] && o2 instanceof Object[]) { + return Arrays.equals((Object[]) o1, (Object[]) o2); + } + if (o1 instanceof boolean[] && o2 instanceof boolean[]) { + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + } + if (o1 instanceof byte[] && o2 instanceof byte[]) { + return Arrays.equals((byte[]) o1, (byte[]) o2); + } + if (o1 instanceof char[] && o2 instanceof char[]) { + return Arrays.equals((char[]) o1, (char[]) o2); + } + if (o1 instanceof double[] && o2 instanceof double[]) { + return Arrays.equals((double[]) o1, (double[]) o2); + } + if (o1 instanceof float[] && o2 instanceof float[]) { + return Arrays.equals((float[]) o1, (float[]) o2); + } + if (o1 instanceof int[] && o2 instanceof int[]) { + return Arrays.equals((int[]) o1, (int[]) o2); + } + if (o1 instanceof long[] && o2 instanceof long[]) { + return Arrays.equals((long[]) o1, (long[]) o2); + } + if (o1 instanceof short[] && o2 instanceof short[]) { + return Arrays.equals((short[]) o1, (short[]) o2); + } + } + return false; + } + + /** + * Return as hash code for the given object; typically the value of + * {@link Object#hashCode()}. If the object is an array, + * this method will delegate to any of the nullSafeHashCode + * methods for arrays in this class. If the object is null, + * this method returns 0. + * + * @see #nullSafeHashCode(Object[]) + * @see #nullSafeHashCode(boolean[]) + * @see #nullSafeHashCode(byte[]) + * @see #nullSafeHashCode(char[]) + * @see #nullSafeHashCode(double[]) + * @see #nullSafeHashCode(float[]) + * @see #nullSafeHashCode(int[]) + * @see #nullSafeHashCode(long[]) + * @see #nullSafeHashCode(short[]) + */ + public static int nullSafeHashCode(Object obj) { + if (obj == null) { + return 0; + } + if (obj.getClass().isArray()) { + if (obj instanceof Object[]) { + return nullSafeHashCode((Object[]) obj); + } + if (obj instanceof boolean[]) { + return nullSafeHashCode((boolean[]) obj); + } + if (obj instanceof byte[]) { + return nullSafeHashCode((byte[]) obj); + } + if (obj instanceof char[]) { + return nullSafeHashCode((char[]) obj); + } + if (obj instanceof double[]) { + return nullSafeHashCode((double[]) obj); + } + if (obj instanceof float[]) { + return nullSafeHashCode((float[]) obj); + } + if (obj instanceof int[]) { + return nullSafeHashCode((int[]) obj); + } + if (obj instanceof long[]) { + return nullSafeHashCode((long[]) obj); + } + if (obj instanceof short[]) { + return nullSafeHashCode((short[]) obj); + } + } + return obj.hashCode(); + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(Object[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + nullSafeHashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(boolean[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(byte[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(char[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(double[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(float[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(int[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(long[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(short[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return the same value as {@link Boolean#hashCode()}. + * + * @see Boolean#hashCode() + */ + public static int hashCode(boolean bool) { + return bool ? 1231 : 1237; + } + + /** + * Return the same value as {@link Double#hashCode()}. + * + * @see Double#hashCode() + */ + public static int hashCode(double dbl) { + long bits = Double.doubleToLongBits(dbl); + return hashCode(bits); + } + + /** + * Return the same value as {@link Float#hashCode()}. + * + * @see Float#hashCode() + */ + public static int hashCode(float flt) { + return Float.floatToIntBits(flt); + } + + /** + * Return the same value as {@link Long#hashCode()}. + * + * @see Long#hashCode() + */ + public static int hashCode(long lng) { + return (int) (lng ^ (lng >>> 32)); + } + + + //--------------------------------------------------------------------- + // Convenience methods for toString output + //--------------------------------------------------------------------- + + /** + * Return a String representation of an object's overall identity. + * + * @param obj the object (may be null) + * @return the object's identity as String representation, + * or an empty String if the object was null + */ + public static String identityToString(Object obj) { + if (obj == null) { + return EMPTY_STRING; + } + return obj.getClass().getName() + "@" + getIdentityHexString(obj); + } + + /** + * Return a hex String form of an object's identity hash code. + * + * @param obj the object + * @return the object's identity code in hex notation + */ + public static String getIdentityHexString(Object obj) { + return Integer.toHexString(System.identityHashCode(obj)); + } + + /** + * Return a content-based String representation if obj is + * not null; otherwise returns an empty String. + *

Differs from {@link #nullSafeToString(Object)} in that it returns + * an empty String rather than "null" for a null value. + * + * @param obj the object to build a display String for + * @return a display String representation of obj + * @see #nullSafeToString(Object) + */ + public static String getDisplayString(Object obj) { + if (obj == null) { + return EMPTY_STRING; + } + return nullSafeToString(obj); + } + + /** + * Determine the class name for the given object. + *

Returns "null" if obj is null. + * + * @param obj the object to introspect (may be null) + * @return the corresponding class name + */ + public static String nullSafeClassName(Object obj) { + return (obj != null ? obj.getClass().getName() : NULL_STRING); + } + + /** + * Return a String representation of the specified Object. + *

Builds a String representation of the contents in case of an array. + * Returns "null" if obj is null. + * + * @param obj the object to build a String representation for + * @return a String representation of obj + */ + public static String nullSafeToString(Object obj) { + if (obj == null) { + return NULL_STRING; + } + if (obj instanceof String) { + return (String) obj; + } + if (obj instanceof Object[]) { + return nullSafeToString((Object[]) obj); + } + if (obj instanceof boolean[]) { + return nullSafeToString((boolean[]) obj); + } + if (obj instanceof byte[]) { + return nullSafeToString((byte[]) obj); + } + if (obj instanceof char[]) { + return nullSafeToString((char[]) obj); + } + if (obj instanceof double[]) { + return nullSafeToString((double[]) obj); + } + if (obj instanceof float[]) { + return nullSafeToString((float[]) obj); + } + if (obj instanceof int[]) { + return nullSafeToString((int[]) obj); + } + if (obj instanceof long[]) { + return nullSafeToString((long[]) obj); + } + if (obj instanceof short[]) { + return nullSafeToString((short[]) obj); + } + String str = obj.toString(); + return (str != null ? str : EMPTY_STRING); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(Object[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + sb.append(String.valueOf(array[i])); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(boolean[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(byte[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(char[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + sb.append("'").append(array[i]).append("'"); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(double[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(float[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(int[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(long[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(short[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (i == 0) { + sb.append(ARRAY_START); + } else { + sb.append(ARRAY_ELEMENT_SEPARATOR); + } + sb.append(array[i]); + } + sb.append(ARRAY_END); + return sb.toString(); + } + + public static void nullSafeClose(Closeable... closeables) { + if (closeables == null) { + return; + } + + for (Closeable closeable : closeables) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + //Ignore the exception during close. + } + } + } + } +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/RuntimeEnvironment.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/RuntimeEnvironment.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/RuntimeEnvironment.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,67 @@ +/* + * 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.security.Provider; +import java.security.Security; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class RuntimeEnvironment { + + private static final RuntimeEnvironment INSTANCE = new RuntimeEnvironment(); + + private RuntimeEnvironment(){} + + private static final String BC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; + + private static final AtomicBoolean bcLoaded = new AtomicBoolean(false); + + public static final boolean BOUNCY_CASTLE_AVAILABLE = Classes.isAvailable(BC_PROVIDER_CLASS_NAME); + + public static void enableBouncyCastleIfPossible() { + + if (bcLoaded.get()) { + return; + } + + try { + Class clazz = Classes.forName(BC_PROVIDER_CLASS_NAME); + + //check to see if the user has already registered the BC provider: + + Provider[] providers = Security.getProviders(); + + for(Provider provider : providers) { + if (clazz.isInstance(provider)) { + bcLoaded.set(true); + return; + } + } + + //bc provider not enabled - add it: + Security.addProvider((Provider)Classes.newInstance(clazz)); + bcLoaded.set(true); + + } catch (UnknownClassException e) { + //not available + } + } + + static { + enableBouncyCastleIfPossible(); + } + +} Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Strings.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Strings.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/Strings.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,1149 @@ +/* + * 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.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; + +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 = "\\"; + + private static final String TOP_PATH = ".."; + + private static final String CURRENT_PATH = "."; + + private static final char EXTENSION_SEPARATOR = '.'; + + public static final Charset UTF_8 = Charset.forName("UTF-8"); + + private Strings(){} + + //--------------------------------------------------------------------- + // General convenience methods for working with Strings + //--------------------------------------------------------------------- + + /** + * Check that the given CharSequence is neither null nor of length 0. + * Note: Will return true for a CharSequence that purely consists of whitespace. + *

+     * Strings.hasLength(null) = false
+     * Strings.hasLength("") = false
+     * Strings.hasLength(" ") = true
+     * Strings.hasLength("Hello") = true
+     * 
+ * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not null and has length + * @see #hasText(String) + */ + public static boolean hasLength(CharSequence str) { + return (str != null && str.length() > 0); + } + + /** + * Check that the given String is neither null nor of length 0. + * Note: Will return true for a String that purely consists of whitespace. + * @param str the String to check (may be null) + * @return true if the String is not null and has length + * @see #hasLength(CharSequence) + */ + public static boolean hasLength(String str) { + return hasLength((CharSequence) str); + } + + /** + * Check whether the given CharSequence has actual text. + * More specifically, returns true if the string not null, + * its length is greater than 0, and it contains at least one non-whitespace character. + *

+     * Strings.hasText(null) = false
+     * Strings.hasText("") = false
+     * Strings.hasText(" ") = false
+     * Strings.hasText("12345") = true
+     * Strings.hasText(" 12345 ") = true
+     * 
+ * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not null, + * its length is greater than 0, and it does not contain whitespace only + * @see java.lang.Character#isWhitespace + */ + public static boolean hasText(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String has actual text. + * More specifically, returns true if the string not null, + * its length is greater than 0, and it contains at least one non-whitespace character. + * @param str the String to check (may be null) + * @return true if the String is not null, its length is + * greater than 0, and it does not contain whitespace only + * @see #hasText(CharSequence) + */ + public static boolean hasText(String str) { + return hasText((CharSequence) str); + } + + /** + * Check whether the given CharSequence contains any whitespace characters. + * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not empty and + * contains at least 1 whitespace character + * @see java.lang.Character#isWhitespace + */ + public static boolean containsWhitespace(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String contains any whitespace characters. + * @param str the String to check (may be null) + * @return true if the String is not empty and + * contains at least 1 whitespace character + * @see #containsWhitespace(CharSequence) + */ + public static boolean containsWhitespace(String str) { + return containsWhitespace((CharSequence) str); + } + + /** + * Trim leading and trailing whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimWhitespace(String str) { + return (String) trimWhitespace((CharSequence)str); + } + + + private static CharSequence trimWhitespace(CharSequence str) { + if (!hasLength(str)) { + return str; + } + final int length = str.length(); + + int start = 0; + while (start < length && Character.isWhitespace(str.charAt(start))) { + start++; + } + + int end = length; + while (start < length && Character.isWhitespace(str.charAt(end - 1))) { + end--; + } + + return ((start > 0) || (end < length)) ? str.subSequence(start, end) : str; + } + + public static String clean(String str) { + CharSequence result = clean((CharSequence) str); + + return result!=null?result.toString():null; + } + + public static CharSequence clean(CharSequence str) { + str = trimWhitespace(str); + if (!hasLength(str)) { + return null; + } + return str; + } + + /** + * Trim all whitespace from the given String: + * leading, trailing, and inbetween characters. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimAllWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuilder sb = new StringBuilder(str); + int index = 0; + while (sb.length() > index) { + if (Character.isWhitespace(sb.charAt(index))) { + sb.deleteCharAt(index); + } + else { + index++; + } + } + return sb.toString(); + } + + /** + * Trim leading whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimLeadingWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuilder sb = new StringBuilder(str); + while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { + sb.deleteCharAt(0); + } + return sb.toString(); + } + + /** + * Trim trailing whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimTrailingWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuilder sb = new StringBuilder(str); + while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { + sb.deleteCharAt(sb.length() - 1); + } + return sb.toString(); + } + + /** + * Trim all occurences of the supplied leading character from the given String. + * @param str the String to check + * @param leadingCharacter the leading character to be trimmed + * @return the trimmed String + */ + public static String trimLeadingCharacter(String str, char leadingCharacter) { + if (!hasLength(str)) { + return str; + } + StringBuilder sb = new StringBuilder(str); + while (sb.length() > 0 && sb.charAt(0) == leadingCharacter) { + sb.deleteCharAt(0); + } + return sb.toString(); + } + + /** + * Trim all occurences of the supplied trailing character from the given String. + * @param str the String to check + * @param trailingCharacter the trailing character to be trimmed + * @return the trimmed String + */ + public static String trimTrailingCharacter(String str, char trailingCharacter) { + if (!hasLength(str)) { + return str; + } + StringBuilder sb = new StringBuilder(str); + while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) { + sb.deleteCharAt(sb.length() - 1); + } + return sb.toString(); + } + + + /** + * Test if the given String starts with the specified prefix, + * ignoring upper/lower case. + * @param str the String to check + * @param prefix the prefix to look for + * @see java.lang.String#startsWith + */ + public static boolean startsWithIgnoreCase(String str, String prefix) { + if (str == null || prefix == null) { + return false; + } + if (str.startsWith(prefix)) { + return true; + } + if (str.length() < prefix.length()) { + return false; + } + String lcStr = str.substring(0, prefix.length()).toLowerCase(); + String lcPrefix = prefix.toLowerCase(); + return lcStr.equals(lcPrefix); + } + + /** + * Test if the given String ends with the specified suffix, + * ignoring upper/lower case. + * @param str the String to check + * @param suffix the suffix to look for + * @see java.lang.String#endsWith + */ + public static boolean endsWithIgnoreCase(String str, String suffix) { + if (str == null || suffix == null) { + return false; + } + if (str.endsWith(suffix)) { + return true; + } + if (str.length() < suffix.length()) { + return false; + } + + String lcStr = str.substring(str.length() - suffix.length()).toLowerCase(); + String lcSuffix = suffix.toLowerCase(); + return lcStr.equals(lcSuffix); + } + + /** + * Test whether the given string matches the given substring + * at the given index. + * @param str the original string (or StringBuilder) + * @param index the index in the original string to start matching against + * @param substring the substring to match at the given index + */ + public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { + for (int j = 0; j < substring.length(); j++) { + int i = index + j; + if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { + return false; + } + } + return true; + } + + /** + * Count the occurrences of the substring in string s. + * @param str string to search in. Return 0 if this is null. + * @param sub string to search for. Return 0 if this is null. + */ + public static int countOccurrencesOf(String str, String sub) { + if (str == null || sub == null || str.length() == 0 || sub.length() == 0) { + return 0; + } + int count = 0; + int pos = 0; + int idx; + while ((idx = str.indexOf(sub, pos)) != -1) { + ++count; + pos = idx + sub.length(); + } + return count; + } + + /** + * Replace all occurences of a substring within a string with + * another string. + * @param inString String to examine + * @param oldPattern String to replace + * @param newPattern String to insert + * @return a String with the replacements + */ + public static String replace(String inString, String oldPattern, String newPattern) { + if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { + return inString; + } + StringBuilder sb = new StringBuilder(); + int pos = 0; // our position in the old string + int index = inString.indexOf(oldPattern); + // the index of an occurrence we've found, or -1 + int patLen = oldPattern.length(); + while (index >= 0) { + sb.append(inString.substring(pos, index)); + sb.append(newPattern); + pos = index + patLen; + index = inString.indexOf(oldPattern, pos); + } + sb.append(inString.substring(pos)); + // remember to append any characters to the right of a match + return sb.toString(); + } + + /** + * Delete all occurrences of the given substring. + * @param inString the original String + * @param pattern the pattern to delete all occurrences of + * @return the resulting String + */ + public static String delete(String inString, String pattern) { + return replace(inString, pattern, ""); + } + + /** + * Delete any character in a given String. + * @param inString the original String + * @param charsToDelete a set of characters to delete. + * E.g. "az\n" will delete 'a's, 'z's and new lines. + * @return the resulting String + */ + public static String deleteAny(String inString, String charsToDelete) { + if (!hasLength(inString) || !hasLength(charsToDelete)) { + return inString; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < inString.length(); i++) { + char c = inString.charAt(i); + if (charsToDelete.indexOf(c) == -1) { + sb.append(c); + } + } + return sb.toString(); + } + + + //--------------------------------------------------------------------- + // Convenience methods for working with formatted Strings + //--------------------------------------------------------------------- + + /** + * Quote the given String with single quotes. + * @param str the input String (e.g. "myString") + * @return the quoted String (e.g. "'myString'"), + * or null if the input was null + */ + public static String quote(String str) { + return (str != null ? "'" + str + "'" : null); + } + + /** + * Turn the given Object into a String with single quotes + * if it is a String; keeping the Object as-is else. + * @param obj the input Object (e.g. "myString") + * @return the quoted String (e.g. "'myString'"), + * or the input object as-is if not a String + */ + public static Object quoteIfString(Object obj) { + return (obj instanceof String ? quote((String) obj) : obj); + } + + /** + * Unqualify a string qualified by a '.' dot character. For example, + * "this.name.is.qualified", returns "qualified". + * @param qualifiedName the qualified name + */ + public static String unqualify(String qualifiedName) { + return unqualify(qualifiedName, '.'); + } + + /** + * Unqualify a string qualified by a separator character. For example, + * "this:name:is:qualified" returns "qualified" if using a ':' separator. + * @param qualifiedName the qualified name + * @param separator the separator + */ + public static String unqualify(String qualifiedName, char separator) { + return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); + } + + /** + * Capitalize a String, changing the first letter to + * upper case as per {@link Character#toUpperCase(char)}. + * No other letters are changed. + * @param str the String to capitalize, may be null + * @return the capitalized String, null if null + */ + public static String capitalize(String str) { + return changeFirstCharacterCase(str, true); + } + + /** + * Uncapitalize a String, changing the first letter to + * lower case as per {@link Character#toLowerCase(char)}. + * No other letters are changed. + * @param str the String to uncapitalize, may be null + * @return the uncapitalized String, null if null + */ + public static String uncapitalize(String str) { + return changeFirstCharacterCase(str, false); + } + + private static String changeFirstCharacterCase(String str, boolean capitalize) { + if (str == null || str.length() == 0) { + return str; + } + StringBuilder sb = new StringBuilder(str.length()); + if (capitalize) { + sb.append(Character.toUpperCase(str.charAt(0))); + } + else { + sb.append(Character.toLowerCase(str.charAt(0))); + } + sb.append(str.substring(1)); + return sb.toString(); + } + + /** + * Extract the filename from the given path, + * e.g. "mypath/myfile.txt" -> "myfile.txt". + * @param path the file path (may be null) + * @return the extracted filename, or null if none + */ + public static String getFilename(String path) { + if (path == null) { + return null; + } + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); + } + + /** + * Extract the filename extension from the given path, + * e.g. "mypath/myfile.txt" -> "txt". + * @param path the file path (may be null) + * @return the extracted filename extension, or null if none + */ + public static String getFilenameExtension(String path) { + if (path == null) { + return null; + } + int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); + if (extIndex == -1) { + return null; + } + int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); + if (folderIndex > extIndex) { + return null; + } + return path.substring(extIndex + 1); + } + + /** + * Strip the filename extension from the given path, + * e.g. "mypath/myfile.txt" -> "mypath/myfile". + * @param path the file path (may be null) + * @return the path with stripped filename extension, + * or null if none + */ + public static String stripFilenameExtension(String path) { + if (path == null) { + return null; + } + int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); + if (extIndex == -1) { + return path; + } + int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); + if (folderIndex > extIndex) { + return path; + } + return path.substring(0, extIndex); + } + + /** + * Apply the given relative path to the given path, + * assuming standard Java folder separation (i.e. "/" separators). + * @param path the path to start from (usually a full file path) + * @param relativePath the relative path to apply + * (relative to the full file path above) + * @return the full file path that results from applying the relative path + */ + public static String applyRelativePath(String path, String relativePath) { + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + if (separatorIndex != -1) { + String newPath = path.substring(0, separatorIndex); + if (!relativePath.startsWith(FOLDER_SEPARATOR)) { + newPath += FOLDER_SEPARATOR; + } + return newPath + relativePath; + } + else { + return relativePath; + } + } + + /** + * Normalize the path by suppressing sequences like "path/.." and + * inner simple dots. + *

The result is convenient for path comparison. For other uses, + * notice that Windows separators ("\") are replaced by simple slashes. + * @param path the original path + * @return the normalized path + */ + public static String cleanPath(String path) { + if (path == null) { + return null; + } + String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); + + // Strip prefix from path to analyze, to not treat it as part of the + // first path element. This is necessary to correctly parse paths like + // "file:core/../core/io/Resource.class", where the ".." should just + // strip the first "core" directory while keeping the "file:" prefix. + int prefixIndex = pathToUse.indexOf(":"); + String prefix = ""; + if (prefixIndex != -1) { + prefix = pathToUse.substring(0, prefixIndex + 1); + pathToUse = pathToUse.substring(prefixIndex + 1); + } + if (pathToUse.startsWith(FOLDER_SEPARATOR)) { + prefix = prefix + FOLDER_SEPARATOR; + pathToUse = pathToUse.substring(1); + } + + String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); + List pathElements = new LinkedList(); + int tops = 0; + + for (int i = pathArray.length - 1; i >= 0; i--) { + String element = pathArray[i]; + if (CURRENT_PATH.equals(element)) { + // Points to current directory - drop it. + } + else if (TOP_PATH.equals(element)) { + // Registering top path found. + tops++; + } + else { + if (tops > 0) { + // Merging path element with element corresponding to top path. + tops--; + } + else { + // Normal path element found. + pathElements.add(0, element); + } + } + } + + // Remaining top paths need to be retained. + for (int i = 0; i < tops; i++) { + pathElements.add(0, TOP_PATH); + } + + return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); + } + + /** + * Compare two paths after normalization of them. + * @param path1 first path for comparison + * @param path2 second path for comparison + * @return whether the two paths are equivalent after normalization + */ + public static boolean pathEquals(String path1, String path2) { + return cleanPath(path1).equals(cleanPath(path2)); + } + + /** + * Parse the given localeString value into a {@link java.util.Locale}. + *

This is the inverse operation of {@link java.util.Locale#toString Locale's toString}. + * @param localeString the locale string, following Locale's + * toString() format ("en", "en_UK", etc); + * also accepts spaces as separators, as an alternative to underscores + * @return a corresponding Locale instance + */ + public static Locale parseLocaleString(String localeString) { + String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); + String language = (parts.length > 0 ? parts[0] : ""); + String country = (parts.length > 1 ? parts[1] : ""); + validateLocalePart(language); + validateLocalePart(country); + String variant = ""; + if (parts.length >= 2) { + // There is definitely a variant, and it is everything after the country + // code sans the separator between the country code and the variant. + int endIndexOfCountryCode = localeString.indexOf(country) + country.length(); + // Strip off any leading '_' and whitespace, what's left is the variant. + variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); + if (variant.startsWith("_")) { + variant = trimLeadingCharacter(variant, '_'); + } + } + return (language.length() > 0 ? new Locale(language, country, variant) : null); + } + + private static void validateLocalePart(String localePart) { + for (int i = 0; i < localePart.length(); i++) { + char ch = localePart.charAt(i); + if (ch != '_' && ch != ' ' && !Character.isLetterOrDigit(ch)) { + throw new IllegalArgumentException( + "Locale part \"" + localePart + "\" contains invalid characters"); + } + } + } + + /** + * Determine the RFC 3066 compliant language tag, + * as used for the HTTP "Accept-Language" header. + * @param locale the Locale to transform to a language tag + * @return the RFC 3066 compliant language tag as String + */ + public static String toLanguageTag(Locale locale) { + return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); + } + + + //--------------------------------------------------------------------- + // Convenience methods for working with String arrays + //--------------------------------------------------------------------- + + /** + * Append the given String to the given String array, returning a new array + * consisting of the input array contents plus the given String. + * @param array the array to append to (can be null) + * @param str the String to append + * @return the new array (never null) + */ + public static String[] addStringToArray(String[] array, String str) { + if (Objects.isEmpty(array)) { + return new String[] {str}; + } + String[] newArr = new String[array.length + 1]; + System.arraycopy(array, 0, newArr, 0, array.length); + newArr[array.length] = str; + return newArr; + } + + /** + * Concatenate the given String arrays into one, + * with overlapping array elements included twice. + *

The order of elements in the original arrays is preserved. + * @param array1 the first array (can be null) + * @param array2 the second array (can be null) + * @return the new array (null if both given arrays were null) + */ + public static String[] concatenateStringArrays(String[] array1, String[] array2) { + if (Objects.isEmpty(array1)) { + return array2; + } + if (Objects.isEmpty(array2)) { + return array1; + } + String[] newArr = new String[array1.length + array2.length]; + System.arraycopy(array1, 0, newArr, 0, array1.length); + System.arraycopy(array2, 0, newArr, array1.length, array2.length); + return newArr; + } + + /** + * Merge the given String arrays into one, with overlapping + * array elements only included once. + *

The order of elements in the original arrays is preserved + * (with the exception of overlapping elements, which are only + * included on their first occurrence). + * @param array1 the first array (can be null) + * @param array2 the second array (can be null) + * @return the new array (null if both given arrays were null) + */ + public static String[] mergeStringArrays(String[] array1, String[] array2) { + if (Objects.isEmpty(array1)) { + return array2; + } + if (Objects.isEmpty(array2)) { + return array1; + } + List result = new ArrayList(); + result.addAll(Arrays.asList(array1)); + for (String str : array2) { + if (!result.contains(str)) { + result.add(str); + } + } + return toStringArray(result); + } + + /** + * Turn given source String array into sorted array. + * @param array the source array + * @return the sorted array (never null) + */ + public static String[] sortStringArray(String[] array) { + if (Objects.isEmpty(array)) { + return new String[0]; + } + Arrays.sort(array); + return array; + } + + /** + * Copy the given Collection into a String array. + * The Collection must contain String elements only. + * @param collection the Collection to copy + * @return the String array (null if the passed-in + * Collection was null) + */ + public static String[] toStringArray(Collection collection) { + if (collection == null) { + return null; + } + return collection.toArray(new String[collection.size()]); + } + + /** + * Copy the given Enumeration into a String array. + * The Enumeration must contain String elements only. + * @param enumeration the Enumeration to copy + * @return the String array (null if the passed-in + * Enumeration was null) + */ + public static String[] toStringArray(Enumeration enumeration) { + if (enumeration == null) { + return null; + } + List list = java.util.Collections.list(enumeration); + return list.toArray(new String[list.size()]); + } + + /** + * Trim the elements of the given String array, + * calling String.trim() on each of them. + * @param array the original String array + * @return the resulting array (of the same size) with trimmed elements + */ + public static String[] trimArrayElements(String[] array) { + if (Objects.isEmpty(array)) { + return new String[0]; + } + String[] result = new String[array.length]; + for (int i = 0; i < array.length; i++) { + String element = array[i]; + result[i] = (element != null ? element.trim() : null); + } + return result; + } + + /** + * Remove duplicate Strings from the given array. + * Also sorts the array, as it uses a TreeSet. + * @param array the String array + * @return an array without duplicates, in natural sort order + */ + public static String[] removeDuplicateStrings(String[] array) { + if (Objects.isEmpty(array)) { + return array; + } + Set set = new TreeSet(); + for (String element : array) { + set.add(element); + } + return toStringArray(set); + } + + /** + * Split a String at the first occurrence of the delimiter. + * Does not include the delimiter in the result. + * @param toSplit the string to split + * @param delimiter to split the string up with + * @return a two element array with index 0 being before the delimiter, and + * index 1 being after the delimiter (neither element includes the delimiter); + * or null if the delimiter wasn't found in the given input String + */ + public static String[] split(String toSplit, String delimiter) { + if (!hasLength(toSplit) || !hasLength(delimiter)) { + return null; + } + int offset = toSplit.indexOf(delimiter); + if (offset < 0) { + return null; + } + String beforeDelimiter = toSplit.substring(0, offset); + String afterDelimiter = toSplit.substring(offset + delimiter.length()); + return new String[] {beforeDelimiter, afterDelimiter}; + } + + /** + * Take an array Strings and split each element based on the given delimiter. + * A Properties instance is then generated, with the left of the + * delimiter providing the key, and the right of the delimiter providing the value. + *

Will trim both the key and value before adding them to the + * Properties instance. + * @param array the array to process + * @param delimiter to split each element using (typically the equals symbol) + * @return a Properties instance representing the array contents, + * or null if the array to process was null or empty + */ + public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { + return splitArrayElementsIntoProperties(array, delimiter, null); + } + + /** + * Take an array Strings and split each element based on the given delimiter. + * A Properties instance is then generated, with the left of the + * delimiter providing the key, and the right of the delimiter providing the value. + *

Will trim both the key and value before adding them to the + * Properties instance. + * @param array the array to process + * @param delimiter to split each element using (typically the equals symbol) + * @param charsToDelete one or more characters to remove from each element + * prior to attempting the split operation (typically the quotation mark + * symbol), or null if no removal should occur + * @return a Properties instance representing the array contents, + * or null if the array to process was null or empty + */ + public static Properties splitArrayElementsIntoProperties( + String[] array, String delimiter, String charsToDelete) { + + if (Objects.isEmpty(array)) { + return null; + } + Properties result = new Properties(); + for (String element : array) { + if (charsToDelete != null) { + element = deleteAny(element, charsToDelete); + } + String[] splittedElement = split(element, delimiter); + if (splittedElement == null) { + continue; + } + result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); + } + return result; + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + * Trims tokens and omits empty tokens. + *

The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using delimitedListToStringArray + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter). + * @return an array of the tokens + * @see java.util.StringTokenizer + * @see java.lang.String#trim() + * @see #delimitedListToStringArray + */ + public static String[] tokenizeToStringArray(String str, String delimiters) { + return tokenizeToStringArray(str, delimiters, true, true); + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + *

The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using delimitedListToStringArray + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter) + * @param trimTokens trim the tokens via String's trim + * @param ignoreEmptyTokens omit empty tokens from the result array + * (only applies to tokens that are empty after trimming; StringTokenizer + * will not consider subsequent delimiters as token in the first place). + * @return an array of the tokens (null if the input String + * was null) + * @see java.util.StringTokenizer + * @see java.lang.String#trim() + * @see #delimitedListToStringArray + */ + public static String[] tokenizeToStringArray( + String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { + + if (str == null) { + return null; + } + StringTokenizer st = new StringTokenizer(str, delimiters); + List tokens = new ArrayList(); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (trimTokens) { + token = token.trim(); + } + if (!ignoreEmptyTokens || token.length() > 0) { + tokens.add(token); + } + } + return toStringArray(tokens); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + *

A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to tokenizeToStringArray. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter) { + return delimitedListToStringArray(str, delimiter, null); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + *

A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to tokenizeToStringArray. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @param charsToDelete a set of characters to delete. Useful for deleting unwanted + * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String. + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { + if (str == null) { + return new String[0]; + } + if (delimiter == null) { + return new String[] {str}; + } + List result = new ArrayList(); + if ("".equals(delimiter)) { + for (int i = 0; i < str.length(); i++) { + result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); + } + } + else { + int pos = 0; + int delPos; + while ((delPos = str.indexOf(delimiter, pos)) != -1) { + result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); + pos = delPos + delimiter.length(); + } + if (str.length() > 0 && pos <= str.length()) { + // Add rest of String, but not in case of empty input. + result.add(deleteAny(str.substring(pos), charsToDelete)); + } + } + return toStringArray(result); + } + + /** + * Convert a CSV list into an array of Strings. + * @param str the input String + * @return an array of Strings, or the empty array in case of empty input + */ + public static String[] commaDelimitedListToStringArray(String str) { + return delimitedListToStringArray(str, ","); + } + + /** + * Convenience method to convert a CSV string list to a set. + * Note that this will suppress duplicates. + * @param str the input String + * @return a Set of String entries in the list + */ + public static Set commaDelimitedListToSet(String str) { + Set set = new TreeSet(); + String[] tokens = commaDelimitedListToStringArray(str); + for (String token : tokens) { + set.add(token); + } + return set; + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @param prefix the String to start each element with + * @param suffix the String to end each element with + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { + if (Collections.isEmpty(coll)) { + return ""; + } + StringBuilder sb = new StringBuilder(); + Iterator it = coll.iterator(); + while (it.hasNext()) { + sb.append(prefix).append(it.next()).append(suffix); + if (it.hasNext()) { + sb.append(delim); + } + } + return sb.toString(); + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection coll, String delim) { + return collectionToDelimitedString(coll, delim, "", ""); + } + + /** + * Convenience method to return a Collection as a CSV String. + * E.g. useful for toString() implementations. + * @param coll the Collection to display + * @return the delimited String + */ + public static String collectionToCommaDelimitedString(Collection coll) { + return collectionToDelimitedString(coll, ","); + } + + /** + * Convenience method to return a String array as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param arr the array to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String arrayToDelimitedString(Object[] arr, String delim) { + if (Objects.isEmpty(arr)) { + return ""; + } + if (arr.length == 1) { + return Objects.nullSafeToString(arr[0]); + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < arr.length; i++) { + if (i > 0) { + sb.append(delim); + } + sb.append(arr[i]); + } + return sb.toString(); + } + + /** + * Convenience method to return a String array as a CSV String. + * E.g. useful for toString() implementations. + * @param arr the array to display + * @return the delimited String + */ + public static String arrayToCommaDelimitedString(Object[] arr) { + return arrayToDelimitedString(arr, ","); + } + +} + Index: 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/UnknownClassException.java =================================================================== diff -u --- 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/UnknownClassException.java (revision 0) +++ 3rdParty_sources/jsonwebtoken/io/jsonwebtoken/lang/UnknownClassException.java (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -0,0 +1,63 @@ +/* + * 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; + +/** + * A RuntimeException equivalent of the JDK's + * ClassNotFoundException, to maintain a RuntimeException paradigm. + * + * @since 0.1 + */ +public class UnknownClassException extends RuntimeException { + + /* + /** + * Creates a new UnknownClassException. + * + public UnknownClassException() { + super(); + }*/ + + /** + * Constructs a new UnknownClassException. + * + * @param message the reason for the exception + */ + public UnknownClassException(String message) { + super(message); + } + + /* + * Constructs a new UnknownClassException. + * + * @param cause the underlying Throwable that caused this exception to be thrown. + * + 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) { + super(message, cause); + } + */ + +} \ No newline at end of file Index: 3rdParty_sources/versions.txt =================================================================== diff -u -r92d4f7d34c60b79bfec1ca66a0fa5239fedd082c -rdd64f16fdf89f789b8c2179d421290dcabf15835 --- 3rdParty_sources/versions.txt (.../versions.txt) (revision 92d4f7d34c60b79bfec1ca66a0fa5239fedd082c) +++ 3rdParty_sources/versions.txt (.../versions.txt) (revision dd64f16fdf89f789b8c2179d421290dcabf15835) @@ -25,6 +25,8 @@ JBoss Web 2.1.3 +jsonwebtoken 0.9.0 + JSP API 2.3 lucene 2.4.0