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

be.atbash.ee.security.octopus.nimbus.jose.Payload Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017-2022 Rudy De Busscher (https://www.atbash.be)
 *
 * 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 be.atbash.ee.security.octopus.nimbus.jose;


import be.atbash.ee.security.octopus.jwt.JWTValidationConstant;
import be.atbash.ee.security.octopus.nimbus.jwt.SignedJWT;
import be.atbash.ee.security.octopus.nimbus.jwt.jws.JWSObject;
import be.atbash.ee.security.octopus.nimbus.util.Base64URLValue;
import be.atbash.ee.security.octopus.nimbus.util.JSONObjectUtils;
import org.slf4j.MDC;

import javax.json.JsonObject;
import java.text.ParseException;

import static java.nio.charset.StandardCharsets.UTF_8;


/**
 * Payload of an unsecured (plain), JSON Web Signature (JWS) or JSON Web
 * Encryption (JWE) object. Supports JSON object, string, byte array,
 * Base64URL, JWS object and signed JWT payload representations. This class is
 * immutable.
 *
 * 

UTF-8 is the character set for all conversions between strings and byte * arrays. * *

Conversion relations: * *

 * JSONObject <=> String <=> Base64URL
 *                       <=> byte[]
 *                       <=> JWSObject
 *                       <=> SignedJWT
 * 
* * Based on code by Vladimir Dzhuvinov */ public final class Payload { /** * Enumeration of the original data types used to create a * {@link Payload}. */ public enum Origin { /** * The payload was created from a JSON object. */ JSON, /** * The payload was created from a string. */ STRING, /** * The payload was created from a byte array. */ BYTE_ARRAY, /** * The payload was created from a Base64URL-encoded object. */ BASE64URL, /** * The payload was created from a JWS object. */ JWS_OBJECT, /** * The payload was created from a signed JSON Web Token (JWT). */ SIGNED_JWT } /** * The original payload data type. */ private final Origin origin; /** * The JSON object representation. */ private final JsonObject jsonObject; /** * The string representation. */ private final String stringPayload; /** * The byte array representation. */ private final byte[] bytes; /** * The Base64URL representation. */ private final Base64URLValue base64URL; /** * The JWS object representation. */ private final JWSObject jwsObject; /** * The signed JWT representation. */ private final SignedJWT signedJWT; /** * Converts a byte array to a string using {@code UTF-8}. * * @param bytes The byte array to convert. May be {@code null}. * @return The resulting string, {@code null} if conversion failed. */ private static String byteArrayToString(byte[] bytes) { return bytes != null ? new String(bytes, UTF_8) : null; } /** * Converts a string to a byte array using {@code UTF-8}. * * @param value The string to convert. May be {@code null}. * @return The resulting byte array, {@code null} if conversion failed. */ private static byte[] stringToByteArray(String value) { return value != null ? value.getBytes(UTF_8) : null; } /** * Creates a new payload from the specified JSON object. * * @param jsonObject The JSON object representing the payload. Must not * be {@code null}. */ public Payload(JsonObject jsonObject) { if (jsonObject == null) { throw new IllegalArgumentException("The JSON object must not be null"); } this.jsonObject = jsonObject; stringPayload = null; bytes = null; base64URL = null; jwsObject = null; signedJWT = null; origin = Origin.JSON; } /** * Creates a new payload from the specified string. * * @param payload The string representing the payload. Must not be * {@code null}. */ public Payload(String payload) { if (payload == null) { throw new IllegalArgumentException("The payload must not be null"); } jsonObject = null; this.stringPayload = payload; bytes = null; base64URL = null; jwsObject = null; signedJWT = null; origin = Origin.STRING; } /** * Creates a new payload from the specified byte array. * * @param bytes The byte array representing the payload. Must not be * {@code null}. */ public Payload(byte[] bytes) { if (bytes == null) { throw new IllegalArgumentException("The byte array must not be null"); } jsonObject = null; stringPayload = null; this.bytes = bytes; base64URL = null; jwsObject = null; signedJWT = null; origin = Origin.BYTE_ARRAY; } /** * Creates a new payload from the specified Base64URL-encoded object. * * @param base64URL The Base64URL-encoded object representing the * payload. Must not be {@code null}. */ public Payload(Base64URLValue base64URL) { if (base64URL == null) { MDC.put(JWTValidationConstant.JWT_VERIFICATION_FAIL_REASON, "The token has no payload section"); throw new IllegalArgumentException("The Base64URL-encoded object must not be null"); } jsonObject = null; stringPayload = null; bytes = null; this.base64URL = base64URL; jwsObject = null; signedJWT = null; origin = Origin.BASE64URL; } /** * Creates a new payload from the specified JWS object. Intended for * signed then encrypted JOSE objects. * * @param jwsObject The JWS object representing the payload. Must be in * a signed state and not {@code null}. */ public Payload(JWSObject jwsObject) { if (jwsObject == null) { throw new IllegalArgumentException("The JWS object must not be null"); } if (jwsObject.getState() == JWSObject.State.UNSIGNED) { throw new IllegalArgumentException("The JWS object must be signed"); } jsonObject = null; stringPayload = null; bytes = null; base64URL = null; this.jwsObject = jwsObject; signedJWT = null; origin = Origin.JWS_OBJECT; } /** * Creates a new payload from the specified signed JSON Web Token * (JWT). Intended for signed then encrypted JWTs. * * @param signedJWT The signed JWT representing the payload. Must be in * a signed state and not {@code null}. */ public Payload(SignedJWT signedJWT) { if (signedJWT == null) { throw new IllegalArgumentException("The signed JWT must not be null"); } if (signedJWT.getState() == JWSObject.State.UNSIGNED) { throw new IllegalArgumentException("The JWT must be signed"); } jsonObject = null; stringPayload = null; bytes = null; base64URL = null; this.signedJWT = signedJWT; jwsObject = signedJWT; // The signed JWT is also a JWS origin = Origin.SIGNED_JWT; } /** * Gets the original data type used to create this payload. * * @return The payload origin. */ public Origin getOrigin() { return origin; } /** * Returns a JSON object representation of this payload. * * @return The JSON object representation, {@code null} if the payload * couldn't be converted to a JSON object. */ public JsonObject toJSONObject() { if (jsonObject != null) { return jsonObject; } // Convert String json = toString(); if (json == null) { // to string conversion failed return null; } try { return JSONObjectUtils.parse(json); } catch (ParseException e) { // Payload not a JSON object // These messages are in function of JWT validation by Atbash Runtime so have slightly narrow meaning of the provided parameters. // TODO According to some tests, the reason can be different than mentioned. But when handling a JWT, it should be OK. Double check! int length = Math.min(json.length(), 200); String continuation = length < json.length() ? "..." : ""; MDC.put(JWTValidationConstant.JWT_VERIFICATION_FAIL_REASON, String.format("The payload of the token is not a valid JSON: %s%s", json.substring(0, length), continuation)); return null; } } /** * Returns a string representation of this payload. * * @return The string representation. */ @Override public String toString() { if (stringPayload != null) { return stringPayload; } // Convert if (jwsObject != null) { if (jwsObject.getParsedString() != null) { return jwsObject.getParsedString(); } else { return jwsObject.serialize(); } } else if (jsonObject != null) { return jsonObject.toString(); } else if (bytes != null) { return byteArrayToString(bytes); } else if (base64URL != null) { return base64URL.decodeToString(); } else { return ""; // should never happen } } /** * Returns a byte array representation of this payload. * * @return The byte array representation. */ public byte[] toBytes() { if (bytes != null) { return bytes; } // Convert if (base64URL != null) { return base64URL.decode(); } return stringToByteArray(toString()); } /** * Returns a Base64URL representation of this payload. * * @return The Base64URL representation. */ public Base64URLValue toBase64URL() { if (base64URL != null) { return base64URL; } // Convert return Base64URLValue.encode(toBytes()); } /** * Returns a JWS object representation of this payload. Intended for * signed then encrypted JOSE objects. * * @return The JWS object representation, {@code null} if the payload * couldn't be converted to a JWS object. */ public JWSObject toJWSObject() { if (jwsObject != null) { return jwsObject; } try { return JWSObject.parse(toString()); } catch (ParseException e) { return null; } } /** * Returns a signed JSON Web Token (JWT) representation of this * payload. Intended for signed then encrypted JWTs. * * @return The signed JWT representation, {@code null} if the payload * couldn't be converted to a signed JWT. */ public SignedJWT toSignedJWT() { if (signedJWT != null) { return signedJWT; } try { return SignedJWT.parse(toString()); } catch (ParseException e) { return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy