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