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 #getRegisteredParameterNames registered header 019 * parameters} 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 registered ones. 030 * 031 * <p>Example: 032 * 033 * <pre> 034 * { 035 * "alg" : "none" 036 * } 037 * </pre> 038 * 039 * @author Vladimir Dzhuvinov 040 * @version $version$ (2013-10-07) 041 */ 042public class PlainHeader extends Header implements ReadOnlyPlainHeader { 043 044 045 /** 046 * The registered parameter names. 047 */ 048 private static final Set<String> REGISTERED_PARAMETER_NAMES; 049 050 051 /** 052 * Initialises the registered 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 REGISTERED_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 registered parameter names for plain headers. 078 * 079 * @return The registered parameter names, as an unmodifiable set. 080 */ 081 public static Set<String> getRegisteredParameterNames() { 082 083 return REGISTERED_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 registered parameter 097 * name. 098 */ 099 @Override 100 public void setCustomParameter(final String name, final Object value) { 101 102 if (getRegisteredParameterNames().contains(name)) { 103 throw new IllegalArgumentException("The parameter name \"" + name + "\" matches a registered name"); 104 } 105 106 super.setCustomParameter(name, value); 107 } 108 109 110 @Override 111 public Set<String> getIncludedParameters() { 112 113 Set<String> includedParameters = 114 new HashSet<String>(getCustomParameters().keySet()); 115 116 includedParameters.add("alg"); 117 118 if (getType() != null) { 119 includedParameters.add("typ"); 120 } 121 122 if (getContentType() != null) { 123 includedParameters.add("cty"); 124 } 125 126 if (getCriticalHeaders() != null && ! getCriticalHeaders().isEmpty()) { 127 includedParameters.add("crit"); 128 } 129 130 return includedParameters; 131 } 132 133 134 /** 135 * Parses a plain header from the specified JSON object. 136 * 137 * @param json The JSON object to parse. Must not be {@code null}. 138 * 139 * @return The plain header. 140 * 141 * @throws ParseException If the specified JSON object doesn't 142 * represent a valid plain header. 143 */ 144 public static PlainHeader parse(final JSONObject json) 145 throws ParseException { 146 147 // Get the "alg" parameter 148 Algorithm alg = Header.parseAlgorithm(json); 149 150 if (alg != Algorithm.NONE) { 151 throw new ParseException("The algorithm \"alg\" header parameter must be \"none\"", 0); 152 } 153 154 155 // Create a minimal header, type may be set later 156 PlainHeader h = new PlainHeader(); 157 158 159 // Parse optional + custom parameters 160 for(final String name: json.keySet()) { 161 162 if (name.equals("alg")) { 163 continue; // skip 164 } else if (name.equals("typ")) { 165 h.setType(new JOSEObjectType(JSONObjectUtils.getString(json, name))); 166 } else if (name.equals("cty")) { 167 h.setContentType(JSONObjectUtils.getString(json, name)); 168 } else if (name.equals("crit")) { 169 h.setCriticalHeaders(new HashSet<String>(JSONObjectUtils.getStringList(json, name))); 170 } else { 171 h.setCustomParameter(name, json.get(name)); 172 } 173 } 174 175 return h; 176 } 177 178 179 /** 180 * Parses a plain header from the specified JSON string. 181 * 182 * @param s The JSON string to parse. Must not be {@code null}. 183 * 184 * @return The plain header. 185 * 186 * @throws ParseException If the specified JSON string doesn't 187 * represent a valid plain header. 188 */ 189 public static PlainHeader parse(final String s) 190 throws ParseException { 191 192 JSONObject jsonObject = JSONObjectUtils.parseJSONObject(s); 193 194 return parse(jsonObject); 195 } 196 197 198 /** 199 * Parses a plain header from the specified Base64URL. 200 * 201 * @param base64URL The Base64URL to parse. Must not be {@code null}. 202 * 203 * @return The plain header. 204 * 205 * @throws ParseException If the specified Base64URL doesn't represent 206 * a valid plain header. 207 */ 208 public static PlainHeader parse(final Base64URL base64URL) 209 throws ParseException { 210 211 if (base64URL == null) { 212 throw new ParseException("The Base64URL must not be null", 0); 213 } 214 215 PlainHeader header = parse(base64URL.decodeToString()); 216 header.setParsedBase64URL(base64URL); 217 return header; 218 } 219}