001    package com.nimbusds.jose;
002    
003    
004    import java.text.ParseException;
005    import java.util.Collections;
006    import java.util.HashSet;
007    import java.util.Set;
008    
009    import net.minidev.json.JSONObject;
010    
011    import com.nimbusds.jose.util.Base64URL;
012    import 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-04-15)
040     */
041    public 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                    PlainHeader header = parse(base64URL.decodeToString());
207                    header.setParsedBase64URL(base64URL);
208                    return header;
209            }
210    }