All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.primeframework.jwt.JWTDecoder Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright (c) 2016, Inversoft Inc., All Rights Reserved
 *
 * 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 org.primeframework.jwt;

import org.primeframework.jwt.domain.Algorithm;
import org.primeframework.jwt.domain.Header;
import org.primeframework.jwt.domain.InvalidJWTException;
import org.primeframework.jwt.domain.JWT;
import org.primeframework.jwt.domain.JWTExpiredException;
import org.primeframework.jwt.domain.JWTUnavailableForProcessingException;
import org.primeframework.jwt.domain.MissingVerifierException;
import org.primeframework.jwt.json.Mapper;

import java.util.Base64;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

/**
 * @author Daniel DeGroff
 */
public class JWTDecoder {

  private static JWTDecoder instance;

  public static JWTDecoder getInstance() {
    if (instance == null) {
      instance = new JWTDecoder();
    }

    return instance;
  }

  /**
   * Decode the JWT using one of they provided verifiers. One more verifiers may be provided, the first verifier found
   * supporting the algorithm reported by the JWT header will be utilized.
   * 

* A JWT that is expired or not yet valid will not be decoded, instead a {@link JWTExpiredException} or {@link * JWTUnavailableForProcessingException} exception will be thrown respectively. * * @param encodedJWT The encoded JWT in string format. * @param verifiers A map of verifiers. * @return a decoded JWT. */ public JWT decode(String encodedJWT, Verifier... verifiers) { Objects.requireNonNull(encodedJWT); Objects.requireNonNull(verifiers); // An unsecured JWT will not contain a signature and should only have a header and a payload. String[] parts = getParts(encodedJWT); Header header = Mapper.deserialize(base64Decode(parts[0].getBytes()), Header.class); // Be particular about decoding an unsecured JWT. If the JWT is signed or any verifiers were provided don't do it. if (header.algorithm == Algorithm.none && parts.length == 2 && verifiers.length == 0) { return Mapper.deserialize(base64Decode(parts[1].getBytes()), JWT.class); } // If verifiers were provided, ensure it is able to verify this JWT. Verifier verifier = null; for (Verifier v : verifiers) { if (v.canVerify(header.algorithm)) { verifier = v; } } return decode(encodedJWT, header, parts, verifier); } /** * Decode the JWT using one of they provided verifiers. A JWT header value named kid is expected to * contain the key to lookup the correct verifier. *

* A JWT that is expired or not yet valid will not be decoded, instead a {@link JWTExpiredException} or {@link * JWTUnavailableForProcessingException} exception will be thrown respectively. * * @param encodedJWT The encoded JWT in string format. * @param verifiers A map of verifiers. * @return a decoded JWT. */ public JWT decode(String encodedJWT, Map verifiers) { return decode(encodedJWT, verifiers, h -> h.get("kid")); } /** * Decode the JWT using one of they provided verifiers. The key used to lookup the correct verifier is provided by the * keyFunction. The key function is provided the JWT header and is expected to return a string key to * look up the correct verifier. *

* A JWT that is expired or not yet valid will not be decoded, instead a {@link JWTExpiredException} or {@link * JWTUnavailableForProcessingException} exception will be thrown respectively. * * @param encodedJWT The encoded JWT in string format. * @param verifiers A map of verifiers. * @param keyFunction A function used to lookup the verifier key from the header. * @return a decoded JWT. */ public JWT decode(String encodedJWT, Map verifiers, Function keyFunction) { Objects.requireNonNull(encodedJWT); Objects.requireNonNull(verifiers); String[] parts = getParts(encodedJWT); Header header = Mapper.deserialize(base64Decode(parts[0].getBytes()), Header.class); // Be particular about decoding an unsecured JWT. If the JWT is signed or any verifiers were provided don't do it. if (header.algorithm == Algorithm.none && parts.length == 2 && verifiers.isEmpty()) { return Mapper.deserialize(base64Decode(parts[1].getBytes()), JWT.class); } // If verifiers were provided, ensure it is able to verify this JWT. String key = keyFunction.apply(header); Verifier verifier = verifiers.get(key); if (verifier != null) { if (!verifier.canVerify(header.algorithm)) { verifier = null; } } return decode(encodedJWT, header, parts, verifier); } private byte[] base64Decode(byte[] bytes) { return Base64.getUrlDecoder().decode(bytes); } private JWT decode(String encodedJWT, Header header, String[] parts, Verifier verifier) { int index = encodedJWT.lastIndexOf("."); // The message comprises the first two segments of the entire JWT, the signature is the last segment. byte[] message = encodedJWT.substring(0, index).getBytes(); // If a signature is provided and verifier must be provided. if (parts.length == 3 && verifier == null) { throw new MissingVerifierException("No Verifier has been provided for verify a signature signed using [" + header.algorithm.getName() + "]"); } if (parts.length == 3) { // Verify the signature before de-serializing the payload. byte[] signature = base64Decode(parts[2].getBytes()); verifier.verify(header.algorithm, message, signature); } JWT jwt = Mapper.deserialize(base64Decode(parts[1].getBytes()), JWT.class); // Verify expiration claim if (jwt.isExpired()) { throw new JWTExpiredException(); } // Verify the notBefore claim if (jwt.isUnavailableForProcessing()) { throw new JWTUnavailableForProcessingException(); } return jwt; } private String[] getParts(String encodedJWT) { String[] parts = encodedJWT.split("\\."); // Secured JWT XXXXX.YYYYY.ZZZZZ, Unsecured JWT XXXXX.YYYYY. if (parts.length == 3 || (parts.length == 2 && encodedJWT.endsWith("."))) { return parts; } throw new InvalidJWTException("The encoded JWT is not properly formatted. Expected a three part dot separated string."); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy