001    package com.nimbusds.jose;
002    
003    
004    import java.text.ParseException;
005    
006    import java.util.Collections;
007    import java.util.HashSet;
008    import java.util.Set;
009    
010    import net.minidev.json.JSONObject;
011    
012    import com.nimbusds.jose.util.Base64URL;
013    import com.nimbusds.jose.util.JSONObjectUtils;
014    
015    
016    /**
017     * Plaintext JOSE header.
018     *
019     * <p>Supports all {@link #getReservedParameterNames reserved header parameters}
020     * of the plain specification:
021     *
022     * <ul>
023     *     <li>alg (set to {@link Algorithm#NONE "none"}).
024     *     <li>typ
025     *     <li>cty
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-01-08)
041     */
042    public 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                    
061                    RESERVED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
062            }
063            
064            
065            /**
066             * Creates a new plain header with algorithm 
067             * {@link Algorithm#NONE none}.
068             */
069            public PlainHeader() {
070            
071                    super(Algorithm.NONE);
072            }
073            
074            
075            /**
076             * Gets the reserved parameter names for plain headers.
077             *
078             * @return The reserved parameter names, as an unmodifiable set.
079             */
080            public static Set<String> getReservedParameterNames() {
081            
082                    return RESERVED_PARAMETER_NAMES;
083            }
084            
085            
086            @Override
087            public Algorithm getAlgorithm() {
088            
089                    return alg;
090            }
091            
092            
093            /**
094             * @throws IllegalArgumentException If the specified parameter name
095             *                                  matches a reserved parameter name.
096             */
097            @Override
098            public void setCustomParameter(final String name, final Object value) {
099            
100                    if (getReservedParameterNames().contains(name))
101                            throw new IllegalArgumentException("The parameter name \"" + name + "\" matches a reserved name");
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                    if (getContentType() != null)
119                            includedParameters.add("cty");
120                    
121                    return includedParameters;
122            }
123            
124            
125            /**
126             * Parses a plain header from the specified JSON object.
127             *
128             * @param json The JSON object to parse. Must not be {@code null}.
129             *
130             * @return The plain header.
131             *
132             * @throws ParseException If the specified JSON object doesn't represent
133             *                        a valid plain header.
134             */
135            public static PlainHeader parse(final JSONObject json)
136                    throws ParseException {
137                    
138                    // Get the "alg" parameter
139                    Algorithm alg = Header.parseAlgorithm(json);
140                    
141                    if (alg != Algorithm.NONE)
142                            throw new ParseException("The algorithm \"alg\" header parameter must be \"none\"", 0);
143                            
144                    
145                    // Create a minimal header, type may be set later
146                    PlainHeader h = new PlainHeader();
147                    
148                    
149                    // Parse optional + custom parameters
150                    for(final String name: json.keySet()) {
151                                    
152                            if (name.equals("alg"))
153                                    continue; // skip
154                                    
155                            else if (name.equals("typ"))
156                                    h.setType(new JOSEObjectType(JSONObjectUtils.getString(json, name)));
157                                    
158                            else if (name.equals("cty"))
159                                    h.setContentType(JSONObjectUtils.getString(json, name));
160                                    
161                            else
162                                    h.setCustomParameter(name, json.get(name));
163                    }
164                    
165                    return h;
166            }
167            
168            
169            /**
170             * Parses a plain header from the specified JSON string.
171             *
172             * @param s The JSON string to parse. Must not be {@code null}.
173             *
174             * @return The plain header.
175             *
176             * @throws ParseException If the specified JSON string doesn't 
177             *                        represent a valid plain header.
178             */
179            public static PlainHeader parse(final String s)
180                    throws ParseException {
181                    
182                    JSONObject jsonObject = JSONObjectUtils.parseJSONObject(s);
183                    
184                    return parse(jsonObject);
185            }
186            
187            
188            /**
189             * Parses a plain header from the specified Base64URL.
190             *
191             * @param base64URL The Base64URL to parse. Must not be {@code null}.
192             *
193             * @return The plain header.
194             *
195             * @throws ParseException If the specified Base64URL doesn't represent a
196             *                        valid plain header.
197             */
198            public static PlainHeader parse(final Base64URL base64URL)
199                    throws ParseException {
200                    
201                    if (base64URL == null)
202                            throw new ParseException("The Base64URL must not be null", 0);
203                            
204                    return parse(base64URL.decodeToString());
205            }
206    }