mirror of
https://github.com/github/codeql.git
synced 2025-12-20 18:56:32 +01:00
[Java] Add stubs for jwtk-jjwt-0.11.2
This commit is contained in:
201
java/ql/test/experimental/stubs/jwtk-jjwt-0.11.2/LICENSE
Normal file
201
java/ql/test/experimental/stubs/jwtk-jjwt-0.11.2/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* ClaimJwtException is a subclass of the {@link JwtException} that is thrown after a validation of an JTW claim failed.
|
||||
*
|
||||
* @since 0.5
|
||||
*/
|
||||
public abstract class ClaimJwtException extends JwtException {
|
||||
|
||||
public static final String INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was: %s.";
|
||||
public static final String MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was not present in the JWT claims.";
|
||||
|
||||
private final Header header;
|
||||
|
||||
private final Claims claims;
|
||||
|
||||
protected ClaimJwtException(Header header, Claims claims, String message) {
|
||||
super(message);
|
||||
this.header = header;
|
||||
this.claims = claims;
|
||||
}
|
||||
|
||||
protected ClaimJwtException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.header = header;
|
||||
this.claims = claims;
|
||||
}
|
||||
|
||||
public Claims getClaims() {
|
||||
return claims;
|
||||
}
|
||||
|
||||
public Header getHeader() {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4">Claims set</a>.
|
||||
*
|
||||
* <p>This is ultimately a JSON map and any values can be added to it, but JWT standard names are provided as
|
||||
* type-safe getters and setters for convenience.</p>
|
||||
*
|
||||
* <p>Because this interface extends {@code Map<String, Object>}, if you would like to add your own properties,
|
||||
* you simply use map methods, for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* claims.{@link Map#put(Object, Object) put}("someKey", "someValue");
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Creation</h3>
|
||||
*
|
||||
* <p>It is easiest to create a {@code Claims} instance by calling one of the
|
||||
* {@link Jwts#claims() JWTs.claims()} factory methods.</p>
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Mutation (modifications) to a {@link io.jsonwebtoken.Claims Claims} instance.
|
||||
*
|
||||
* @param <T> the type of mutator
|
||||
* @see io.jsonwebtoken.JwtBuilder
|
||||
* @see io.jsonwebtoken.Claims
|
||||
* @since 0.2
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2015 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Compresses and decompresses byte arrays according to a compression algorithm.
|
||||
*
|
||||
* @see 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;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2015 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Looks for a JWT {@code 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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2015 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception indicating that either compressing or decompressing an JWT body failed.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public class CompressionException extends JwtException {
|
||||
|
||||
public CompressionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CompressionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception indicating that a JWT was accepted after it expired and must be rejected.
|
||||
*
|
||||
* @since 0.3
|
||||
*/
|
||||
public class ExpiredJwtException extends ClaimJwtException {
|
||||
|
||||
public ExpiredJwtException(Header header, Claims claims, String message) {
|
||||
super(header, claims, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param header jwt header
|
||||
* @param claims jwt claims (body)
|
||||
* @param message exception message
|
||||
* @param cause cause
|
||||
* @since 0.5
|
||||
*/
|
||||
public ExpiredJwtException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(header, claims, message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5">JOSE header</a>.
|
||||
*
|
||||
* <p>This is ultimately a JSON map and any values can be added to it, but JWT JOSE standard names are provided as
|
||||
* type-safe getters and setters for convenience.</p>
|
||||
*
|
||||
* <p>Because this interface extends {@code Map<String, Object>}, if you would like to add your own properties,
|
||||
* you simply use map methods, for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* header.{@link Map#put(Object, Object) put}("headerParamName", "headerParamValue");
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Creation</h3>
|
||||
*
|
||||
* <p>It is easiest to create a {@code Header} instance by calling one of the
|
||||
* {@link Jwts#header() JWTs.header()} factory methods.</p>
|
||||
*
|
||||
* @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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2015 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2015 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* An expanded (not compact/serialized) Signed JSON Web Token.
|
||||
*
|
||||
* @param <B> the type of the JWS body contents, either a String or a {@link Claims} instance.
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface Jws<B> extends Jwt<JwsHeader,B> {
|
||||
|
||||
String getSignature();
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* A <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31">JWS</a> header.
|
||||
*
|
||||
* @param <T> header type
|
||||
* @since 0.1
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* An expanded (not compact/serialized) JSON Web Token.
|
||||
*
|
||||
* @param <B> the type of the JWT body contents, either a String or a {@link Claims} instance.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return the JWT body, either a {@code String} or a {@code Claims} instance.
|
||||
*/
|
||||
B getBody();
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Base class for JWT-related runtime exceptions.
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public class JwtException extends RuntimeException {
|
||||
|
||||
public JwtException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JwtException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* A JwtHandler is invoked by a {@link io.jsonwebtoken.JwtParser JwtParser} after parsing a JWT to indicate the exact
|
||||
* type of JWT or JWS parsed.
|
||||
*
|
||||
* @param <T> the type of object to return to the parser caller after handling the parsed JWT.
|
||||
* @since 0.2
|
||||
*/
|
||||
public interface JwtHandler<T> {
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
* a plaintext JWT. A plaintext JWT has a String (non-JSON) body payload and it is not cryptographically signed.
|
||||
*
|
||||
* @param jwt the parsed plaintext JWT
|
||||
* @return any object to be used after inspecting the JWT, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
T onPlaintextJwt(Jwt<Header, String> jwt);
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
* a Claims JWT. A Claims JWT has a {@link Claims} body and it is not cryptographically signed.
|
||||
*
|
||||
* @param jwt the parsed claims JWT
|
||||
* @return any object to be used after inspecting the JWT, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
T onClaimsJwt(Jwt<Header, Claims> jwt);
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
* a plaintext JWS. A plaintext JWS is a JWT with a String (non-JSON) body (payload) that has been
|
||||
* cryptographically signed.
|
||||
*
|
||||
* <p>This method will only be invoked if the cryptographic signature can be successfully verified.</p>
|
||||
*
|
||||
* @param jws the parsed plaintext JWS
|
||||
* @return any object to be used after inspecting the JWS, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
T onPlaintextJws(Jws<String> jws);
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
* a valid Claims JWS. A Claims JWS is a JWT with a {@link Claims} body that has been cryptographically signed.
|
||||
*
|
||||
* <p>This method will only be invoked if the cryptographic signature can be successfully verified.</p>
|
||||
*
|
||||
* @param jws the parsed claims JWS
|
||||
* @return any object to be used after inspecting the JWS, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
T onClaimsJws(Jws<Claims> jws);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* An <a href="http://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a> implementation of the
|
||||
* {@link JwtHandler} interface that allows for anonymous subclasses to process only the JWT results that are
|
||||
* known/expected for a particular use case.
|
||||
*
|
||||
* <p>All of the methods in this implementation throw exceptions: overridden methods represent
|
||||
* scenarios expected by calling code in known situations. It would be unexpected to receive a JWS or JWT that did
|
||||
* not match parsing expectations, so all non-overridden methods throw exceptions to indicate that the JWT
|
||||
* input was unexpected.</p>
|
||||
*
|
||||
* @param <T> the type of object to return to the parser caller after handling the parsed JWT.
|
||||
* @since 0.2
|
||||
*/
|
||||
public class JwtHandlerAdapter<T> implements JwtHandler<T> {
|
||||
|
||||
@Override
|
||||
public T onPlaintextJwt(Jwt<Header, String> jwt) {
|
||||
throw new UnsupportedJwtException("Unsigned plaintext JWTs are not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T onClaimsJwt(Jwt<Header, Claims> jwt) {
|
||||
throw new UnsupportedJwtException("Unsigned Claims JWTs are not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T onPlaintextJws(Jws<String> jws) {
|
||||
throw new UnsupportedJwtException("Signed plaintext JWSs are not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T onClaimsJws(Jws<Claims> jws) {
|
||||
throw new UnsupportedJwtException("Signed Claims JWSs are not supported.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* 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.Deserializer;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface JwtParser {
|
||||
|
||||
public static final char SEPARATOR_CHAR = '.';
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param id
|
||||
* @return the parser method for chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
* @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.
|
||||
* <p>
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
* <p>
|
||||
* <p>This method overwrites any previously set key.</p>
|
||||
*
|
||||
* @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
|
||||
* signature.
|
||||
* @return the parser for method chaining.
|
||||
* @deprecated see {@link JwtParserBuilder#setSigningKey(byte[])}.
|
||||
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
|
||||
* immutable JwtParser.
|
||||
* <p><b>NOTE: this method will be removed before version 1.0</b>
|
||||
*/
|
||||
@Deprecated
|
||||
JwtParser setSigningKey(byte[] key);
|
||||
|
||||
/**
|
||||
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
||||
* a JWS (no signature), this key is not used.
|
||||
*
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
*
|
||||
* <p>This method overwrites any previously set key.</p>
|
||||
*
|
||||
* <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 #setSigningKey(byte[])}.</p>
|
||||
*
|
||||
* <h4>Deprecation Notice: Deprecated as of 0.10.0, will be removed in 1.0.0</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 setSigningKey(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>Finally, please use the {@link #setSigningKey(Key) setSigningKey(Key)} instead, as this method and the
|
||||
* {@code byte[]} variant will be removed before the 1.0.0 release.</p>
|
||||
*
|
||||
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signature verification key to use to validate
|
||||
* any discovered JWS digital signature.
|
||||
* @return the parser for method chaining.
|
||||
* @deprecated see {@link JwtParserBuilder#setSigningKey(String)}.
|
||||
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
|
||||
* immutable JwtParser.
|
||||
* <p><b>NOTE: this method will be removed before version 1.0</b>
|
||||
*/
|
||||
@Deprecated
|
||||
JwtParser setSigningKey(String base64EncodedSecretKey);
|
||||
|
||||
/**
|
||||
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
||||
* a JWS (no signature), this key is not used.
|
||||
* <p>
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
* <p>
|
||||
* <p>This method overwrites any previously set key.</p>
|
||||
*
|
||||
* @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
|
||||
* signature.
|
||||
* @return the parser for method chaining.
|
||||
* @deprecated see {@link JwtParserBuilder#setSigningKey(Key)}.
|
||||
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
|
||||
* immutable JwtParser.
|
||||
* <p><b>NOTE: this method will be removed before version 1.0</b>
|
||||
*/
|
||||
@Deprecated
|
||||
JwtParser setSigningKey(Key key);
|
||||
|
||||
/**
|
||||
* Sets the {@link SigningKeyResolver} used to acquire the <code>signing key</code> that should be used to verify
|
||||
* a JWS's signature. If the parsed String is not a JWS (no signature), this resolver is not used.
|
||||
* <p>
|
||||
* <p>Specifying a {@code SigningKeyResolver} is necessary when the signing key is not already known before parsing
|
||||
* the JWT and the JWT header or payload (plaintext body or Claims) must be inspected first to determine how to
|
||||
* look up the signing key. Once returned by the resolver, the JwtParser will then verify the JWS signature with the
|
||||
* returned key. For example:</p>
|
||||
* <p>
|
||||
* <pre>
|
||||
* Jws<Claims> jws = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
|
||||
* @Override
|
||||
* public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
|
||||
* //inspect the header or claims, lookup and return the signing key
|
||||
* return getSigningKey(header, claims); //implement me
|
||||
* }})
|
||||
* .parseClaimsJws(compact);
|
||||
* </pre>
|
||||
* <p>
|
||||
* <p>A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.</p>
|
||||
* <p>
|
||||
* <p>This method should only be used if a signing key is not provided by the other {@code setSigningKey*} builder
|
||||
* methods.</p>
|
||||
*
|
||||
* @param signingKeyResolver the signing key resolver used to retrieve the signing key.
|
||||
* @return the parser for method chaining.
|
||||
* @since 0.4
|
||||
* @deprecated see {@link JwtParserBuilder#setSigningKeyResolver(SigningKeyResolver)}.
|
||||
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
|
||||
* immutable JwtParser.
|
||||
* <p><b>NOTE: this method will be removed before version 1.0</b>
|
||||
*/
|
||||
@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 < 0.6.0) are able to consume a compressed JWT body correctly. This method is only
|
||||
* useful if the compact JWT was compressed with JJWT >= 0.6.0 or another library that you know implements
|
||||
* the same behavior.</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.
|
||||
* <p>
|
||||
* <p>This method returns a JWT or JWS based on the parsed string. Because it may be cumbersome to determine if it
|
||||
* is a JWT or JWS, or if the body/payload is a Claims or String with {@code instanceof} checks, the
|
||||
* {@link #parse(String, JwtHandler) parse(String,JwtHandler)} method allows for a type-safe callback approach that
|
||||
* may help reduce code or instanceof checks.</p>
|
||||
*
|
||||
* @param jwt the compact serialized JWT to parse
|
||||
* @return the specified compact serialized JWT string based on the builder's current configuration state.
|
||||
* @throws MalformedJwtException if the specified JWT was incorrectly constructed (and therefore invalid).
|
||||
* Invalid
|
||||
* JWTs should not be trusted and should be discarded.
|
||||
* @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail
|
||||
* signature validation should not be trusted and should be discarded.
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace.
|
||||
* @see #parse(String, JwtHandler)
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parseClaimsJwt(String)
|
||||
* @see #parsePlaintextJws(String)
|
||||
* @see #parseClaimsJws(String)
|
||||
*/
|
||||
Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
|
||||
* invokes the specified {@code handler} with the resulting JWT or JWS instance.
|
||||
* <p>
|
||||
* <p>If you are confident of the format of the JWT before parsing, you can create an anonymous subclass using the
|
||||
* {@link io.jsonwebtoken.JwtHandlerAdapter JwtHandlerAdapter} and override only the methods you know are relevant
|
||||
* for your use case(s), for example:</p>
|
||||
* <p>
|
||||
* <pre>
|
||||
* String compactJwt = request.getParameter("jwt"); //we are confident this is a signed JWS
|
||||
*
|
||||
* String subject = Jwts.parser().setSigningKey(key).parse(compactJwt, new JwtHandlerAdapter<String>() {
|
||||
* @Override
|
||||
* public String onClaimsJws(Jws<Claims> jws) {
|
||||
* return jws.getBody().getSubject();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* <p>
|
||||
* <p>If you know the JWT string can be only one type of JWT, then it is even easier to invoke one of the
|
||||
* following convenience methods instead of this one:</p>
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>{@link #parsePlaintextJwt(String)}</li>
|
||||
* <li>{@link #parseClaimsJwt(String)}</li>
|
||||
* <li>{@link #parsePlaintextJws(String)}</li>
|
||||
* <li>{@link #parseClaimsJws(String)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param jwt the compact serialized JWT to parse
|
||||
* @return the result returned by the {@code JwtHandler}
|
||||
* @throws MalformedJwtException if the specified JWT was incorrectly constructed (and therefore invalid).
|
||||
* Invalid JWTs should not be trusted and should be discarded.
|
||||
* @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail
|
||||
* signature validation should not be trusted and should be discarded.
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace, or if the
|
||||
* {@code handler} is {@code null}.
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parseClaimsJwt(String)
|
||||
* @see #parsePlaintextJws(String)
|
||||
* @see #parseClaimsJws(String)
|
||||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
<T> T parse(String jwt, JwtHandler<T> handler)
|
||||
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
|
||||
* returns
|
||||
* the resulting unsigned plaintext JWT instance.
|
||||
* <p>
|
||||
* <p>This is a convenience method that is usable if you are confident that the compact string argument reflects an
|
||||
* unsigned plaintext JWT. An unsigned plaintext JWT has a String (non-JSON) body payload and it is not
|
||||
* cryptographically signed.</p>
|
||||
* <p>
|
||||
* <p><b>If the compact string presented does not reflect an unsigned plaintext JWT with non-JSON string body,
|
||||
* an {@link UnsupportedJwtException} will be thrown.</b></p>
|
||||
*
|
||||
* @param plaintextJwt a compact serialized unsigned plaintext JWT string.
|
||||
* @return the {@link Jwt Jwt} instance that reflects the specified compact JWT string.
|
||||
* @throws UnsupportedJwtException if the {@code plaintextJwt} argument does not represent an unsigned plaintext
|
||||
* JWT
|
||||
* @throws MalformedJwtException if the {@code plaintextJwt} string is not a valid JWT
|
||||
* @throws SignatureException if the {@code plaintextJwt} string is actually a JWS and signature validation
|
||||
* fails
|
||||
* @throws IllegalArgumentException if the {@code plaintextJwt} string is {@code null} or empty or only whitespace
|
||||
* @see #parseClaimsJwt(String)
|
||||
* @see #parsePlaintextJws(String)
|
||||
* @see #parseClaimsJws(String)
|
||||
* @see #parse(String, JwtHandler)
|
||||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
Jwt<Header, String> parsePlaintextJwt(String plaintextJwt)
|
||||
throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
|
||||
* returns
|
||||
* the resulting unsigned plaintext JWT instance.
|
||||
* <p>
|
||||
* <p>This is a convenience method that is usable if you are confident that the compact string argument reflects an
|
||||
* unsigned Claims JWT. An unsigned Claims JWT has a {@link Claims} body and it is not cryptographically
|
||||
* signed.</p>
|
||||
* <p>
|
||||
* <p><b>If the compact string presented does not reflect an unsigned Claims JWT, an
|
||||
* {@link UnsupportedJwtException} will be thrown.</b></p>
|
||||
*
|
||||
* @param claimsJwt a compact serialized unsigned Claims JWT string.
|
||||
* @return the {@link Jwt Jwt} instance that reflects the specified compact JWT string.
|
||||
* @throws UnsupportedJwtException if the {@code claimsJwt} argument does not represent an unsigned Claims JWT
|
||||
* @throws MalformedJwtException if the {@code claimsJwt} string is not a valid JWT
|
||||
* @throws SignatureException if the {@code claimsJwt} string is actually a JWS and signature validation
|
||||
* fails
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the {@code claimsJwt} string is {@code null} or empty or only whitespace
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parsePlaintextJws(String)
|
||||
* @see #parseClaimsJws(String)
|
||||
* @see #parse(String, JwtHandler)
|
||||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
Jwt<Header, Claims> parseClaimsJwt(String claimsJwt)
|
||||
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWS string based on the builder's current configuration state and
|
||||
* returns
|
||||
* the resulting plaintext JWS instance.
|
||||
* <p>
|
||||
* <p>This is a convenience method that is usable if you are confident that the compact string argument reflects a
|
||||
* plaintext JWS. A plaintext JWS is a JWT with a String (non-JSON) body (payload) that has been
|
||||
* cryptographically signed.</p>
|
||||
* <p>
|
||||
* <p><b>If the compact string presented does not reflect a plaintext JWS, an {@link UnsupportedJwtException}
|
||||
* will be thrown.</b></p>
|
||||
*
|
||||
* @param plaintextJws a compact serialized JWS string.
|
||||
* @return the {@link Jws Jws} instance that reflects the specified compact JWS string.
|
||||
* @throws UnsupportedJwtException if the {@code plaintextJws} argument does not represent an plaintext JWS
|
||||
* @throws MalformedJwtException if the {@code plaintextJws} string is not a valid JWS
|
||||
* @throws SignatureException if the {@code plaintextJws} JWS signature validation fails
|
||||
* @throws IllegalArgumentException if the {@code plaintextJws} string is {@code null} or empty or only whitespace
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parseClaimsJwt(String)
|
||||
* @see #parseClaimsJws(String)
|
||||
* @see #parse(String, JwtHandler)
|
||||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
Jws<String> parsePlaintextJws(String plaintextJws)
|
||||
throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWS string based on the builder's current configuration state and
|
||||
* returns
|
||||
* the resulting Claims JWS instance.
|
||||
* <p>
|
||||
* <p>This is a convenience method that is usable if you are confident that the compact string argument reflects a
|
||||
* Claims JWS. A Claims JWS is a JWT with a {@link Claims} body that has been cryptographically signed.</p>
|
||||
* <p>
|
||||
* <p><b>If the compact string presented does not reflect a Claims JWS, an {@link UnsupportedJwtException} will be
|
||||
* thrown.</b></p>
|
||||
*
|
||||
* @param claimsJws a compact serialized Claims JWS string.
|
||||
* @return the {@link Jws Jws} instance that reflects the specified compact Claims JWS string.
|
||||
* @throws UnsupportedJwtException if the {@code claimsJws} argument does not represent an Claims JWS
|
||||
* @throws MalformedJwtException if the {@code claimsJws} string is not a valid JWS
|
||||
* @throws SignatureException if the {@code claimsJws} JWS signature validation fails
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the {@code claimsJws} string is {@code null} or empty or only whitespace
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parseClaimsJwt(String)
|
||||
* @see #parsePlaintextJws(String)
|
||||
* @see #parse(String, JwtHandler)
|
||||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
Jws<Claims> parseClaimsJws(String claimsJws)
|
||||
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (C) 2019 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Deserializer;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A builder to construct a {@link JwtParser}. Example usage:
|
||||
* <pre>{@code
|
||||
* Jwts.parserBuilder()
|
||||
* .setSigningKey(...)
|
||||
* .requireIssuer("https://issuer.example.com")
|
||||
* .build()
|
||||
* .parse(jwtString)
|
||||
* }</pre>
|
||||
* @since 0.11.0
|
||||
*/
|
||||
public interface JwtParserBuilder {
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param id
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireId(String id);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code sub} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param subject
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireSubject(String subject);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code aud} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param audience
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireAudience(String audience);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code iss} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param issuer
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireIssuer(String issuer);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code iat} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param issuedAt
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireIssuedAt(Date issuedAt);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code exp} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param expiration
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireExpiration(Date expiration);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code nbf} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param notBefore
|
||||
* @return the parser builder for method chaining
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder requireNotBefore(Date notBefore);
|
||||
|
||||
/**
|
||||
* Ensures that the specified {@code claimName} exists in the parsed JWT. If missing or if the parsed
|
||||
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||
* JWT is invalid and may not be used.
|
||||
*
|
||||
* @param claimName
|
||||
* @param value
|
||||
* @return the parser builder for method chaining.
|
||||
* @see MissingClaimException
|
||||
* @see IncorrectClaimException
|
||||
*/
|
||||
JwtParserBuilder require(String claimName, Object value);
|
||||
|
||||
/**
|
||||
* Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
|
||||
* The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
|
||||
*
|
||||
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
|
||||
* @return the parser builder for method chaining.
|
||||
*/
|
||||
JwtParserBuilder setClock(Clock clock);
|
||||
|
||||
/**
|
||||
* Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp}
|
||||
* and {@code nbf} claims.
|
||||
*
|
||||
* @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
|
||||
* @return the parser builder for method chaining.
|
||||
* @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
|
||||
* any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
|
||||
*/
|
||||
JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
||||
* a JWS (no signature), this key is not used.
|
||||
* <p>
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
* <p>
|
||||
* <p>This method overwrites any previously set key.</p>
|
||||
*
|
||||
* @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
|
||||
* signature.
|
||||
* @return the parser builder for method chaining.
|
||||
*/
|
||||
JwtParserBuilder setSigningKey(byte[] key);
|
||||
|
||||
/**
|
||||
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
||||
* a JWS (no signature), this key is not used.
|
||||
*
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
*
|
||||
* <p>This method overwrites any previously set key.</p>
|
||||
*
|
||||
* <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 #setSigningKey(byte[])}.</p>
|
||||
*
|
||||
* <h4>Deprecation Notice: Deprecated as of 0.10.0, will be removed in 1.0.0</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 setSigningKey(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>Finally, please use the {@link #setSigningKey(Key) setSigningKey(Key)} instead, as this method and the
|
||||
* {@code byte[]} variant will be removed before the 1.0.0 release.</p>
|
||||
*
|
||||
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signature verification key to use to validate
|
||||
* any discovered JWS digital signature.
|
||||
* @return the parser builder for method chaining.
|
||||
*/
|
||||
JwtParserBuilder setSigningKey(String base64EncodedSecretKey);
|
||||
|
||||
/**
|
||||
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
||||
* a JWS (no signature), this key is not used.
|
||||
* <p>
|
||||
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
|
||||
* (as the {@code alg} header parameter).</p>
|
||||
* <p>
|
||||
* <p>This method overwrites any previously set key.</p>
|
||||
*
|
||||
* @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
|
||||
* signature.
|
||||
* @return the parser builder for method chaining.
|
||||
*/
|
||||
JwtParserBuilder setSigningKey(Key key);
|
||||
|
||||
/**
|
||||
* Sets the {@link SigningKeyResolver} used to acquire the <code>signing key</code> that should be used to verify
|
||||
* a JWS's signature. If the parsed String is not a JWS (no signature), this resolver is not used.
|
||||
* <p>
|
||||
* <p>Specifying a {@code SigningKeyResolver} is necessary when the signing key is not already known before parsing
|
||||
* the JWT and the JWT header or payload (plaintext body or Claims) must be inspected first to determine how to
|
||||
* look up the signing key. Once returned by the resolver, the JwtParser will then verify the JWS signature with the
|
||||
* returned key. For example:</p>
|
||||
* <p>
|
||||
* <pre>
|
||||
* Jws<Claims> jws = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
|
||||
* @Override
|
||||
* public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
|
||||
* //inspect the header or claims, lookup and return the signing key
|
||||
* return getSigningKey(header, claims); //implement me
|
||||
* }})
|
||||
* .parseClaimsJws(compact);
|
||||
* </pre>
|
||||
* <p>
|
||||
* <p>A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.</p>
|
||||
* <p>
|
||||
* <p>This method should only be used if a signing key is not provided by the other {@code setSigningKey*} builder
|
||||
* methods.</p>
|
||||
*
|
||||
* @param signingKeyResolver the signing key resolver used to retrieve the signing key.
|
||||
* @return the parser builder for method chaining.
|
||||
*/
|
||||
JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
|
||||
|
||||
/**
|
||||
* Sets the {@link CompressionCodecResolver} used to acquire the {@link CompressionCodec} that should be used to
|
||||
* decompress the JWT body. If the parsed JWT is not compressed, this resolver is not used.
|
||||
* <p><b>NOTE:</b> Compression is not defined by the JWT Specification, and it is not expected that other libraries
|
||||
* (including JJWT versions < 0.6.0) are able to consume a compressed JWT body correctly. This method is only
|
||||
* useful if the compact JWT was compressed with JJWT >= 0.6.0 or another library that you know implements
|
||||
* the same behavior.</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.
|
||||
*/
|
||||
JwtParser build();
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Factory class useful for creating instances of JWT interfaces. Using this factory class can be a good
|
||||
* alternative to tightly coupling your code to implementation classes.
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public final class Jwts {
|
||||
|
||||
private 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.
|
||||
*
|
||||
* @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
|
||||
* @deprecated use {@link Jwts#parserBuilder()} instead. See {@link JwtParserBuilder} for usage details.
|
||||
* <p>Migration to new method structure is minimal, for example:
|
||||
* <p>Old code:
|
||||
* <pre>{@code
|
||||
* Jwts.parser()
|
||||
* .requireAudience("string")
|
||||
* .parse(jwtString)
|
||||
* }</pre>
|
||||
* <p>New code:
|
||||
* <pre>{@code
|
||||
* Jwts.parserBuilder()
|
||||
* .requireAudience("string")
|
||||
* .build()
|
||||
* .parse(jwtString)
|
||||
* }</pre>
|
||||
* <p><b>NOTE: this method will be removed before version 1.0</b>
|
||||
*/
|
||||
@Deprecated
|
||||
public static JwtParser parser() {
|
||||
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParser");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link JwtParserBuilder} instance that can be configured to create an immutable/thread-safe {@link JwtParser).
|
||||
*
|
||||
* @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser).
|
||||
*/
|
||||
public static JwtParserBuilder parserBuilder() {
|
||||
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
|
||||
* strings.
|
||||
*
|
||||
* @return a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
|
||||
* strings.
|
||||
*/
|
||||
public static JwtBuilder builder() {
|
||||
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception indicating that a JWT was not correctly constructed and should be rejected.
|
||||
*
|
||||
* @since 0.2
|
||||
*/
|
||||
public class MalformedJwtException extends JwtException {
|
||||
|
||||
public MalformedJwtException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MalformedJwtException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2015 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception thrown when discovering that a required claim is not present, indicating the JWT is
|
||||
* invalid and may not be used.
|
||||
*
|
||||
* @since 0.6
|
||||
*/
|
||||
public class MissingClaimException extends InvalidClaimException {
|
||||
public MissingClaimException(Header header, Claims claims, String message) {
|
||||
super(header, claims, message);
|
||||
}
|
||||
|
||||
public MissingClaimException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(header, claims, message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception indicating that a JWT was accepted before it is allowed to be accessed and must be rejected.
|
||||
*
|
||||
* @since 0.3
|
||||
*/
|
||||
public class PrematureJwtException extends ClaimJwtException {
|
||||
|
||||
public PrematureJwtException(Header header, Claims claims, String message) {
|
||||
super(header, claims, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param header jwt header
|
||||
* @param claims jwt claims (body)
|
||||
* @param message exception message
|
||||
* @param cause cause
|
||||
* @since 0.5
|
||||
*/
|
||||
public PrematureJwtException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(header, claims, message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception thrown when {@link Claims#get(String, Class)} is called and the value does not match the type of the
|
||||
* {@code Class} argument.
|
||||
*
|
||||
* @since 0.6
|
||||
*/
|
||||
public class RequiredTypeException extends JwtException {
|
||||
public RequiredTypeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RequiredTypeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,655 @@
|
||||
/*
|
||||
* 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 <= size <= 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 <= size <= 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 <= size</td>
|
||||
* <td>{@link SignatureAlgorithm#HS512 HS512}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link ECKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>256 <= size <= 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 <= size <= 511</td>
|
||||
* <td>{@link SignatureAlgorithm#ES384 ES384}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link ECKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>4096 <= size</td>
|
||||
* <td>{@link SignatureAlgorithm#ES512 ES512}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link RSAKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>2048 <= size <= 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 <= size <= 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 <= 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 + "'");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
|
||||
/**
|
||||
* Exception indicating that either calculating a signature or verifying an existing signature of a JWT failed.
|
||||
*
|
||||
* @since 0.1
|
||||
* @deprecated in favor of {@link io.jsonwebtoken.security.SecurityException}; this class will be removed before 1.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class SignatureException extends SecurityException {
|
||||
|
||||
public SignatureException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SignatureException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* A {@code SigningKeyResolver} can be used by a {@link io.jsonwebtoken.JwtParser JwtParser} to find a signing key that
|
||||
* should be used to verify a JWS signature.
|
||||
*
|
||||
* <p>A {@code SigningKeyResolver} is necessary when the signing key is not already known before parsing the JWT and the
|
||||
* JWT header or payload (plaintext body or Claims) must be inspected first to determine how to look up the signing key.
|
||||
* Once returned by the resolver, the JwtParser will then verify the JWS signature with the returned key. For
|
||||
* example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* Jws<Claims> jws = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
|
||||
* @Override
|
||||
* public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
|
||||
* //inspect the header or claims, lookup and return the signing key
|
||||
* return getSigningKeyBytes(header, claims); //implement me
|
||||
* }})
|
||||
* .parseClaimsJws(compact);
|
||||
* </pre>
|
||||
*
|
||||
* <p>A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.</p>
|
||||
*
|
||||
* <h3>SigningKeyResolverAdapter</h3>
|
||||
*
|
||||
* <p>If you only need to resolve a signing key for a particular JWS (either a plaintext or Claims JWS), consider using
|
||||
* the {@link io.jsonwebtoken.SigningKeyResolverAdapter} and overriding only the method you need to support instead of
|
||||
* implementing this interface directly.</p>
|
||||
*
|
||||
* @see io.jsonwebtoken.SigningKeyResolverAdapter
|
||||
* @since 0.4
|
||||
*/
|
||||
public interface SigningKeyResolver {
|
||||
|
||||
/**
|
||||
* Returns the signing key that should be used to validate a digital signature for the Claims JWS with the specified
|
||||
* header and claims.
|
||||
*
|
||||
* @param header the header of the JWS to validate
|
||||
* @param claims the claims (body) of the JWS to validate
|
||||
* @return the signing key that should be used to validate a digital signature for the Claims JWS with the specified
|
||||
* header and claims.
|
||||
*/
|
||||
Key resolveSigningKey(JwsHeader header, Claims claims);
|
||||
|
||||
/**
|
||||
* Returns the signing key that should be used to validate a digital signature for the Plaintext JWS with the
|
||||
* specified header and plaintext payload.
|
||||
*
|
||||
* @param header the header of the JWS to validate
|
||||
* @param plaintext the plaintext body of the JWS to validate
|
||||
* @return the signing key that should be used to validate a digital signature for the Plaintext JWS with the
|
||||
* specified header and plaintext payload.
|
||||
*/
|
||||
Key resolveSigningKey(JwsHeader header, String plaintext);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* An <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.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception thrown when receiving a JWT in a particular format/configuration that does not match the format expected
|
||||
* by the application.
|
||||
*
|
||||
* <p>For example, this exception would be thrown if parsing an unsigned plaintext JWT when the application
|
||||
* requires a cryptographically signed Claims JWS instead.</p>
|
||||
*
|
||||
* @since 0.2
|
||||
*/
|
||||
public class UnsupportedJwtException extends JwtException {
|
||||
|
||||
public UnsupportedJwtException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnsupportedJwtException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.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.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 {
|
||||
@Deprecated
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParser setSigningKey(String base64EncodedSecretKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParser setSigningKey(Key key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver) {
|
||||
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 {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jwt<Header, String> parsePlaintextJwt(String plaintextJwt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jwt<Header, Claims> parseClaimsJwt(String claimsJwt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jws<String> parsePlaintextJws(String plaintextJws) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jws<Claims> parseClaimsJws(String claimsJws) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<String, ?> readValue(String val) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl.crypto;
|
||||
|
||||
public interface JwtSignatureValidator {
|
||||
|
||||
boolean isValid(String jwtWithoutSignature, String base64UrlEncodedSignature);
|
||||
}
|
||||
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A very fast and memory efficient class to encode and decode to and from BASE64 or BASE64URL in full accordance
|
||||
* with <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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class Base64Decoder extends Base64Support implements Decoder<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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class Base64Encoder extends Base64Support implements Encoder<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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class Base64Support {
|
||||
|
||||
protected final Base64 base64;
|
||||
|
||||
Base64Support(Base64 base64) {
|
||||
Assert.notNull(base64, "Base64 argument cannot be null");
|
||||
this.base64 = base64;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class Base64UrlDecoder extends Base64Decoder {
|
||||
|
||||
Base64UrlDecoder() {
|
||||
super(Base64.URL_SAFE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class Base64UrlEncoder extends Base64Encoder {
|
||||
|
||||
Base64UrlEncoder() {
|
||||
super(Base64.URL_SAFE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class CodecException extends IOException {
|
||||
|
||||
public CodecException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CodecException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public interface Decoder<T, R> {
|
||||
|
||||
R decode(T t) throws DecodingException;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public final class Decoders {
|
||||
|
||||
public static final Decoder<String, byte[]> BASE64 = new ExceptionPropagatingDecoder<>(new Base64Decoder());
|
||||
public static final Decoder<String, byte[]> BASE64URL = new ExceptionPropagatingDecoder<>(new Base64UrlDecoder());
|
||||
|
||||
private Decoders() { //prevent instantiation
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class DecodingException extends CodecException {
|
||||
|
||||
public DecodingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DecodingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class DeserializationException extends SerialException {
|
||||
|
||||
public DeserializationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public DeserializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public interface Deserializer<T> {
|
||||
|
||||
T deserialize(byte[] bytes) throws DeserializationException;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public interface Encoder<T, R> {
|
||||
|
||||
R encode(T t) throws EncodingException;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public final class Encoders {
|
||||
|
||||
public static final Encoder<byte[], String> BASE64 = new ExceptionPropagatingEncoder<>(new Base64Encoder());
|
||||
public static final Encoder<byte[], String> BASE64URL = new ExceptionPropagatingEncoder<>(new Base64UrlEncoder());
|
||||
|
||||
private Encoders() { //prevent instantiation
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class EncodingException extends CodecException {
|
||||
|
||||
public EncodingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class ExceptionPropagatingDecoder<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
class ExceptionPropagatingEncoder<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
import io.jsonwebtoken.JwtException;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class IOException extends JwtException {
|
||||
|
||||
public IOException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public IOException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class SerialException extends IOException {
|
||||
|
||||
public SerialException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public SerialException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class SerializationException extends SerialException {
|
||||
|
||||
public SerializationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public SerializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.io;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public interface Serializer<T> {
|
||||
|
||||
byte[] serialize(T t) throws SerializationException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* 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 > 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 > 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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.lang;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class DateFormats {
|
||||
|
||||
private static final String ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
||||
|
||||
private static final String ISO_8601_MILLIS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
|
||||
|
||||
private static final ThreadLocal<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.lang;
|
||||
|
||||
/**
|
||||
* @since 0.1
|
||||
*/
|
||||
public class InstantiationException extends RuntimeException {
|
||||
|
||||
public InstantiationException(String s, Throwable t) {
|
||||
super(s, t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2019 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.lang;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class to help with the manipulation of working with Maps.
|
||||
* @since 0.11.0
|
||||
*/
|
||||
public final class Maps {
|
||||
|
||||
private Maps() {} //prevent instantiation
|
||||
|
||||
/**
|
||||
* Creates a new map builder with a single entry.
|
||||
* <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,927 @@
|
||||
/*
|
||||
* 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class InvalidKeyException extends KeyException {
|
||||
|
||||
public InvalidKeyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class KeyException extends SecurityException {
|
||||
|
||||
public KeyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class for securely generating {@link SecretKey}s and {@link KeyPair}s.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public final class Keys {
|
||||
|
||||
private static final String MAC = "io.jsonwebtoken.impl.crypto.MacProvider";
|
||||
private static final String RSA = "io.jsonwebtoken.impl.crypto.RsaProvider";
|
||||
private static final String EC = "io.jsonwebtoken.impl.crypto.EllipticCurveProvider";
|
||||
|
||||
private static final Class[] SIG_ARG_TYPES = new Class[]{SignatureAlgorithm.class};
|
||||
|
||||
//purposefully ordered higher to lower:
|
||||
private static final List<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
import io.jsonwebtoken.JwtException;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class SecurityException extends JwtException {
|
||||
|
||||
public SecurityException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SecurityException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class SignatureException extends io.jsonwebtoken.SignatureException {
|
||||
|
||||
public SignatureException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SignatureException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
/**
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class WeakKeyException extends InvalidKeyException {
|
||||
|
||||
public WeakKeyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user