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