package com.nimbusds.jose;
import java.text.ParseException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.minidev.json.JSONObject;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jose.util.JSONObjectUtils;
/**
* The base abstract class for plaintext, JSON Web Signature (JWS) and JSON Web
* Encryption (JWE) headers.
*
* <p>The header may also carry {@link #setCustomParameters custom parameters};
* these will be serialised and parsed along the reserved ones.
*
* @author Vladimir Dzhuvinov
* @version $version$ (2012-10-01)
*/
public abstract class Header implements ReadOnlyHeader {
/**
* The algorithm ({@code alg}) parameter.
*/
final protected Algorithm alg;
/**
* The JOSE object type ({@code typ}) parameter.
*/
private JOSEObjectType typ;
/**
* The content type ({@code cty}) parameter.
*/
private String cty;
/**
* Custom header parameters.
*/
private Map<String,Object> customParameters = new HashMap<String,Object>();
/**
* Creates a new header with the specified algorithm ({@code alg})
* parameter.
*
* @param alg The algorithm parameter. Must not be {@code null}.
*/
protected Header(final Algorithm alg) {
if (alg == null)
throw new IllegalArgumentException("The algorithm \"alg\" header parameter must not be null");
this.alg = alg;
}
@Override
public JOSEObjectType getType() {
return typ;
}
/**
* Sets the type ({@code typ}) parameter.
*
* @param typ The type parameter, {@code null} if not specified.
*/
public void setType(final JOSEObjectType typ) {
this.typ = typ;
}
@Override
public String getContentType() {
return cty;
}
/**
* Sets the content type ({@code cty}) parameter.
*
* @param cty The content type parameter, {@code null} if not specified.
*/
public void setContentType(final String cty) {
this.cty = cty;
}
@Override
public Object getCustomParameter(final String name) {
return customParameters.get(name);
}
/**
* Sets a custom (non-reserved) parameter. Callers and extending classes
* should ensure the parameter name doesn't match a reserved parameter
* name.
*
* @param name The name of the custom parameter. Must not match a
* reserved parameter name and must not be {@code null}.
* @param value The value of the custom parameter, should map to a valid
* JSON entity, {@code null} if not specified.
*/
protected void setCustomParameter(final String name, final Object value) {
customParameters.put(name, value);
}
@Override
public Map<String,Object> getCustomParameters() {
return Collections.unmodifiableMap(customParameters);
}
/**
* Sets the custom (non-reserved) parameters. The values must be
* serialisable to a JSON entity, otherwise will be ignored.
*
* @param customParameters The custom parameters, empty map or
* {@code null} if none.
*/
public void setCustomParameters(final Map<String,Object> customParameters) {
if (customParameters == null)
return;
this.customParameters = customParameters;
}
@Override
public JSONObject toJSONObject() {
// Include custom parameters, they will be overwritten if their
// names match specified reserved ones
JSONObject o = new JSONObject(customParameters);
// Alg is always defined
o.put("alg", alg.toString());
if (typ != null)
o.put("typ", typ.toString());
if (cty != null)
o.put("cty", cty);
return o;
}
/**
* Returns a JSON string representation of this header. All custom
* parameters will be included if they serialise to a JSON entity and
* their names don't conflict with the reserved ones.
*
* @return The JSON string representation of this header.
*/
public String toString() {
return toJSONObject().toString();
}
/**
* Returns a Base64URL representation of this header.
*
* @return The Base64URL representation of this header.
*/
public Base64URL toBase64URL() {
return Base64URL.encode(toString());
}
/**
* Parses an algorithm ({@code alg}) parameter from the specified
* header JSON object. Intended for initial parsing of plain, JWS and
* JWE headers.
*
* <p>The algorithm type (none, JWS or JWE) is determined by inspecting
* the algorithm name for "none" and the presence of an "enc" parameter.
*
* @param json The JSON object to parse. Must not be {@code null}.
*
* @return The algorithm, an instance of {@link Algorithm#NONE},
* {@link JWSAlgorithm} or {@link JWEAlgorithm}.
*
* @throws ParseException If the {@code alg} parameter couldn't be
* parsed.
*/
public static Algorithm parseAlgorithm(final JSONObject json)
throws ParseException {
String algName = JSONObjectUtils.getString(json, "alg");
// Infer algorithm type
// Plain
if (algName.equals(Algorithm.NONE.getName()))
return Algorithm.NONE;
// JWE
else if (json.containsKey("enc"))
return JWEAlgorithm.parse(algName);
// JWS
else
return JWSAlgorithm.parse(algName);
}
/**
* Parses a {@link PlainHeader}, {@link JWSHeader} or {@link JWEHeader}
* from the specified JSON object.
*
* @param json 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(final JSONObject json)
throws ParseException {
Algorithm alg = parseAlgorithm(json);
if (alg.equals(Algorithm.NONE))
return PlainHeader.parse(json);
else if (alg instanceof JWSAlgorithm)
return JWSHeader.parse(json);
else if (alg instanceof JWEAlgorithm)
return JWEHeader.parse(json);
else
throw new AssertionError("Unexpected algorithm type: " + alg);
}
}