001package com.nimbusds.jose.jwk;
002
003
004import java.util.*;
005
006import com.nimbusds.jose.Algorithm;
007
008
009/**
010 * Utility for selecting one or more JSON Web Keys (JWKs) from a JWK set.
011 *
012 * <p>Supports key selection by:
013 *
014 * <ul>
015 *     <li>Any, unspecified, one or more key types (typ).
016 *     <li>Any, unspecified, one or more key uses (use).
017 *     <li>Any, unspecified, one or more key operations (key_ops).
018 *     <li>Any, unspecified, one or more key algorithms (alg).
019 *     <li>Any, unspecified, one or more key identifiers (kid).
020 *     <li>Private only key.
021 *     <li>Public only key.
022 * </ul>
023 *
024 * <p>Selection by X.509 certificate URL, thumbprint and chain is not
025 * supported.
026 *
027 * @author Vladimir Dzhuvinov
028 * @version $version$ (2014-04-03)
029 */
030public class JWKSelector {
031
032
033        /**
034         * The selected key types.
035         */
036        private Set<KeyType> types;
037
038
039        /**
040         * The selected public key uses.
041         */
042        private Set<KeyUse> uses;
043
044
045        /**
046         * The selected key operations.
047         */
048        private Set<KeyOperation> ops;
049
050
051        /**
052         * The selected algorithms.
053         */
054        private Set<Algorithm> algs;
055
056
057        /**
058         * The selected key IDs.
059         */
060        private Set<String> ids;
061
062
063        /**
064         * If {@code true} only private keys are matched.
065         */
066        private boolean privateOnly = false;
067
068
069        /**
070         * If {@code true} only public keys are matched.
071         */
072        private boolean publicOnly = false;
073
074
075        /**
076         * Gets the selected key types.
077         *
078         * @return The key types, {@code null} if not specified.
079         */
080        public Set<KeyType> getKeyTypes() {
081
082                return types;
083        }
084
085
086        /**
087         * Sets a single selected key type.
088         *
089         * @param kty The key type, {@code null} if not specified.
090         */
091        public void setKeyType(final KeyType kty) {
092
093                if (kty == null) {
094                        types = null;
095                } else {
096                        types = new HashSet<>(Arrays.asList(kty));
097                }
098        }
099
100
101        /**
102         * Sets the selected key types.
103         *
104         * @param types The key types.
105         */
106        public void setKeyTypes(final KeyType ... types) {
107
108                setKeyTypes(new HashSet<>(Arrays.asList(types)));
109        }
110
111
112        /**
113         * Sets the selected key types.
114         *
115         * @param types The key types, {@code null} if not specified.
116         */
117        public void setKeyTypes(final Set<KeyType> types) {
118
119                this.types = types;
120        }
121
122
123        /**
124         * Gets the selected public key uses.
125         *
126         * @return The public key uses, {@code null} if not specified.
127         */
128        public Set<KeyUse> getKeyUses() {
129
130                return uses;
131        }
132
133
134        /**
135         * Sets a single selected public key use.
136         *
137         * @param use The public key use, {@code null} if not specified.
138         */
139        public void setKeyUse(final KeyUse use) {
140
141                if (use == null) {
142                        uses = null;
143                } else {
144                        uses = new HashSet<>(Arrays.asList(use));
145                }
146        }
147
148
149        /**
150         * Sets the selected public key uses.
151         *
152         * @param uses The public key uses.
153         */
154        public void setKeyUses(final KeyUse... uses) {
155
156                setKeyUses(new HashSet<>(Arrays.asList(uses)));
157        }
158
159
160        /**
161         * Sets the selected public key uses.
162         *
163         * @param uses The public key uses, {@code null} if not specified.
164         */
165        public void setKeyUses(final Set<KeyUse> uses) {
166
167                this.uses = uses;
168        }
169
170
171        /**
172         * Gets the selected key operations.
173         *
174         * @return The key operations, {@code null} if not specified.
175         */
176        public Set<KeyOperation> getKeyOperations() {
177
178                return ops;
179        }
180
181
182        /**
183         * Sets a single selected key operation.
184         *
185         * @param op The key operation, {@code null} if not specified.
186         */
187        public void setKeyOperation(final KeyOperation op) {
188
189                if (op == null) {
190                        ops = null;
191                } else {
192                        ops = new HashSet<>(Arrays.asList(op));
193                }
194        }
195
196
197        /**
198         * Sets the selected key operations.
199         *
200         * @param ops The key operations.
201         */
202        public void setKeyOperations(final KeyOperation... ops) {
203
204                setKeyOperations(new HashSet<>(Arrays.asList(ops)));
205        }
206
207
208        /**
209         * Sets the selected key operations.
210         *
211         * @param ops The key operations, {@code null} if not specified.
212         */
213        public void setKeyOperations(final Set<KeyOperation> ops) {
214
215                this.ops = ops;
216        }
217
218
219        /**
220         * Gets the selected JOSE algorithms.
221         *
222         * @return The JOSE algorithms, {@code null} if not specified.
223         */
224        public Set<Algorithm> getAlgorithms() {
225
226                return algs;
227        }
228
229
230        /**
231         * Sets a singled selected JOSE algorithm.
232         *
233         * @param alg The JOSE algorithm, {@code null} if not specified.
234         */
235        public void setAlgorithm(final Algorithm alg) {
236
237                if (alg == null) {
238                        algs = null;
239                } else {
240                        algs = new HashSet<>(Arrays.asList(alg));
241                }
242        }
243
244
245        /**
246         * Sets the selected JOSE algorithms.
247         *
248         * @param algs The JOSE algorithms.
249         */
250        public void setAlgorithms(final Algorithm ... algs) {
251
252                setAlgorithms(new HashSet<>(Arrays.asList(algs)));
253        }
254
255
256        /**
257         * Sets the selected JOSE algorithms.
258         *
259         * @param algs The JOSE algorithms, {@code null} if not specified.
260         */
261        public void setAlgorithms(final Set<Algorithm> algs) {
262
263                this.algs = algs;
264        }
265
266
267        /**
268         * Gets the selected key IDs.
269         *
270         * @return The key IDs, {@code null} if not specified.
271         */
272        public Set<String> getKeyIDs() {
273
274                return ids;
275        }
276
277
278        /**
279         * Sets the selected key IDs.
280         *
281         * @param ids The key IDs.
282         */
283        public void setKeyIDs(final String ... ids) {
284
285                setKeyIDs(new HashSet<>(Arrays.asList(ids)));
286        }
287
288
289        /**
290         * Sets the selected key IDs.
291         *
292         * @param ids The key IDs, {@code null} if not specified.
293         */
294        public void setKeyIDs(final Set<String> ids) {
295
296                this.ids = ids;
297        }
298
299
300        /**
301         * Sets a single selected key ID.
302         *
303         * @param id The key ID, {@code null} if not specified.
304         */
305        public void setKeyID(final String id) {
306
307                if (id == null) {
308                        ids = null;
309                } else {
310                        ids = new HashSet<>(Arrays.asList(id));
311                }
312        }
313
314
315        /**
316         * Gets the selection of private keys.
317         *
318         * @return If {@code true} only private keys are selected.
319         */
320        public boolean isPrivateOnly() {
321
322                return privateOnly;
323        }
324
325
326        /**
327         * Sets the selection of private keys.
328         *
329         * @param privateOnly If {@code true} only private keys are selected.
330         */
331        public void setPrivateOnly(final boolean privateOnly) {
332
333                this.privateOnly = privateOnly;
334        }
335
336
337        /**
338         * Gets the selection of public keys.
339         *
340         * @return  If {@code true} only public keys are selected.
341         */
342        public boolean isPublicOnly() {
343
344                return publicOnly;
345        }
346
347
348        /**
349         * Sets the selection of public keys.
350         *
351         * @param publicOnly  If {@code true} only public keys are selected.
352         */
353        public void setPublicOnly(final boolean publicOnly) {
354
355                this.publicOnly = publicOnly;
356        }
357
358
359        /**
360         * Selects the keys from the specified JWK set that match the
361         * configured criteria.
362         *
363         * @param jwkSet The JWK set. May be {@code null}.
364         *
365         * @return The selected keys, ordered by their position in the JWK set,
366         *         empty list if none were matched or the JWK is {@code null}.
367         *
368         */
369        public List<JWK> select(final JWKSet jwkSet) {
370
371                List<JWK> matches = new LinkedList<>();
372
373                if (jwkSet == null)
374                        return matches;
375
376                for (JWK key: jwkSet.getKeys()) {
377
378                        if (privateOnly && ! key.isPrivate())
379                                continue;
380
381                        if (publicOnly && key.isPrivate())
382                                continue;
383
384                        if (types != null && ! types.contains(key.getKeyType()))
385                                continue;
386
387                        if (uses != null && ! uses.contains(key.getKeyUse()))
388                                continue;
389
390                        if (ops != null) {
391
392                                if (ops.contains(null) && key.getKeyOperations() == null) {
393                                        // pass
394                                } else if (key.getKeyOperations() != null && ops.containsAll(key.getKeyOperations())) {
395                                        // pass
396                                } else {
397                                        continue;
398                                }
399                        }
400
401                        if (algs != null && ! algs.contains(key.getAlgorithm()))
402                                continue;
403
404                        if (ids != null && ! ids.contains(key.getKeyID()))
405                                continue;
406
407                        matches.add(key);
408                }
409
410                return matches;
411        }
412}