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                        
897                        for (ACR acr: defaultACRs) {
898                                acrList.add(acr.getValue());
899                        }
900                        o.put("default_acr_values", acrList);
901                }
902
903
904                if (initiateLoginURI != null)
905                        o.put("initiate_login_uri", initiateLoginURI.toString());
906
907
908                if (postLogoutRedirectURIs != null) {
909
910                        JSONArray uriList = new JSONArray();
911
912                        for (URI uri: postLogoutRedirectURIs)
913                                uriList.add(uri.toString());
914
915                        o.put("post_logout_redirect_uris", uriList);
916                }
917                
918                if (frontChannelLogoutURI != null) {
919                        o.put("frontchannel_logout_uri", frontChannelLogoutURI.toString());
920                        o.put("frontchannel_logout_session_required", frontChannelLogoutSessionRequired);
921                }
922                
923                if (backChannelLogoutURI != null) {
924                        o.put("backchannel_logout_uri", backChannelLogoutURI.toString());
925                        o.put("backchannel_logout_session_required", backChannelLogoutSessionRequired);
926                }
927
928                return o;
929        }
930
931
932        /**
933         * Parses an OpenID Connect client metadata instance from the specified
934         * JSON object.
935         *
936         * @param jsonObject The JSON object to parse. Must not be 
937         *                   {@code null}.
938         *
939         * @return The OpenID Connect client metadata.
940         *
941         * @throws ParseException If the JSON object couldn't be parsed to an
942         *                        OpenID Connect client metadata instance.
943         */
944        public static OIDCClientMetadata parse(final JSONObject jsonObject)
945                throws ParseException {
946
947                ClientMetadata baseMetadata = ClientMetadata.parse(jsonObject);
948                
949                OIDCClientMetadata metadata = new OIDCClientMetadata(baseMetadata);
950
951                // Parse the OIDC-specific fields from the custom OAuth 2.0 dyn
952                // reg fields
953
954                JSONObject oidcFields = baseMetadata.getCustomFields();
955
956                try {
957                        if (jsonObject.get("application_type") != null) {
958                                metadata.setApplicationType(JSONObjectUtils.getEnum(jsonObject, "application_type", ApplicationType.class));
959                                oidcFields.remove("application_type");
960                        }
961
962                        if (jsonObject.get("subject_type") != null) {
963                                metadata.setSubjectType(JSONObjectUtils.getEnum(jsonObject, "subject_type", SubjectType.class));
964                                oidcFields.remove("subject_type");
965                        }
966
967                        if (jsonObject.get("sector_identifier_uri") != null) {
968                                metadata.setSectorIDURI(JSONObjectUtils.getURI(jsonObject, "sector_identifier_uri"));
969                                oidcFields.remove("sector_identifier_uri");
970                        }
971
972                        if (jsonObject.get("id_token_signed_response_alg") != null) {
973                                metadata.setIDTokenJWSAlg(JWSAlgorithm.parse(
974                                        JSONObjectUtils.getString(jsonObject, "id_token_signed_response_alg")));
975
976                                oidcFields.remove("id_token_signed_response_alg");
977                        }
978
979                        if (jsonObject.get("id_token_encrypted_response_alg") != null) {
980                                metadata.setIDTokenJWEAlg(JWEAlgorithm.parse(
981                                        JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_alg")));
982
983                                oidcFields.remove("id_token_encrypted_response_alg");
984                        }
985
986                        if (jsonObject.get("id_token_encrypted_response_enc") != null) {
987                                metadata.setIDTokenJWEEnc(EncryptionMethod.parse(
988                                        JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_enc")));
989
990                                oidcFields.remove("id_token_encrypted_response_enc");
991                        }
992
993                        if (jsonObject.get("userinfo_signed_response_alg") != null) {
994                                metadata.setUserInfoJWSAlg(JWSAlgorithm.parse(
995                                        JSONObjectUtils.getString(jsonObject, "userinfo_signed_response_alg")));
996
997                                oidcFields.remove("userinfo_signed_response_alg");
998                        }
999
1000                        if (jsonObject.get("userinfo_encrypted_response_alg") != null) {
1001                                metadata.setUserInfoJWEAlg(JWEAlgorithm.parse(
1002                                        JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_alg")));
1003
1004                                oidcFields.remove("userinfo_encrypted_response_alg");
1005                        }
1006
1007                        if (jsonObject.get("userinfo_encrypted_response_enc") != null) {
1008                                metadata.setUserInfoJWEEnc(EncryptionMethod.parse(
1009                                        JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_enc")));
1010
1011                                oidcFields.remove("userinfo_encrypted_response_enc");
1012                        }
1013
1014                        if (jsonObject.get("default_max_age") != null) {
1015                                metadata.setDefaultMaxAge(JSONObjectUtils.getInt(jsonObject, "default_max_age"));
1016                                oidcFields.remove("default_max_age");
1017                        }
1018
1019                        if (jsonObject.get("require_auth_time") != null) {
1020                                metadata.requiresAuthTime(JSONObjectUtils.getBoolean(jsonObject, "require_auth_time"));
1021                                oidcFields.remove("require_auth_time");
1022                        }
1023
1024                        if (jsonObject.get("default_acr_values") != null) {
1025
1026                                List<ACR> acrValues = new LinkedList<>();
1027
1028                                for (String acrString : JSONObjectUtils.getStringArray(jsonObject, "default_acr_values"))
1029                                        acrValues.add(new ACR(acrString));
1030
1031                                metadata.setDefaultACRs(acrValues);
1032
1033                                oidcFields.remove("default_acr_values");
1034                        }
1035
1036                        if (jsonObject.get("initiate_login_uri") != null) {
1037                                try {
1038                                        metadata.setInitiateLoginURI(JSONObjectUtils.getURI(jsonObject, "initiate_login_uri"));
1039                                } catch (IllegalArgumentException e) {
1040                                        throw new ParseException("Invalid initiate_login_uri parameter: " + e.getMessage());
1041                                }
1042                                oidcFields.remove("initiate_login_uri");
1043                        }
1044
1045                        if (jsonObject.get("post_logout_redirect_uris") != null) {
1046
1047                                Set<URI> logoutURIs = new LinkedHashSet<>();
1048
1049                                for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "post_logout_redirect_uris")) {
1050
1051                                        try {
1052                                                logoutURIs.add(new URI(uriString));
1053                                        } catch (URISyntaxException e) {
1054                                                throw new ParseException("Invalid post_logout_redirect_uris parameter");
1055                                        }
1056                                }
1057
1058                                try {
1059                                        metadata.setPostLogoutRedirectionURIs(logoutURIs);
1060                                } catch (IllegalArgumentException e) {
1061                                        throw new ParseException("Invalid post_logout_redirect_uris parameter: " + e.getMessage());
1062                                }
1063                                oidcFields.remove("post_logout_redirect_uris");
1064                        }
1065                        
1066                        if (jsonObject.get("frontchannel_logout_uri") != null) {
1067                                
1068                                try {
1069                                        metadata.setFrontChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "frontchannel_logout_uri"));
1070                                } catch (IllegalArgumentException e) {
1071                                        throw new ParseException("Invalid frontchannel_logout_uri parameter: " + e.getMessage());
1072                                }
1073                                oidcFields.remove("frontchannel_logout_uri");
1074                        
1075                                if (jsonObject.get("frontchannel_logout_session_required") != null) {
1076                                        metadata.requiresFrontChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_required"));
1077                                        oidcFields.remove("frontchannel_logout_session_required");
1078                                }
1079                        }
1080                        
1081                        
1082                        if (jsonObject.get("backchannel_logout_uri") != null) {
1083                                
1084                                try {
1085                                        metadata.setBackChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "backchannel_logout_uri"));
1086                                } catch (IllegalArgumentException e) {
1087                                        throw new ParseException("Invalid backchannel_logout_uri parameter: " + e.getMessage());
1088                                }
1089                                oidcFields.remove("backchannel_logout_uri");
1090                                
1091                                if (jsonObject.get("backchannel_logout_session_required") != null) {
1092                                        metadata.requiresBackChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_required"));
1093                                        oidcFields.remove("backchannel_logout_session_required");
1094                                }
1095                        }
1096                        
1097                } catch (ParseException e) {
1098                        // Insert client_client_metadata error code so that it
1099                        // can be reported back to the client if we have a
1100                        // registration event
1101                        throw new ParseException(e.getMessage(), RegistrationError.INVALID_CLIENT_METADATA.appendDescription(": " + e.getMessage()), e.getCause());
1102                }
1103
1104                // The remaining fields are custom
1105                metadata.setCustomFields(oidcFields);
1106
1107                return metadata;
1108        }
1109}