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