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 14).
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         * Creates a shallow copy of the specified OpenID Connect client
244         * metadata instance.
245         *
246         * @param metadata The client metadata to copy. Must not be
247         *                 {@code null}.
248         */
249        public OIDCClientMetadata(final OIDCClientMetadata metadata) {
250                
251                super(metadata);
252                applicationType = metadata.getApplicationType();
253                subjectType = metadata.getSubjectType();
254                sectorIDURI = metadata.getSectorIDURI();
255                idTokenJWSAlg = metadata.getIDTokenJWSAlg();
256                idTokenJWEAlg = metadata.getIDTokenJWEAlg();
257                idTokenJWEEnc = metadata.getIDTokenJWEEnc();
258                userInfoJWSAlg = metadata.getUserInfoJWSAlg();
259                userInfoJWEAlg = metadata.getUserInfoJWEAlg();
260                userInfoJWEEnc = metadata.getUserInfoJWEEnc();
261                defaultMaxAge = metadata.getDefaultMaxAge();
262                requiresAuthTime = metadata.requiresAuthTime();
263                defaultACRs = metadata.getDefaultACRs();
264                initiateLoginURI = metadata.getInitiateLoginURI();
265                postLogoutRedirectURIs = metadata.getPostLogoutRedirectionURIs();
266                frontChannelLogoutURI = metadata.getFrontChannelLogoutURI();
267                frontChannelLogoutSessionRequired = metadata.requiresFrontChannelLogoutSession();
268                backChannelLogoutURI = metadata.getBackChannelLogoutURI();
269                backChannelLogoutSessionRequired = metadata.requiresBackChannelLogoutSession();
270        }
271
272
273        /**
274         * Gets the registered (standard) OpenID Connect client metadata
275         * parameter names.
276         *
277         * @return The registered OpenID Connect parameter names, as an
278         *         unmodifiable set.
279         */
280        public static Set<String> getRegisteredParameterNames() {
281
282                return REGISTERED_PARAMETER_NAMES;
283        }
284
285
286        /**
287         * Gets the client application type. Corresponds to the
288         * {@code application_type} client metadata field.
289         *
290         * @return The client application type, {@code null} if not specified.
291         */
292        public ApplicationType getApplicationType() {
293
294                return applicationType;
295        }
296
297
298        /**
299         * Sets the client application type. Corresponds to the
300         * {@code application_type} client metadata field.
301         *
302         * @param applicationType The client application type, {@code null} if
303         *                        not specified.
304         */
305        public void setApplicationType(final ApplicationType applicationType) {
306
307                this.applicationType = applicationType;
308        }
309
310
311        /**
312         * Gets the subject identifier type for responses to this client. 
313         * Corresponds to the {@code subject_type} client metadata field.
314         *
315         * @return The subject identifier type, {@code null} if not specified.
316         */
317        public SubjectType getSubjectType() {
318
319                return subjectType;
320        }
321
322
323        /**
324         * Sets the subject identifier type for responses to this client. 
325         * Corresponds to the {@code subject_type} client metadata field.
326         *
327         * @param subjectType The subject identifier type, {@code null} if not 
328         *                    specified.
329         */
330        public void setSubjectType(final SubjectType subjectType) {
331
332                this.subjectType = subjectType;
333        }
334
335
336        /**
337         * Gets the sector identifier URI. Corresponds to the 
338         * {@code sector_identifier_uri} client metadata field.
339         *
340         * @return The sector identifier URI, {@code null} if not specified.
341         */
342        public URI getSectorIDURI() {
343
344                return sectorIDURI;
345        }
346
347
348        /**
349         * Sets the sector identifier URI. Corresponds to the 
350         * {@code sector_identifier_uri} client metadata field.
351         *
352         * @param sectorIDURI The sector identifier URI, {@code null} if not 
353         *                    specified.
354         */
355        public void setSectorIDURI(final URI sectorIDURI) {
356
357                if (sectorIDURI != null) {
358                        SectorID.ensureHTTPScheme(sectorIDURI);
359                        SectorID.ensureHostComponent(sectorIDURI);
360                }
361
362                this.sectorIDURI = sectorIDURI;
363        }
364
365
366        /**
367         * Resolves the sector identifier from the client metadata.
368         *
369         * @return The sector identifier, {@code null} if the subject type is
370         *         set to public.
371         *
372         * @throws IllegalStateException If resolution failed due to incomplete
373         *                               or inconsistent metadata.
374         */
375        public SectorID resolveSectorID() {
376
377                if (! SubjectType.PAIRWISE.equals(getSubjectType())) {
378                        // subject type is not pairwise or null
379                        return null;
380                }
381
382                // Check sector identifier URI first
383                if (getSectorIDURI() != null) {
384                        return new SectorID(getSectorIDURI());
385                }
386
387                // Check redirect URIs second
388                if (CollectionUtils.isEmpty(getRedirectionURIs())) {
389                        throw new IllegalStateException("Couldn't resolve sector ID: Missing redirect_uris");
390                }
391
392                if (getRedirectionURIs().size() > 1) {
393                        throw new IllegalStateException("Couldn't resolve sector ID: More than one redirect_uri, sector_identifier_uri not specified");
394                }
395
396                return new SectorID(getRedirectionURIs().iterator().next());
397        }
398
399
400        /**
401         * Gets the JSON Web Signature (JWS) algorithm required for the ID 
402         * Tokens issued to this client. Corresponds to the 
403         * {@code id_token_signed_response_alg} client metadata field.
404         *
405         * @return The JWS algorithm, {@code null} if not specified.
406         */
407        public JWSAlgorithm getIDTokenJWSAlg() {
408
409                return idTokenJWSAlg;
410        }
411
412
413        /**
414         * Sets the JSON Web Signature (JWS) algorithm required for the ID 
415         * Tokens issued to this client. Corresponds to the 
416         * {@code id_token_signed_response_alg} client metadata field.
417         *
418         * @param idTokenJWSAlg The JWS algorithm, {@code null} if not 
419         *                      specified.
420         */
421        public void setIDTokenJWSAlg(final JWSAlgorithm idTokenJWSAlg) {
422
423                this.idTokenJWSAlg = idTokenJWSAlg;
424        }
425
426
427        /**
428         * Gets the JSON Web Encryption (JWE) algorithm required for the ID 
429         * Tokens issued to this client. Corresponds to the 
430         * {@code id_token_encrypted_response_alg} client metadata field.
431         *
432         * @return The JWE algorithm, {@code null} if not specified.
433         */
434        public JWEAlgorithm getIDTokenJWEAlg() {
435
436                return idTokenJWEAlg;
437        }
438
439
440        /**
441         * Sets the JSON Web Encryption (JWE) algorithm required for the ID 
442         * Tokens issued to this client. Corresponds to the 
443         * {@code id_token_encrypted_response_alg} client metadata field.
444         *
445         * @param idTokenJWEAlg The JWE algorithm, {@code null} if not 
446         *                      specified.
447         */
448        public void setIDTokenJWEAlg(final JWEAlgorithm idTokenJWEAlg) {
449
450                this.idTokenJWEAlg = idTokenJWEAlg;
451        }
452
453
454        /**
455         * Gets the JSON Web Encryption (JWE) method required for the ID Tokens
456         * issued to this client. Corresponds to the 
457         * {@code id_token_encrypted_response_enc} client metadata field.
458         *
459         * @return The JWE method, {@code null} if not specified.
460         */
461        public EncryptionMethod getIDTokenJWEEnc() {
462
463                return idTokenJWEEnc;
464        }
465
466
467        /**
468         * Sets the JSON Web Encryption (JWE) method required for the ID Tokens
469         * issued to this client. Corresponds to the 
470         * {@code id_token_encrypted_response_enc} client metadata field.
471         *
472         * @param idTokenJWEEnc The JWE method, {@code null} if not specified.
473         */
474        public void setIDTokenJWEEnc(final EncryptionMethod idTokenJWEEnc) {
475
476                this.idTokenJWEEnc = idTokenJWEEnc;
477        }
478
479
480        /**
481         * Gets the JSON Web Signature (JWS) algorithm required for the 
482         * UserInfo responses to this client. Corresponds to the 
483         * {@code userinfo_signed_response_alg} client metadata field.
484         *
485         * @return The JWS algorithm, {@code null} if not specified.
486         */
487        public JWSAlgorithm getUserInfoJWSAlg() {
488
489                return userInfoJWSAlg;
490        }
491
492
493        /**
494         * Sets the JSON Web Signature (JWS) algorithm required for the 
495         * UserInfo responses to this client. Corresponds to the
496         * {@code userinfo_signed_response_alg} client metadata field.
497         *
498         * @param userInfoJWSAlg The JWS algorithm, {@code null} if not 
499         *                       specified.
500         */
501        public void setUserInfoJWSAlg(final JWSAlgorithm userInfoJWSAlg) {
502
503                this.userInfoJWSAlg = userInfoJWSAlg;
504        }
505
506
507        /**
508         * Gets the JSON Web Encryption (JWE) algorithm required for the 
509         * UserInfo responses to this client. Corresponds to the 
510         * {@code userinfo_encrypted_response_alg} client metadata field.
511         *
512         * @return The JWE algorithm, {@code null} if not specified.
513         */
514        public JWEAlgorithm getUserInfoJWEAlg() {
515
516                return userInfoJWEAlg;
517        }
518
519
520        /**
521         * Sets the JSON Web Encryption (JWE) algorithm required for the 
522         * UserInfo responses to this client. Corresponds to the 
523         * {@code userinfo_encrypted_response_alg} client metadata field.
524         *
525         * @param userInfoJWEAlg The JWE algorithm, {@code null} if not
526         *                       specified.
527         */
528        public void setUserInfoJWEAlg(final JWEAlgorithm userInfoJWEAlg) {
529
530                this.userInfoJWEAlg = userInfoJWEAlg;
531        }
532
533
534        /**
535         * Gets the JSON Web Encryption (JWE) method required for the UserInfo
536         * responses to this client. Corresponds to the 
537         * {@code userinfo_encrypted_response_enc} client metadata field.
538         *
539         * @return The JWE method, {@code null} if not specified.
540         */
541        public EncryptionMethod getUserInfoJWEEnc() {
542
543                return userInfoJWEEnc;
544        }
545
546
547        /**
548         * Sets the JSON Web Encryption (JWE) method required for the UserInfo
549         * responses to this client. Corresponds to the 
550         * {@code userinfo_encrypted_response_enc} client metadata field.
551         *
552         * @param userInfoJWEEnc The JWE method, {@code null} if not specified.
553         */
554        public void setUserInfoJWEEnc(final EncryptionMethod userInfoJWEEnc) {
555
556                this.userInfoJWEEnc = userInfoJWEEnc;
557        }
558
559
560        /**
561         * Gets the default maximum authentication age. Corresponds to the 
562         * {@code default_max_age} client metadata field.
563         *
564         * @return The default max authentication age, in seconds. If not
565         *         specified -1.
566         */
567        public int getDefaultMaxAge() {
568
569                return defaultMaxAge;
570        }
571
572
573        /**
574         * Sets the default maximum authentication age. Corresponds to the 
575         * {@code default_max_age} client metadata field.
576         *
577         * @param defaultMaxAge The default max authentication age, in seconds.
578         *                      If not specified -1.
579         */
580        public void setDefaultMaxAge(final int defaultMaxAge) {
581
582                this.defaultMaxAge = defaultMaxAge;
583        }
584
585
586        /**
587         * Gets the default requirement for the {@code auth_time} claim in the
588         * ID Token. Corresponds to the {@code require_auth_time} client 
589         * metadata field.
590         *
591         * @return If {@code true} the {@code auth_Time} claim in the ID Token 
592         *         is required by default.
593         */
594        public boolean requiresAuthTime() {
595
596                return requiresAuthTime;
597        }
598
599
600        /**
601         * Sets the default requirement for the {@code auth_time} claim in the
602         * ID Token. Corresponds to the {@code require_auth_time} client 
603         * metadata field.
604         *
605         * @param requiresAuthTime If {@code true} the {@code auth_Time} claim 
606         *                         in the ID Token is required by default.
607         */
608        public void requiresAuthTime(final boolean requiresAuthTime) {
609
610                this.requiresAuthTime = requiresAuthTime;
611        }
612
613
614        /**
615         * Gets the default Authentication Context Class Reference (ACR) 
616         * values. Corresponds to the {@code default_acr_values} client 
617         * metadata field.
618         *
619         * @return The default ACR values, by order of preference, 
620         *         {@code null} if not specified.
621         */
622        public List<ACR> getDefaultACRs() {
623
624                return defaultACRs;
625        }
626
627
628        /**
629         * Sets the default Authentication Context Class Reference (ACR)
630         * values. Corresponds to the {@code default_acr_values} client 
631         * metadata field.
632         *
633         * @param defaultACRs The default ACRs, by order of preference, 
634         *                    {@code null} if not specified.
635         */
636        public void setDefaultACRs(final List<ACR> defaultACRs) {
637
638                this.defaultACRs = defaultACRs;
639        }
640
641
642        /**
643         * Gets the HTTPS URI that the authorisation server can call to
644         * initiate a login at the client. Corresponds to the 
645         * {@code initiate_login_uri} client metadata field.
646         *
647         * @return The login URI, {@code null} if not specified.
648         */
649        public URI getInitiateLoginURI() {
650
651                return initiateLoginURI;
652        }
653
654
655        /**
656         * Sets the HTTPS URI that the authorisation server can call to
657         * initiate a login at the client. Corresponds to the 
658         * {@code initiate_login_uri} client metadata field.
659         *
660         * @param loginURI The login URI, {@code null} if not specified. The
661         *                 URI scheme must be https.
662         */
663        public void setInitiateLoginURI(final URI loginURI) {
664                
665                URIUtils.ensureSchemeIsHTTPS(loginURI);
666                this.initiateLoginURI = loginURI;
667        }
668
669
670        /**
671         * Gets the post logout redirection URIs. Corresponds to the
672         * {@code post_logout_redirect_uris} client metadata field.
673         *
674         * @return The logout redirection URIs, {@code null} if not specified.
675         */
676        public Set<URI> getPostLogoutRedirectionURIs() {
677
678                return postLogoutRedirectURIs;
679        }
680
681
682        /**
683         * Sets the post logout redirection URIs. Corresponds to the
684         * {@code post_logout_redirect_uris} client metadata field.
685         *
686         * @param logoutURIs The post logout redirection URIs, {@code null} if
687         *                   not specified.
688         */
689        public void setPostLogoutRedirectionURIs(final Set<URI> logoutURIs) {
690
691                if (logoutURIs != null) {
692                        for (URI uri: logoutURIs) {
693                                URIUtils.ensureSchemeIsNotProhibited(uri, PROHIBITED_REDIRECT_URI_SCHEMES);
694                        }
695                }
696                postLogoutRedirectURIs = logoutURIs;
697        }
698        
699        
700        /**
701         * Gets the front-channel logout URI. Corresponds to the
702         * {@code frontchannel_logout_uri} client metadata field.
703         *
704         * @return The front-channel logout URI, {@code null} if not specified.
705         */
706        public URI getFrontChannelLogoutURI() {
707                
708                return frontChannelLogoutURI;
709        }
710        
711        
712        /**
713         * Sets the front-channel logout URI. Corresponds to the
714         * {@code frontchannel_logout_uri} client metadata field.
715         *
716         * @param frontChannelLogoutURI The front-channel logout URI,
717         *                              {@code null} if not specified. The URI
718         *                              scheme must be https or http.
719         */
720        public void setFrontChannelLogoutURI(final URI frontChannelLogoutURI) {
721                
722                URIUtils.ensureSchemeIsHTTPSorHTTP(frontChannelLogoutURI);
723                this.frontChannelLogoutURI = frontChannelLogoutURI;
724        }
725        
726        
727        /**
728         * Gets the requirement for a session identifier on front-channel
729         * logout. Corresponds to
730         * the {@code frontchannel_logout_session_required} client metadata
731         * field.
732         *
733         * @return {@code true} if a session identifier is required, else
734         *         {@code false}.
735         */
736        public boolean requiresFrontChannelLogoutSession() {
737                
738                return frontChannelLogoutSessionRequired;
739        }
740        
741        
742        /**
743         * Sets the requirement for a session identifier on front-channel
744         * logout. Corresponds to
745         * the {@code frontchannel_logout_session_required} client metadata
746         * field.
747         *
748         * @param requiresSession  {@code true} if a session identifier is
749         *                         required, else {@code false}.
750         */
751        public void requiresFrontChannelLogoutSession(boolean requiresSession) {
752                
753                frontChannelLogoutSessionRequired = requiresSession;
754        }
755        
756        
757        /**
758         * Gets the back-channel logout URI. Corresponds to the
759         * {@code backchannel_logout_uri} client metadata field.
760         *
761         * @return The back-channel logout URI, {@code null} if not specified.
762         */
763        public URI getBackChannelLogoutURI() {
764                
765                return backChannelLogoutURI;
766        }
767        
768        
769        /**
770         * Sets the back-channel logout URI. Corresponds to the
771         * {@code backchannel_logout_uri} client metadata field.
772         *
773         * @param backChannelLogoutURI The back-channel logout URI,
774         *                             {@code null} if not specified. The URI
775         *                             scheme must be https or http.
776         */
777        public void setBackChannelLogoutURI(final URI backChannelLogoutURI) {
778                
779                URIUtils.ensureSchemeIsHTTPSorHTTP(backChannelLogoutURI);
780                this.backChannelLogoutURI = backChannelLogoutURI;
781        }
782        
783        
784        /**
785         * Gets the requirement for a session identifier on back-channel
786         * logout. Corresponds to
787         * the {@code backchannel_logout_session_required} client metadata
788         * field.
789         *
790         * @return {@code true} if a session identifier is required, else
791         *         {@code false}.
792         */
793        public boolean requiresBackChannelLogoutSession() {
794                
795                return backChannelLogoutSessionRequired;
796        }
797        
798        
799        /**
800         * Sets the requirement for a session identifier on back-channel
801         * logout. Corresponds to
802         * the {@code backchannel_logout_session_required} client metadata
803         * field.
804         *
805         * @param requiresSession {@code true} if a session identifier is
806         *                        required, else {@code false}.
807         */
808        public void requiresBackChannelLogoutSession(final boolean requiresSession) {
809                
810                backChannelLogoutSessionRequired = requiresSession;
811        }
812        
813        
814        /**
815         * Applies the client metadata defaults where no values have been
816         * specified.
817         * 
818         * <ul>
819         *     <li>The response types default to {@code ["code"]}.
820         *     <li>The grant types default to {@code "authorization_code".}
821         *     <li>The client authentication method defaults to
822         *         "client_secret_basic".
823         *     <li>The application type defaults to
824         *         {@link ApplicationType#WEB}.
825         *     <li>The ID token JWS algorithm defaults to "RS256".
826         * </ul>
827         */
828        @Override
829        public void applyDefaults() {
830                
831                super.applyDefaults();
832
833                if (applicationType == null) {
834                        applicationType = ApplicationType.WEB;
835                }
836                
837                if (idTokenJWSAlg == null) {
838                        idTokenJWSAlg = JWSAlgorithm.RS256;
839                }
840        }
841
842
843        @Override
844        public JSONObject toJSONObject(boolean includeCustomFields) {
845
846                JSONObject o = super.toJSONObject(includeCustomFields);
847
848                o.putAll(getCustomFields());
849
850                if (applicationType != null)
851                        o.put("application_type", applicationType.toString());
852
853                if (subjectType != null)
854                        o.put("subject_type", subjectType.toString());
855
856
857                if (sectorIDURI != null)
858                        o.put("sector_identifier_uri", sectorIDURI.toString());
859
860
861                if (idTokenJWSAlg != null)
862                        o.put("id_token_signed_response_alg", idTokenJWSAlg.getName());
863
864
865                if (idTokenJWEAlg != null)
866                        o.put("id_token_encrypted_response_alg", idTokenJWEAlg.getName());
867
868
869                if (idTokenJWEEnc != null)
870                        o.put("id_token_encrypted_response_enc", idTokenJWEEnc.getName());
871
872
873                if (userInfoJWSAlg != null)
874                        o.put("userinfo_signed_response_alg", userInfoJWSAlg.getName());
875
876
877                if (userInfoJWEAlg != null)
878                        o.put("userinfo_encrypted_response_alg", userInfoJWEAlg.getName());
879
880
881                if (userInfoJWEEnc != null)
882                        o.put("userinfo_encrypted_response_enc", userInfoJWEEnc.getName());
883
884
885                if (defaultMaxAge > 0)
886                        o.put("default_max_age", defaultMaxAge);
887
888
889                if (requiresAuthTime())
890                        o.put("require_auth_time", requiresAuthTime);
891
892
893                if (defaultACRs != null) {
894
895                        JSONArray acrList = new JSONArray();
896                        acrList.addAll(defaultACRs);
897                        o.put("default_acr_values", acrList);
898                }
899
900
901                if (initiateLoginURI != null)
902                        o.put("initiate_login_uri", initiateLoginURI.toString());
903
904
905                if (postLogoutRedirectURIs != null) {
906
907                        JSONArray uriList = new JSONArray();
908
909                        for (URI uri: postLogoutRedirectURIs)
910                                uriList.add(uri.toString());
911
912                        o.put("post_logout_redirect_uris", uriList);
913                }
914                
915                if (frontChannelLogoutURI != null) {
916                        o.put("frontchannel_logout_uri", frontChannelLogoutURI.toString());
917                        o.put("frontchannel_logout_session_required", frontChannelLogoutSessionRequired);
918                }
919                
920                if (backChannelLogoutURI != null) {
921                        o.put("backchannel_logout_uri", backChannelLogoutURI.toString());
922                        o.put("backchannel_logout_session_required", backChannelLogoutSessionRequired);
923                }
924
925                return o;
926        }
927
928
929        /**
930         * Parses an OpenID Connect client metadata instance from the specified
931         * JSON object.
932         *
933         * @param jsonObject The JSON object to parse. Must not be 
934         *                   {@code null}.
935         *
936         * @return The OpenID Connect client metadata.
937         *
938         * @throws ParseException If the JSON object couldn't be parsed to an
939         *                        OpenID Connect client metadata instance.
940         */
941        public static OIDCClientMetadata parse(final JSONObject jsonObject)
942                throws ParseException {
943
944                ClientMetadata baseMetadata = ClientMetadata.parse(jsonObject);
945                
946                OIDCClientMetadata metadata = new OIDCClientMetadata(baseMetadata);
947
948                // Parse the OIDC-specific fields from the custom OAuth 2.0 dyn
949                // reg fields
950
951                JSONObject oidcFields = baseMetadata.getCustomFields();
952
953                try {
954                        if (jsonObject.get("application_type") != null) {
955                                metadata.setApplicationType(JSONObjectUtils.getEnum(jsonObject, "application_type", ApplicationType.class));
956                                oidcFields.remove("application_type");
957                        }
958
959                        if (jsonObject.get("subject_type") != null) {
960                                metadata.setSubjectType(JSONObjectUtils.getEnum(jsonObject, "subject_type", SubjectType.class));
961                                oidcFields.remove("subject_type");
962                        }
963
964                        if (jsonObject.get("sector_identifier_uri") != null) {
965                                metadata.setSectorIDURI(JSONObjectUtils.getURI(jsonObject, "sector_identifier_uri"));
966                                oidcFields.remove("sector_identifier_uri");
967                        }
968
969                        if (jsonObject.get("id_token_signed_response_alg") != null) {
970                                metadata.setIDTokenJWSAlg(JWSAlgorithm.parse(
971                                        JSONObjectUtils.getString(jsonObject, "id_token_signed_response_alg")));
972
973                                oidcFields.remove("id_token_signed_response_alg");
974                        }
975
976                        if (jsonObject.get("id_token_encrypted_response_alg") != null) {
977                                metadata.setIDTokenJWEAlg(JWEAlgorithm.parse(
978                                        JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_alg")));
979
980                                oidcFields.remove("id_token_encrypted_response_alg");
981                        }
982
983                        if (jsonObject.get("id_token_encrypted_response_enc") != null) {
984                                metadata.setIDTokenJWEEnc(EncryptionMethod.parse(
985                                        JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_enc")));
986
987                                oidcFields.remove("id_token_encrypted_response_enc");
988                        }
989
990                        if (jsonObject.get("userinfo_signed_response_alg") != null) {
991                                metadata.setUserInfoJWSAlg(JWSAlgorithm.parse(
992                                        JSONObjectUtils.getString(jsonObject, "userinfo_signed_response_alg")));
993
994                                oidcFields.remove("userinfo_signed_response_alg");
995                        }
996
997                        if (jsonObject.get("userinfo_encrypted_response_alg") != null) {
998                                metadata.setUserInfoJWEAlg(JWEAlgorithm.parse(
999                                        JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_alg")));
1000
1001                                oidcFields.remove("userinfo_encrypted_response_alg");
1002                        }
1003
1004                        if (jsonObject.get("userinfo_encrypted_response_enc") != null) {
1005                                metadata.setUserInfoJWEEnc(EncryptionMethod.parse(
1006                                        JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_enc")));
1007
1008                                oidcFields.remove("userinfo_encrypted_response_enc");
1009                        }
1010
1011                        if (jsonObject.get("default_max_age") != null) {
1012                                metadata.setDefaultMaxAge(JSONObjectUtils.getInt(jsonObject, "default_max_age"));
1013                                oidcFields.remove("default_max_age");
1014                        }
1015
1016                        if (jsonObject.get("require_auth_time") != null) {
1017                                metadata.requiresAuthTime(JSONObjectUtils.getBoolean(jsonObject, "require_auth_time"));
1018                                oidcFields.remove("require_auth_time");
1019                        }
1020
1021                        if (jsonObject.get("default_acr_values") != null) {
1022
1023                                List<ACR> acrValues = new LinkedList<>();
1024
1025                                for (String acrString : JSONObjectUtils.getStringArray(jsonObject, "default_acr_values"))
1026                                        acrValues.add(new ACR(acrString));
1027
1028                                metadata.setDefaultACRs(acrValues);
1029
1030                                oidcFields.remove("default_acr_values");
1031                        }
1032
1033                        if (jsonObject.get("initiate_login_uri") != null) {
1034                                try {
1035                                        metadata.setInitiateLoginURI(JSONObjectUtils.getURI(jsonObject, "initiate_login_uri"));
1036                                } catch (IllegalArgumentException e) {
1037                                        throw new ParseException("Invalid initiate_login_uri parameter: " + e.getMessage());
1038                                }
1039                                oidcFields.remove("initiate_login_uri");
1040                        }
1041
1042                        if (jsonObject.get("post_logout_redirect_uris") != null) {
1043
1044                                Set<URI> logoutURIs = new LinkedHashSet<>();
1045
1046                                for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "post_logout_redirect_uris")) {
1047
1048                                        try {
1049                                                logoutURIs.add(new URI(uriString));
1050                                        } catch (URISyntaxException e) {
1051                                                throw new ParseException("Invalid post_logout_redirect_uris parameter");
1052                                        }
1053                                }
1054
1055                                try {
1056                                        metadata.setPostLogoutRedirectionURIs(logoutURIs);
1057                                } catch (IllegalArgumentException e) {
1058                                        throw new ParseException("Invalid post_logout_redirect_uris parameter: " + e.getMessage());
1059                                }
1060                                oidcFields.remove("post_logout_redirect_uris");
1061                        }
1062                        
1063                        if (jsonObject.get("frontchannel_logout_uri") != null) {
1064                                
1065                                try {
1066                                        metadata.setFrontChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "frontchannel_logout_uri"));
1067                                } catch (IllegalArgumentException e) {
1068                                        throw new ParseException("Invalid frontchannel_logout_uri parameter: " + e.getMessage());
1069                                }
1070                                oidcFields.remove("frontchannel_logout_uri");
1071                        
1072                                if (jsonObject.get("frontchannel_logout_session_required") != null) {
1073                                        metadata.requiresFrontChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_required"));
1074                                        oidcFields.remove("frontchannel_logout_session_required");
1075                                }
1076                        }
1077                        
1078                        
1079                        if (jsonObject.get("backchannel_logout_uri") != null) {
1080                                
1081                                try {
1082                                        metadata.setBackChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "backchannel_logout_uri"));
1083                                } catch (IllegalArgumentException e) {
1084                                        throw new ParseException("Invalid backchannel_logout_uri parameter: " + e.getMessage());
1085                                }
1086                                oidcFields.remove("backchannel_logout_uri");
1087                                
1088                                if (jsonObject.get("backchannel_logout_session_required") != null) {
1089                                        metadata.requiresBackChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_required"));
1090                                        oidcFields.remove("backchannel_logout_session_required");
1091                                }
1092                        }
1093                        
1094                } catch (ParseException e) {
1095                        // Insert client_client_metadata error code so that it
1096                        // can be reported back to the client if we have a
1097                        // registration event
1098                        throw new ParseException(e.getMessage(), RegistrationError.INVALID_CLIENT_METADATA.appendDescription(": " + e.getMessage()), e.getCause());
1099                }
1100
1101                // The remaining fields are custom
1102                metadata.setCustomFields(oidcFields);
1103
1104                return metadata;
1105        }
1106}