Merge pull request #4 from jwtk/jwt-builder-claims-convenience-methods

Jwt builder claims convenience methods
This commit is contained in:
Les Hazlewood 2014-09-26 18:01:46 -07:00
commit 1be528b58b
8 changed files with 639 additions and 57 deletions

View File

@ -33,9 +33,7 @@ Random random = new SecureRandom();
byte[] key = new byte[64]; byte[] key = new byte[64];
random.nextBytes(key); random.nextBytes(key);
Claims claims = Jwts.claims().setIssuer("Me").setSubject("Joe"); String compactJwt = Jwts.builder().setIssuer("Me").setSubject("Joe").signWith(HS256, key).compact();
String compactJwt = Jwts.builder().setClaims(claims).signWith(HS256, key).compact();
``` ```
How easy was that!? How easy was that!?
@ -45,7 +43,7 @@ Now let's verify the JWT (you should always discard JWTs that don't match an exp
```java ```java
Jwt jwt = Jwts.parser().setSigningKey(key).parse(compactJwt); Jwt jwt = Jwts.parser().setSigningKey(key).parse(compactJwt);
assert jwt.getClaims().getSubject().equals("Joe"); assert ((Claims)jwt.getBody()).getSubject().equals("Joe");
``` ```
You have to love one-line code snippets in Java! You have to love one-line code snippets in Java!
@ -88,6 +86,28 @@ try {
These feature sets will be implemented in a future release when possible. Community contributions are welcome! These feature sets will be implemented in a future release when possible. Community contributions are welcome!
## Release Notes
### 0.2
#### More convenient Claims building
This release adds convenience methods to the `JwtBuilder` interface so you can set claims directly on the builder without having to create a separate Claims instance/builder, reducing the amount of code you have to write. For example, this:
```java
Claims claims = Jwts.claims().setIssuer("Me").setSubject("Joe");
String compactJwt = Jwts.builder().setClaims(claims).signWith(HS256, key).compact();
```
can now be written as:
```java
String compactJwt = Jwts.builder().setIssuer("Me").setSubject("Joe").signWith(HS256, key).compact();
```
A Claims instance based on the specified claims will be created and set as the JWT's payload automatically.
<a name="olderJackson"></a> <a name="olderJackson"></a>
#### Already using an older Jackson dependency? #### Already using an older Jackson dependency?

View File

@ -38,7 +38,7 @@ import java.util.Map;
* *
* @since 0.1 * @since 0.1
*/ */
public interface Claims extends Map<String, Object> { public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */ /** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */
public static final String ISSUER = "iss"; public static final String ISSUER = "iss";
@ -70,12 +70,9 @@ public interface Claims extends Map<String, Object> {
String getIssuer(); String getIssuer();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setIssuer(String iss); Claims setIssuer(String iss);
/** /**
@ -87,12 +84,9 @@ public interface Claims extends Map<String, Object> {
String getSubject(); String getSubject();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setSubject(String sub); Claims setSubject(String sub);
/** /**
@ -104,12 +98,9 @@ public interface Claims extends Map<String, Object> {
String getAudience(); String getAudience();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setAudience(String aud); Claims setAudience(String aud);
/** /**
@ -123,14 +114,9 @@ public interface Claims extends Map<String, Object> {
Date getExpiration(); Date getExpiration();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setExpiration(Date exp); Claims setExpiration(Date exp);
/** /**
@ -144,14 +130,9 @@ public interface Claims extends Map<String, Object> {
Date getNotBefore(); Date getNotBefore();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setNotBefore(Date nbf); Claims setNotBefore(Date nbf);
/** /**
@ -165,14 +146,9 @@ public interface Claims extends Map<String, Object> {
Date getIssuedAt(); Date getIssuedAt();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setIssuedAt(Date iat); Claims setIssuedAt(Date iat);
/** /**
@ -189,16 +165,9 @@ public interface Claims extends Map<String, Object> {
String getId(); String getId();
/** /**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7"> * {@inheritDoc}
* <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.
*/ */
@Override //only for better/targeted JavaDoc
Claims setId(String jti); Claims setId(String jti);
} }

View File

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

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken; package io.jsonwebtoken;
import java.security.Key; import java.security.Key;
import java.util.Date;
import java.util.Map; import java.util.Map;
/** /**
@ -23,7 +24,7 @@ import java.util.Map;
* *
* @since 0.1 * @since 0.1
*/ */
public interface JwtBuilder { public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
//replaces any existing header with the specified header. //replaces any existing header with the specified header.
@ -100,6 +101,223 @@ public interface JwtBuilder {
*/ */
JwtBuilder setClaims(Map<String, Object> claims); JwtBuilder setClaims(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().setSubject("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().setIssuedAt(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 using the specified algorithm with the specified key, producing a JWS. * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
* *

View File

@ -29,9 +29,11 @@ import io.jsonwebtoken.impl.crypto.JwtSigner;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Objects; import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.security.Key; import java.security.Key;
import java.util.Date;
import java.util.Map; import java.util.Map;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -117,6 +119,13 @@ public class DefaultJwtBuilder implements JwtBuilder {
return this; return this;
} }
protected Claims ensureClaims() {
if (this.claims == null) {
this.claims = new DefaultClaims();
}
return this.claims;
}
@Override @Override
public JwtBuilder setClaims(Claims claims) { public JwtBuilder setClaims(Claims claims) {
this.claims = claims; this.claims = claims;
@ -129,13 +138,118 @@ public class DefaultJwtBuilder implements JwtBuilder {
return this; return this;
} }
@Override
public JwtBuilder setIssuer(String iss) {
if (Strings.hasText(iss)) {
ensureClaims().setIssuer(iss);
} else {
if (this.claims != null) {
claims.setIssuer(iss);
}
}
return this;
}
@Override
public JwtBuilder setSubject(String sub) {
if (Strings.hasText(sub)) {
ensureClaims().setSubject(sub);
} else {
if (this.claims != null) {
claims.setSubject(sub);
}
}
return this;
}
@Override
public JwtBuilder setAudience(String aud) {
if (Strings.hasText(aud)) {
ensureClaims().setAudience(aud);
} else {
if (this.claims != null) {
claims.setAudience(aud);
}
}
return this;
}
@Override
public JwtBuilder setExpiration(Date exp) {
if (exp != null) {
ensureClaims().setExpiration(exp);
} else {
if (this.claims != null) {
//noinspection ConstantConditions
this.claims.setExpiration(exp);
}
}
return this;
}
@Override
public JwtBuilder setNotBefore(Date nbf) {
if (nbf != null) {
ensureClaims().setNotBefore(nbf);
} else {
if (this.claims != null) {
//noinspection ConstantConditions
this.claims.setNotBefore(nbf);
}
}
return this;
}
@Override
public JwtBuilder setIssuedAt(Date iat) {
if (iat != null) {
ensureClaims().setIssuedAt(iat);
} else {
if (this.claims != null) {
//noinspection ConstantConditions
this.claims.setIssuedAt(iat);
}
}
return this;
}
@Override
public JwtBuilder setId(String jti) {
if (Strings.hasText(jti)) {
ensureClaims().setId(jti);
} else {
if (this.claims != null) {
claims.setId(jti);
}
}
return this;
}
@Override
public JwtBuilder claim(String name, Object value) {
Assert.hasText(name, "Claim property name cannot be null or empty.");
if (this.claims == null) {
if (value != null) {
ensureClaims().put(name, value);
}
} else {
if (value == null) {
this.claims.remove(name);
} else {
this.claims.put(name, value);
}
}
return this;
}
@Override @Override
public String compact() { public String compact() {
if (payload == null && claims == null) { if (payload == null && Collections.isEmpty(claims)) {
throw new IllegalStateException("Either 'payload' or 'claims' must be specified."); throw new IllegalStateException("Either 'payload' or 'claims' must be specified.");
} }
if (payload != null && claims != null) { if (payload != null && !Collections.isEmpty(claims)) {
throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one."); throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one.");
} }

View File

@ -47,11 +47,13 @@ public class JwtMap implements Map<String,Object> {
} else if (v instanceof Date) { } else if (v instanceof Date) {
return (Date) v; return (Date) v;
} else if (v instanceof Number) { } else if (v instanceof Number) {
int seconds = ((Number) v).intValue(); long seconds = ((Number) v).longValue();
return new Date(seconds * 1000); long millis = seconds * 1000;
return new Date(millis);
} else if (v instanceof String) { } else if (v instanceof String) {
int seconds = Integer.parseInt((String) v); long seconds = Long.parseLong((String) v);
return new Date(seconds * 1000); long millis = seconds * 1000;
return new Date(millis);
} else { } else {
throw new IllegalStateException("Cannot convert '" + name + "' value [" + v + "] to Date instance."); throw new IllegalStateException("Cannot convert '" + name + "' value [" + v + "] to Date instance.");
} }

View File

@ -134,6 +134,128 @@ class JwtsTest {
} }
} }
@Test
void testConvenienceIssuer() {
String compact = Jwts.builder().setIssuer("Me").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getIssuer(), "Me"
compact = Jwts.builder().setSubject("Joe")
.setIssuer("Me") //set it
.setIssuer(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getIssuer()
}
@Test
void testConvenienceSubject() {
String compact = Jwts.builder().setSubject("Joe").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getSubject(), "Joe"
compact = Jwts.builder().setIssuer("Me")
.setSubject("Joe") //set it
.setSubject(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getSubject()
}
@Test
void testConvenienceAudience() {
String compact = Jwts.builder().setAudience("You").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getAudience(), "You"
compact = Jwts.builder().setIssuer("Me")
.setAudience("You") //set it
.setAudience(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getAudience()
}
private Date dateWithOnlySecondPrecision() {
return dateWithOnlySecondPrecision(System.currentTimeMillis());
}
private Date dateWithOnlySecondPrecision(long millis) {
long seconds = millis / 1000;
long secondOnlyPrecisionMillis = seconds * 1000;
return new Date(secondOnlyPrecisionMillis);
}
@Test
void testConvenienceExpiration() {
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
String compact = Jwts.builder().setExpiration(now).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
def claimedDate = claims.getExpiration()
assertEquals claimedDate, now
compact = Jwts.builder().setIssuer("Me")
.setExpiration(now) //set it
.setExpiration(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getExpiration()
}
@Test
void testConvenienceNotBefore() {
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
String compact = Jwts.builder().setNotBefore(now).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
def claimedDate = claims.getNotBefore()
assertEquals claimedDate, now
compact = Jwts.builder().setIssuer("Me")
.setNotBefore(now) //set it
.setNotBefore(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getNotBefore()
}
@Test
void testConvenienceIssuedAt() {
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
String compact = Jwts.builder().setIssuedAt(now).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
def claimedDate = claims.getIssuedAt()
assertEquals claimedDate, now
compact = Jwts.builder().setIssuer("Me")
.setIssuedAt(now) //set it
.setIssuedAt(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getIssuedAt()
}
@Test
void testConvenienceId() {
String id = UUID.randomUUID().toString();
String compact = Jwts.builder().setId(id).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getId(), id
compact = Jwts.builder().setIssuer("Me")
.setId(id) //set it
.setId(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getId()
}
@Test @Test
void testHS256() { void testHS256() {
testHmac(SignatureAlgorithm.HS256); testHmac(SignatureAlgorithm.HS256);

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken package io.jsonwebtoken
import org.testng.annotations.Test import org.testng.annotations.Test
import static org.testng.Assert.* import static org.testng.Assert.*
class SignatureAlgorithmTest { class SignatureAlgorithmTest {
@ -41,4 +42,38 @@ class SignatureAlgorithmTest {
void testUnrecognizedAlgorithmName() { void testUnrecognizedAlgorithmName() {
SignatureAlgorithm.forName('whatever') SignatureAlgorithm.forName('whatever')
} }
@Test
void testIsHmac() {
for(SignatureAlgorithm alg : SignatureAlgorithm.values()) {
if (alg.name().startsWith("HS")) {
assertTrue alg.isHmac()
} else {
assertFalse alg.isHmac()
}
}
}
@Test
void testIsRsa() {
for(SignatureAlgorithm alg : SignatureAlgorithm.values()) {
if (alg.getDescription().startsWith("RSASSA")) {
assertTrue alg.isRsa()
} else {
assertFalse alg.isRsa()
}
}
}
@Test
void testIsEllipticCurve() {
for(SignatureAlgorithm alg : SignatureAlgorithm.values()) {
if (alg.name().startsWith("ES")) {
assertTrue alg.isEllipticCurve()
} else {
assertFalse alg.isEllipticCurve()
}
}
}
} }