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}