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