001package com.nimbusds.openid.connect.sdk.rp;
002
003
004import java.net.URI;
005import java.net.URISyntaxException;
006import java.util.*;
007
008import com.nimbusds.jose.EncryptionMethod;
009import com.nimbusds.jose.JWEAlgorithm;
010import com.nimbusds.jose.JWSAlgorithm;
011import com.nimbusds.oauth2.sdk.ParseException;
012import com.nimbusds.oauth2.sdk.client.ClientMetadata;
013import com.nimbusds.oauth2.sdk.client.RegistrationError;
014import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
015import com.nimbusds.openid.connect.sdk.SubjectType;
016import com.nimbusds.openid.connect.sdk.claims.ACR;
017import com.nimbusds.openid.connect.sdk.id.SectorID;
018import net.minidev.json.JSONArray;
019import net.minidev.json.JSONObject;
020import org.apache.commons.collections.CollectionUtils;
021
022
023/**
024 * OpenID Connect client metadata.
025 *
026 * <p>Related specifications:
027 *
028 * <ul>
029 *     <li>OpenID Connect Dynamic Client Registration 1.0, section 2.
030 *     <li>OpenID Connect Session Management 1.0, section 5.1.1.
031 *     <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591), section
032 *         2.
033 * </ul>
034 */
035public class OIDCClientMetadata extends ClientMetadata {
036
037
038        /**
039         * The registered parameter names.
040         */
041        private static final Set<String> REGISTERED_PARAMETER_NAMES;
042
043
044        /**
045         * Initialises the registered parameter name set.
046         */
047        static {
048                // Start with the base OAuth 2.0 client params
049                Set<String> p = new HashSet<>(ClientMetadata.getRegisteredParameterNames());
050
051                // OIDC params
052                p.add("application_type");
053                p.add("subject_type");
054                p.add("sector_identifier_uri");
055                p.add("request_uris");
056                p.add("request_object_signing_alg");
057                p.add("request_object_encryption_alg");
058                p.add("request_object_encryption_enc");
059                p.add("id_token_signed_response_alg");
060                p.add("id_token_encrypted_response_alg");
061                p.add("id_token_encrypted_response_enc");
062                p.add("userinfo_signed_response_alg");
063                p.add("userinfo_encrypted_response_alg");
064                p.add("userinfo_encrypted_response_enc");
065                p.add("default_max_age");
066                p.add("require_auth_time");
067                p.add("default_acr_values");
068                p.add("initiate_login_uri");
069
070                // OIDC session
071                p.add("post_logout_redirect_uris");
072
073                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
074        }
075
076
077        /**
078         * The client application type.
079         */
080        private ApplicationType applicationType;
081
082
083        /**
084         * The subject identifier type for responses to this client.
085         */
086        private SubjectType subjectType;
087
088
089        /**
090         * Sector identifier URI.
091         */
092        private URI sectorIDURI;
093        
094        
095        /**
096         * Pre-registered OpenID Connect request URIs.
097         */
098        private Set<URI> requestObjectURIs;
099
100
101        /**
102         * The JSON Web Signature (JWS) algorithm required for the OpenID 
103         * Connect request objects sent by this client.
104         */
105        private JWSAlgorithm requestObjectJWSAlg;
106
107
108        /**
109         * The JSON Web Encryption (JWE) algorithm required for the OpenID
110         * Connect request objects sent by this client.
111         */
112        private JWEAlgorithm requestObjectJWEAlg;
113
114
115        /**
116         * The JSON Web Encryption (JWE) method required for the OpenID Connect
117         * request objects sent by this client.
118         */
119        private EncryptionMethod requestObjectJWEEnc;
120
121
122        /**
123         * The JSON Web Signature (JWS) algorithm required for the ID Tokens
124         * issued to this client.
125         */
126        private JWSAlgorithm idTokenJWSAlg;
127
128
129        /**
130         * The JSON Web Encryption (JWE) algorithm required for the ID Tokens
131         * issued to this client.
132         */
133        private JWEAlgorithm idTokenJWEAlg;
134
135
136        /**
137         * The JSON Web Encryption (JWE) method required for the ID Tokens
138         * issued to this client.
139         */
140        private EncryptionMethod idTokenJWEEnc;
141
142
143        /**
144         * The JSON Web Signature (JWS) algorithm required for the UserInfo
145         * responses to this client.
146         */
147        private JWSAlgorithm userInfoJWSAlg;
148
149
150        /**
151         * The JSON Web Encryption (JWE) algorithm required for the UserInfo
152         * responses to this client.
153         */
154        private JWEAlgorithm userInfoJWEAlg;
155
156
157        /**
158         * The JSON Web Encryption (JWE) method required for the UserInfo
159         * responses to this client.
160         */
161        private EncryptionMethod userInfoJWEEnc;
162
163
164        /**
165         * The default max authentication age, in seconds. If not specified 0.
166         */
167        private int defaultMaxAge;
168
169
170        /**
171         * If {@code true} the {@code auth_time} claim in the ID Token is
172         * required by default.
173         */
174        private boolean requiresAuthTime;
175
176
177        /**
178         * The default Authentication Context Class Reference (ACR) values, by
179         * order of preference.
180         */
181        private List<ACR> defaultACRs;
182
183
184        /**
185         * Authorisation server initiated login HTTPS URI.
186         */
187        private URI initiateLoginURI;
188
189
190        /**
191         * Logout redirection URIs.
192         */
193        private Set<URI> postLogoutRedirectURIs;
194
195
196        /** 
197         * Creates a new OpenID Connect client metadata instance.
198         */
199        public OIDCClientMetadata() {
200
201                super();
202        }
203        
204        
205        /**
206         * Creates a new OpenID Connect client metadata instance from the
207         * specified base OAuth 2.0 client metadata.
208         * 
209         * @param metadata The base OAuth 2.0 client metadata. Must not be
210         *                 {@code null}.
211         */
212        public OIDCClientMetadata(final ClientMetadata metadata) {
213                
214                super(metadata);
215        }
216
217
218        /**
219         * Gets the registered (standard) OpenID Connect client metadata
220         * parameter names.
221         *
222         * @return The registered OpenID Connect parameter names, as an
223         *         unmodifiable set.
224         */
225        public static Set<String> getRegisteredParameterNames() {
226
227                return REGISTERED_PARAMETER_NAMES;
228        }
229
230
231        /**
232         * Gets the client application type. Corresponds to the
233         * {@code application_type} client metadata field.
234         *
235         * @return The client application type, {@code null} if not specified.
236         */
237        public ApplicationType getApplicationType() {
238
239                return applicationType;
240        }
241
242
243        /**
244         * Sets the client application type. Corresponds to the
245         * {@code application_type} client metadata field.
246         *
247         * @param applicationType The client application type, {@code null} if
248         *                        not specified.
249         */
250        public void setApplicationType(final ApplicationType applicationType) {
251
252                this.applicationType = applicationType;
253        }
254
255
256        /**
257         * Gets the subject identifier type for responses to this client. 
258         * Corresponds to the {@code subject_type} client metadata field.
259         *
260         * @return The subject identifier type, {@code null} if not specified.
261         */
262        public SubjectType getSubjectType() {
263
264                return subjectType;
265        }
266
267
268        /**
269         * Sets the subject identifier type for responses to this client. 
270         * Corresponds to the {@code subject_type} client metadata field.
271         *
272         * @param subjectType The subject identifier type, {@code null} if not 
273         *                    specified.
274         */
275        public void setSubjectType(final SubjectType subjectType) {
276
277                this.subjectType = subjectType;
278        }
279
280
281        /**
282         * Gets the sector identifier URI. Corresponds to the 
283         * {@code sector_identifier_uri} client metadata field.
284         *
285         * @return The sector identifier URI, {@code null} if not specified.
286         */
287        public URI getSectorIDURI() {
288
289                return sectorIDURI;
290        }
291
292
293        /**
294         * Sets the sector identifier URI. Corresponds to the 
295         * {@code sector_identifier_uri} client metadata field.
296         *
297         * @param sectorIDURI The sector identifier URI, {@code null} if not 
298         *                    specified.
299         */
300        public void setSectorIDURI(final URI sectorIDURI) {
301
302                if (sectorIDURI != null) {
303                        SectorID.ensureHTTPScheme(sectorIDURI);
304                        SectorID.ensureHostComponent(sectorIDURI);
305                }
306
307                this.sectorIDURI = sectorIDURI;
308        }
309
310
311        /**
312         * Resolves the sector identifier from the client metadata.
313         *
314         * @return The sector identifier, {@code null} if the subject type is
315         *         set to public.
316         *
317         * @throws IllegalStateException If resolution failed due to incomplete
318         *                               or inconsistent metadata.
319         */
320        public SectorID resolveSectorID() {
321
322                if (! SubjectType.PAIRWISE.equals(getSubjectType())) {
323                        // subject type is not pairwise or null
324                        return null;
325                }
326
327                // Check sector identifier URI first
328                if (getSectorIDURI() != null) {
329                        return new SectorID(getSectorIDURI());
330                }
331
332                // Check redirect URIs second
333                if (CollectionUtils.isEmpty(getRedirectionURIs())) {
334                        throw new IllegalStateException("Couldn't resolve sector ID: Missing redirect_uris");
335                }
336
337                if (getRedirectionURIs().size() > 1) {
338                        throw new IllegalStateException("Couldn't resolve sector ID: More than one redirect_uri, sector_identifier_uri not specified");
339                }
340
341                return new SectorID(getRedirectionURIs().iterator().next());
342        }
343        
344        
345        /**
346         * Gets the pre-registered OpenID Connect request object URIs.
347         * Corresponds to the {@code request_uris} client metadata field.
348         * 
349         * @return The request object URIs, {@code null} if not specified.
350         */
351        public Set<URI> getRequestObjectURIs() {
352                
353                return requestObjectURIs;
354        }
355        
356        
357        /**
358         * Sets the pre-registered OpenID Connect request object URIs.
359         * Corresponds to the {@code request_uris} client metadata field.
360         *
361         * @param requestObjectURIs The request object URIs, {@code null} if
362         *                          not specified.
363         */
364        public void setRequestObjectURIs(final Set<URI> requestObjectURIs) {
365
366                this.requestObjectURIs = requestObjectURIs;
367        }
368
369
370        /**
371         * Gets the JSON Web Signature (JWS) algorithm required for the OpenID 
372         * Connect request objects sent by this client. Corresponds to the 
373         * {@code request_object_signing_alg} client metadata field.
374         *
375         * @return The JWS algorithm, {@code null} if not specified.
376         */
377        public JWSAlgorithm getRequestObjectJWSAlg() {
378
379                return requestObjectJWSAlg;
380        }
381
382
383        /**
384         * Sets the JSON Web Signature (JWS) algorithm required for the OpenID 
385         * Connect request objects sent by this client. Corresponds to the 
386         * {@code request_object_signing_alg} client metadata field.
387         *
388         * @param requestObjectJWSAlg The JWS algorithm, {@code null} if not 
389         *                            specified.
390         */
391        public void setRequestObjectJWSAlg(final JWSAlgorithm requestObjectJWSAlg) {
392
393                this.requestObjectJWSAlg = requestObjectJWSAlg;
394        }
395
396
397        /**
398         * Gets the JSON Web Encryption (JWE) algorithm required for the OpenID
399         * Connect request objects sent by this client. Corresponds to the
400         * {@code request_object_encryption_alg} client metadata field.
401         *
402         * @return The JWE algorithm, {@code null} if not specified.
403         */
404        public JWEAlgorithm getRequestObjectJWEAlg() {
405
406                return requestObjectJWEAlg;
407        }
408
409
410        /**
411         * Sets the JSON Web Encryption (JWE) algorithm required for the OpenID
412         * Connect request objects sent by this client. Corresponds to the
413         * {@code request_object_encryption_alg} client metadata field.
414         *
415         * @param requestObjectJWEAlg The JWE algorithm, {@code null} if not
416         *                            specified.
417         */
418        public void setRequestObjectJWEAlg(final JWEAlgorithm requestObjectJWEAlg) {
419
420                this.requestObjectJWEAlg = requestObjectJWEAlg;
421        }
422
423
424        /**
425         * Gets the JSON Web Encryption (JWE) method required for the OpenID
426         * Connect request objects sent by this client. Corresponds to the
427         * {@code request_object_encryption_enc} client metadata field.
428         *
429         * @return The JWE method, {@code null} if not specified.
430         */
431        public EncryptionMethod getRequestObjectJWEEnc() {
432
433                return requestObjectJWEEnc;
434        }
435
436
437        /**
438         * Sets the JSON Web Encryption (JWE) method required for the OpenID
439         * Connect request objects sent by this client. Corresponds to the
440         * {@code request_object_encryption_enc} client metadata field.
441         *
442         * @param requestObjectJWEEnc The JWE method, {@code null} if not
443         *                            specified.
444         */
445        public void setRequestObjectJWEEnc(final EncryptionMethod requestObjectJWEEnc) {
446
447                this.requestObjectJWEEnc = requestObjectJWEEnc;
448        }
449
450
451        /**
452         * Gets the JSON Web Signature (JWS) algorithm required for the ID 
453         * Tokens issued to this client. Corresponds to the 
454         * {@code id_token_signed_response_alg} client metadata field.
455         *
456         * @return The JWS algorithm, {@code null} if not specified.
457         */
458        public JWSAlgorithm getIDTokenJWSAlg() {
459
460                return idTokenJWSAlg;
461        }
462
463
464        /**
465         * Sets the JSON Web Signature (JWS) algorithm required for the ID 
466         * Tokens issued to this client. Corresponds to the 
467         * {@code id_token_signed_response_alg} client metadata field.
468         *
469         * @param idTokenJWSAlg The JWS algorithm, {@code null} if not 
470         *                      specified.
471         */
472        public void setIDTokenJWSAlg(final JWSAlgorithm idTokenJWSAlg) {
473
474                this.idTokenJWSAlg = idTokenJWSAlg;
475        }
476
477
478        /**
479         * Gets the JSON Web Encryption (JWE) algorithm required for the ID 
480         * Tokens issued to this client. Corresponds to the 
481         * {@code id_token_encrypted_response_alg} client metadata field.
482         *
483         * @return The JWE algorithm, {@code null} if not specified.
484         */
485        public JWEAlgorithm getIDTokenJWEAlg() {
486
487                return idTokenJWEAlg;
488        }
489
490
491        /**
492         * Sets the JSON Web Encryption (JWE) algorithm required for the ID 
493         * Tokens issued to this client. Corresponds to the 
494         * {@code id_token_encrypted_response_alg} client metadata field.
495         *
496         * @param idTokenJWEAlg The JWE algorithm, {@code null} if not 
497         *                      specified.
498         */
499        public void setIDTokenJWEAlg(final JWEAlgorithm idTokenJWEAlg) {
500
501                this.idTokenJWEAlg = idTokenJWEAlg;
502        }
503
504
505        /**
506         * Gets the JSON Web Encryption (JWE) method required for the ID Tokens
507         * issued to this client. Corresponds to the 
508         * {@code id_token_encrypted_response_enc} client metadata field.
509         *
510         * @return The JWE method, {@code null} if not specified.
511         */
512        public EncryptionMethod getIDTokenJWEEnc() {
513
514                return idTokenJWEEnc;
515        }
516
517
518        /**
519         * Sets the JSON Web Encryption (JWE) method required for the ID Tokens
520         * issued to this client. Corresponds to the 
521         * {@code id_token_encrypted_response_enc} client metadata field.
522         *
523         * @param idTokenJWEEnc The JWE method, {@code null} if not specified.
524         */
525        public void setIDTokenJWEEnc(final EncryptionMethod idTokenJWEEnc) {
526
527                this.idTokenJWEEnc = idTokenJWEEnc;
528        }
529
530
531        /**
532         * Gets the JSON Web Signature (JWS) algorithm required for the 
533         * UserInfo responses to this client. Corresponds to the 
534         * {@code userinfo_signed_response_alg} client metadata field.
535         *
536         * @return The JWS algorithm, {@code null} if not specified.
537         */
538        public JWSAlgorithm getUserInfoJWSAlg() {
539
540                return userInfoJWSAlg;
541        }
542
543
544        /**
545         * Sets the JSON Web Signature (JWS) algorithm required for the 
546         * UserInfo responses to this client. Corresponds to the
547         * {@code userinfo_signed_response_alg} client metadata field.
548         *
549         * @param userInfoJWSAlg The JWS algorithm, {@code null} if not 
550         *                       specified.
551         */
552        public void setUserInfoJWSAlg(final JWSAlgorithm userInfoJWSAlg) {
553
554                this.userInfoJWSAlg = userInfoJWSAlg;
555        }
556
557
558        /**
559         * Gets the JSON Web Encryption (JWE) algorithm required for the 
560         * UserInfo responses to this client. Corresponds to the 
561         * {@code userinfo_encrypted_response_alg} client metadata field.
562         *
563         * @return The JWE algorithm, {@code null} if not specified.
564         */
565        public JWEAlgorithm getUserInfoJWEAlg() {
566
567                return userInfoJWEAlg;
568        }
569
570
571        /**
572         * Sets the JSON Web Encryption (JWE) algorithm required for the 
573         * UserInfo responses to this client. Corresponds to the 
574         * {@code userinfo_encrypted_response_alg} client metadata field.
575         *
576         * @param userInfoJWEAlg The JWE algorithm, {@code null} if not
577         *                       specified.
578         */
579        public void setUserInfoJWEAlg(final JWEAlgorithm userInfoJWEAlg) {
580
581                this.userInfoJWEAlg = userInfoJWEAlg;
582        }
583
584
585        /**
586         * Gets the JSON Web Encryption (JWE) method required for the UserInfo
587         * responses to this client. Corresponds to the 
588         * {@code userinfo_encrypted_response_enc} client metadata field.
589         *
590         * @return The JWE method, {@code null} if not specified.
591         */
592        public EncryptionMethod getUserInfoJWEEnc() {
593
594                return userInfoJWEEnc;
595        }
596
597
598        /**
599         * Sets the JSON Web Encryption (JWE) method required for the UserInfo
600         * responses to this client. Corresponds to the 
601         * {@code userinfo_encrypted_response_enc} client metadata field.
602         *
603         * @param userInfoJWEEnc The JWE method, {@code null} if not specified.
604         */
605        public void setUserInfoJWEEnc(final EncryptionMethod userInfoJWEEnc) {
606
607                this.userInfoJWEEnc = userInfoJWEEnc;
608        }
609
610
611        /**
612         * Gets the default maximum authentication age. Corresponds to the 
613         * {@code default_max_age} client metadata field.
614         *
615         * @return The default max authentication age, in seconds. If not
616         *         specified 0.
617         */
618        public int getDefaultMaxAge() {
619
620                return defaultMaxAge;
621        }
622
623
624        /**
625         * Sets the default maximum authentication age. Corresponds to the 
626         * {@code default_max_age} client metadata field.
627         *
628         * @param defaultMaxAge The default max authentication age, in seconds.
629         *                      If not specified 0.
630         */
631        public void setDefaultMaxAge(final int defaultMaxAge) {
632
633                this.defaultMaxAge = defaultMaxAge;
634        }
635
636
637        /**
638         * Gets the default requirement for the {@code auth_time} claim in the
639         * ID Token. Corresponds to the {@code require_auth_time} client 
640         * metadata field.
641         *
642         * @return If {@code true} the {@code auth_Time} claim in the ID Token 
643         *         is required by default.
644         */
645        public boolean requiresAuthTime() {
646
647                return requiresAuthTime;
648        }
649
650
651        /**
652         * Sets the default requirement for the {@code auth_time} claim in the
653         * ID Token. Corresponds to the {@code require_auth_time} client 
654         * metadata field.
655         *
656         * @param requiresAuthTime If {@code true} the {@code auth_Time} claim 
657         *                         in the ID Token is required by default.
658         */
659        public void requiresAuthTime(final boolean requiresAuthTime) {
660
661                this.requiresAuthTime = requiresAuthTime;
662        }
663
664
665        /**
666         * Gets the default Authentication Context Class Reference (ACR) 
667         * values. Corresponds to the {@code default_acr_values} client 
668         * metadata field.
669         *
670         * @return The default ACR values, by order of preference, 
671         *         {@code null} if not specified.
672         */
673        public List<ACR> getDefaultACRs() {
674
675                return defaultACRs;
676        }
677
678
679        /**
680         * Sets the default Authentication Context Class Reference (ACR)
681         * values. Corresponds to the {@code default_acr_values} client 
682         * metadata field.
683         *
684         * @param defaultACRs The default ACRs, by order of preference, 
685         *                    {@code null} if not specified.
686         */
687        public void setDefaultACRs(final List<ACR> defaultACRs) {
688
689                this.defaultACRs = defaultACRs;
690        }
691
692
693        /**
694         * Gets the HTTPS URI that the authorisation server can call to
695         * initiate a login at the client. Corresponds to the 
696         * {@code initiate_login_uri} client metadata field.
697         *
698         * @return The login URI, {@code null} if not specified.
699         */
700        public URI getInitiateLoginURI() {
701
702                return initiateLoginURI;
703        }
704
705
706        /**
707         * Sets the HTTPS URI that the authorisation server can call to
708         * initiate a login at the client. Corresponds to the 
709         * {@code initiate_login_uri} client metadata field.
710         *
711         * @param loginURI The login URI, {@code null} if not specified.
712         */
713        public void setInitiateLoginURI(final URI loginURI) {
714
715                this.initiateLoginURI = loginURI;
716        }
717
718
719        /**
720         * Gets the post logout redirection URIs. Corresponds to the
721         * {@code post_logout_redirect_uris} client metadata field.
722         *
723         * @return The logout redirection URIs, {@code null} if not specified.
724         */
725        public Set<URI> getPostLogoutRedirectionURIs() {
726
727                return postLogoutRedirectURIs;
728        }
729
730
731        /**
732         * Sets the post logout redirection URIs. Corresponds to the
733         * {@code post_logout_redirect_uris} client metadata field.
734         *
735         * @param logoutURIs The logout redirection URIs, {@code null} if not
736         *                   specified.
737         */
738        public void setPostLogoutRedirectionURIs(final Set<URI> logoutURIs) {
739
740                postLogoutRedirectURIs = logoutURIs;
741        }
742        
743        
744        /**
745         * Applies the client metadata defaults where no values have been
746         * specified.
747         * 
748         * <ul>
749         *     <li>The response types default to {@code ["code"]}.
750         *     <li>The grant types default to {@code "authorization_code".}
751         *     <li>The client authentication method defaults to
752         *         "client_secret_basic".
753         *     <li>The application type defaults to
754         *         {@link ApplicationType#WEB}.
755         *     <li>The ID token JWS algorithm defaults to "RS256".
756         * </ul>
757         */
758        @Override
759        public void applyDefaults() {
760                
761                super.applyDefaults();
762
763                if (applicationType == null) {
764                        applicationType = ApplicationType.WEB;
765                }
766                
767                if (idTokenJWSAlg == null) {
768                        idTokenJWSAlg = JWSAlgorithm.RS256;
769                }
770        }
771
772
773        @Override
774        public JSONObject toJSONObject() {
775
776                JSONObject o = super.toJSONObject(false);
777
778                o.putAll(getCustomFields());
779
780                if (applicationType != null)
781                        o.put("application_type", applicationType.toString());
782
783                if (subjectType != null)
784                        o.put("subject_type", subjectType.toString());
785
786
787                if (sectorIDURI != null)
788                        o.put("sector_identifier_uri", sectorIDURI.toString());
789                
790                
791                if (requestObjectURIs != null) {
792                        
793                        JSONArray uriList = new JSONArray();
794                        
795                        for (URI uri: requestObjectURIs)
796                                uriList.add(uri.toString());
797                        
798                        o.put("request_uris", uriList);
799                }
800
801
802                if (requestObjectJWSAlg != null)
803                        o.put("request_object_signing_alg", requestObjectJWSAlg.getName());
804
805                if (requestObjectJWEAlg != null)
806                        o.put("request_object_encryption_alg", requestObjectJWEAlg.getName());
807
808                if (requestObjectJWEEnc != null)
809                        o.put("request_object_encryption_enc", requestObjectJWEEnc.getName());
810
811
812                if (idTokenJWSAlg != null)
813                        o.put("id_token_signed_response_alg", idTokenJWSAlg.getName());
814
815
816                if (idTokenJWEAlg != null)
817                        o.put("id_token_encrypted_response_alg", idTokenJWEAlg.getName());
818
819
820                if (idTokenJWEEnc != null)
821                        o.put("id_token_encrypted_response_enc", idTokenJWEEnc.getName());
822
823
824                if (userInfoJWSAlg != null)
825                        o.put("userinfo_signed_response_alg", userInfoJWSAlg.getName());
826
827
828                if (userInfoJWEAlg != null)
829                        o.put("userinfo_encrypted_response_alg", userInfoJWEAlg.getName());
830
831
832                if (userInfoJWEEnc != null)
833                        o.put("userinfo_encrypted_response_enc", userInfoJWEEnc.getName());
834
835
836                if (defaultMaxAge > 0)
837                        o.put("default_max_age", defaultMaxAge);
838
839
840                if (requiresAuthTime())
841                        o.put("require_auth_time", requiresAuthTime);
842
843
844                if (defaultACRs != null) {
845
846                        JSONArray acrList = new JSONArray();
847
848                        for (ACR acr: defaultACRs)
849                                acrList.add(acr);
850
851                        o.put("default_acr_values", acrList);
852                }
853
854
855                if (initiateLoginURI != null)
856                        o.put("initiate_login_uri", initiateLoginURI.toString());
857
858
859                if (postLogoutRedirectURIs != null) {
860
861                        JSONArray uriList = new JSONArray();
862
863                        for (URI uri: postLogoutRedirectURIs)
864                                uriList.add(uri.toString());
865
866                        o.put("post_logout_redirect_uris", uriList);
867                }
868
869                return o;
870        }
871
872
873        /**
874         * Parses an OpenID Connect client metadata instance from the specified
875         * JSON object.
876         *
877         * @param jsonObject The JSON object to parse. Must not be 
878         *                   {@code null}.
879         *
880         * @return The OpenID Connect client metadata.
881         *
882         * @throws ParseException If the JSON object couldn't be parsed to an
883         *                        OpenID Connect client metadata instance.
884         */
885        public static OIDCClientMetadata parse(final JSONObject jsonObject)
886                throws ParseException {
887
888                ClientMetadata baseMetadata = ClientMetadata.parse(jsonObject);
889                
890                OIDCClientMetadata metadata = new OIDCClientMetadata(baseMetadata);
891
892                // Parse the OIDC-specific fields from the custom OAuth 2.0 dyn
893                // reg fields
894
895                JSONObject oidcFields = baseMetadata.getCustomFields();
896
897                try {
898                        if (jsonObject.containsKey("application_type")) {
899                                metadata.setApplicationType(JSONObjectUtils.getEnum(jsonObject, "application_type", ApplicationType.class));
900                                oidcFields.remove("application_type");
901                        }
902
903                        if (jsonObject.containsKey("subject_type")) {
904                                metadata.setSubjectType(JSONObjectUtils.getEnum(jsonObject, "subject_type", SubjectType.class));
905                                oidcFields.remove("subject_type");
906                        }
907
908                        if (jsonObject.containsKey("sector_identifier_uri")) {
909                                metadata.setSectorIDURI(JSONObjectUtils.getURI(jsonObject, "sector_identifier_uri"));
910                                oidcFields.remove("sector_identifier_uri");
911                        }
912
913                        if (jsonObject.containsKey("request_uris")) {
914
915                                Set<URI> requestURIs = new LinkedHashSet<>();
916
917                                for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "request_uris")) {
918
919                                        try {
920                                                requestURIs.add(new URI(uriString));
921
922                                        } catch (URISyntaxException e) {
923
924                                                throw new ParseException("Invalid \"request_uris\" parameter");
925                                        }
926                                }
927
928                                metadata.setRequestObjectURIs(requestURIs);
929                                oidcFields.remove("request_uris");
930                        }
931
932                        if (jsonObject.containsKey("request_object_signing_alg")) {
933                                metadata.setRequestObjectJWSAlg(new JWSAlgorithm(
934                                        JSONObjectUtils.getString(jsonObject, "request_object_signing_alg")));
935
936                                oidcFields.remove("request_object_signing_alg");
937                        }
938
939                        if (jsonObject.containsKey("request_object_encryption_alg")) {
940                                metadata.setRequestObjectJWEAlg(new JWEAlgorithm(
941                                        JSONObjectUtils.getString(jsonObject, "request_object_encryption_alg")));
942
943                                oidcFields.remove("request_object_encryption_alg");
944                        }
945
946                        if (jsonObject.containsKey("request_object_encryption_enc")) {
947                                metadata.setRequestObjectJWEEnc(EncryptionMethod.parse(
948                                        JSONObjectUtils.getString(jsonObject, "request_object_encryption_enc")));
949
950                                oidcFields.remove("request_object_encryption_enc");
951                        }
952
953                        if (jsonObject.containsKey("id_token_signed_response_alg")) {
954                                metadata.setIDTokenJWSAlg(new JWSAlgorithm(
955                                        JSONObjectUtils.getString(jsonObject, "id_token_signed_response_alg")));
956
957                                oidcFields.remove("id_token_signed_response_alg");
958                        }
959
960                        if (jsonObject.containsKey("id_token_encrypted_response_alg")) {
961                                metadata.setIDTokenJWEAlg(new JWEAlgorithm(
962                                        JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_alg")));
963
964                                oidcFields.remove("id_token_encrypted_response_alg");
965                        }
966
967                        if (jsonObject.containsKey("id_token_encrypted_response_enc")) {
968                                metadata.setIDTokenJWEEnc(EncryptionMethod.parse(
969                                        JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_enc")));
970
971                                oidcFields.remove("id_token_encrypted_response_enc");
972                        }
973
974                        if (jsonObject.containsKey("userinfo_signed_response_alg")) {
975                                metadata.setUserInfoJWSAlg(new JWSAlgorithm(
976                                        JSONObjectUtils.getString(jsonObject, "userinfo_signed_response_alg")));
977
978                                oidcFields.remove("userinfo_signed_response_alg");
979                        }
980
981                        if (jsonObject.containsKey("userinfo_encrypted_response_alg")) {
982                                metadata.setUserInfoJWEAlg(new JWEAlgorithm(
983                                        JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_alg")));
984
985                                oidcFields.remove("userinfo_encrypted_response_alg");
986                        }
987
988                        if (jsonObject.containsKey("userinfo_encrypted_response_enc")) {
989                                metadata.setUserInfoJWEEnc(EncryptionMethod.parse(
990                                        JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_enc")));
991
992                                oidcFields.remove("userinfo_encrypted_response_enc");
993                        }
994
995                        if (jsonObject.containsKey("default_max_age")) {
996                                metadata.setDefaultMaxAge(JSONObjectUtils.getInt(jsonObject, "default_max_age"));
997                                oidcFields.remove("default_max_age");
998                        }
999
1000                        if (jsonObject.containsKey("require_auth_time")) {
1001                                metadata.requiresAuthTime(JSONObjectUtils.getBoolean(jsonObject, "require_auth_time"));
1002                                oidcFields.remove("require_auth_time");
1003                        }
1004
1005                        if (jsonObject.containsKey("default_acr_values")) {
1006
1007                                List<ACR> acrValues = new LinkedList<>();
1008
1009                                for (String acrString : JSONObjectUtils.getStringArray(jsonObject, "default_acr_values"))
1010                                        acrValues.add(new ACR(acrString));
1011
1012                                metadata.setDefaultACRs(acrValues);
1013
1014                                oidcFields.remove("default_acr_values");
1015                        }
1016
1017                        if (jsonObject.containsKey("initiate_login_uri")) {
1018                                metadata.setInitiateLoginURI(JSONObjectUtils.getURI(jsonObject, "initiate_login_uri"));
1019                                oidcFields.remove("initiate_login_uri");
1020                        }
1021
1022                        if (jsonObject.containsKey("post_logout_redirect_uris")) {
1023
1024                                Set<URI> logoutURIs = new LinkedHashSet<>();
1025
1026                                for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "post_logout_redirect_uris")) {
1027
1028                                        try {
1029                                                logoutURIs.add(new URI(uriString));
1030
1031                                        } catch (URISyntaxException e) {
1032
1033                                                throw new ParseException("Invalid \"post_logout_redirect_uris\" parameter");
1034                                        }
1035                                }
1036
1037                                metadata.setPostLogoutRedirectionURIs(logoutURIs);
1038                                oidcFields.remove("post_logout_redirect_uris");
1039                        }
1040                } catch (ParseException e) {
1041                        // Insert client_client_metadata error code so that it
1042                        // can be reported back to the client if we have a
1043                        // registration event
1044                        throw new ParseException(e.getMessage(), RegistrationError.INVALID_CLIENT_METADATA.appendDescription(": " + e.getMessage()), e.getCause());
1045                }
1046
1047                // The remaining fields are custom
1048                metadata.setCustomFields(oidcFields);
1049
1050                return metadata;
1051        }
1052}