JavaDoc updates

This commit is contained in:
Les Hazlewood 2014-09-19 19:00:39 -07:00
parent 39b456b1a3
commit 482731ca0c
21 changed files with 656 additions and 92 deletions

View File

@ -62,5 +62,6 @@ try {
* [Non-compact](https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-7.2) serialization and parsing are not yet implemented.
* Elliptic Curve signature algorithms `ES256`, `ES384` and `ES512` are not yet implemented.
* JWE (Encryption for JWT) is not yet implemented.
* Awesome JavaDoc
These feature sets will be implemented in a future release when possible. Community contributions are welcome!

88
pom.xml
View File

@ -55,6 +55,10 @@
</ciManagement>
<properties>
<!-- Turn off JDK 8's lint checks: -->
<additionalparam>-Xdoclint:none</additionalparam>
<maven.jar.version>2.4</maven.jar.version>
<maven.compiler.version>3.1</maven.compiler.version>
@ -74,6 +78,7 @@
<easymock.version>3.1</easymock.version>
<testng.version>6.8</testng.version>
<failsafe.plugin.version>2.12.4</failsafe.plugin.version>
</properties>
<dependencies>
@ -136,6 +141,30 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>enforce-banned-dependencies</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<searchTransitive>true</searchTransitive>
<excludes>
<exclude>commons-logging</exclude>
</excludes>
</bannedDependencies>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@ -236,11 +265,68 @@
<configuration>
<mavenExecutorId>forked-path</mavenExecutorId>
<useReleaseProfile>false</useReleaseProfile>
<arguments>${arguments} -Psonatype-oss-release</arguments>
<arguments>${arguments} -Psonatype-oss-release -Pdocs -Psign</arguments>
<autoVersionSubmodules>true</autoVersionSubmodules>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>docs</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -18,42 +18,187 @@ package io.jsonwebtoken;
import java.util.Date;
import java.util.Map;
public interface Claims extends Map<String,Object> {
/**
* 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&lt;String, Object&gt;}, 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>
*
* <h4>Creation</h4>
*
* <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> {
/** 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();
/**
* 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.
*/
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();
/**
* 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.
*/
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();
/**
* 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.
*/
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();
/**
* 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.
*/
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();
/**
* 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.
*/
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 nbf} value or {@code null} if not present.
*/
Date getIssuedAt();
/**
* 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.
*/
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();
/**
* 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.
*/
Claims setId(String jti);
}

View File

@ -17,23 +17,87 @@ package io.jsonwebtoken;
import java.util.Map;
public interface Header extends Map<String,Object> {
/**
* 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&lt;String, Object&gt;}, 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>
*
* <h4>Creation</h4>
*
* <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";
public static final String ALGORITHM = "alg";
/** JWT {@code Content Type} header parameter name: <code>"cty"</code> */
public static final String CONTENT_TYPE = "cty";
public String getType();
/**
* 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();
public Header setType(String typ);
/**
* 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);
public String getAlgorithm();
/**
* 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();
public Header setAlgorithm(String alg);
public String getContentType();
public void setContentType(String cty);
/**
* 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);
}

View File

@ -15,7 +15,7 @@
*/
package io.jsonwebtoken;
public interface SignedToken<B> extends Token<B> {
public interface Jws<B> extends Jwt<JwsHeader,B> {
String getDigest();
String getSignature();
}

View File

@ -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);
}

View File

@ -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;
/**
* An JWT instance.
*
* @param <B> the type of the JWT body, either a {@link String} or a {@link Claims} instance.
*/
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();
}

View File

@ -18,6 +18,11 @@ package io.jsonwebtoken;
import java.security.Key;
import java.util.Map;
/**
* A builder for constructing JWT instances.
*
* @since 0.1
*/
public interface JwtBuilder {
//replaces any existing header with the specified header.

View File

@ -15,6 +15,11 @@
*/
package io.jsonwebtoken;
/**
* Base class for JWT-related runtime exceptions.
*
* @since 0.1
*/
public class JwtException extends RuntimeException {
public JwtException(String message) {

View File

@ -17,6 +17,11 @@ package io.jsonwebtoken;
import java.security.Key;
/**
* 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 = '.';
@ -29,5 +34,5 @@ public interface JwtParser {
boolean isSigned(String jwt);
Token parse(String jwt) throws MalformedJwtException, SignatureException;
Jwt parse(String jwt) throws MalformedJwtException, SignatureException;
}

View File

@ -16,12 +16,36 @@
package io.jsonwebtoken;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.impl.DefaultHeader;
import io.jsonwebtoken.impl.DefaultJwsHeader;
import io.jsonwebtoken.impl.DefaultJwtBuilder;
import io.jsonwebtoken.impl.DefaultJwtParser;
import java.util.Map;
public class JWTs {
/**
* 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 class Jwts {
public static Header header() {
return new DefaultHeader();
}
public static Header header(Map<String,Object> header) {
return new DefaultHeader(header);
}
public static JwsHeader jwsHeader() {
return new DefaultJwsHeader();
}
public static JwsHeader jwsHeader(Map<String,Object> header) {
return new DefaultJwsHeader(header);
}
public static Claims claims() {
return new DefaultClaims();

View File

@ -15,6 +15,11 @@
*/
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) {

View File

@ -17,6 +17,12 @@ package io.jsonwebtoken;
import io.jsonwebtoken.lang.RuntimeEnvironment;
/**
* Type-safe representation of standard JWT 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 {
NONE("none", "No digital signature or MAC performed", null, false),

View File

@ -15,6 +15,11 @@
*/
package io.jsonwebtoken;
/**
* Exception indicating that either calculating a signature or verifying an existing signature of a JWT failed.
*
* @since 0.1
*/
public class SignatureException extends JwtException {
public SignatureException(String message) {

View File

@ -19,7 +19,8 @@ import io.jsonwebtoken.Header;
import java.util.Map;
public class DefaultHeader extends JwtMap implements Header {
@SuppressWarnings("unchecked")
public class DefaultHeader<T extends Header<T>> extends JwtMap implements Header<T> {
public DefaultHeader() {
super();
@ -35,20 +36,9 @@ public class DefaultHeader extends JwtMap implements Header {
}
@Override
public Header setType(String typ) {
public T setType(String typ) {
setValue(TYPE, typ);
return this;
}
@Override
public String getAlgorithm() {
return getString(ALGORITHM);
}
@Override
public Header setAlgorithm(String alg) {
setValue(ALGORITHM, alg);
return this;
return (T)this;
}
@Override
@ -57,7 +47,8 @@ public class DefaultHeader extends JwtMap implements Header {
}
@Override
public void setContentType(String cty) {
public T setContentType(String cty) {
setValue(CONTENT_TYPE, cty);
return (T)this;
}
}

View File

@ -15,44 +15,33 @@
*/
package io.jsonwebtoken.impl;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Token;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
public class DefaultToken<B> implements Token<B> {
public class DefaultJws<B> implements Jws {
private final Header header;
private final JwsHeader header;
private final B body;
private final String signature;
public DefaultToken(Header header, B body, String signature) {
public DefaultJws(JwsHeader header, B body, String signature) {
this.header = header;
this.body = body;
this.signature = signature;
}
public boolean hasHeader() {
return this.header != null;
}
public boolean isSigned() {
return this.signature != null;
}
@Override
public String getSignature() {
Assert.notNull(signature, "Not a signed token. Call 'isSigned()' before calling this method.");
return this.signature;
}
@Override
public Header getHeader() {
Assert.notNull(header, "Header is not present. Call 'hasHeader()' before calling this method.");
return header;
public JwsHeader getHeader() {
return this.header;
}
@Override
public B getBody() {
return body;
return this.body;
}
@Override
public String getSignature() {
return this.signature;
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.impl;
import io.jsonwebtoken.JwsHeader;
import java.util.Map;
public class DefaultJwsHeader extends DefaultHeader implements JwsHeader {
public DefaultJwsHeader() {
super();
}
public DefaultJwsHeader(Map<String, Object> map) {
super(map);
}
@Override
public String getAlgorithm() {
return getString(ALGORITHM);
}
@Override
public JwsHeader setAlgorithm(String alg) {
setValue(ALGORITHM, alg);
return this;
}
@Override
public String getKeyId() {
return getString(KEY_ID);
}
@Override
public JwsHeader setKeyId(String kid) {
setValue(KEY_ID, kid);
return this;
}
}

View File

@ -13,15 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken;
package io.jsonwebtoken.impl;
public interface Token<B> {
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
Header getHeader();
public class DefaultJwt<B> implements Jwt<Header,B> {
B getBody();
private final Header header;
private final B body;
boolean isSigned();
public DefaultJwt(Header header, B body) {
this.header = header;
this.body = body;
}
String getSignature();
@Override
public Header getHeader() {
return header;
}
@Override
public B getBody() {
return body;
}
}

View File

@ -19,7 +19,8 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JWTs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.SignatureAlgorithm;
@ -33,6 +34,7 @@ import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Map;
@SuppressWarnings("unchecked")
public class DefaultJwtBuilder implements JwtBuilder {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@ -123,7 +125,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
@Override
public JwtBuilder setClaims(Map<String, Object> claims) {
this.claims = JWTs.claims(claims);
this.claims = Jwts.claims(claims);
return this;
}
@ -148,14 +150,22 @@ public class DefaultJwtBuilder implements JwtBuilder {
key = new SecretKeySpec(keyBytes, algorithm.getJcaName());
}
if (key != null) {
header.setAlgorithm(algorithm.getValue());
JwsHeader jwsHeader;
if (header instanceof JwsHeader) {
jwsHeader = (JwsHeader)header;
} else {
//no signature - plaintext JWT:
header.setAlgorithm(SignatureAlgorithm.NONE.getValue());
jwsHeader = new DefaultJwsHeader(header);
}
String base64UrlEncodedHeader = base64UrlEncode(header, "Unable to serialize header to json.");
if (key != null) {
jwsHeader.setAlgorithm(algorithm.getValue());
} else {
//no signature - plaintext JWT:
jwsHeader.setAlgorithm(SignatureAlgorithm.NONE.getValue());
}
String base64UrlEncodedHeader = base64UrlEncode(jwsHeader, "Unable to serialize header to json.");
String base64UrlEncodedBody = this.payload != null ?
TextCodec.BASE64URL.encode(this.payload) :

View File

@ -18,11 +18,12 @@ package io.jsonwebtoken.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.Token;
import io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator;
import io.jsonwebtoken.impl.crypto.JwtSignatureValidator;
import io.jsonwebtoken.lang.Assert;
@ -34,6 +35,7 @@ import java.io.IOException;
import java.security.Key;
import java.util.Map;
@SuppressWarnings("unchecked")
public class DefaultJwtParser implements JwtParser {
private ObjectMapper objectMapper = new ObjectMapper();
@ -88,7 +90,7 @@ public class DefaultJwtParser implements JwtParser {
}
@Override
public Token parse(String jwt) throws MalformedJwtException, SignatureException {
public Jwt parse(String jwt) throws MalformedJwtException, SignatureException {
Assert.hasText(jwt, "JWT String argument cannot be null or empty.");
@ -137,7 +139,12 @@ public class DefaultJwtParser implements JwtParser {
if (base64UrlEncodedHeader != null) {
String origValue = TextCodec.BASE64URL.decodeToString(base64UrlEncodedHeader);
Map<String, Object> m = readValue(origValue);
header = new DefaultHeader(m);
if (base64UrlEncodedDigest != null) {
header = new DefaultJwsHeader(m);
} else {
header = new DefaultHeader(m);
}
}
// =============== Body =================
@ -153,10 +160,12 @@ public class DefaultJwtParser implements JwtParser {
// =============== Signature =================
if (base64UrlEncodedDigest != null) { //it is signed - validate the signature
JwsHeader jwsHeader = (JwsHeader)header;
SignatureAlgorithm algorithm = null;
if (header != null) {
String alg = header.getAlgorithm();
String alg = jwsHeader.getAlgorithm();
if (Strings.hasText(alg)) {
algorithm = SignatureAlgorithm.forName(alg);
}
@ -200,10 +209,12 @@ public class DefaultJwtParser implements JwtParser {
}
}
if (claims != null) {
return new DefaultToken<Claims>(header, claims, base64UrlEncodedDigest);
Object body = claims != null ? claims : payload;
if (base64UrlEncodedDigest != null) {
return new DefaultJws<Object>((JwsHeader)header, body, base64UrlEncodedDigest);
} else {
return new DefaultToken<String>(header, payload, base64UrlEncodedDigest);
return new DefaultJwt<Object>(header, body);
}
}

View File

@ -25,7 +25,7 @@ import java.security.SecureRandom
import static org.testng.Assert.*
class JWTsTest {
class JwtsTest {
@Test
void testPlaintextJwtString() {
@ -40,7 +40,7 @@ class JWTsTest {
' "exp":1300819380,\r\n' +
' "http://example.com/is_root":true}'
String val = JWTs.builder().setPayload(payload).compact();
String val = Jwts.builder().setPayload(payload).compact();
def specOutput = 'eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
@ -52,32 +52,32 @@ class JWTsTest {
def claims = [iss: 'joe', exp: 1300819380, 'http://example.com/is_root':true]
String jwt = JWTs.builder().setClaims(claims).compact();
String jwt = Jwts.builder().setClaims(claims).compact();
def token = JWTs.parser().parse(jwt);
def token = Jwts.parser().parse(jwt);
assertEquals token.body, claims
}
@Test(expectedExceptions = IllegalArgumentException)
void testParseNull() {
JWTs.parser().parse(null)
Jwts.parser().parse(null)
}
@Test(expectedExceptions = IllegalArgumentException)
void testParseEmptyString() {
JWTs.parser().parse('')
Jwts.parser().parse('')
}
@Test(expectedExceptions = IllegalArgumentException)
void testParseWhitespaceString() {
JWTs.parser().parse(' ')
Jwts.parser().parse(' ')
}
@Test
void testParseWithNoPeriods() {
try {
JWTs.parser().parse('foo')
Jwts.parser().parse('foo')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT strings must contain exactly 2 period characters. Found: 0"
@ -87,7 +87,7 @@ class JWTsTest {
@Test
void testParseWithOnePeriodOnly() {
try {
JWTs.parser().parse('.')
Jwts.parser().parse('.')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT strings must contain exactly 2 period characters. Found: 1"
@ -97,7 +97,7 @@ class JWTsTest {
@Test
void testParseWithTwoPeriodsOnly() {
try {
JWTs.parser().parse('..')
Jwts.parser().parse('..')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string '..' is missing a body/payload."
@ -107,7 +107,7 @@ class JWTsTest {
@Test
void testParseWithHeaderOnly() {
try {
JWTs.parser().parse('foo..')
Jwts.parser().parse('foo..')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string 'foo..' is missing a body/payload."
@ -117,7 +117,7 @@ class JWTsTest {
@Test
void testParseWithSignatureOnly() {
try {
JWTs.parser().parse('..bar')
Jwts.parser().parse('..bar')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string '..bar' is missing a body/payload."
@ -127,7 +127,7 @@ class JWTsTest {
@Test
void testParseWithHeaderAndSignatureOnly() {
try {
JWTs.parser().parse('foo..bar')
Jwts.parser().parse('foo..bar')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string 'foo..bar' is missing a body/payload."
@ -209,14 +209,14 @@ class JWTsTest {
def claims = [iss: 'joe', exp: 1300819380, 'http://example.com/is_root':true]
String jwt = JWTs.builder().setClaims(claims).signWith(alg, privateKey).compact();
String jwt = Jwts.builder().setClaims(claims).signWith(alg, privateKey).compact();
def key = publicKey;
if (verifyWithPrivateKey) {
key = privateKey;
}
def token = JWTs.parser().setSigningKey(key).parse(jwt);
def token = Jwts.parser().setSigningKey(key).parse(jwt);
assertEquals token.header, [alg: alg.name()]
@ -232,9 +232,9 @@ class JWTsTest {
def claims = [iss: 'joe', exp: 1300819380, 'http://example.com/is_root':true]
String jwt = JWTs.builder().setClaims(claims).signWith(alg, key).compact();
String jwt = Jwts.builder().setClaims(claims).signWith(alg, key).compact();
def token = JWTs.parser().setSigningKey(key).parse(jwt)
def token = Jwts.parser().setSigningKey(key).parse(jwt)
assertEquals token.header, [alg: alg.name()]