001package com.nimbusds.jose; 002 003 004import java.text.ParseException; 005import java.util.Collections; 006import java.util.HashSet; 007import java.util.Set; 008 009import net.minidev.json.JSONObject; 010 011import com.nimbusds.jose.util.Base64URL; 012import com.nimbusds.jose.util.JSONObjectUtils; 013 014 015/** 016 * Plaintext JOSE header. 017 * 018 * <p>Supports all {@link #getReservedParameterNames reserved header parameters} 019 * of the plain specification: 020 * 021 * <ul> 022 * <li>alg (set to {@link Algorithm#NONE "none"}). 023 * <li>typ 024 * <li>cty 025 * <li>crit 026 * </ul> 027 * 028 * <p>The header may also carry {@link #setCustomParameters custom parameters}; 029 * these will be serialised and parsed along the reserved ones. 030 * 031 * <p>Example: 032 * 033 * <pre> 034 * { 035 * "alg" : "none" 036 * } 037 * </pre> 038 * 039 * @author Vladimir Dzhuvinov 040 * @version $version$ (2013-05-07) 041 */ 042public class PlainHeader extends Header implements ReadOnlyPlainHeader { 043 044 045 /** 046 * The reserved parameter names. 047 */ 048 private static final Set<String> RESERVED_PARAMETER_NAMES; 049 050 051 /** 052 * Initialises the reserved parameter name set. 053 */ 054 static { 055 Set<String> p = new HashSet<String>(); 056 057 p.add("alg"); 058 p.add("typ"); 059 p.add("cty"); 060 p.add("crit"); 061 062 RESERVED_PARAMETER_NAMES = Collections.unmodifiableSet(p); 063 } 064 065 066 /** 067 * Creates a new plain header with algorithm 068 * {@link Algorithm#NONE none}. 069 */ 070 public PlainHeader() { 071 072 super(Algorithm.NONE); 073 } 074 075 076 /** 077 * Gets the reserved parameter names for plain headers. 078 * 079 * @return The reserved parameter names, as an unmodifiable set. 080 */ 081 public static Set<String> getReservedParameterNames() { 082 083 return RESERVED_PARAMETER_NAMES; 084 } 085 086 087 @Override 088 public Algorithm getAlgorithm() { 089 090 return alg; 091 } 092 093 094 /** 095 * @throws IllegalArgumentException If the specified parameter name 096 * matches a reserved parameter name. 097 */ 098 @Override 099 public void setCustomParameter(final String name, final Object value) { 100 101 if (getReservedParameterNames().contains(name)) { 102 throw new IllegalArgumentException("The parameter name \"" + name + "\" matches a reserved name"); 103 } 104 105 super.setCustomParameter(name, value); 106 } 107 108 109 @Override 110 public Set<String> getIncludedParameters() { 111 112 Set<String> includedParameters = 113 new HashSet<String>(getCustomParameters().keySet()); 114 115 includedParameters.add("alg"); 116 117 if (getType() != null) { 118 includedParameters.add("typ"); 119 } 120 121 if (getContentType() != null) { 122 includedParameters.add("cty"); 123 } 124 125 if (getCriticalHeaders() != null && ! getCriticalHeaders().isEmpty()) { 126 includedParameters.add("crit"); 127 } 128 129 return includedParameters; 130 } 131 132 133 /** 134 * Parses a plain header from the specified JSON object. 135 * 136 * @param json The JSON object to parse. Must not be {@code null}. 137 * 138 * @return The plain header. 139 * 140 * @throws ParseException If the specified JSON object doesn't represent 141 * a valid plain header. 142 */ 143 public static PlainHeader parse(final JSONObject json) 144 throws ParseException { 145 146 // Get the "alg" parameter 147 Algorithm alg = Header.parseAlgorithm(json); 148 149 if (alg != Algorithm.NONE) { 150 throw new ParseException("The algorithm \"alg\" header parameter must be \"none\"", 0); 151 } 152 153 154 // Create a minimal header, type may be set later 155 PlainHeader h = new PlainHeader(); 156 157 158 // Parse optional + custom parameters 159 for(final String name: json.keySet()) { 160 161 if (name.equals("alg")) { 162 continue; // skip 163 } else if (name.equals("typ")) { 164 h.setType(new JOSEObjectType(JSONObjectUtils.getString(json, name))); 165 } else if (name.equals("cty")) { 166 h.setContentType(JSONObjectUtils.getString(json, name)); 167 } else if (name.equals("crit")) { 168 h.setCriticalHeaders(new HashSet<String>(JSONObjectUtils.getStringList(json, name))); 169 } else { 170 h.setCustomParameter(name, json.get(name)); 171 } 172 } 173 174 return h; 175 } 176 177 178 /** 179 * Parses a plain header from the specified JSON string. 180 * 181 * @param s The JSON string to parse. Must not be {@code null}. 182 * 183 * @return The plain header. 184 * 185 * @throws ParseException If the specified JSON string doesn't 186 * represent a valid plain header. 187 */ 188 public static PlainHeader parse(final String s) 189 throws ParseException { 190 191 JSONObject jsonObject = JSONObjectUtils.parseJSONObject(s); 192 193 return parse(jsonObject); 194 } 195 196 197 /** 198 * Parses a plain header from the specified Base64URL. 199 * 200 * @param base64URL The Base64URL to parse. Must not be {@code null}. 201 * 202 * @return The plain header. 203 * 204 * @throws ParseException If the specified Base64URL doesn't represent a 205 * valid plain header. 206 */ 207 public static PlainHeader parse(final Base64URL base64URL) 208 throws ParseException { 209 210 if (base64URL == null) { 211 throw new ParseException("The Base64URL must not be null", 0); 212 } 213 214 PlainHeader header = parse(base64URL.decodeToString()); 215 header.setParsedBase64URL(base64URL); 216 return header; 217 } 218}