Java: Cleanup jwt stubs.

This commit is contained in:
intrigus
2021-04-28 20:46:09 +02:00
parent b1a3633495
commit a8865e2fa2
63 changed files with 6 additions and 7813 deletions

View File

@@ -22,30 +22,19 @@ package io.jsonwebtoken;
*/
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;
return null;
}
public Header getHeader() {
return header;
return null;
}
}

View File

@@ -40,152 +40,4 @@ import java.util.Map;
*/
public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */
public static final String ISSUER = "iss";
/** JWT {@code Subject} claims parameter name: <code>"sub"</code> */
public static final String SUBJECT = "sub";
/** JWT {@code Audience} claims parameter name: <code>"aud"</code> */
public static final String AUDIENCE = "aud";
/** JWT {@code Expiration} claims parameter name: <code>"exp"</code> */
public static final String EXPIRATION = "exp";
/** JWT {@code Not Before} claims parameter name: <code>"nbf"</code> */
public static final String NOT_BEFORE = "nbf";
/** JWT {@code Issued At} claims parameter name: <code>"iat"</code> */
public static final String ISSUED_AT = "iat";
/** JWT {@code JWT ID} claims parameter name: <code>"jti"</code> */
public static final String ID = "jti";
/**
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
* <code>iss</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
* <code>sub</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
* <code>aud</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
* <code>exp</code></a> (expiration) timestamp or {@code null} if not present.
*
* <p>A JWT obtained after this timestamp should not be used.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
* <code>nbf</code></a> (not before) timestamp or {@code null} if not present.
*
* <p>A JWT obtained before this timestamp should not be used.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
* <code>iat</code></a> (issued at) timestamp or {@code null} if not present.
*
* <p>If present, this value is the timestamp when the JWT was created.</p>
*
* @return the JWT {@code iat} value or {@code null} if not present.
*/
Date getIssuedAt();
/**
* {@inheritDoc}
*/
@Override //only for better/targeted JavaDoc
Claims setIssuedAt(Date iat);
/**
* Returns the JWTs <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
* <code>jti</code></a> (JWT ID) value or {@code null} if not present.
*
* <p>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.</p>
*
* @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);
/**
* Returns the JWTs claim ({@code claimName}) value as a type {@code requiredType}, or {@code null} if not present.
*
* <p>JJWT only converts simple String, Date, Long, Integer, Short and Byte types automatically. Anything more
* complex is expected to be already converted to your desired type by the JSON
* {@link io.jsonwebtoken.io.Deserializer Deserializer} implementation. You may specify a custom Deserializer for a
* JwtParser with the desired conversion configuration via the {@link JwtParserBuilder#deserializeJsonWith} method.
* See <a href="https://github.com/jwtk/jjwt#custom-json-processor">custom JSON processor</a></a> for more
* information. If using Jackson, you can specify custom claim POJO types as described in
* <a href="https://github.com/jwtk/jjwt#json-jackson-custom-types">custom claim types</a>.
*
* @param claimName name of claim
* @param requiredType the type of the value expected to be returned
* @param <T> the type of the value expected to be returned
* @return the JWT {@code claimName} value or {@code null} if not present.
* @throws RequiredTypeException throw if the claim value is not null and not of type {@code requiredType}
*/
<T> T get(String claimName, Class<T> requiredType);
}

View File

@@ -27,76 +27,4 @@ import java.util.Date;
*/
public interface ClaimsMutator<T extends ClaimsMutator> {
/**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
* <code>iss</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
* <code>sub</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
* <code>aud</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
* <code>exp</code></a> (expiration) timestamp. A {@code null} value will remove the property from the JSON map.
*
* <p>A JWT obtained after this timestamp should not be used.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
* <code>nbf</code></a> (not before) timestamp. A {@code null} value will remove the property from the JSON map.
*
* <p>A JWT obtained before this timestamp should not be used.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
* <code>iat</code></a> (issued at) timestamp. A {@code null} value will remove the property from the JSON map.
*
* <p>The value is the timestamp when the JWT was created.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the JSON map.
*
* <p>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.</p>
*
* @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);
}

View File

@@ -1,33 +0,0 @@
/*
* 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;
/**
* 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();
}

View File

@@ -1,55 +0,0 @@
/*
* 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 CompressionCodecs#DEFLATE
* @see CompressionCodecs#GZIP
* @since 0.6.0
*/
public interface CompressionCodec {
/**
* The compression algorithm name to use as the JWT's {@code zip} header value.
*
* @return the compression algorithm name to use as the JWT's {@code zip} 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;
}

View File

@@ -1,46 +0,0 @@
/*
* 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 zip} header, and if found, returns the corresponding {@link CompressionCodec} the parser
* can use to decompress the JWT body.
*
* <p>JJWT's default {@link JwtParser} implementation supports both the
* {@link CompressionCodecs#DEFLATE DEFLATE}
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.</p>
*
* <p>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.</p>
*
* @since 0.6.0
*/
public interface CompressionCodecResolver {
/**
* Looks for a JWT {@code zip} 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 zip} header, or null if there is no {@code zip} header.
* @throws CompressionException if a {@code zip} header value is found and not supported.
*/
CompressionCodec resolveCompressionCodec(Header header) throws CompressionException;
}

View File

@@ -1,49 +0,0 @@
/*
* 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.Classes;
/**
* Provides default implementations of the {@link CompressionCodec} interface.
*
* @see #DEFLATE
* @see #GZIP
* @since 0.7.0
*/
public final class CompressionCodecs {
private CompressionCodecs() {
} //prevent external instantiation
/**
* Codec implementing the <a href="https://tools.ietf.org/html/rfc7518">JWA</a> standard
* <a href="https://en.wikipedia.org/wiki/DEFLATE">deflate</a> compression algorithm
*/
public static final CompressionCodec DEFLATE =
Classes.newInstance("io.jsonwebtoken.impl.compression.DeflateCompressionCodec");
/**
* Codec implementing the <a href="https://en.wikipedia.org/wiki/Gzip">gzip</a> compression algorithm.
* <h3>Compatibility Warning</h3>
* <p><b>This is not a standard JWA compression algorithm</b>. Be sure to use this only when you are confident
* that all parties accessing the token support the gzip algorithm.</p>
* <p>If you're concerned about compatibility, the {@link #DEFLATE DEFLATE} code is JWA standards-compliant.</p>
*/
public static final CompressionCodec GZIP =
Classes.newInstance("io.jsonwebtoken.impl.compression.GzipCompressionCodec");
}

View File

@@ -1,33 +0,0 @@
/*
* 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);
}
}

View File

@@ -38,95 +38,4 @@ import java.util.Map;
* @since 0.1
*/
public interface Header<T extends Header<T>> extends Map<String,Object> {
/** JWT {@code Type} (typ) value: <code>"JWT"</code> */
public static final String JWT_TYPE = "JWT";
/** JWT {@code Type} header parameter name: <code>"typ"</code> */
public static final String TYPE = "typ";
/** JWT {@code Content Type} header parameter name: <code>"cty"</code> */
public static final String CONTENT_TYPE = "cty";
/** JWT {@code Compression Algorithm} header parameter name: <code>"zip"</code> */
public static final String COMPRESSION_ALGORITHM = "zip";
/** JJWT legacy/deprecated compression algorithm header parameter name: <code>"calg"</code>
* @deprecated use {@link #COMPRESSION_ALGORITHM} instead. */
@Deprecated
public static final String DEPRECATED_COMPRESSION_ALGORITHM = "calg";
/**
* Returns the <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5.1">
* <code>typ</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5.1">
* <code>typ</code></a> (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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5.2">
* <code>cty</code></a> (Content Type) header value or {@code null} if not present.
*
* <p>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
* <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#appendix-A.2">JWT Appendix A.2</a> for
* an example of a Nested JWT.</p>
*
* @return the {@code typ} header parameter value or {@code null} if not present.
*/
String getContentType();
/**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5.2">
* <code>cty</code></a> (Content Type) header parameter value. A {@code null} value will remove the property from
* the JSON map.
*
* <p>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
* <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#appendix-A.2">JWT Appendix A.2</a> for
* an example of a Nested JWT.</p>
*
* @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 <code>zip</code> (Compression Algorithm) header value or {@code null} if not present.
*
* @return the {@code zip} header parameter value or {@code null} if not present.
* @since 0.6.0
*/
String getCompressionAlgorithm();
/**
* Sets the JWT <code>zip</code> (Compression Algorithm) header parameter value. A {@code null} value will remove
* the property from the JSON map.
* <p>
* <p>The compression algorithm is NOT part of the <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25">JWT specification</a>
* 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. </p>
*
* @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the JSON map.
* @since 0.6.0
*/
T setCompressionAlgorithm(String zip);
}

View File

@@ -1,33 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,55 +0,0 @@
/*
* 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;
}
}

View File

@@ -20,9 +20,6 @@ package io.jsonwebtoken;
*
* @param <B> the type of the JWS body contents, either a String or a {@link Claims} instance.
*
* @since 0.1
*/
* @since 0.1 */
public interface Jws<B> extends Jwt<JwsHeader,B> {
String getSignature();
}

View File

@@ -23,85 +23,4 @@ package io.jsonwebtoken;
*/
public interface JwsHeader<T extends JwsHeader<T>> extends Header<T> {
/** JWS {@code Algorithm} header parameter name: <code>"alg"</code> */
public static final String ALGORITHM = "alg";
/** JWS {@code JWT Set URL} header parameter name: <code>"jku"</code> */
public static final String JWK_SET_URL = "jku";
/** JWS {@code JSON Web Key} header parameter name: <code>"jwk"</code> */
public static final String JSON_WEB_KEY = "jwk";
/** JWS {@code Key ID} header parameter name: <code>"kid"</code> */
public static final String KEY_ID = "kid";
/** JWS {@code X.509 URL} header parameter name: <code>"x5u"</code> */
public static final String X509_URL = "x5u";
/** JWS {@code X.509 Certificate Chain} header parameter name: <code>"x5c"</code> */
public static final String X509_CERT_CHAIN = "x5c";
/** JWS {@code X.509 Certificate SHA-1 Thumbprint} header parameter name: <code>"x5t"</code> */
public static final String X509_CERT_SHA1_THUMBPRINT = "x5t";
/** JWS {@code X.509 Certificate SHA-256 Thumbprint} header parameter name: <code>"x5t#S256"</code> */
public static final String X509_CERT_SHA256_THUMBPRINT = "x5t#S256";
/** JWS {@code Critical} header parameter name: <code>"crit"</code> */
public static final String CRITICAL = "crit";
/**
* Returns the JWS <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.1">
* <code>alg</code></a> (algorithm) header value or {@code null} if not present.
*
* <p>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.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.1">
* <code>alg</code></a> (Algorithm) header value. A {@code null} value will remove the property from the JSON map.
*
* <p>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.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.4">
* <code>kid</code></a> (Key ID) header value or {@code null} if not present.
*
* <p>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.</p>
*
* <p>When used with a JWK, the keyId value is used to match a JWK {@code keyId} parameter value.</p>
*
* @return the JWS {@code kid} header value or {@code null} if not present.
*/
String getKeyId();
/**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.4">
* <code>kid</code></a> (Key ID) header value. A {@code null} value will remove the property from the JSON map.
*
* <p>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.</p>
*
* <p>When used with a JWK, the keyId value is used to match a JWK {@code keyId} parameter value.</p>
*
* @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);
}

View File

@@ -23,14 +23,6 @@ package io.jsonwebtoken;
* @since 0.1
*/
public interface Jwt<H extends Header, B> {
/**
* 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.
*

View File

@@ -1,530 +0,0 @@
/*
* 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.io.Decoder;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoder;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.Keys;
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<JwtBuilder> {
//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<String, Object> 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<String, Object> 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.
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @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.
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @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.
*
* <p>The payload* and claims* properties are mutually exclusive - only one of the two may be used.</p>
*
* @param claims the JWT claims to be set as the JWT body.
* @return the builder for method chaining.
*/
JwtBuilder setClaims(Map<String, ?> 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.
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @param claims the JWT claims to be added to the JWT body.
* @return the builder for method chaining.
* @since 0.8
*/
JwtBuilder addClaims(Map<String, Object> claims);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
* <code>iss</code></a> (issuer) value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setIssuer("Joe").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setIssuer("Joe");
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
* <code>sub</code></a> (subject) value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setSubject("Me").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setSubject("Me");
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
* <code>aud</code></a> (audience) value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setAudience("You").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setAudience("You");
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
* <code>exp</code></a> (expiration) value. A {@code null} value will remove the property from the Claims.
*
* <p>A JWT obtained after this timestamp should not be used.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setExpiration(new Date(System.currentTimeMillis() + 3600000)).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setExpiration(new Date(System.currentTimeMillis() + 3600000));
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
* <code>nbf</code></a> (not before) value. A {@code null} value will remove the property from the Claims.
*
* <p>A JWT obtained before this timestamp should not be used.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setNotBefore(new Date()).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setNotBefore(new Date());
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
* <code>iat</code></a> (issued at) value. A {@code null} value will remove the property from the Claims.
*
* <p>The value is the timestamp when the JWT was created.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setIssuedAt(new Date()).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setIssuedAt(new Date());
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the Claims.
*
* <p>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.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setId(UUID.randomUUID().toString()).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setId(UUID.randomUUID().toString());
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().claim("aName", "aValue").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().put("aName", "aValue");
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 with the specified key using the key's
* {@link SignatureAlgorithm#forSigningKey(Key) recommended signature algorithm}, producing a JWS. If the
* recommended signature algorithm isn't sufficient for your needs, consider using
* {@link #signWith(Key, SignatureAlgorithm)} instead.
*
* <p>If you are looking to invoke this method with a byte array that you are confident may be used for HMAC-SHA
* algorithms, consider using {@link Keys Keys}.{@link Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor(bytes)} to
* convert the byte array into a valid {@code Key}.</p>
*
* @param key the key to use for signing
* @return the builder instance for method chaining.
* @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification as
* described by {@link SignatureAlgorithm#forSigningKey(Key)}.
* @see #signWith(Key, SignatureAlgorithm)
* @since 0.10.0
*/
JwtBuilder signWith(Key key) throws InvalidKeyException;
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* <h4>Deprecation Notice: Deprecated as of 0.10.0</h4>
*
* <p>Use {@link Keys Keys}.{@link Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor(bytes)} to
* obtain the {@code Key} and then invoke {@link #signWith(Key)} or {@link #signWith(Key, SignatureAlgorithm)}.</p>
*
* <p>This method will be removed in the 1.0 release.</p>
*
* @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.
* @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification as
* described by {@link SignatureAlgorithm#forSigningKey(Key)}.
* @deprecated as of 0.10.0: use {@link Keys Keys}.{@link Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor(bytes)} to
* obtain the {@code Key} and then invoke {@link #signWith(Key)} or {@link #signWith(Key, SignatureAlgorithm)}.
* This method will be removed in the 1.0 release.
*/
@Deprecated
JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey) throws InvalidKeyException;
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* <p>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[])}.</p>
*
* <h4>Deprecation Notice: Deprecated as of 0.10.0, will be removed in the 1.0 release.</h4>
*
* <p>This method has been deprecated because the {@code key} argument for this method can be confusing: keys for
* cryptographic operations are always binary (byte arrays), and many people were confused as to how bytes were
* obtained from the String argument.</p>
*
* <p>This method always expected a String argument that was effectively the same as the result of the following
* (pseudocode):</p>
*
* <p>{@code String base64EncodedSecretKey = base64Encode(secretKeyBytes);}</p>
*
* <p>However, a non-trivial number of JJWT users were confused by the method signature and attempted to
* use raw password strings as the key argument - for example {@code signWith(HS256, myPassword)} - which is
* almost always incorrect for cryptographic hashes and can produce erroneous or insecure results.</p>
*
* <p>See this
* <a href="https://stackoverflow.com/questions/40252903/static-secret-as-byte-key-or-string/40274325#40274325">
* StackOverflow answer</a> explaining why raw (non-base64-encoded) strings are almost always incorrect for
* signature operations.</p>
*
* <p>To perform the correct logic with base64EncodedSecretKey strings with JJWT >= 0.10.0, you may do this:
* <pre><code>
* byte[] keyBytes = {@link Decoders Decoders}.{@link Decoders#BASE64 BASE64}.{@link Decoder#decode(Object) decode(base64EncodedSecretKey)};
* Key key = {@link Keys Keys}.{@link Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor(keyBytes)};
* jwtBuilder.signWith(key); //or {@link #signWith(Key, SignatureAlgorithm)}
* </code></pre>
* </p>
*
* <p>This method will be removed in the 1.0 release.</p>
*
* @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.
* @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification as
* described by {@link SignatureAlgorithm#forSigningKey(Key)}.
* @deprecated as of 0.10.0: use {@link #signWith(Key)} or {@link #signWith(Key, SignatureAlgorithm)} instead. This
* method will be removed in the 1.0 release.
*/
@Deprecated
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) throws InvalidKeyException;
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* <p>It is typically recommended to call the {@link #signWith(Key)} instead for simplicity.
* However, this method can be useful if the recommended algorithm heuristics do not meet your needs or if
* you want explicit control over the signature algorithm used with the specified key.</p>
*
* @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.
* @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification for
* the specified algorithm.
* @see #signWith(Key)
* @deprecated since 0.10.0: use {@link #signWith(Key, SignatureAlgorithm)} instead. This method will be removed
* in the 1.0 release.
*/
@Deprecated
JwtBuilder signWith(SignatureAlgorithm alg, Key key) throws InvalidKeyException;
/**
* Signs the constructed JWT with the specified key using the specified algorithm, producing a JWS.
*
* <p>It is typically recommended to call the {@link #signWith(Key)} instead for simplicity.
* However, this method can be useful if the recommended algorithm heuristics do not meet your needs or if
* you want explicit control over the signature algorithm used with the specified key.</p>
*
* @param key the signing key to use to digitally sign the JWT.
* @param alg the JWS algorithm to use with the key to digitally sign the JWT, thereby producing a JWS.
* @return the builder for method chaining.
* @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification for
* the specified algorithm.
* @see #signWith(Key)
* @since 0.10.0
*/
JwtBuilder signWith(Key key, SignatureAlgorithm alg) throws InvalidKeyException;
/**
* Compresses the JWT body using the specified {@link CompressionCodec}.
*
* <p>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:</p>
*
* <h3>Compatibility Warning</h3>
*
* <p>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 <b>if you use compression when creating a JWS token, other libraries may not be able to
* parse that JWS token</b>. When using compression for JWS tokens, be sure that that all parties accessing the
* JWS token support compression for JWS.</p>
*
* <p>Compression when creating JWE tokens however should be universally accepted for any
* library that supports JWE.</p>
*
* @param codec implementation of the {@link CompressionCodec} to be used.
* @return the builder for method chaining.
* @see io.jsonwebtoken.CompressionCodecs
* @since 0.6.0
*/
JwtBuilder compressWith(CompressionCodec codec);
/**
* Perform Base64Url encoding with the specified Encoder.
*
* <p>JJWT uses a spec-compliant encoder that works on all supported JDK versions, but you may call this method
* to specify a different encoder if you desire.</p>
*
* @param base64UrlEncoder the encoder to use when Base64Url-encoding
* @return the builder for method chaining.
* @since 0.10.0
*/
JwtBuilder base64UrlEncodeWith(Encoder<byte[], String> base64UrlEncoder);
/**
* Performs object-to-JSON serialization with the specified Serializer. This is used by the builder to convert
* JWT/JWS/JWT headers and claims Maps to JSON strings as required by the JWT specification.
*
* <p>If this method is not called, JJWT will use whatever serializer it can find at runtime, checking for the
* presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
* in the runtime classpath, an exception will be thrown when the {@link #compact()} method is invoked.</p>
*
* @param serializer the serializer to use when converting Map objects to JSON strings.
* @return the builder for method chaining.
* @since 0.10.0
*/
JwtBuilder serializeToJsonWith(Serializer<Map<String, ?>> serializer);
/**
* Actually builds the JWT and serializes it to a compact, URL-safe string according to the
* <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-7">JWT Compact Serialization</a>
* rules.
*
* @return A compact URL-safe JWT string.
*/
String compact();
}

View File

@@ -15,10 +15,6 @@
*/
package io.jsonwebtoken;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.security.SignatureException;
import java.security.Key;
import java.util.Date;
import java.util.Map;
@@ -30,177 +26,6 @@ import java.util.Map;
*/
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
* @deprecated see {@link JwtParserBuilder#requireId(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#requireSubject(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#requireAudience(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#requireIssuer(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#requireIssuedAt(Date)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#requireExpiration(Date)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#requireNotBefore(Date)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @deprecated see {@link JwtParserBuilder#require(String, Object)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser require(String claimName, Object value);
/**
* Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
* The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
*
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
* @return the parser for method chaining.
* @since 0.7.0
* @deprecated see {@link JwtParserBuilder#setClock(Clock)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
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
* @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
* any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
* @deprecated see {@link JwtParserBuilder#setAllowedClockSkewSeconds(long)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
* a JWS (no signature), this key is not used.
@@ -322,84 +147,6 @@ public interface JwtParser {
@Deprecated
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.
* <p><b>NOTE:</b> Compression is not defined by the JWT Specification, and it is not expected that other libraries
* (including JJWT versions &lt; 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 &gt;= 0.6.0 or another library that you know implements
* the same behavior.</p>
* <h3>Default Support</h3>
* <p>JJWT's default {@link JwtParser} implementation supports both the
* {@link CompressionCodecs#DEFLATE DEFLATE}
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.</p>
* <p>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.</p>
*
* @param compressionCodecResolver the compression codec resolver used to decompress the JWT body.
* @return the parser for method chaining.
* @since 0.6.0
* @deprecated see {@link JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
/**
* Perform Base64Url decoding with the specified Decoder
*
* <p>JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method
* to specify a different decoder if you desire.</p>
*
* @param base64UrlDecoder the decoder to use when Base64Url-decoding
* @return the parser for method chaining.
* @since 0.10.0
* @deprecated see {@link JwtParserBuilder#base64UrlDecodeWith(Decoder)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder);
/**
* Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is
* used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map
* objects.
*
* <p>If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the
* presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
* in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is
* invoked.</p>
*
* @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
* @return the parser for method chaining.
* @since 0.10.0
* @deprecated see {@link JwtParserBuilder#deserializeJsonWith(Deserializer)} )}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser deserializeJsonWith(Deserializer<Map<String,?>> deserializer);
/**
* Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
* otherwise.
* <p>
* <p>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.</p>
*
* @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.

View File

@@ -15,9 +15,6 @@
*/
package io.jsonwebtoken;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Deserializer;
import java.security.Key;
import java.util.Date;
import java.util.Map;
@@ -35,122 +32,6 @@ import java.util.Map;
*/
public interface JwtParserBuilder {
/**
* Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param id
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireId(String id);
/**
* Ensures that the specified {@code sub} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param subject
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireSubject(String subject);
/**
* Ensures that the specified {@code aud} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param audience
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireAudience(String audience);
/**
* Ensures that the specified {@code iss} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param issuer
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireIssuer(String issuer);
/**
* Ensures that the specified {@code iat} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param issuedAt
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireIssuedAt(Date issuedAt);
/**
* Ensures that the specified {@code exp} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param expiration
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireExpiration(Date expiration);
/**
* Ensures that the specified {@code nbf} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param notBefore
* @return the parser builder for method chaining
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireNotBefore(Date notBefore);
/**
* Ensures that the specified {@code claimName} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param claimName
* @param value
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder require(String claimName, Object value);
/**
* Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
* The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
*
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setClock(Clock clock);
/**
* Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp}
* and {@code nbf} claims.
*
* @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
* @return the parser builder for method chaining.
* @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
* any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
*/
JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
@@ -252,53 +133,6 @@ public interface JwtParserBuilder {
*/
JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
/**
* Sets the {@link CompressionCodecResolver} used to acquire the {@link CompressionCodec} that should be used to
* decompress the JWT body. If the parsed JWT is not compressed, this resolver is not used.
* <p><b>NOTE:</b> Compression is not defined by the JWT Specification, and it is not expected that other libraries
* (including JJWT versions &lt; 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 &gt;= 0.6.0 or another library that you know implements
* the same behavior.</p>
* <h3>Default Support</h3>
* <p>JJWT's default {@link JwtParser} implementation supports both the
* {@link CompressionCodecs#DEFLATE DEFLATE}
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.</p>
* <p>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.</p>
*
* @param compressionCodecResolver the compression codec resolver used to decompress the JWT body.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
/**
* Perform Base64Url decoding with the specified Decoder
*
* <p>JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method
* to specify a different decoder if you desire.</p>
*
* @param base64UrlDecoder the decoder to use when Base64Url-decoding
* @return the parser builder for method chaining.
*/
JwtParserBuilder base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder);
/**
* Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is
* used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map
* objects.
*
* <p>If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the
* presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
* in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is
* invoked.</p>
*
* @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
* @return the builder for method chaining.
*/
JwtParserBuilder deserializeJsonWith(Deserializer<Map<String,?>> deserializer);
/**
* Returns an immutable/thread-safe {@link JwtParser} created from the configuration from this JwtParserBuilder.
* @return an immutable/thread-safe JwtParser created from the configuration from this JwtParserBuilder.

View File

@@ -15,8 +15,6 @@
*/
package io.jsonwebtoken;
import io.jsonwebtoken.lang.Classes;
import java.util.Map;
/**
@@ -27,73 +25,9 @@ import java.util.Map;
*/
public final class Jwts {
private static final Class[] MAP_ARG = new Class[]{Map.class};
private Jwts() {
}
/**
* Creates a new {@link Header} instance suitable for <em>plaintext</em> (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 <em>plaintext</em> (not digitally signed) JWTs.
*/
public static Header header() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultHeader");
}
/**
* Creates a new {@link Header} instance suitable for <em>plaintext</em> (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 <em>plaintext</em> (not digitally signed) JWTs.
*/
public static Header header(Map<String, Object> header) {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultHeader", MAP_ARG, 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 Classes.newInstance("io.jsonwebtoken.impl.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<String, Object> header) {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwsHeader", MAP_ARG, 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 Classes.newInstance("io.jsonwebtoken.impl.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<String, Object> claims) {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultClaims", MAP_ARG, claims);
}
/**
* Returns a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
@@ -118,7 +52,7 @@ public final class Jwts {
*/
@Deprecated
public static JwtParser parser() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParser");
return null;
}
/**
@@ -127,17 +61,6 @@ public final class Jwts {
* @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser).
*/
public static JwtParserBuilder parserBuilder() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder");
}
/**
* Returns a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.
*
* @return a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.
*/
public static JwtBuilder builder() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder");
return null;
}
}

View File

@@ -1,32 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,39 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,32 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,655 +0,0 @@
/*
* 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.security.InvalidKeyException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import io.jsonwebtoken.security.WeakKeyException;
import javax.crypto.SecretKey;
import java.security.Key;
import java.security.PrivateKey;
import java.security.interfaces.ECKey;
import java.security.interfaces.RSAKey;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Type-safe representation of standard JWT signature algorithm names as defined in the
* <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31">JSON Web Algorithms</a> 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, 0, 0),
/**
* JWA algorithm name for {@code HMAC using SHA-256}
*/
HS256("HS256", "HMAC using SHA-256", "HMAC", "HmacSHA256", true, 256, 256, "1.2.840.113549.2.9"),
/**
* JWA algorithm name for {@code HMAC using SHA-384}
*/
HS384("HS384", "HMAC using SHA-384", "HMAC", "HmacSHA384", true, 384, 384, "1.2.840.113549.2.10"),
/**
* JWA algorithm name for {@code HMAC using SHA-512}
*/
HS512("HS512", "HMAC using SHA-512", "HMAC", "HmacSHA512", true, 512, 512, "1.2.840.113549.2.11"),
/**
* JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-256}
*/
RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "RSA", "SHA256withRSA", true, 256, 2048),
/**
* JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-384}
*/
RS384("RS384", "RSASSA-PKCS-v1_5 using SHA-384", "RSA", "SHA384withRSA", true, 384, 2048),
/**
* JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-512}
*/
RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "RSA", "SHA512withRSA", true, 512, 2048),
/**
* JWA algorithm name for {@code ECDSA using P-256 and SHA-256}
*/
ES256("ES256", "ECDSA using P-256 and SHA-256", "ECDSA", "SHA256withECDSA", true, 256, 256),
/**
* JWA algorithm name for {@code ECDSA using P-384 and SHA-384}
*/
ES384("ES384", "ECDSA using P-384 and SHA-384", "ECDSA", "SHA384withECDSA", true, 384, 384),
/**
* JWA algorithm name for {@code ECDSA using P-521 and SHA-512}
*/
ES512("ES512", "ECDSA using P-521 and SHA-512", "ECDSA", "SHA512withECDSA", true, 512, 521),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-256 and MGF1 with SHA-256}. <b>This algorithm requires
* Java 11 or later or a JCA provider like BouncyCastle to be in the runtime classpath.</b> If on Java 10 or
* earlier, BouncyCastle will be used automatically if found in the runtime classpath.
*/
PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "RSA", "RSASSA-PSS", false, 256, 2048),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-384 and MGF1 with SHA-384}. <b>This algorithm requires
* Java 11 or later or a JCA provider like BouncyCastle to be in the runtime classpath.</b> If on Java 10 or
* earlier, BouncyCastle will be used automatically if found in the runtime classpath.
*/
PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "RSA", "RSASSA-PSS", false, 384, 2048),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-512 and MGF1 with SHA-512}. <b>This algorithm requires
* Java 11 or later or a JCA provider like BouncyCastle to be in the runtime classpath.</b> If on Java 10 or
* earlier, BouncyCastle will be used automatically if found in the runtime classpath.
*/
PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "RSA", "RSASSA-PSS", false, 512, 2048);
//purposefully ordered higher to lower:
private static final List<SignatureAlgorithm> PREFERRED_HMAC_ALGS = Collections.unmodifiableList(Arrays.asList(
SignatureAlgorithm.HS512, SignatureAlgorithm.HS384, SignatureAlgorithm.HS256));
//purposefully ordered higher to lower:
private static final List<SignatureAlgorithm> PREFERRED_EC_ALGS = Collections.unmodifiableList(Arrays.asList(
SignatureAlgorithm.ES512, SignatureAlgorithm.ES384, SignatureAlgorithm.ES256));
private final String value;
private final String description;
private final String familyName;
private final String jcaName;
private final boolean jdkStandard;
private final int digestLength;
private final int minKeyLength;
/**
* Algorithm name as given by {@link Key#getAlgorithm()} if the key was loaded from a pkcs12 Keystore.
*
* @deprecated This is just a workaround for https://bugs.openjdk.java.net/browse/JDK-8243551
*/
@Deprecated
private final String pkcs12Name;
SignatureAlgorithm(String value, String description, String familyName, String jcaName, boolean jdkStandard,
int digestLength, int minKeyLength) {
this(value, description,familyName, jcaName, jdkStandard, digestLength, minKeyLength, jcaName);
}
SignatureAlgorithm(String value, String description, String familyName, String jcaName, boolean jdkStandard,
int digestLength, int minKeyLength, String pkcs12Name) {
this.value = value;
this.description = description;
this.familyName = familyName;
this.jcaName = jcaName;
this.jdkStandard = jdkStandard;
this.digestLength = digestLength;
this.minKeyLength = minKeyLength;
this.pkcs12Name = pkcs12Name;
}
/**
* 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:
*
* <table>
* <caption>Crypto Family</caption>
* <thead>
* <tr>
* <th>SignatureAlgorithm</th>
* <th>Family Name</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>HS256</td>
* <td>HMAC</td>
* </tr>
* <tr>
* <td>HS384</td>
* <td>HMAC</td>
* </tr>
* <tr>
* <td>HS512</td>
* <td>HMAC</td>
* </tr>
* <tr>
* <td>RS256</td>
* <td>RSA</td>
* </tr>
* <tr>
* <td>RS384</td>
* <td>RSA</td>
* </tr>
* <tr>
* <td>RS512</td>
* <td>RSA</td>
* </tr>
* <tr>
* <td>PS256</td>
* <td>RSA</td>
* </tr>
* <tr>
* <td>PS384</td>
* <td>RSA</td>
* </tr>
* <tr>
* <td>PS512</td>
* <td>RSA</td>
* </tr>
* <tr>
* <td>ES256</td>
* <td>ECDSA</td>
* </tr>
* <tr>
* <td>ES384</td>
* <td>ECDSA</td>
* </tr>
* <tr>
* <td>ES512</td>
* <td>ECDSA</td>
* </tr>
* </tbody>
* </table>
*
* @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 familyName.equals("HMAC");
}
/**
* 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 familyName.equals("RSA");
}
/**
* Returns {@code true} if the enum instance represents an Elliptic Curve ECDSA signature algorithm, {@code false}
* otherwise.
*
* @return {@code true} if the enum instance represents an Elliptic Curve ECDSA signature algorithm, {@code false}
* otherwise.
*/
public boolean isEllipticCurve() {
return familyName.equals("ECDSA");
}
/**
* Returns the minimum key length in bits (not bytes) that may be used with this algorithm according to the
* <a href="https://tools.ietf.org/html/rfc7518">JWT JWA Specification (RFC 7518)</a>.
*
* @return the minimum key length in bits (not bytes) that may be used with this algorithm according to the
* <a href="https://tools.ietf.org/html/rfc7518">JWT JWA Specification (RFC 7518)</a>.
* @since 0.10.0
*/
public int getMinKeyLength() {
return this.minKeyLength;
}
/**
* Returns quietly if the specified key is allowed to create signatures using this algorithm
* according to the <a href="https://tools.ietf.org/html/rfc7518">JWT JWA Specification (RFC 7518)</a> or throws an
* {@link InvalidKeyException} if the key is not allowed or not secure enough for this algorithm.
*
* @param key the key to check for validity.
* @throws InvalidKeyException if the key is not allowed or not secure enough for this algorithm.
* @since 0.10.0
*/
public void assertValidSigningKey(Key key) throws InvalidKeyException {
assertValid(key, true);
}
/**
* Returns quietly if the specified key is allowed to verify signatures using this algorithm
* according to the <a href="https://tools.ietf.org/html/rfc7518">JWT JWA Specification (RFC 7518)</a> or throws an
* {@link InvalidKeyException} if the key is not allowed or not secure enough for this algorithm.
*
* @param key the key to check for validity.
* @throws InvalidKeyException if the key is not allowed or not secure enough for this algorithm.
* @since 0.10.0
*/
public void assertValidVerificationKey(Key key) throws InvalidKeyException {
assertValid(key, false);
}
/**
* @since 0.10.0 to support assertValid(Key, boolean)
*/
private static String keyType(boolean signing) {
return signing ? "signing" : "verification";
}
/**
* @since 0.10.0
*/
private void assertValid(Key key, boolean signing) throws InvalidKeyException {
if (this == NONE) {
String msg = "The 'NONE' signature algorithm does not support cryptographic keys.";
throw new InvalidKeyException(msg);
} else if (isHmac()) {
if (!(key instanceof SecretKey)) {
String msg = this.familyName + " " + keyType(signing) + " keys must be SecretKey instances.";
throw new InvalidKeyException(msg);
}
SecretKey secretKey = (SecretKey) key;
byte[] encoded = secretKey.getEncoded();
if (encoded == null) {
throw new InvalidKeyException("The " + keyType(signing) + " key's encoded bytes cannot be null.");
}
String alg = secretKey.getAlgorithm();
if (alg == null) {
throw new InvalidKeyException("The " + keyType(signing) + " key's algorithm cannot be null.");
}
// These next checks use equalsIgnoreCase per https://github.com/jwtk/jjwt/issues/381#issuecomment-412912272
if (!HS256.jcaName.equalsIgnoreCase(alg) &&
!HS384.jcaName.equalsIgnoreCase(alg) &&
!HS512.jcaName.equalsIgnoreCase(alg) &&
!HS256.pkcs12Name.equals(alg) &&
!HS384.pkcs12Name.equals(alg) &&
!HS512.pkcs12Name.equals(alg)) {
throw new InvalidKeyException("The " + keyType(signing) + " key's algorithm '" + alg +
"' does not equal a valid HmacSHA* algorithm name and cannot be used with " + name() + ".");
}
int size = encoded.length * 8; //size in bits
if (size < this.minKeyLength) {
String msg = "The " + keyType(signing) + " key's size is " + size + " bits which " +
"is not secure enough for the " + name() + " algorithm. The JWT " +
"JWA Specification (RFC 7518, Section 3.2) states that keys used with " + name() + " MUST have a " +
"size >= " + minKeyLength + " bits (the key size must be greater than or equal to the hash " +
"output size). Consider using the " + Keys.class.getName() + " class's " +
"'secretKeyFor(SignatureAlgorithm." + name() + ")' method to create a key guaranteed to be " +
"secure enough for " + name() + ". See " +
"https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
throw new WeakKeyException(msg);
}
} else { //EC or RSA
if (signing) {
if (!(key instanceof PrivateKey)) {
String msg = familyName + " signing keys must be PrivateKey instances.";
throw new InvalidKeyException(msg);
}
}
if (isEllipticCurve()) {
if (!(key instanceof ECKey)) {
String msg = familyName + " " + keyType(signing) + " keys must be ECKey instances.";
throw new InvalidKeyException(msg);
}
ECKey ecKey = (ECKey) key;
int size = ecKey.getParams().getOrder().bitLength();
if (size < this.minKeyLength) {
String msg = "The " + keyType(signing) + " key's size (ECParameterSpec order) is " + size +
" bits which is not secure enough for the " + name() + " algorithm. The JWT " +
"JWA Specification (RFC 7518, Section 3.4) states that keys used with " +
name() + " MUST have a size >= " + this.minKeyLength +
" bits. Consider using the " + Keys.class.getName() + " class's " +
"'keyPairFor(SignatureAlgorithm." + name() + ")' method to create a key pair guaranteed " +
"to be secure enough for " + name() + ". See " +
"https://tools.ietf.org/html/rfc7518#section-3.4 for more information.";
throw new WeakKeyException(msg);
}
} else { //RSA
if (!(key instanceof RSAKey)) {
String msg = familyName + " " + keyType(signing) + " keys must be RSAKey instances.";
throw new InvalidKeyException(msg);
}
RSAKey rsaKey = (RSAKey) key;
int size = rsaKey.getModulus().bitLength();
if (size < this.minKeyLength) {
String section = name().startsWith("P") ? "3.5" : "3.3";
String msg = "The " + keyType(signing) + " key's size is " + size + " bits which is not secure " +
"enough for the " + name() + " algorithm. The JWT JWA Specification (RFC 7518, Section " +
section + ") states that keys used with " + name() + " MUST have a size >= " +
this.minKeyLength + " bits. Consider using the " + Keys.class.getName() + " class's " +
"'keyPairFor(SignatureAlgorithm." + name() + ")' method to create a key pair guaranteed " +
"to be secure enough for " + name() + ". See " +
"https://tools.ietf.org/html/rfc7518#section-" + section + " for more information.";
throw new WeakKeyException(msg);
}
}
}
}
/**
* Returns the recommended signature algorithm to be used with the specified key according to the following
* heuristics:
*
* <table>
* <caption>Key Signature Algorithm</caption>
* <thead>
* <tr>
* <th>If the Key is a:</th>
* <th>And:</th>
* <th>With a key size of:</th>
* <th>The returned SignatureAlgorithm will be:</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>{@link SecretKey}</td>
* <td><code>{@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA256")</code><sup>1</sup></td>
* <td>256 &lt;= size &lt;= 383 <sup>2</sup></td>
* <td>{@link SignatureAlgorithm#HS256 HS256}</td>
* </tr>
* <tr>
* <td>{@link SecretKey}</td>
* <td><code>{@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA384")</code><sup>1</sup></td>
* <td>384 &lt;= size &lt;= 511</td>
* <td>{@link SignatureAlgorithm#HS384 HS384}</td>
* </tr>
* <tr>
* <td>{@link SecretKey}</td>
* <td><code>{@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA512")</code><sup>1</sup></td>
* <td>512 &lt;= size</td>
* <td>{@link SignatureAlgorithm#HS512 HS512}</td>
* </tr>
* <tr>
* <td>{@link ECKey}</td>
* <td><code>instanceof {@link PrivateKey}</code></td>
* <td>256 &lt;= size &lt;= 383 <sup>3</sup></td>
* <td>{@link SignatureAlgorithm#ES256 ES256}</td>
* </tr>
* <tr>
* <td>{@link ECKey}</td>
* <td><code>instanceof {@link PrivateKey}</code></td>
* <td>384 &lt;= size &lt;= 511</td>
* <td>{@link SignatureAlgorithm#ES384 ES384}</td>
* </tr>
* <tr>
* <td>{@link ECKey}</td>
* <td><code>instanceof {@link PrivateKey}</code></td>
* <td>4096 &lt;= size</td>
* <td>{@link SignatureAlgorithm#ES512 ES512}</td>
* </tr>
* <tr>
* <td>{@link RSAKey}</td>
* <td><code>instanceof {@link PrivateKey}</code></td>
* <td>2048 &lt;= size &lt;= 3071 <sup>4,5</sup></td>
* <td>{@link SignatureAlgorithm#RS256 RS256}</td>
* </tr>
* <tr>
* <td>{@link RSAKey}</td>
* <td><code>instanceof {@link PrivateKey}</code></td>
* <td>3072 &lt;= size &lt;= 4095 <sup>5</sup></td>
* <td>{@link SignatureAlgorithm#RS384 RS384}</td>
* </tr>
* <tr>
* <td>{@link RSAKey}</td>
* <td><code>instanceof {@link PrivateKey}</code></td>
* <td>4096 &lt;= size <sup>5</sup></td>
* <td>{@link SignatureAlgorithm#RS512 RS512}</td>
* </tr>
* </tbody>
* </table>
* <p>Notes:</p>
* <ol>
* <li>{@code SecretKey} instances must have an {@link Key#getAlgorithm() algorithm} name equal
* to {@code HmacSHA256}, {@code HmacSHA384} or {@code HmacSHA512}. If not, the key bytes might not be
* suitable for HMAC signatures will be rejected with a {@link InvalidKeyException}. </li>
* <li>The JWT <a href="https://tools.ietf.org/html/rfc7518#section-3.2">JWA Specification (RFC 7518,
* Section 3.2)</a> mandates that HMAC-SHA-* signing keys <em>MUST</em> be 256 bits or greater.
* {@code SecretKey}s with key lengths less than 256 bits will be rejected with an
* {@link WeakKeyException}.</li>
* <li>The JWT <a href="https://tools.ietf.org/html/rfc7518#section-3.4">JWA Specification (RFC 7518,
* Section 3.4)</a> mandates that ECDSA signing key lengths <em>MUST</em> be 256 bits or greater.
* {@code ECKey}s with key lengths less than 256 bits will be rejected with a
* {@link WeakKeyException}.</li>
* <li>The JWT <a href="https://tools.ietf.org/html/rfc7518#section-3.3">JWA Specification (RFC 7518,
* Section 3.3)</a> mandates that RSA signing key lengths <em>MUST</em> be 2048 bits or greater.
* {@code RSAKey}s with key lengths less than 2048 bits will be rejected with a
* {@link WeakKeyException}.</li>
* <li>Technically any RSA key of length >= 2048 bits may be used with the {@link #RS256}, {@link #RS384}, and
* {@link #RS512} algorithms, so we assume an RSA signature algorithm based on the key length to
* parallel similar decisions in the JWT specification for HMAC and ECDSA signature algorithms.
* This is not required - just a convenience.</li>
* </ol>
* <p>This implementation does not return the {@link #PS256}, {@link #PS256}, {@link #PS256} RSA variant for any
* specified {@link RSAKey} because:
* <ul>
* <li>The JWT <a href="https://tools.ietf.org/html/rfc7518#section-3.1">JWA Specification (RFC 7518,
* Section 3.1)</a> indicates that {@link #RS256}, {@link #RS384}, and {@link #RS512} are
* recommended algorithms while the {@code PS}* variants are simply marked as optional.</li>
* <li>The {@link #RS256}, {@link #RS384}, and {@link #RS512} algorithms are available in the JDK by default
* while the {@code PS}* variants require an additional JCA Provider (like BouncyCastle).</li>
* </ul>
* </p>
*
* <p>Finally, this method will throw an {@link InvalidKeyException} for any key that does not match the
* heuristics and requirements documented above, since that inevitably means the Key is either insufficient or
* explicitly disallowed by the JWT specification.</p>
*
* @param key the key to inspect
* @return the recommended signature algorithm to be used with the specified key
* @throws InvalidKeyException for any key that does not match the heuristics and requirements documented above,
* since that inevitably means the Key is either insufficient or explicitly disallowed by the JWT specification.
* @since 0.10.0
*/
public static SignatureAlgorithm forSigningKey(Key key) throws InvalidKeyException {
if (key == null) {
throw new InvalidKeyException("Key argument cannot be null.");
}
if (!(key instanceof SecretKey ||
(key instanceof PrivateKey && (key instanceof ECKey || key instanceof RSAKey)))) {
String msg = "JWT standard signing algorithms require either 1) a SecretKey for HMAC-SHA algorithms or " +
"2) a private RSAKey for RSA algorithms or 3) a private ECKey for Elliptic Curve algorithms. " +
"The specified key is of type " + key.getClass().getName();
throw new InvalidKeyException(msg);
}
if (key instanceof SecretKey) {
SecretKey secretKey = (SecretKey)key;
int bitLength = io.jsonwebtoken.lang.Arrays.length(secretKey.getEncoded()) * Byte.SIZE;
for(SignatureAlgorithm alg : PREFERRED_HMAC_ALGS) {
// ensure compatibility check is based on key length. See https://github.com/jwtk/jjwt/issues/381
if (bitLength >= alg.minKeyLength) {
return alg;
}
}
String msg = "The specified SecretKey is not strong enough to be used with JWT HMAC signature " +
"algorithms. The JWT specification requires HMAC keys to be >= 256 bits long. The specified " +
"key is " + bitLength + " bits. See https://tools.ietf.org/html/rfc7518#section-3.2 for more " +
"information.";
throw new WeakKeyException(msg);
}
if (key instanceof RSAKey) {
RSAKey rsaKey = (RSAKey) key;
int bitLength = rsaKey.getModulus().bitLength();
if (bitLength >= 4096) {
RS512.assertValidSigningKey(key);
return RS512;
} else if (bitLength >= 3072) {
RS384.assertValidSigningKey(key);
return RS384;
} else if (bitLength >= RS256.minKeyLength) {
RS256.assertValidSigningKey(key);
return RS256;
}
String msg = "The specified RSA signing key is not strong enough to be used with JWT RSA signature " +
"algorithms. The JWT specification requires RSA keys to be >= 2048 bits long. The specified RSA " +
"key is " + bitLength + " bits. See https://tools.ietf.org/html/rfc7518#section-3.3 for more " +
"information.";
throw new WeakKeyException(msg);
}
// if we've made it this far in the method, the key is an ECKey due to the instanceof assertions at the
// top of the method
ECKey ecKey = (ECKey) key;
int bitLength = ecKey.getParams().getOrder().bitLength();
for (SignatureAlgorithm alg : PREFERRED_EC_ALGS) {
if (bitLength >= alg.minKeyLength) {
alg.assertValidSigningKey(key);
return alg;
}
}
String msg = "The specified Elliptic Curve signing key is not strong enough to be used with JWT ECDSA " +
"signature algorithms. The JWT specification requires ECDSA keys to be >= 256 bits long. " +
"The specified ECDSA key is " + bitLength + " bits. See " +
"https://tools.ietf.org/html/rfc7518#section-3.4 for more information.";
throw new WeakKeyException(msg);
}
/**
* Looks up and returns the corresponding {@code SignatureAlgorithm} enum instance based on a
* case-<em>insensitive</em> 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-<em>insensitive</em> 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 + "'");
}
}

View File

@@ -49,25 +49,4 @@ import java.security.Key;
*/
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);
}

View File

@@ -1,99 +0,0 @@
/*
* 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 <a href="http://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a> 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.
*
* <p>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.</p>
*
* <p>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.</p>
*
* @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.
*
* <p><b>NOTE:</b> You cannot override this method when validating RSA signatures. If you expect RSA signatures,
* you must override the {@link #resolveSigningKey(JwsHeader, Claims)} method instead.</p>
*
* @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.");
}
}

View File

@@ -15,44 +15,19 @@
*/
package io.jsonwebtoken.impl;
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.impl.crypto.JwtSignatureValidator;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.DateFormats;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.SignatureException;
import io.jsonwebtoken.security.WeakKeyException;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.Map;
@SuppressWarnings("unchecked")
public class DefaultJwtParser implements JwtParser {
@@ -60,71 +35,6 @@ public class DefaultJwtParser implements JwtParser {
public DefaultJwtParser() {
}
DefaultJwtParser(SigningKeyResolver signingKeyResolver, Key key, byte[] keyBytes, Clock clock,
long allowedClockSkewMillis, Claims expectedClaims, Decoder<String, byte[]> base64UrlDecoder,
Deserializer<Map<String, ?>> deserializer, CompressionCodecResolver compressionCodecResolver) {
}
@Override
public JwtParser deserializeJsonWith(Deserializer<Map<String, ?>> deserializer) {
return null;
}
@Override
public JwtParser base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder) {
return null;
}
@Override
public JwtParser requireIssuedAt(Date issuedAt) {
return null;
}
@Override
public JwtParser requireIssuer(String issuer) {
return null;
}
@Override
public JwtParser requireAudience(String audience) {
return null;
}
@Override
public JwtParser requireSubject(String subject) {
return null;
}
@Override
public JwtParser requireId(String id) {
return null;
}
@Override
public JwtParser requireExpiration(Date expiration) {
return null;
}
@Override
public JwtParser requireNotBefore(Date notBefore) {
return null;
}
@Override
public JwtParser require(String claimName, Object value) {
return null;
}
@Override
public JwtParser setClock(Clock clock) {
return null;
}
@Override
public JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException {
return null;
}
@Override
public JwtParser setSigningKey(byte[] key) {
return null;
@@ -145,39 +55,11 @@ public class DefaultJwtParser implements JwtParser {
return null;
}
@Override
public JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) {
return null;
}
@Override
public boolean isSigned(String jwt) {
return false;
}
@Override
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
return null;
}
/**
* @since 0.10.0
*/
private static Object normalize(Object o) {
return null;
}
private void validateExpectedClaims(Header header, Claims claims) {
return;
}
/*
* @since 0.5 mostly to allow testing overrides
*/
protected JwtSignatureValidator createSignatureValidator(SignatureAlgorithm alg, Key key) {
return null;
}
@Override
public <T> T parse(String compact, JwtHandler<T> handler)
throws ExpiredJwtException, MalformedJwtException, SignatureException {
@@ -203,9 +85,4 @@ public class DefaultJwtParser implements JwtParser {
public Jws<Claims> parseClaimsJws(String claimsJws) {
return null;
}
@SuppressWarnings("unchecked")
protected Map<String, ?> readValue(String val) {
return null;
}
}

View File

@@ -1,21 +0,0 @@
/*
* 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);
}

View File

@@ -1,680 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import java.util.Arrays;
/**
* A very fast and memory efficient class to encode and decode to and from BASE64 or BASE64URL in full accordance
* with <a href="https://tools.ietf.org/html/rfc4648">RFC 4648</a>.
*
* <p>Based initially on MigBase64 with continued modifications for Base64 URL support and JDK-standard code formatting.</p>
*
* <p>This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
* allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
* as large as algorithms that create a temporary array.</p>
*
* <p>There is also a "fast" version of all decode methods that works the same way as the normal ones, but
* has a few demands on the decoded input. Normally though, these fast versions should be used if the source if
* the input is known and it hasn't bee tampered with.</p>
*
* @author Mikael Grev
* @author Les Hazlewood
* @since 0.10.0
*/
@SuppressWarnings("Duplicates")
final class Base64 { //final and package-protected on purpose
private static final char[] BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static final char[] BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();
private static final int[] BASE64_IALPHABET = new int[256];
private static final int[] BASE64URL_IALPHABET = new int[256];
private static final int IALPHABET_MAX_INDEX = BASE64_IALPHABET.length - 1;
static {
Arrays.fill(BASE64_IALPHABET, -1);
System.arraycopy(BASE64_IALPHABET, 0, BASE64URL_IALPHABET, 0, BASE64_IALPHABET.length);
for (int i = 0, iS = BASE64_ALPHABET.length; i < iS; i++) {
BASE64_IALPHABET[BASE64_ALPHABET[i]] = i;
BASE64URL_IALPHABET[BASE64URL_ALPHABET[i]] = i;
}
BASE64_IALPHABET['='] = 0;
BASE64URL_IALPHABET['='] = 0;
}
static final Base64 DEFAULT = new Base64(false);
static final Base64 URL_SAFE = new Base64(true);
private final boolean urlsafe;
private final char[] ALPHABET;
private final int[] IALPHABET;
private Base64(boolean urlsafe) {
this.urlsafe = urlsafe;
this.ALPHABET = urlsafe ? BASE64URL_ALPHABET : BASE64_ALPHABET;
this.IALPHABET = urlsafe ? BASE64URL_IALPHABET : BASE64_IALPHABET;
}
// ****************************************************************************************
// * char[] version
// ****************************************************************************************
private String getName() {
return urlsafe ? "base64url" : "base64"; // RFC 4648 codec names are all lowercase
}
/**
* Encodes a raw byte array into a BASE64 <code>char[]</code> representation in accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
private char[] encodeToChar(byte[] sArr, boolean lineSep) {
// Check special case
int sLen = sArr != null ? sArr.length : 0;
if (sLen == 0) {
return new char[0];
}
int eLen = (sLen / 3) * 3; // # of bytes that can encode evenly into 24-bit chunks
int left = sLen - eLen; // # of bytes that remain after 24-bit chunking. Always 0, 1 or 2
int cCnt = (((sLen - 1) / 3 + 1) << 2); // # of base64-encoded characters including padding
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned char array with padding and any line separators
int padCount = 0;
if (left == 2) {
padCount = 1;
} else if (left == 1) {
padCount = 2;
}
char[] dArr = new char[urlsafe ? (dLen - padCount) : dLen];
// Encode even 24-bits
for (int s = 0, d = 0, cc = 0; s < eLen; ) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
// Encode the int into four chars
dArr[d++] = ALPHABET[(i >>> 18) & 0x3f];
dArr[d++] = ALPHABET[(i >>> 12) & 0x3f];
dArr[d++] = ALPHABET[(i >>> 6) & 0x3f];
dArr[d++] = ALPHABET[i & 0x3f];
// Add optional line separator
if (lineSep && ++cc == 19 && d < dLen - 2) {
dArr[d++] = '\r';
dArr[d++] = '\n';
cc = 0;
}
}
// Pad and encode last bits if source isn't even 24 bits.
if (left > 0) {
// Prepare the int
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
// Set last four chars
dArr[dLen - 4] = ALPHABET[i >> 12];
dArr[dLen - 3] = ALPHABET[(i >>> 6) & 0x3f];
//dArr[dLen - 2] = left == 2 ? ALPHABET[i & 0x3f] : '=';
//dArr[dLen - 1] = '=';
if (left == 2) {
dArr[dLen - 2] = ALPHABET[i & 0x3f];
} else if (!urlsafe) { // if not urlsafe, we need to include the padding characters
dArr[dLen - 2] = '=';
}
if (!urlsafe) { // include padding
dArr[dLen - 1] = '=';
}
}
return dArr;
}
/*
* Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
*
* @param sArr The source array. <code>null</code> or length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*
public final byte[] decode(char[] sArr) {
// Check special case
int sLen = sArr != null ? sArr.length : 0;
if (sLen == 0) {
return new byte[0];
}
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) { // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
if (IALPHABET[sArr[i]] < 0) {
sepCnt++;
}
}
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0) {
return null;
}
int pad = 0;
for (int i = sLen; i > 1 && IALPHABET[sArr[--i]] <= 0; ) {
if (sArr[i] == '=') {
pad++;
}
}
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
for (int s = 0, d = 0; d < len; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IALPHABET[sArr[s++]];
if (c >= 0) {
i |= c << (18 - j * 6);
} else {
j--;
}
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++] = (byte) (i >> 8);
if (d < len) {
dArr[d++] = (byte) i;
}
}
}
return dArr;
}
*/
private int ctoi(char c) {
int i = c > IALPHABET_MAX_INDEX ? -1 : IALPHABET[c];
if (i < 0) {
String msg = "Illegal " + getName() + " character: '" + c + "'";
throw new DecodingException(msg);
}
return i;
}
/**
* Decodes a BASE64 encoded char array that is known to be reasonably well formatted. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
*
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
* @throws DecodingException on illegal input
*/
final byte[] decodeFast(char[] sArr) throws DecodingException {
// Check special case
int sLen = sArr != null ? sArr.length : 0;
if (sLen == 0) {
return new byte[0];
}
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
// Trim illegal chars from start
while (sIx < eIx && IALPHABET[sArr[sIx]] < 0) {
sIx++;
}
// Trim illegal chars from end
while (eIx > 0 && IALPHABET[sArr[eIx]] < 0) {
eIx--;
}
// get the padding count (=) (0, 1 or 2)
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = ctoi(sArr[sIx++]) << 18 | ctoi(sArr[sIx++]) << 12 | ctoi(sArr[sIx++]) << 6 | ctoi(sArr[sIx++]);
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++) {
i |= ctoi(sArr[sIx++]) << (18 - j * 6);
}
for (int r = 16; d < len; r -= 8) {
dArr[d++] = (byte) (i >> r);
}
}
return dArr;
}
// ****************************************************************************************
// * byte[] version
// ****************************************************************************************
/*
* Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*
public final byte[] encodeToByte(byte[] sArr, boolean lineSep) {
return encodeToByte(sArr, 0, sArr != null ? sArr.length : 0, lineSep);
}
/**
* Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> an empty array will be returned.
* @param sOff The starting position in the bytes to convert.
* @param sLen The number of bytes to convert. If 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*
public final byte[] encodeToByte(byte[] sArr, int sOff, int sLen, boolean lineSep) {
// Check special case
if (sArr == null || sLen == 0) {
return new byte[0];
}
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
byte[] dArr = new byte[dLen];
// Encode even 24-bits
for (int s = sOff, d = 0, cc = 0; s < sOff + eLen; ) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
// Encode the int into four chars
dArr[d++] = (byte) ALPHABET[(i >>> 18) & 0x3f];
dArr[d++] = (byte) ALPHABET[(i >>> 12) & 0x3f];
dArr[d++] = (byte) ALPHABET[(i >>> 6) & 0x3f];
dArr[d++] = (byte) ALPHABET[i & 0x3f];
// Add optional line separator
if (lineSep && ++cc == 19 && d < dLen - 2) {
dArr[d++] = '\r';
dArr[d++] = '\n';
cc = 0;
}
}
// Pad and encode last bits if source isn't an even 24 bits.
int left = sLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = ((sArr[sOff + eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sOff + sLen - 1] & 0xff) << 2) : 0);
// Set last four chars
dArr[dLen - 4] = (byte) ALPHABET[i >> 12];
dArr[dLen - 3] = (byte) ALPHABET[(i >>> 6) & 0x3f];
dArr[dLen - 2] = left == 2 ? (byte) ALPHABET[i & 0x3f] : (byte) '=';
dArr[dLen - 1] = '=';
}
return dArr;
}
/**
* Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
*
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*
public final byte[] decode(byte[] sArr) {
return decode(sArr, 0, sArr.length);
}
/**
* Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
*
* @param sArr The source array. <code>null</code> will throw an exception.
* @param sOff The starting position in the source array.
* @param sLen The number of bytes to decode from the source array. Length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*
public final byte[] decode(byte[] sArr, int sOff, int sLen) {
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) { // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
if (IALPHABET[sArr[sOff + i] & 0xff] < 0) {
sepCnt++;
}
}
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0) {
return null;
}
int pad = 0;
for (int i = sLen; i > 1 && IALPHABET[sArr[sOff + --i] & 0xff] <= 0; ) {
if (sArr[sOff + i] == '=') {
pad++;
}
}
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
for (int s = 0, d = 0; d < len; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IALPHABET[sArr[sOff + s++] & 0xff];
if (c >= 0) {
i |= c << (18 - j * 6);
} else {
j--;
}
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++] = (byte) (i >> 8);
if (d < len) {
dArr[d++] = (byte) i;
}
}
}
return dArr;
}
/*
* Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(byte[])}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
*
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*
public final byte[] decodeFast(byte[] sArr) {
// Check special case
int sLen = sArr.length;
if (sLen == 0) {
return new byte[0];
}
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
// Trim illegal chars from start
while (sIx < eIx && IALPHABET[sArr[sIx] & 0xff] < 0) {
sIx++;
}
// Trim illegal chars from end
while (eIx > 0 && IALPHABET[sArr[eIx] & 0xff] < 0) {
eIx--;
}
// get the padding count (=) (0, 1 or 2)
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = IALPHABET[sArr[sIx++]] << 18 | IALPHABET[sArr[sIx++]] << 12 | IALPHABET[sArr[sIx++]] << 6 | IALPHABET[sArr[sIx++]];
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++) {
i |= IALPHABET[sArr[sIx++]] << (18 - j * 6);
}
for (int r = 16; d < len; r -= 8) {
dArr[d++] = (byte) (i >> r);
}
}
return dArr;
}
*/
// ****************************************************************************************
// * String version
// ****************************************************************************************
/**
* Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
final String encodeToString(byte[] sArr, boolean lineSep) {
// Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
return new String(encodeToChar(sArr, lineSep));
}
/*
* Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
* and without line separators.<br>
* <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
* will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
*
* @param str The source string. <code>null</code> or length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*
public final byte[] decode(String str) {
// Check special case
int sLen = str != null ? str.length() : 0;
if (sLen == 0) {
return new byte[0];
}
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) { // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
if (IALPHABET[str.charAt(i)] < 0) {
sepCnt++;
}
}
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0) {
return null;
}
// Count '=' at end
int pad = 0;
for (int i = sLen; i > 1 && IALPHABET[str.charAt(--i)] <= 0; ) {
if (str.charAt(i) == '=') {
pad++;
}
}
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
for (int s = 0, d = 0; d < len; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IALPHABET[str.charAt(s++)];
if (c >= 0) {
i |= c << (18 - j * 6);
} else {
j--;
}
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++] = (byte) (i >> 8);
if (d < len) {
dArr[d++] = (byte) i;
}
}
}
return dArr;
}
/**
* Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(String)}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
*
* @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*
public final byte[] decodeFast(String s) {
// Check special case
int sLen = s.length();
if (sLen == 0) {
return new byte[0];
}
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
// Trim illegal chars from start
while (sIx < eIx && IALPHABET[s.charAt(sIx) & 0xff] < 0) {
sIx++;
}
// Trim illegal chars from end
while (eIx > 0 && IALPHABET[s.charAt(eIx) & 0xff] < 0) {
eIx--;
}
// get the padding count (=) (0, 1 or 2)
int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = IALPHABET[s.charAt(sIx++)] << 18 | IALPHABET[s.charAt(sIx++)] << 12 | IALPHABET[s.charAt(sIx++)] << 6 | IALPHABET[s.charAt(sIx++)];
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++) {
i |= IALPHABET[s.charAt(sIx++)] << (18 - j * 6);
}
for (int r = 16; d < len; r -= 8) {
dArr[d++] = (byte) (i >> r);
}
}
return dArr;
}
*/
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import io.jsonwebtoken.lang.Assert;
/**
* @since 0.10.0
*/
class Base64Decoder extends Base64Support implements Decoder<String, byte[]> {
Base64Decoder() {
super(Base64.DEFAULT);
}
Base64Decoder(Base64 base64) {
super(base64);
}
@Override
public byte[] decode(String s) throws DecodingException {
Assert.notNull(s, "String argument cannot be null");
return this.base64.decodeFast(s.toCharArray());
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import io.jsonwebtoken.lang.Assert;
/**
* @since 0.10.0
*/
class Base64Encoder extends Base64Support implements Encoder<byte[], String> {
Base64Encoder() {
super(Base64.DEFAULT);
}
Base64Encoder(Base64 base64) {
super(base64);
}
@Override
public String encode(byte[] bytes) throws EncodingException {
Assert.notNull(bytes, "byte array argument cannot be null");
return this.base64.encodeToString(bytes, false);
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import io.jsonwebtoken.lang.Assert;
/**
* @since 0.10.0
*/
class Base64Support {
protected final Base64 base64;
Base64Support(Base64 base64) {
Assert.notNull(base64, "Base64 argument cannot be null");
this.base64 = base64;
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
class Base64UrlDecoder extends Base64Decoder {
Base64UrlDecoder() {
super(Base64.URL_SAFE);
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
class Base64UrlEncoder extends Base64Encoder {
Base64UrlEncoder() {
super(Base64.URL_SAFE);
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class CodecException extends IOException {
public CodecException(String message) {
super(message);
}
public CodecException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Decoder<T, R> {
R decode(T t) throws DecodingException;
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public final class Decoders {
public static final Decoder<String, byte[]> BASE64 = new ExceptionPropagatingDecoder<>(new Base64Decoder());
public static final Decoder<String, byte[]> BASE64URL = new ExceptionPropagatingDecoder<>(new Base64UrlDecoder());
private Decoders() { //prevent instantiation
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class DecodingException extends CodecException {
public DecodingException(String message) {
super(message);
}
public DecodingException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class DeserializationException extends SerialException {
public DeserializationException(String msg) {
super(msg);
}
public DeserializationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Deserializer<T> {
T deserialize(byte[] bytes) throws DeserializationException;
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Encoder<T, R> {
R encode(T t) throws EncodingException;
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public final class Encoders {
public static final Encoder<byte[], String> BASE64 = new ExceptionPropagatingEncoder<>(new Base64Encoder());
public static final Encoder<byte[], String> BASE64URL = new ExceptionPropagatingEncoder<>(new Base64UrlEncoder());
private Encoders() { //prevent instantiation
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class EncodingException extends CodecException {
public EncodingException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import io.jsonwebtoken.lang.Assert;
/**
* @since 0.10.0
*/
class ExceptionPropagatingDecoder<T, R> implements Decoder<T, R> {
private final Decoder<T, R> decoder;
ExceptionPropagatingDecoder(Decoder<T, R> decoder) {
Assert.notNull(decoder, "Decoder cannot be null.");
this.decoder = decoder;
}
@Override
public R decode(T t) throws DecodingException {
Assert.notNull(t, "Decode argument cannot be null.");
try {
return decoder.decode(t);
} catch (DecodingException e) {
throw e; //propagate
} catch (Exception e) {
String msg = "Unable to decode input: " + e.getMessage();
throw new DecodingException(msg, e);
}
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import io.jsonwebtoken.lang.Assert;
/**
* @since 0.10.0
*/
class ExceptionPropagatingEncoder<T, R> implements Encoder<T, R> {
private final Encoder<T, R> encoder;
ExceptionPropagatingEncoder(Encoder<T, R> encoder) {
Assert.notNull(encoder, "Encoder cannot be null.");
this.encoder = encoder;
}
@Override
public R encode(T t) throws EncodingException {
Assert.notNull(t, "Encode argument cannot be null.");
try {
return this.encoder.encode(t);
} catch (EncodingException e) {
throw e; //propagate
} catch (Exception e) {
String msg = "Unable to encode input: " + e.getMessage();
throw new EncodingException(msg, e);
}
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
import io.jsonwebtoken.JwtException;
/**
* @since 0.10.0
*/
public class IOException extends JwtException {
public IOException(String msg) {
super(msg);
}
public IOException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class SerialException extends IOException {
public SerialException(String msg) {
super(msg);
}
public SerialException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class SerializationException extends SerialException {
public SerializationException(String msg) {
super(msg);
}
public SerializationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Serializer<T> {
byte[] serialize(T t) throws SerializationException;
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.lang;
/**
* @since 0.6
*/
public final class Arrays {
private Arrays(){} //prevent instantiation
public static int length(byte[] bytes) {
return bytes != null ? bytes.length : 0;
}
public static byte[] clean(byte[] bytes) {
return length(bytes) > 0 ? bytes : null;
}
}

View File

@@ -1,377 +0,0 @@
/*
* 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 {
private Assert(){} //prevent instantiation
/**
* Assert a boolean expression, throwing <code>IllegalArgumentException</code>
* if the test result is <code>false</code>.
* <pre class="code">Assert.isTrue(i &gt; 0, "The value must be greater than zero");</pre>
* @param expression a boolean expression
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if expression is <code>false</code>
*/
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
/**
* Assert a boolean expression, throwing <code>IllegalArgumentException</code>
* if the test result is <code>false</code>.
* <pre class="code">Assert.isTrue(i &gt; 0);</pre>
* @param expression a boolean expression
* @throws IllegalArgumentException if expression is <code>false</code>
*/
public static void isTrue(boolean expression) {
isTrue(expression, "[Assertion failed] - this expression must be true");
}
/**
* Assert that an object is <code>null</code> .
* <pre class="code">Assert.isNull(value, "The value must be null");</pre>
* @param object the object to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object is not <code>null</code>
*/
public static void isNull(Object object, String message) {
if (object != null) {
throw new IllegalArgumentException(message);
}
}
/**
* Assert that an object is <code>null</code> .
* <pre class="code">Assert.isNull(value);</pre>
* @param object the object to check
* @throws IllegalArgumentException if the object is not <code>null</code>
*/
public static void isNull(Object object) {
isNull(object, "[Assertion failed] - the object argument must be null");
}
/**
* Assert that an object is not <code>null</code> .
* <pre class="code">Assert.notNull(clazz, "The class must not be null");</pre>
* @param object the object to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object is <code>null</code>
*/
public static void notNull(Object object, String message) {
if (object == null) {
throw new IllegalArgumentException(message);
}
}
/**
* Assert that an object is not <code>null</code> .
* <pre class="code">Assert.notNull(clazz);</pre>
* @param object the object to check
* @throws IllegalArgumentException if the object is <code>null</code>
*/
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 <code>null</code> and not the empty String.
* <pre class="code">Assert.hasLength(name, "Name must not be empty");</pre>
* @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 <code>null</code> and not the empty String.
* <pre class="code">Assert.hasLength(name);</pre>
* @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 <code>null</code> and must contain at least one non-whitespace character.
* <pre class="code">Assert.hasText(name, "'name' must not be empty");</pre>
* @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 <code>null</code> and must contain at least one non-whitespace character.
* <pre class="code">Assert.hasText(name, "'name' must not be empty");</pre>
* @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.
* <pre class="code">Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");</pre>
* @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.
* <pre class="code">Assert.doesNotContain(name, "rod");</pre>
* @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
* <code>null</code> and must have at least one element.
* <pre class="code">Assert.notEmpty(array, "The array must have elements");</pre>
* @param array the array to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object array is <code>null</code> 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
* <code>null</code> and must have at least one element.
* <pre class="code">Assert.notEmpty(array);</pre>
* @param array the array to check
* @throws IllegalArgumentException if the object array is <code>null</code> 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!
* <pre class="code">Assert.noNullElements(array, "The array must have non-null elements");</pre>
* @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 <code>null</code> 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!
* <pre class="code">Assert.noNullElements(array);</pre>
* @param array the array to check
* @throws IllegalArgumentException if the object array contains a <code>null</code> 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
* <code>null</code> and must have at least one element.
* <pre class="code">Assert.notEmpty(collection, "Collection must have elements");</pre>
* @param collection the collection to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the collection is <code>null</code> 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
* <code>null</code> and must have at least one element.
* <pre class="code">Assert.notEmpty(collection, "Collection must have elements");</pre>
* @param collection the collection to check
* @throws IllegalArgumentException if the collection is <code>null</code> 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 <code>null</code>
* and must have at least one entry.
* <pre class="code">Assert.notEmpty(map, "Map must have entries");</pre>
* @param map the map to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the map is <code>null</code> 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 <code>null</code>
* and must have at least one entry.
* <pre class="code">Assert.notEmpty(map);</pre>
* @param map the map to check
* @throws IllegalArgumentException if the map is <code>null</code> 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.
* <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
* @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.
* <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
* @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 <code>superType.isAssignableFrom(subType)</code> is <code>true</code>.
* <pre class="code">Assert.isAssignable(Number.class, myClass);</pre>
* @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 <code>superType.isAssignableFrom(subType)</code> is <code>true</code>.
* <pre class="code">Assert.isAssignable(Number.class, myClass);</pre>
* @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 <code>IllegalStateException</code>
* if the test result is <code>false</code>. Call isTrue if you wish to
* throw IllegalArgumentException on an assertion failure.
* <pre class="code">Assert.state(id == null, "The id property must not already be initialized");</pre>
* @param expression a boolean expression
* @param message the exception message to use if the assertion fails
* @throws IllegalStateException if expression is <code>false</code>
*/
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 <code>false</code>.
* <p>Call {@link #isTrue(boolean)} if you wish to
* throw {@link IllegalArgumentException} on an assertion failure.
* <pre class="code">Assert.state(id == null);</pre>
* @param expression a boolean expression
* @throws IllegalStateException if the supplied expression is <code>false</code>
*/
public static void state(boolean expression) {
state(expression, "[Assertion failed] - this state invariant must be true");
}
}

View File

@@ -1,254 +0,0 @@
/*
* 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;
import java.lang.reflect.Method;
/**
* @since 0.1
*/
public final class Classes {
private Classes() {} //prevent instantiation
/**
* @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 (<code>Classes.class.getClassLoader()</code>), then the system/application
* ClassLoader (<code>ClassLoader.getSystemClassLoader()</code>, in that order. If any of them cannot locate
* the specified class, an <code>UnknownClassException</code> is thrown (our RuntimeException equivalent of
* the JRE's <code>ClassNotFoundException</code>.
*
* @param fqcn the fully qualified class name to load
* @return the located class
* @throws UnknownClassException if the class cannot be found.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> 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("io.jsonwebtoken.impl")) {
msg += " Have you remembered to include the jjwt-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 (<code>Classes.class.getClassLoader()</code>), then the system/application
* ClassLoader (<code>ClassLoader.getSystemClassLoader()</code>, 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 <code>null</code> 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 <T> T newInstance(String fqcn) {
return (T)newInstance(forName(fqcn));
}
public static <T> T newInstance(String fqcn, Class[] ctorArgTypes, Object... args) {
Class<T> clazz = forName(fqcn);
Constructor<T> ctor = getConstructor(clazz, ctorArgTypes);
return instantiate(ctor, args);
}
@SuppressWarnings("unchecked")
public static <T> T newInstance(String fqcn, Object... args) {
return (T)newInstance(forName(fqcn), args);
}
public static <T> T newInstance(Class<T> 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> T newInstance(Class<T> clazz, Object... args) {
Class[] argTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
argTypes[i] = args[i].getClass();
}
Constructor<T> ctor = getConstructor(clazz, argTypes);
return instantiate(ctor, args);
}
public static <T> Constructor<T> getConstructor(Class<T> clazz, Class... argTypes) {
try {
return clazz.getConstructor(argTypes);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
public static <T> T instantiate(Constructor<T> 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 0.10.0
*/
@SuppressWarnings("unchecked")
public static <T> T invokeStatic(String fqcn, String methodName, Class[] argTypes, Object... args) {
try {
Class clazz = Classes.forName(fqcn);
Method method = clazz.getDeclaredMethod(methodName, argTypes);
method.setAccessible(true);
return(T)method.invoke(null, args);
} catch (Exception e) {
String msg = "Unable to invoke class method " + fqcn + "#" + methodName + ". Ensure the necessary " +
"implementation is in the runtime classpath.";
throw new IllegalStateException(msg, e);
}
}
/**
* @since 1.0
*/
private static interface ClassLoaderAccessor {
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;
}
}

View File

@@ -1,365 +0,0 @@
/*
* 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 {
private Collections(){} //prevent instantiation
/**
* Return <code>true</code> if the supplied Collection is <code>null</code>
* or empty. Otherwise, return <code>false</code>.
* @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 <code>true</code> if the supplied Map is <code>null</code>
* or empty. Otherwise, return <code>false</code>.
* @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.
* <p>A <code>null</code> 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 <code>null</code>)
* @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.
* <p>Uses <code>Properties.propertyNames()</code> to even catch
* default properties linked into the original Properties instance.
* @param props the Properties instance to merge (may be <code>null</code>)
* @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 <code>true</code> if found, <code>false</code> 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 <code>true</code> if found, <code>false</code> 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.
* <p>Enforces the given instance to be present, rather than returning
* <code>true</code> for an equal element as well.
* @param collection the Collection to check
* @param element the element to look for
* @return <code>true</code> if found, <code>false</code> else
*/
public static boolean containsInstance(Collection collection, Object element) {
if (collection != null) {
for (Object candidate : collection) {
if (candidate == element) {
return true;
}
}
}
return false;
}
/**
* Return <code>true</code> if any element in '<code>candidates</code>' is
* contained in '<code>source</code>'; otherwise returns <code>false</code>.
* @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 '<code>candidates</code>' that is contained in
* '<code>source</code>'. If no element in '<code>candidates</code>' is present in
* '<code>source</code>' returns <code>null</code>. 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 <code>null</code> 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 <code>null</code> if none or more than one such value found
*/
@SuppressWarnings("unchecked")
public static <T> T findValueOfType(Collection<?> collection, Class<T> 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 <code>null</code> 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 <code>true</code> if the collection contains a single reference or
* multiple references to the same instance, <code>false</code> 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 <code>null</code> 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,E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) {
ArrayList<A> elements = new ArrayList<A>();
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 <E> Iterator<E> toIterator(Enumeration<E> enumeration) {
return new EnumerationIterator<E>(enumeration);
}
/**
* Iterator wrapping an Enumeration.
*/
private static class EnumerationIterator<E> implements Iterator<E> {
private Enumeration<E> enumeration;
public EnumerationIterator(Enumeration<E> 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");
}
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.lang;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
* @since 0.10.0
*/
public class DateFormats {
private static final String ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final String ISO_8601_MILLIS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private static final ThreadLocal<DateFormat> ISO_8601 = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
SimpleDateFormat format = new SimpleDateFormat(ISO_8601_PATTERN);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
return format;
}
};
private static final ThreadLocal<DateFormat> ISO_8601_MILLIS = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
SimpleDateFormat format = new SimpleDateFormat(ISO_8601_MILLIS_PATTERN);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
return format;
}
};
public static String formatIso8601(Date date) {
return formatIso8601(date, true);
}
public static String formatIso8601(Date date, boolean includeMillis) {
if (includeMillis) {
return ISO_8601_MILLIS.get().format(date);
}
return ISO_8601.get().format(date);
}
public static Date parseIso8601Date(String s) throws ParseException {
Assert.notNull(s, "String argument cannot be null.");
if (s.lastIndexOf('.') > -1) { //assume ISO-8601 with milliseconds
return ISO_8601_MILLIS.get().parse(s);
} else { //assume ISO-8601 without millis:
return ISO_8601.get().parse(s);
}
}
}

View File

@@ -1,26 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (C) 2019 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.lang;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Utility class to help with the manipulation of working with Maps.
* @since 0.11.0
*/
public final class Maps {
private Maps() {} //prevent instantiation
/**
* Creates a new map builder with a single entry.
* <p> Typical usage: <pre>{@code
* Map<K,V> result = Maps.of("key1", value1)
* .and("key2", value2)
* // ...
* .build();
* }</pre>
* @param key the key of an map entry to be added
* @param value the value of map entry to be added
* @param <K> the maps key type
* @param <V> the maps value type
* Creates a new map builder with a single entry.
*/
public static <K, V> MapBuilder<K, V> of(K key, V value) {
return new HashMapBuilder<K, V>().and(key, value);
}
/**
* Utility Builder class for fluently building maps:
* <p> Typical usage: <pre>{@code
* Map<K,V> result = Maps.of("key1", value1)
* .and("key2", value2)
* // ...
* .build();
* }</pre>
* @param <K> the maps key type
* @param <V> the maps value type
*/
public interface MapBuilder<K, V> {
/**
* Add a new entry to this map builder
* @param key the key of an map entry to be added
* @param value the value of map entry to be added
* @return the current MapBuilder to allow for method chaining.
*/
MapBuilder<K, V> and(K key, V value);
/**
* Returns a the resulting Map object from this MapBuilder.
* @return Returns a the resulting Map object from this MapBuilder.
*/
Map<K, V> build();
}
private static class HashMapBuilder<K, V> implements MapBuilder<K, V> {
private final Map<K, V> data = new HashMap<>();
public MapBuilder<K, V> and(K key, V value) {
data.put(key, value);
return this;
}
public Map<K, V> build() {
return Collections.unmodifiableMap(data);
}
}
}

View File

@@ -1,927 +0,0 @@
/*
* 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 {
private Objects(){} //prevent instantiation
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. <code>null</code> 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 <code>null</code>,
* in which case the return value will always be <code>false</code>)
* @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 <E> 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 extends Enum<?>> 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 <code>null</code>)
* @param obj the object to append
* @return the new array (of the same component type; never <code>null</code>)
*/
public static <A, O extends A> 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).
* <p>A <code>null</code> source value will be converted to an
* empty Object array.
*
* @param source the (potentially primitive) array
* @return the corresponding object array (never <code>null</code>)
* @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 <code>true</code>
* if both are <code>null</code> or <code>false</code> if only one is
* <code>null</code>.
* <p>Compares arrays with <code>Arrays.equals</code>, 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
* <code>{@link Object#hashCode()}</code>. If the object is an array,
* this method will delegate to any of the <code>nullSafeHashCode</code>
* methods for arrays in this class. If the object is <code>null</code>,
* 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>array</code> is <code>null</code>, 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 <code>{@link Boolean#hashCode()}</code>.
*
* @see Boolean#hashCode()
*/
public static int hashCode(boolean bool) {
return bool ? 1231 : 1237;
}
/**
* Return the same value as <code>{@link Double#hashCode()}</code>.
*
* @see Double#hashCode()
*/
public static int hashCode(double dbl) {
long bits = Double.doubleToLongBits(dbl);
return hashCode(bits);
}
/**
* Return the same value as <code>{@link Float#hashCode()}</code>.
*
* @see Float#hashCode()
*/
public static int hashCode(float flt) {
return Float.floatToIntBits(flt);
}
/**
* Return the same value as <code>{@link Long#hashCode()}</code>.
*
* @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 <code>null</code>)
* @return the object's identity as String representation,
* or an empty String if the object was <code>null</code>
*/
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 <code>obj</code> is
* not <code>null</code>; otherwise returns an empty String.
* <p>Differs from {@link #nullSafeToString(Object)} in that it returns
* an empty String rather than "null" for a <code>null</code> value.
*
* @param obj the object to build a display String for
* @return a display String representation of <code>obj</code>
* @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.
* <p>Returns <code>"null"</code> if <code>obj</code> is <code>null</code>.
*
* @param obj the object to introspect (may be <code>null</code>)
* @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.
* <p>Builds a String representation of the contents in case of an array.
* Returns <code>"null"</code> if <code>obj</code> is <code>null</code>.
*
* @param obj the object to build a String representation for
* @return a String representation of <code>obj</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
* <p>The String representation consists of a list of the array's elements,
* enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated
* by the characters <code>", "</code> (a comma followed by a space). Returns
* <code>"null"</code> if <code>array</code> is <code>null</code>.
*
* @param array the array to build a String representation for
* @return a String representation of <code>array</code>
*/
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.
}
}
}
}
}

View File

@@ -1,65 +0,0 @@
/*
* 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 RuntimeEnvironment(){} //prevent instantiation
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 (!BOUNCY_CASTLE_AVAILABLE || 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();
}
}

View File

@@ -1,64 +0,0 @@
/*
* 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 <code>RuntimeException</code> equivalent of the JDK's
* <code>ClassNotFoundException</code>, 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) {
// TODO: remove in v1.0, this constructor is only exposed to allow for backward compatible behavior
super(message, cause);
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.security;
/**
* @since 0.10.0
*/
public class InvalidKeyException extends KeyException {
public InvalidKeyException(String message) {
super(message);
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.security;
/**
* @since 0.10.0
*/
public class KeyException extends SecurityException {
public KeyException(String message) {
super(message);
}
}

View File

@@ -1,231 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.security;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Classes;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.KeyPair;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Utility class for securely generating {@link SecretKey}s and {@link KeyPair}s.
*
* @since 0.10.0
*/
public final class Keys {
private static final String MAC = "io.jsonwebtoken.impl.crypto.MacProvider";
private static final String RSA = "io.jsonwebtoken.impl.crypto.RsaProvider";
private static final String EC = "io.jsonwebtoken.impl.crypto.EllipticCurveProvider";
private static final Class[] SIG_ARG_TYPES = new Class[]{SignatureAlgorithm.class};
//purposefully ordered higher to lower:
private static final List<SignatureAlgorithm> PREFERRED_HMAC_ALGS = Collections.unmodifiableList(Arrays.asList(
SignatureAlgorithm.HS512, SignatureAlgorithm.HS384, SignatureAlgorithm.HS256));
//prevent instantiation
private Keys() {
}
/*
public static final int bitLength(Key key) throws IllegalArgumentException {
Assert.notNull(key, "Key cannot be null.");
if (key instanceof SecretKey) {
byte[] encoded = key.getEncoded();
return Arrays.length(encoded) * 8;
} else if (key instanceof RSAKey) {
return ((RSAKey)key).getModulus().bitLength();
} else if (key instanceof ECKey) {
return ((ECKey)key).getParams().getOrder().bitLength();
}
throw new IllegalArgumentException("Unsupported key type: " + key.getClass().getName());
}
*/
/**
* Creates a new SecretKey instance for use with HMAC-SHA algorithms based on the specified key byte array.
*
* @param bytes the key byte array
* @return a new SecretKey instance for use with HMAC-SHA algorithms based on the specified key byte array.
* @throws WeakKeyException if the key byte array length is less than 256 bits (32 bytes) as mandated by the
* <a href="https://tools.ietf.org/html/rfc7518#section-3.2">JWT JWA Specification
* (RFC 7518, Section 3.2)</a>
*/
public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException {
if (bytes == null) {
throw new InvalidKeyException("SecretKey byte array cannot be null.");
}
int bitLength = bytes.length * 8;
for (SignatureAlgorithm alg : PREFERRED_HMAC_ALGS) {
if (bitLength >= alg.getMinKeyLength()) {
return new SecretKeySpec(bytes, alg.getJcaName());
}
}
String msg = "The specified key byte array is " + bitLength + " bits which " +
"is not secure enough for any JWT HMAC-SHA algorithm. The JWT " +
"JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " +
"size >= 256 bits (the key size must be greater than or equal to the hash " +
"output size). Consider using the " + Keys.class.getName() + "#secretKeyFor(SignatureAlgorithm) method " +
"to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm. See " +
"https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
throw new WeakKeyException(msg);
}
/**
* Returns a new {@link SecretKey} with a key length suitable for use with the specified {@link SignatureAlgorithm}.
*
* <p><a href="https://tools.ietf.org/html/rfc7518#section-3.2">JWA Specification (RFC 7518), Section 3.2</a>
* requires minimum key lengths to be used for each respective Signature Algorithm. This method returns a
* secure-random generated SecretKey that adheres to the required minimum key length. The lengths are:</p>
*
* <table>
* <tr>
* <th>Algorithm</th>
* <th>Key Length</th>
* </tr>
* <tr>
* <td>HS256</td>
* <td>256 bits (32 bytes)</td>
* </tr>
* <tr>
* <td>HS384</td>
* <td>384 bits (48 bytes)</td>
* </tr>
* <tr>
* <td>HS512</td>
* <td>512 bits (64 bytes)</td>
* </tr>
* </table>
*
* @param alg the {@code SignatureAlgorithm} to inspect to determine which key length to use.
* @return a new {@link SecretKey} instance suitable for use with the specified {@link SignatureAlgorithm}.
* @throws IllegalArgumentException for any input value other than {@link SignatureAlgorithm#HS256},
* {@link SignatureAlgorithm#HS384}, or {@link SignatureAlgorithm#HS512}
*/
public static SecretKey secretKeyFor(SignatureAlgorithm alg) throws IllegalArgumentException {
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
switch (alg) {
case HS256:
case HS384:
case HS512:
return Classes.invokeStatic(MAC, "generateKey", SIG_ARG_TYPES, alg);
default:
String msg = "The " + alg.name() + " algorithm does not support shared secret keys.";
throw new IllegalArgumentException(msg);
}
}
/**
* Returns a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
*
* <p>If the {@code alg} argument is an RSA algorithm, a KeyPair is generated based on the following:</p>
*
* <table>
* <tr>
* <th>JWA Algorithm</th>
* <th>Key Size</th>
* </tr>
* <tr>
* <td>RS256</td>
* <td>2048 bits</td>
* </tr>
* <tr>
* <td>PS256</td>
* <td>2048 bits</td>
* </tr>
* <tr>
* <td>RS384</td>
* <td>3072 bits</td>
* </tr>
* <tr>
* <td>PS384</td>
* <td>3072 bits</td>
* </tr>
* <tr>
* <td>RS512</td>
* <td>4096 bits</td>
* </tr>
* <tr>
* <td>PS512</td>
* <td>4096 bits</td>
* </tr>
* </table>
*
* <p>If the {@code alg} argument is an Elliptic Curve algorithm, a KeyPair is generated based on the following:</p>
*
* <table>
* <tr>
* <th>JWA Algorithm</th>
* <th>Key Size</th>
* <th><a href="https://tools.ietf.org/html/rfc7518#section-7.6.2">JWA Curve Name</a></th>
* <th><a href="https://tools.ietf.org/html/rfc5480#section-2.1.1.1">ASN1 OID Curve Name</a></th>
* </tr>
* <tr>
* <td>EC256</td>
* <td>256 bits</td>
* <td>{@code P-256}</td>
* <td>{@code secp256r1}</td>
* </tr>
* <tr>
* <td>EC384</td>
* <td>384 bits</td>
* <td>{@code P-384}</td>
* <td>{@code secp384r1}</td>
* </tr>
* <tr>
* <td>EC512</td>
* <td>512 bits</td>
* <td>{@code P-521}</td>
* <td>{@code secp521r1}</td>
* </tr>
* </table>
*
* @param alg the {@code SignatureAlgorithm} to inspect to determine which asymmetric algorithm to use.
* @return a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
* @throws IllegalArgumentException if {@code alg} is not an asymmetric algorithm
*/
public static KeyPair keyPairFor(SignatureAlgorithm alg) throws IllegalArgumentException {
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
switch (alg) {
case RS256:
case PS256:
case RS384:
case PS384:
case RS512:
case PS512:
return Classes.invokeStatic(RSA, "generateKeyPair", SIG_ARG_TYPES, alg);
case ES256:
case ES384:
case ES512:
return Classes.invokeStatic(EC, "generateKeyPair", SIG_ARG_TYPES, alg);
default:
String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
throw new IllegalArgumentException(msg);
}
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.security;
/**
* @since 0.10.0
*/
public class SignatureException extends io.jsonwebtoken.SignatureException {
public SignatureException(String message) {
super(message);
}
public SignatureException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.security;
/**
* @since 0.10.0
*/
public class WeakKeyException extends InvalidKeyException {
public WeakKeyException(String message) {
super(message);
}
}