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