33import com .auth0 .jwt .algorithms .Algorithm ;
44import com .auth0 .jwt .exceptions .*;
55import com .auth0 .jwt .impl .PublicClaims ;
6+ import com .auth0 .jwt .interfaces .Claim ;
67import org .apache .commons .codec .binary .Base64 ;
78
89import java .util .*;
@@ -53,6 +54,7 @@ static class Verification {
5354 /**
5455 * Require a specific Issuer ("iss") claim.
5556 *
57+ * @param issuer the required Issuer value
5658 * @return this same Verification instance.
5759 */
5860 public Verification withIssuer (String issuer ) {
@@ -63,6 +65,7 @@ public Verification withIssuer(String issuer) {
6365 /**
6466 * Require a specific Subject ("sub") claim.
6567 *
68+ * @param subject the required Subject value
6669 * @return this same Verification instance.
6770 */
6871 public Verification withSubject (String subject ) {
@@ -73,6 +76,7 @@ public Verification withSubject(String subject) {
7376 /**
7477 * Require a specific Audience ("aud") claim.
7578 *
79+ * @param audience the required Audience value
7680 * @return this same Verification instance.
7781 */
7882 public Verification withAudience (String [] audience ) {
@@ -147,13 +151,36 @@ public Verification acceptIssuedAt(long delta) throws IllegalArgumentException {
147151 /**
148152 * Require a specific JWT Id ("jti") claim.
149153 *
154+ * @param jwtId the required Id value
150155 * @return this same Verification instance.
151156 */
152157 public Verification withJWTId (String jwtId ) {
153158 requireClaim (PublicClaims .JWT_ID , jwtId );
154159 return this ;
155160 }
156161
162+ /**
163+ * Require a specific Claim value.
164+ *
165+ * @param name the Claim's name
166+ * @param value the Claim's value. Must be an instance of Integer, Double, Boolean, Date or String class.
167+ * @return this same Verification instance.
168+ * @throws IllegalArgumentException if the name is null or the value class is not allowed.
169+ */
170+ public Verification withClaim (String name , Object value ) throws IllegalArgumentException {
171+ final boolean validValue = value instanceof Integer || value instanceof Double ||
172+ value instanceof Boolean || value instanceof Date || value instanceof String ;
173+ if (name == null ) {
174+ throw new IllegalArgumentException ("The Custom Claim's name can't be null." );
175+ }
176+ if (!validValue ) {
177+ throw new IllegalArgumentException ("The Custom Claim's value class must be an instance of Integer, Double, Boolean, Date or String." );
178+ }
179+
180+ requireClaim (name , value );
181+ return this ;
182+ }
183+
157184 /**
158185 * Creates a new and reusable instance of the JWTVerifier with the configuration already provided.
159186 *
@@ -227,35 +254,81 @@ private void verifyAlgorithm(JWT jwt, Algorithm expectedAlgorithm) throws Algori
227254
228255 private void verifyClaims (JWT jwt , Map <String , Object > claims ) {
229256 for (Map .Entry <String , Object > entry : claims .entrySet ()) {
230- assertValidClaim (jwt , entry .getKey (), entry .getValue ());
257+ switch (entry .getKey ()) {
258+ case PublicClaims .AUDIENCE :
259+ assertValidAudienceClaim (jwt .getAudience (), (String []) entry .getValue ());
260+ break ;
261+ case PublicClaims .EXPIRES_AT :
262+ assertValidDateClaim (jwt .getExpiresAt (), (Long ) entry .getValue (), true );
263+ break ;
264+ case PublicClaims .ISSUED_AT :
265+ assertValidDateClaim (jwt .getIssuedAt (), (Long ) entry .getValue (), false );
266+ break ;
267+ case PublicClaims .NOT_BEFORE :
268+ assertValidDateClaim (jwt .getNotBefore (), (Long ) entry .getValue (), false );
269+ break ;
270+ case PublicClaims .ISSUER :
271+ assertValidStringClaim (entry .getKey (), jwt .getIssuer (), (String ) entry .getValue ());
272+ break ;
273+ case PublicClaims .JWT_ID :
274+ assertValidStringClaim (entry .getKey (), jwt .getId (), (String ) entry .getValue ());
275+ break ;
276+ case PublicClaims .SUBJECT :
277+ assertValidStringClaim (entry .getKey (), jwt .getSubject (), (String ) entry .getValue ());
278+ break ;
279+ default :
280+ assertValidClaim (jwt .getClaim (entry .getKey ()), entry .getKey (), entry .getValue ());
281+ break ;
282+ }
231283 }
232284 }
233285
234- private void assertValidClaim (JWT jwt , String claimName , Object expectedValue ) throws InvalidClaimException {
235- String errMessage = String .format ("The Claim '%s' value doesn't match the required one." , claimName );
286+ private void assertValidClaim (Claim claim , String claimName , Object value ) {
287+ boolean isValid = false ;
288+ if (value instanceof String ) {
289+ isValid = value .equals (claim .asString ());
290+ } else if (value instanceof Integer ) {
291+ isValid = value .equals (claim .asInt ());
292+ } else if (value instanceof Boolean ) {
293+ isValid = value .equals (claim .asBoolean ());
294+ } else if (value instanceof Double ) {
295+ isValid = value .equals (claim .asDouble ());
296+ } else if (value instanceof Date ) {
297+ isValid = value .equals (claim .asDate ());
298+ }
299+
300+ if (!isValid ) {
301+ throw new InvalidClaimException (String .format ("The Claim '%s' value doesn't match the required one." , claimName ));
302+ }
303+ }
304+
305+ private void assertValidStringClaim (String claimName , String value , String expectedValue ) {
306+ if (!expectedValue .equals (value )) {
307+ throw new InvalidClaimException (String .format ("The Claim '%s' value doesn't match the required one." , claimName ));
308+ }
309+ }
310+
311+ private void assertValidDateClaim (Date date , long delta , boolean shouldBeFuture ) {
312+ Date today = clock .getToday ();
236313 boolean isValid ;
237- if (PublicClaims .AUDIENCE .equals (claimName )) {
238- isValid = Arrays .equals (jwt .getAudience (), (String []) expectedValue );
239- } else if (PublicClaims .NOT_BEFORE .equals (claimName ) || PublicClaims .EXPIRES_AT .equals (claimName ) || PublicClaims .ISSUED_AT .equals (claimName )) {
240- long deltaValue = (long ) expectedValue ;
241- Date today = clock .getToday ();
242- Date date = jwt .getClaim (claimName ).asDate ();
243- if (PublicClaims .EXPIRES_AT .equals (claimName )) {
244- today .setTime (today .getTime () - deltaValue );
245- isValid = date == null || !today .after (date );
246- errMessage = String .format ("The Token has expired on %s." , date );
247- } else {
248- today .setTime (today .getTime () + deltaValue );
249- isValid = date == null || !today .before (date );
250- errMessage = String .format ("The Token can't be used before %s." , date );
251- }
314+ String errMessage ;
315+ if (shouldBeFuture ) {
316+ today .setTime (today .getTime () - delta );
317+ isValid = date == null || !today .after (date );
318+ errMessage = String .format ("The Token has expired on %s." , date );
252319 } else {
253- String stringValue = (String ) expectedValue ;
254- isValid = stringValue .equals (jwt .getClaim (claimName ).asString ());
320+ today .setTime (today .getTime () + delta );
321+ isValid = date == null || !today .before (date );
322+ errMessage = String .format ("The Token can't be used before %s." , date );
255323 }
256-
257324 if (!isValid ) {
258325 throw new InvalidClaimException (errMessage );
259326 }
260327 }
328+
329+ private void assertValidAudienceClaim (String [] audience , String [] value ) {
330+ if (!Arrays .equals (audience , value )) {
331+ throw new InvalidClaimException ("The Claim 'aud' value doesn't match the required one." );
332+ }
333+ }
261334}
0 commit comments