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

be.atbash.ee.security.octopus.nimbus.jose.Header 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.nimbus.HeaderParameterType;
import be.atbash.ee.security.octopus.nimbus.jwt.jwe.JWEAlgorithm;
import be.atbash.ee.security.octopus.nimbus.jwt.jwe.JWEHeader;
import be.atbash.ee.security.octopus.nimbus.jwt.jws.JWSAlgorithm;
import be.atbash.ee.security.octopus.nimbus.jwt.jws.JWSHeader;
import be.atbash.ee.security.octopus.nimbus.util.Base64URLValue;
import be.atbash.ee.security.octopus.nimbus.util.JSONObjectUtils;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import java.text.ParseException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/**
 * The base abstract class for unsecured ({@code alg=none}), JSON Web Signature
 * (JWS) and JSON Web Encryption (JWE) headers.
 *
 * 

The header may also include {@link #getCustomParameters custom * parameters}; these will be serialised and parsed along the registered ones. *

* Based on code by Vladimir Dzhuvinov */ public abstract class Header { /** * The max allowed string length when parsing a JOSE header (after the * BASE64URL decoding). 20K chars should be sufficient to accommodate * JOSE headers with an X.509 certificate chain in the {@code x5c} * header parameter. */ public static final int MAX_HEADER_STRING_LENGTH = 20_000; /** * The algorithm ({@code alg}) parameter. */ private final Algorithm alg; /** * The JOSE object type ({@code typ}) parameter. */ private final JOSEObjectType typ; /** * The content type ({@code cty}) parameter. */ private final String cty; /** * The critical headers ({@code crit}) parameter. */ private final Set crit; /** * Custom header parameters. */ private final Map customParameters; /** * The original parsed Base64URL, {@code null} if the header was * created from scratch. */ private final Base64URLValue parsedBase64URL; /** * The registered parameter names. */ private static final Set REGISTERED_PARAMETER_NAMES = HeaderParameterType.getHeaderParameters(); /** * Creates a new abstract header. * * @param alg The algorithm ({@code alg}) parameter. Must * not be {@code null}. * @param typ The type ({@code typ}) parameter, * {@code null} if not specified. * @param cty The content type ({@code cty}) parameter, * {@code null} if not specified. * @param crit The names of the critical header * ({@code crit}) parameters, empty set or * {@code null} if none. * @param parameters The custom parameters, empty map or * {@code null} if none. * @param parsedBase64URL The parsed Base64URL, {@code null} if the * header is created from scratch. */ protected Header(Algorithm alg, JOSEObjectType typ, String cty, Set crit, Map parameters, Base64URLValue parsedBase64URL) { this.alg = HeaderParameterType.getParameterValue(HeaderParameterNames.ALGORITHM, alg, parameters); if (this.alg == null) { throw new IllegalArgumentException("The algorithm \"" + HeaderParameterNames.ALGORITHM + "\" header parameter must not be null"); } this.typ = HeaderParameterType.getParameterValue(HeaderParameterNames.TYPE, typ, parameters); this.cty = HeaderParameterType.getParameterValue(HeaderParameterNames.CONTENT_TYPE, cty, parameters); if (crit == null) { Set temp = HeaderParameterType.getParameterValue(HeaderParameterNames.CRITICAL, crit, parameters); if (temp != null) { // Copy and make unmodifiable this.crit = Collections.unmodifiableSet(new HashSet<>(temp)); } else { this.crit = null; } } else { this.crit = Collections.unmodifiableSet(crit); } this.customParameters = HeaderParameterType.filterOutRegisteredNames(parameters, REGISTERED_PARAMETER_NAMES); this.parsedBase64URL = parsedBase64URL; } /** * Deep copy constructor. * * @param header The header to copy. Must not be {@code null}. */ protected Header(Header header) { this( header.getAlgorithm(), header.getType(), header.getContentType(), header.getCriticalParams(), header.getCustomParameters(), header.getParsedBase64URL()); } /** * Gets the algorithm ({@code alg}) parameter. * * @return The algorithm parameter. */ public Algorithm getAlgorithm() { return alg; } /** * Gets the type ({@code typ}) parameter. * * @return The type parameter, {@code null} if not specified. */ public JOSEObjectType getType() { return typ; } /** * Gets the content type ({@code cty}) parameter. * * @return The content type parameter, {@code null} if not specified. */ public String getContentType() { return cty; } /** * Gets the critical header parameters ({@code crit}) parameter. * * @return The names of the critical header parameters, as a * unmodifiable set, {@code null} if not specified. */ public Set getCriticalParams() { return crit; } /** * Gets a custom (non-registered) parameter. * * @param name The name of the custom parameter. Must not be * {@code null}. * @return The custom parameter, {@code null} if not specified. */ public Object getCustomParameter(String name) { return customParameters.get(name); } /** * Gets the custom (non-registered) parameters. * * @return The custom parameters, as a unmodifiable map, empty map if * none. */ public Map getCustomParameters() { return customParameters; } /** * Gets the original Base64URL used to create this header. * * @return The parsed Base64URL, {@code null} if the header was created * from scratch. */ public Base64URLValue getParsedBase64URL() { return parsedBase64URL; } /** * Gets the names of all included parameters (registered and custom) in * the header instance. * * @return The included parameters. */ public Set getIncludedParameters() { Set includedParameters = new HashSet<>(getCustomParameters().keySet()); includedParameters.add(HeaderParameterNames.ALGORITHM); if (getType() != null) { includedParameters.add(HeaderParameterNames.TYPE); } if (getContentType() != null) { includedParameters.add(HeaderParameterNames.CONTENT_TYPE); } if (getCriticalParams() != null && !getCriticalParams().isEmpty()) { includedParameters.add(HeaderParameterNames.CRITICAL); } return includedParameters; } /** * Returns a JSON object representation of the header. All custom * parameters are included if they serialise to a JSON entity and * their names don't conflict with the registered ones. * * @return The JSON object representation of the header. */ public JsonObjectBuilder toJSONObject() { // Include custom parameters, they will be overwritten if their // names match specified registered ones JsonObjectBuilder result = Json.createObjectBuilder(); customParameters.forEach((key, value) -> JSONObjectUtils.addValue(result, key, value)); // Alg is always defined result.add(HeaderParameterNames.ALGORITHM, alg.toString()); if (typ != null) { result.add(HeaderParameterNames.TYPE, typ.toString()); } if (cty != null) { result.add(HeaderParameterNames.CONTENT_TYPE, cty); } if (crit != null && !crit.isEmpty()) { result.add(HeaderParameterNames.CRITICAL, Json.createArrayBuilder(crit)); } return result; } /** * Returns a JSON string representation of the header. All custom * parameters will be included if they serialise to a JSON entity and * their names don't conflict with the registered ones. * * @return The JSON string representation of the header. */ public String toString() { return toJSONObject().build().toString(); } /** * Returns a Base64URL representation of the header. If the header was * parsed always returns the original Base64URL (required for JWS * validation and authenticated JWE decryption). * * @return The original parsed Base64URL representation of the header, * or a new Base64URL representation if the header was created * from scratch. */ public Base64URLValue toBase64URL() { if (parsedBase64URL == null) { // Header was created from scratch, return new Base64URL return Base64URLValue.encode(toString()); } else { // Header was parsed, return original Base64URL return parsedBase64URL; } } public static Set getRegisteredParameterNames() { return REGISTERED_PARAMETER_NAMES; } /** * Parses a {@link PlainHeader}, {@link JWSHeader} or {@link JWEHeader} * from the specified JSON object. * * @param jsonObject The JSON object to parse. Must not be * {@code null}. * @return The header. * @throws ParseException If the specified JSON object doesn't * represent a valid header. */ public static Header parse(JsonObject jsonObject) throws ParseException { return parse(jsonObject, null); } /** * Parses a {@link PlainHeader}, {@link JWSHeader} or {@link JWEHeader} * from the specified JSON object. * * @param jsonObject The JSON object to parse. Must not be * {@code null}. * @param parsedBase64URL The original parsed Base64URL, {@code null} * if not applicable. * @return The header. * @throws ParseException If the specified JSON object doesn't * represent a valid header. */ public static Header parse(JsonObject jsonObject, Base64URLValue parsedBase64URL) throws ParseException { Algorithm alg = Algorithm.parseAlgorithm(jsonObject); if (alg.equals(Algorithm.NONE)) { return PlainHeader.parse(jsonObject, parsedBase64URL); } else if (alg instanceof JWSAlgorithm) { return JWSHeader.parse(jsonObject, parsedBase64URL); } else if (alg instanceof JWEAlgorithm) { return JWEHeader.parse(jsonObject, parsedBase64URL); } else { throw new AssertionError("Unexpected algorithm type: " + alg); } } /** * Parses a {@link PlainHeader}, {@link JWSHeader} or {@link JWEHeader} * from the specified JSON object string. * * @param jsonString The JSON object string to parse. Must not be * {@code null}. * @return The header. * @throws ParseException If the specified JSON object string doesn't * represent a valid header. */ public static Header parse(String jsonString) throws ParseException { return parse(jsonString, null); } /** * Parses a {@link PlainHeader}, {@link JWSHeader} or {@link JWEHeader} * from the specified JSON object string. * * @param jsonString The JSON object string to parse. Must not be * {@code null}. * @param parsedBase64URL The original parsed Base64URL, {@code null} * if not applicable. * @return The header. * @throws ParseException If the specified JSON object string doesn't * represent a valid header. */ public static Header parse(String jsonString, Base64URLValue parsedBase64URL) throws ParseException { JsonObject jsonObject = JSONObjectUtils.parse(jsonString, MAX_HEADER_STRING_LENGTH); return parse(jsonObject, parsedBase64URL); } /** * Parses a {@link PlainHeader}, {@link JWSHeader} or {@link JWEHeader} * from the specified Base64URL. * * @param base64URL The Base64URL to parse. Must not be {@code null}. * @return The header. * @throws ParseException If the specified Base64URL doesn't represent * a valid header. */ public static Header parse(Base64URLValue base64URL) throws ParseException { return parse(base64URL.decodeToString(), base64URL); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy