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.op;
019
020
021import java.net.URI;
022import java.net.URISyntaxException;
023import java.util.*;
024
025import com.nimbusds.jose.Algorithm;
026import com.nimbusds.jose.EncryptionMethod;
027import com.nimbusds.jose.JWEAlgorithm;
028import com.nimbusds.jose.JWSAlgorithm;
029import com.nimbusds.langtag.LangTag;
030import com.nimbusds.langtag.LangTagException;
031import com.nimbusds.oauth2.sdk.*;
032import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
033import com.nimbusds.oauth2.sdk.id.Issuer;
034import com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod;
035import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
036import com.nimbusds.oauth2.sdk.util.OrderedJSONObject;
037import com.nimbusds.openid.connect.sdk.Display;
038import com.nimbusds.openid.connect.sdk.SubjectType;
039import com.nimbusds.openid.connect.sdk.claims.ACR;
040import com.nimbusds.openid.connect.sdk.claims.ClaimType;
041import net.minidev.json.JSONObject;
042
043
044/**
045 * OpenID Connect provider metadata.
046 *
047 * <p>Related specifications:
048 *
049 * <ul>
050 *     <li>OpenID Connect Discovery 1.0, section 3.
051 *     <li>OpenID Connect Session Management 1.0, section 2.1 (draft 28).
052 *     <li>OpenID Connect Front-Channel Logout 1.0, section 3 (draft 02).
053 *     <li>OpenID Connect Back-Channel Logout 1.0, section 2.1 (draft 04).
054 * </ul>
055 */
056public class OIDCProviderMetadata {
057
058
059        /**
060         * The registered parameter names.
061         */
062        private static final Set<String> REGISTERED_PARAMETER_NAMES;
063
064
065        static {
066                Set<String> p = new HashSet<>();
067
068                p.add("issuer");
069                p.add("authorization_endpoint");
070                p.add("token_endpoint");
071                p.add("userinfo_endpoint");
072                p.add("registration_endpoint");
073                p.add("check_session_iframe");
074                p.add("end_session_endpoint");
075                p.add("jwks_uri");
076                p.add("scopes_supported");
077                p.add("response_types_supported");
078                p.add("response_modes_supported");
079                p.add("grant_types_supported");
080                p.add("code_challenge_methods_supported");
081                p.add("acr_values_supported");
082                p.add("subject_types_supported");
083                p.add("token_endpoint_auth_methods_supported");
084                p.add("token_endpoint_auth_signing_alg_values_supported");
085                p.add("request_object_signing_alg_values_supported");
086                p.add("request_object_encryption_alg_values_supported");
087                p.add("request_object_encryption_enc_values_supported");
088                p.add("id_token_signing_alg_values_supported");
089                p.add("id_token_encryption_alg_values_supported");
090                p.add("id_token_encryption_enc_values_supported");
091                p.add("userinfo_signing_alg_values_supported");
092                p.add("userinfo_encryption_alg_values_supported");
093                p.add("userinfo_encryption_enc_values_supported");
094                p.add("display_values_supported");
095                p.add("claim_types_supported");
096                p.add("claims_supported");
097                p.add("claims_locales_supported");
098                p.add("ui_locales_supported");
099                p.add("service_documentation");
100                p.add("op_policy_uri");
101                p.add("op_tos_uri");
102                p.add("claims_parameter_supported");
103                p.add("request_parameter_supported");
104                p.add("request_uri_parameter_supported");
105                p.add("require_request_uri_registration");
106                p.add("introspection_endpoint");
107                p.add("revocation_endpoint");
108                p.add("backchannel_logout_supported");
109                p.add("backchannel_logout_session_supported");
110                p.add("frontchannel_logout_supported");
111                p.add("frontchannel_logout_session_supported");
112                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
113        }
114
115
116        /**
117         * The issuer.
118         */
119        private final Issuer issuer;
120
121
122        /**
123         * The authorisation endpoint.
124         */
125        private URI authzEndpoint;
126
127
128        /**
129         * The token endpoint.
130         */
131        private URI tokenEndpoint;
132
133
134        /**
135         * The UserInfo endpoint.
136         */
137        private URI userInfoEndpoint;
138
139
140        /**
141         * The registration endpoint.
142         */
143        private URI regEndpoint;
144        
145        
146        /**
147         * The token introspection endpoint.
148         */
149        private URI introspectionEndpoint;
150        
151        
152        /**
153         * The token revocation endpoint.
154         */
155        private URI revocationEndpoint;
156        
157        
158        /**
159         * The cross-origin check session iframe.
160         */
161        private URI checkSessionIframe;
162        
163        
164        /**
165         * The logout endpoint.
166         */
167        private URI endSessionEndpoint;
168
169
170        /**
171         * The JWK set URI.
172         */
173        private final URI jwkSetURI;
174
175
176        /**
177         * The supported scope values.
178         */
179        private Scope scope;
180
181
182        /**
183         * The supported response types.
184         */
185        private List<ResponseType> rts;
186
187
188        /**
189         * The supported response modes.
190         */
191        private List<ResponseMode> rms;
192        
193        
194        /**
195         * The supported grant types.
196         */
197        private List<GrantType> gts;
198
199
200        /**
201         * The supported code challenge methods for PKCE.
202         */
203        private List<CodeChallengeMethod> codeChallengeMethods;
204
205
206        /**
207         * The supported ACRs.
208         */
209        private List<ACR> acrValues;
210
211
212        /**
213         * The supported subject types.
214         */
215        private final List<SubjectType> subjectTypes;
216
217
218        /**
219         * The supported token endpoint authentication methods.
220         */
221        private List<ClientAuthenticationMethod> tokenEndpointAuthMethods;
222
223
224        /**
225         * The supported JWS algorithms for the {@code private_key_jwt} and 
226         * {@code client_secret_jwt} token endpoint authentication methods.
227         */
228        private List<JWSAlgorithm> tokenEndpointJWSAlgs;
229
230
231        /**
232         * The supported JWS algorithms for OpenID Connect request objects.
233         */
234        private List<JWSAlgorithm> requestObjectJWSAlgs;
235
236
237        /**
238         * The supported JWE algorithms for OpenID Connect request objects.
239         */
240        private List<JWEAlgorithm> requestObjectJWEAlgs;
241
242
243        /**
244         * The supported encryption methods for OpenID Connect request objects.
245         */
246        private List<EncryptionMethod> requestObjectJWEEncs;
247
248
249        /**
250         * The supported ID token JWS algorithms.
251         */
252        private List<JWSAlgorithm> idTokenJWSAlgs;
253
254
255        /**
256         * The supported ID token JWE algorithms.
257         */
258        private List<JWEAlgorithm> idTokenJWEAlgs;
259
260
261        /**
262         * The supported ID token encryption methods.
263         */
264        private List<EncryptionMethod> idTokenJWEEncs;
265
266
267        /**
268         * The supported UserInfo JWS algorithms.
269         */
270        private List<JWSAlgorithm> userInfoJWSAlgs;
271
272
273        /**
274         * The supported UserInfo JWE algorithms.
275         */
276        private List<JWEAlgorithm> userInfoJWEAlgs;
277
278
279        /**
280         * The supported UserInfo encryption methods.
281         */
282        private List<EncryptionMethod> userInfoJWEEncs;
283
284
285        /**
286         * The supported displays.
287         */
288        private List<Display> displays;
289        
290        
291        /**
292         * The supported claim types.
293         */
294        private List<ClaimType> claimTypes;
295
296
297        /**
298         * The supported claims names.
299         */
300        private List<String> claims;
301        
302        
303        /**
304         * The supported claims locales.
305         */
306        private List<LangTag> claimsLocales;
307        
308        
309        /**
310         * The supported UI locales.
311         */
312        private List<LangTag> uiLocales;
313
314
315        /**
316         * The service documentation URI.
317         */
318        private URI serviceDocsURI;
319        
320        
321        /**
322         * The provider's policy regarding relying party use of data.
323         */
324        private URI policyURI;
325        
326        
327        /**
328         * The provider's terms of service.
329         */
330        private URI tosURI;
331        
332        
333        /**
334         * If {@code true} the {@code claims} parameter is supported, else not.
335         */
336        private boolean claimsParamSupported = false;
337        
338        
339        /**
340         * If {@code true} the {@code request} parameter is supported, else 
341         * not.
342         */
343        private boolean requestParamSupported = false;
344        
345        
346        /**
347         * If {@code true} the {@code request_uri} parameter is supported, else
348         * not.
349         */
350        private boolean requestURIParamSupported = true;
351        
352        
353        /**
354         * If {@code true} the {@code request_uri} parameters must be
355         * pre-registered with the provider, else not.
356         */
357        private boolean requireRequestURIReg = false;
358        
359        
360        /**
361         * If {@code true} the {@code frontchannel_logout_supported} parameter
362         * is set, else not.
363         */
364        private boolean frontChannelLogoutSupported = false;
365        
366        
367        /**
368         * If {@code true} the {@code frontchannel_logout_session_supported}
369         * parameter is set, else not.
370         */
371        private boolean frontChannelLogoutSessionSupported = false;
372        
373        
374        /**
375         * If {@code true} the {@code backchannel_logout_supported} parameter
376         * is set, else not.
377         */
378        private boolean backChannelLogoutSupported = false;
379        
380        
381        /**
382         * If {@code true} the {@code backchannel_logout_session_supported}
383         * parameter is set, else not.
384         */
385        private boolean backChannelLogoutSessionSupported = false;
386
387
388        /**
389         * Custom (not-registered) parameters.
390         */
391        private final JSONObject customParameters = new JSONObject();
392
393
394        /**
395         * Creates a new OpenID Connect provider metadata instance.
396         * 
397         * @param issuer       The issuer identifier. Must be an URI using the
398         *                     https scheme with no query or fragment 
399         *                     component. Must not be {@code null}.
400         * @param subjectTypes The supported subject types. At least one must
401         *                     be specified. Must not be {@code null}.
402         */
403        public OIDCProviderMetadata(final Issuer issuer,
404                                    final List<SubjectType> subjectTypes,
405                                    final URI jwkSetURI) {
406        
407                URI url;
408                
409                try {
410                        url = new URI(issuer.getValue());
411                        
412                } catch (URISyntaxException e) {
413                        
414                        throw new IllegalArgumentException("The issuer identifier must be a URI: " + e.getMessage(), e);
415                }
416                
417                if (url.getRawQuery() != null)
418                        throw new IllegalArgumentException("The issuer URI must be without a query component");
419                
420                if (url.getRawFragment() != null)
421                        throw new IllegalArgumentException("The issuer URI must be without a fragment component ");
422                
423                this.issuer = issuer;
424                
425                
426                if (subjectTypes.size() < 1)
427                        throw new IllegalArgumentException("At least one supported subject type must be specified");
428                
429                this.subjectTypes = subjectTypes;
430
431                if (jwkSetURI == null)
432                        throw new IllegalArgumentException("The public JWK set URI must not be null");
433
434                this.jwkSetURI = jwkSetURI;
435        }
436
437
438        /**
439         * Gets the registered OpenID Connect provider metadata parameter
440         * names.
441         *
442         * @return The registered OpenID Connect provider metadata parameter
443         *         names, as an unmodifiable set.
444         */
445        public static Set<String> getRegisteredParameterNames() {
446
447                return REGISTERED_PARAMETER_NAMES;
448        }
449
450
451        /**
452         * Gets the issuer identifier. Corresponds to the {@code issuer} 
453         * metadata field.
454         *
455         * @return The issuer identifier.
456         */
457        public Issuer getIssuer() {
458
459                return issuer;
460        }
461
462
463        /**
464         * Gets the authorisation endpoint URI. Corresponds the
465         * {@code authorization_endpoint} metadata field.
466         *
467         * @return The authorisation endpoint URI, {@code null} if not
468         *         specified.
469         */
470        public URI getAuthorizationEndpointURI() {
471
472                return authzEndpoint;
473        }
474
475
476        /**
477         * Sets the authorisation endpoint URI. Corresponds the
478         * {@code authorization_endpoint} metadata field.
479         *
480         * @param authzEndpoint The authorisation endpoint URI, {@code null} if
481         *                      not specified.
482         */
483        public void setAuthorizationEndpointURI(final URI authzEndpoint) {
484
485                this.authzEndpoint = authzEndpoint;
486        }
487
488
489        /**
490         * Gets the token endpoint URI. Corresponds the {@code token_endpoint}
491         * metadata field.
492         *
493         * @return The token endpoint URI, {@code null} if not specified.
494         */
495        public URI getTokenEndpointURI() {
496
497                return tokenEndpoint;
498        }
499
500
501        /**
502         * Sts the token endpoint URI. Corresponds the {@code token_endpoint}
503         * metadata field.
504         *
505         * @param tokenEndpoint The token endpoint URI, {@code null} if not
506         *                      specified.
507         */
508        public void setTokenEndpointURI(final URI tokenEndpoint) {
509
510                this.tokenEndpoint = tokenEndpoint;
511        }
512
513
514        /**
515         * Gets the UserInfo endpoint URI. Corresponds the
516         * {@code userinfo_endpoint} metadata field.
517         *
518         * @return The UserInfo endpoint URI, {@code null} if not specified.
519         */
520        public URI getUserInfoEndpointURI() {
521
522                return userInfoEndpoint;
523        }
524
525
526        /**
527         * Sets the UserInfo endpoint URI. Corresponds the
528         * {@code userinfo_endpoint} metadata field.
529         *
530         * @param userInfoEndpoint The UserInfo endpoint URI, {@code null} if
531         *                         not specified.
532         */
533        public void setUserInfoEndpointURI(final URI userInfoEndpoint) {
534
535                this.userInfoEndpoint = userInfoEndpoint;
536        }
537
538
539        /**
540         * Gets the client registration endpoint URI. Corresponds to the
541         * {@code registration_endpoint} metadata field.
542         *
543         * @return The client registration endpoint URI, {@code null} if not
544         *         specified.
545         */
546        public URI getRegistrationEndpointURI() {
547
548                return regEndpoint;
549        }
550
551
552        /**
553         * Sets the client registration endpoint URI. Corresponds to the
554         * {@code registration_endpoint} metadata field.
555         *
556         * @param regEndpoint The client registration endpoint URI,
557         *                    {@code null} if not specified.
558         */
559        public void setRegistrationEndpointURI(final URI regEndpoint) {
560
561                this.regEndpoint = regEndpoint;
562        }
563        
564        
565        /**
566         * Gets the token introspection endpoint URI. Corresponds to the
567         * {@code introspection_endpoint} metadata field.
568         *
569         * @return The token introspection endpoint URI, {@code null} if not
570         *         specified.
571         */
572        public URI getIntrospectionEndpointURI() {
573                
574                return introspectionEndpoint;
575        }
576        
577        
578        /**
579         * Sets the token introspection endpoint URI. Corresponds to the
580         * {@code introspection_endpoint} metadata field.
581         *
582         * @param introspectionEndpoint  The token introspection endpoint URI,
583         *                               {@code null} if not specified.
584         */
585        public void setIntrospectionEndpointURI(final URI introspectionEndpoint) {
586                
587                this.introspectionEndpoint = introspectionEndpoint;
588        }
589        
590        
591        /**
592         * Gets the token revocation endpoint URI. Corresponds to the
593         * {@code revocation_endpoint} metadata field.
594         *
595         * @return The token revocation endpoint URI, {@code null} if not
596         *         specified.
597         */
598        public URI getRevocationEndpointURI() {
599                
600                return revocationEndpoint;
601        }
602        
603        
604        /**
605         * Sets the token revocation endpoint URI. Corresponds to the
606         * {@code revocation_endpoint} metadata field.
607         *
608         * @param revocationEndpoint The token revocation endpoint URI,
609         *                           {@code null} if not specified.
610         */
611        public void setRevocationEndpointURI(final URI revocationEndpoint) {
612                
613                this.revocationEndpoint = revocationEndpoint;
614        }
615        
616        
617        /**
618         * Gets the cross-origin check session iframe URI. Corresponds to the
619         * {@code check_session_iframe} metadata field.
620         * 
621         * @return The check session iframe URI, {@code null} if not specified.
622         */
623        public URI getCheckSessionIframeURI() {
624                
625                return checkSessionIframe;
626        }
627
628
629        /**
630         * Sets the cross-origin check session iframe URI. Corresponds to the
631         * {@code check_session_iframe} metadata field.
632         *
633         * @param checkSessionIframe The check session iframe URI, {@code null}
634         *                           if not specified.
635         */
636        public void setCheckSessionIframeURI(final URI checkSessionIframe) {
637
638                this.checkSessionIframe = checkSessionIframe;
639        }
640        
641        
642        /**
643         * Gets the logout endpoint URI. Corresponds to the
644         * {@code end_session_endpoint} metadata field.
645         * 
646         * @return The logoout endpoint URI, {@code null} if not specified.
647         */
648        public URI getEndSessionEndpointURI() {
649                
650                return endSessionEndpoint;
651        }
652
653
654        /**
655         * Sets the logout endpoint URI. Corresponds to the
656         * {@code end_session_endpoint} metadata field.
657         *
658         * @param endSessionEndpoint The logoout endpoint URI, {@code null} if
659         *                           not specified.
660         */
661        public void setEndSessionEndpointURI(final URI endSessionEndpoint) {
662
663                this.endSessionEndpoint = endSessionEndpoint;
664        }
665
666
667        /**
668         * Gets the JSON Web Key (JWK) set URI. Corresponds to the
669         * {@code jwks_uri} metadata field.
670         *
671         * @return The JWK set URI.
672         */
673        public URI getJWKSetURI() {
674
675                return jwkSetURI;
676        }
677
678
679        /**
680         * Gets the supported scope values. Corresponds to the
681         * {@code scopes_supported} metadata field.
682         *
683         * @return The supported scope values, {@code null} if not specified.
684         */
685        public Scope getScopes() {
686
687                return scope;
688        }
689
690
691        /**
692         * Sets the supported scope values. Corresponds to the
693         * {@code scopes_supported} metadata field.
694         *
695         * @param scope The supported scope values, {@code null} if not
696         *              specified.
697         */
698        public void setScopes(final Scope scope) {
699
700                this.scope = scope;
701        }
702
703
704        /**
705         * Gets the supported response type values. Corresponds to the
706         * {@code response_types_supported} metadata field.
707         *
708         * @return The supported response type values, {@code null} if not 
709         *         specified.
710         */
711        public List<ResponseType> getResponseTypes() {
712
713                return rts;
714        }
715
716
717        /**
718         * Sets the supported response type values. Corresponds to the
719         * {@code response_types_supported} metadata field.
720         *
721         * @param rts The supported response type values, {@code null} if not
722         *            specified.
723         */
724        public void setResponseTypes(final List<ResponseType> rts) {
725
726                this.rts = rts;
727        }
728
729
730        /**
731         * Gets the supported response mode values. Corresponds to the
732         * {@code response_modes_supported}.
733         *
734         * @return The supported response mode values, {@code null} if not
735         *         specified.
736         */
737        public List<ResponseMode> getResponseModes() {
738
739                return rms;
740        }
741
742
743        /**
744         * Sets the supported response mode values. Corresponds to the
745         * {@code response_modes_supported}.
746         *
747         * @param rms The supported response mode values, {@code null} if not
748         *            specified.
749         */
750        public void setResponseModes(final List<ResponseMode> rms) {
751
752                this.rms = rms;
753        }
754        
755        
756        /**
757         * Gets the supported OAuth 2.0 grant types. Corresponds to the
758         * {@code grant_types_supported} metadata field.
759         * 
760         * @return The supported grant types, {@code null} if not specified.
761         */
762        public List<GrantType> getGrantTypes() {
763                
764                return gts;
765        }
766
767
768        /**
769         * Sets the supported OAuth 2.0 grant types. Corresponds to the
770         * {@code grant_types_supported} metadata field.
771         *
772         * @param gts The supported grant types, {@code null} if not specified.
773         */
774        public void setGrantTypes(final List<GrantType> gts) {
775
776                this.gts = gts;
777        }
778
779
780        /**
781         * Gets the supported authorisation code challenge methods for PKCE.
782         * Corresponds to the {@code code_challenge_methods_supported} metadata
783         * field.
784         *
785         * @return The supported code challenge methods, {@code null} if not
786         *         specified.
787         */
788        public List<CodeChallengeMethod> getCodeChallengeMethods() {
789
790                return codeChallengeMethods;
791        }
792
793
794        /**
795         * Gets the supported authorisation code challenge methods for PKCE.
796         * Corresponds to the {@code code_challenge_methods_supported} metadata
797         * field.
798         *
799         * @param codeChallengeMethods The supported code challenge methods,
800         *                             {@code null} if not specified.
801         */
802        public void setCodeChallengeMethods(final List<CodeChallengeMethod> codeChallengeMethods) {
803
804                this.codeChallengeMethods = codeChallengeMethods;
805        }
806
807        /**
808         * Gets the supported Authentication Context Class References (ACRs).
809         * Corresponds to the {@code acr_values_supported} metadata field.
810         *
811         * @return The supported ACRs, {@code null} if not specified.
812         */
813        public List<ACR> getACRs() {
814
815                return acrValues;
816        }
817
818
819        /**
820         * Sets the supported Authentication Context Class References (ACRs).
821         * Corresponds to the {@code acr_values_supported} metadata field.
822         *
823         * @param acrValues The supported ACRs, {@code null} if not specified.
824         */
825        public void setACRs(final List<ACR> acrValues) {
826
827                this.acrValues = acrValues;
828        }
829
830
831        /**
832         * Gets the supported subject types. Corresponds to the
833         * {@code subject_types_supported} metadata field.
834         *
835         * @return The supported subject types.
836         */
837        public List<SubjectType> getSubjectTypes() {
838
839                return subjectTypes;
840        }
841
842
843        /**
844         * Gets the supported token endpoint authentication methods. 
845         * Corresponds to the {@code token_endpoint_auth_methods_supported} 
846         * metadata field.
847         *
848         * @return The supported token endpoint authentication methods, 
849         *         {@code null} if not specified.
850         */
851        public List<ClientAuthenticationMethod> getTokenEndpointAuthMethods() {
852
853                return tokenEndpointAuthMethods;
854        }
855
856
857        /**
858         * Sets the supported token endpoint authentication methods.
859         * Corresponds to the {@code token_endpoint_auth_methods_supported}
860         * metadata field.
861         *
862         * @param tokenEndpointAuthMethods The supported token endpoint
863         *                                 authentication methods, {@code null}
864         *                                 if not specified.
865         */
866        public void setTokenEndpointAuthMethods(final List<ClientAuthenticationMethod> tokenEndpointAuthMethods) {
867
868                this.tokenEndpointAuthMethods = tokenEndpointAuthMethods;
869        }
870
871
872        /**
873         * Gets the supported JWS algorithms for the {@code private_key_jwt}
874         * and {@code client_secret_jwt} token endpoint authentication methods.
875         * Corresponds to the 
876         * {@code token_endpoint_auth_signing_alg_values_supported} metadata 
877         * field.
878         *
879         * @return The supported JWS algorithms, {@code null} if not specified.
880         */
881        public List<JWSAlgorithm> getTokenEndpointJWSAlgs() {
882
883                return tokenEndpointJWSAlgs;
884        }
885
886
887        /**
888         * Sets the supported JWS algorithms for the {@code private_key_jwt}
889         * and {@code client_secret_jwt} token endpoint authentication methods.
890         * Corresponds to the
891         * {@code token_endpoint_auth_signing_alg_values_supported} metadata
892         * field.
893         *
894         * @param tokenEndpointJWSAlgs The supported JWS algorithms,
895         *                             {@code null} if not specified. Must not
896         *                             contain the {@code none} algorithm.
897         */
898        public void setTokenEndpointJWSAlgs(final List<JWSAlgorithm> tokenEndpointJWSAlgs) {
899
900                if (tokenEndpointJWSAlgs != null && tokenEndpointJWSAlgs.contains(Algorithm.NONE))
901                        throw new IllegalArgumentException("The none algorithm is not accepted");
902
903                this.tokenEndpointJWSAlgs = tokenEndpointJWSAlgs;
904        }
905
906
907        /**
908         * Gets the supported JWS algorithms for OpenID Connect request 
909         * objects. Corresponds to the 
910         * {@code request_object_signing_alg_values_supported} metadata field.
911         *
912         * @return The supported JWS algorithms, {@code null} if not specified.
913         */
914        public List<JWSAlgorithm> getRequestObjectJWSAlgs() {
915
916                return requestObjectJWSAlgs;
917        }
918
919
920        /**
921         * Sets the supported JWS algorithms for OpenID Connect request
922         * objects. Corresponds to the
923         * {@code request_object_signing_alg_values_supported} metadata field.
924         *
925         * @param requestObjectJWSAlgs The supported JWS algorithms,
926         *                             {@code null} if not specified.
927         */
928        public void setRequestObjectJWSAlgs(final List<JWSAlgorithm> requestObjectJWSAlgs) {
929
930                this.requestObjectJWSAlgs = requestObjectJWSAlgs;
931        }
932
933
934        /**
935         * Gets the supported JWE algorithms for OpenID Connect request 
936         * objects. Corresponds to the
937         * {@code request_object_encryption_alg_values_supported} metadata 
938         * field.
939         *
940         * @return The supported JWE algorithms, {@code null} if not specified.
941         */
942        public List<JWEAlgorithm> getRequestObjectJWEAlgs() {
943
944                return requestObjectJWEAlgs;
945        }
946
947
948        /**
949         * Sets the supported JWE algorithms for OpenID Connect request
950         * objects. Corresponds to the
951         * {@code request_object_encryption_alg_values_supported} metadata
952         * field.
953         *
954         * @param requestObjectJWEAlgs The supported JWE algorithms,
955         *                            {@code null} if not specified.
956         */
957        public void setRequestObjectJWEAlgs(final List<JWEAlgorithm> requestObjectJWEAlgs) {
958
959                this.requestObjectJWEAlgs = requestObjectJWEAlgs;
960        }
961
962
963        /**
964         * Gets the supported encryption methods for OpenID Connect request 
965         * objects. Corresponds to the 
966         * {@code request_object_encryption_enc_values_supported} metadata 
967         * field.
968         *
969         * @return The supported encryption methods, {@code null} if not 
970         *         specified.
971         */
972        public List<EncryptionMethod> getRequestObjectJWEEncs() {
973
974                return requestObjectJWEEncs;
975        }
976
977
978        /**
979         * Sets the supported encryption methods for OpenID Connect request
980         * objects. Corresponds to the
981         * {@code request_object_encryption_enc_values_supported} metadata
982         * field.
983         *
984         * @param requestObjectJWEEncs The supported encryption methods,
985         *                             {@code null} if not specified.
986         */
987        public void setRequestObjectJWEEncs(final List<EncryptionMethod> requestObjectJWEEncs) {
988
989                this.requestObjectJWEEncs = requestObjectJWEEncs;
990        }
991
992
993        /**
994         * Gets the supported JWS algorithms for ID tokens. Corresponds to the 
995         * {@code id_token_signing_alg_values_supported} metadata field.
996         *
997         * @return The supported JWS algorithms, {@code null} if not specified.
998         */
999        public List<JWSAlgorithm> getIDTokenJWSAlgs() {
1000
1001                return idTokenJWSAlgs;
1002        }
1003
1004
1005        /**
1006         * Sets the supported JWS algorithms for ID tokens. Corresponds to the
1007         * {@code id_token_signing_alg_values_supported} metadata field.
1008         *
1009         * @param idTokenJWSAlgs The supported JWS algorithms, {@code null} if
1010         *                       not specified.
1011         */
1012        public void setIDTokenJWSAlgs(final List<JWSAlgorithm> idTokenJWSAlgs) {
1013
1014                this.idTokenJWSAlgs = idTokenJWSAlgs;
1015        }
1016
1017
1018        /**
1019         * Gets the supported JWE algorithms for ID tokens. Corresponds to the 
1020         * {@code id_token_encryption_alg_values_supported} metadata field.
1021         *
1022         * @return The supported JWE algorithms, {@code null} if not specified.
1023         */
1024        public List<JWEAlgorithm> getIDTokenJWEAlgs() {
1025
1026                return idTokenJWEAlgs;
1027        }
1028
1029
1030        /**
1031         * Sets the supported JWE algorithms for ID tokens. Corresponds to the
1032         * {@code id_token_encryption_alg_values_supported} metadata field.
1033         *
1034         * @param idTokenJWEAlgs The supported JWE algorithms, {@code null} if
1035         *                       not specified.
1036         */
1037        public void setIDTokenJWEAlgs(final List<JWEAlgorithm> idTokenJWEAlgs) {
1038
1039                this.idTokenJWEAlgs = idTokenJWEAlgs;
1040        }
1041
1042
1043        /**
1044         * Gets the supported encryption methods for ID tokens. Corresponds to 
1045         * the {@code id_token_encryption_enc_values_supported} metadata field.
1046         *
1047         * @return The supported encryption methods, {@code null} if not 
1048         *         specified.
1049         */
1050        public List<EncryptionMethod> getIDTokenJWEEncs() {
1051
1052                return idTokenJWEEncs;
1053        }
1054
1055
1056        /**
1057         * Sets the supported encryption methods for ID tokens. Corresponds to
1058         * the {@code id_token_encryption_enc_values_supported} metadata field.
1059         *
1060         * @param idTokenJWEEncs The supported encryption methods, {@code null}
1061         *                       if not specified.
1062         */
1063        public void setIDTokenJWEEncs(final List<EncryptionMethod> idTokenJWEEncs) {
1064
1065                this.idTokenJWEEncs = idTokenJWEEncs;
1066        }
1067
1068
1069        /**
1070         * Gets the supported JWS algorithms for UserInfo JWTs. Corresponds to 
1071         * the {@code userinfo_signing_alg_values_supported} metadata field.
1072         *
1073         * @return The supported JWS algorithms, {@code null} if not specified.
1074         */
1075        public List<JWSAlgorithm> getUserInfoJWSAlgs() {
1076
1077                return userInfoJWSAlgs;
1078        }
1079
1080
1081        /**
1082         * Sets the supported JWS algorithms for UserInfo JWTs. Corresponds to
1083         * the {@code userinfo_signing_alg_values_supported} metadata field.
1084         *
1085         * @param userInfoJWSAlgs The supported JWS algorithms, {@code null} if
1086         *                        not specified.
1087         */
1088        public void setUserInfoJWSAlgs(final List<JWSAlgorithm> userInfoJWSAlgs) {
1089
1090                this.userInfoJWSAlgs = userInfoJWSAlgs;
1091        }
1092
1093
1094        /**
1095         * Gets the supported JWE algorithms for UserInfo JWTs. Corresponds to 
1096         * the {@code userinfo_encryption_alg_values_supported} metadata field.
1097         *
1098         * @return The supported JWE algorithms, {@code null} if not specified.
1099         */
1100        public List<JWEAlgorithm> getUserInfoJWEAlgs() {
1101
1102                return userInfoJWEAlgs;
1103        }
1104
1105
1106        /**
1107         * Sets the supported JWE algorithms for UserInfo JWTs. Corresponds to
1108         * the {@code userinfo_encryption_alg_values_supported} metadata field.
1109         *
1110         * @param userInfoJWEAlgs The supported JWE algorithms, {@code null} if
1111         *                        not specified.
1112         */
1113        public void setUserInfoJWEAlgs(final List<JWEAlgorithm> userInfoJWEAlgs) {
1114
1115                this.userInfoJWEAlgs = userInfoJWEAlgs;
1116        }
1117
1118
1119        /**
1120         * Gets the supported encryption methods for UserInfo JWTs. Corresponds 
1121         * to the {@code userinfo_encryption_enc_values_supported} metadata 
1122         * field.
1123         *
1124         * @return The supported encryption methods, {@code null} if not 
1125         *         specified.
1126         */
1127        public List<EncryptionMethod> getUserInfoJWEEncs() {
1128
1129                return userInfoJWEEncs;
1130        }
1131
1132
1133        /**
1134         * Sets the supported encryption methods for UserInfo JWTs. Corresponds
1135         * to the {@code userinfo_encryption_enc_values_supported} metadata
1136         * field.
1137         *
1138         * @param userInfoJWEEncs The supported encryption methods,
1139         *                        {@code null} if not specified.
1140         */
1141        public void setUserInfoJWEEncs(final List<EncryptionMethod> userInfoJWEEncs) {
1142
1143                this.userInfoJWEEncs = userInfoJWEEncs;
1144        }
1145
1146
1147        /**
1148         * Gets the supported displays. Corresponds to the 
1149         * {@code display_values_supported} metadata field.
1150         *
1151         * @return The supported displays, {@code null} if not specified.
1152         */
1153        public List<Display> getDisplays() {
1154
1155                return displays;
1156        }
1157
1158
1159        /**
1160         * Sets the supported displays. Corresponds to the
1161         * {@code display_values_supported} metadata field.
1162         *
1163         * @param displays The supported displays, {@code null} if not
1164         *                 specified.
1165         */
1166        public void setDisplays(final List<Display> displays) {
1167
1168                this.displays = displays;
1169        }
1170        
1171        
1172        /**
1173         * Gets the supported claim types. Corresponds to the 
1174         * {@code claim_types_supported} metadata field.
1175         * 
1176         * @return The supported claim types, {@code null} if not specified.
1177         */
1178        public List<ClaimType> getClaimTypes() {
1179                
1180                return claimTypes;
1181        }
1182
1183
1184        /**
1185         * Sets the supported claim types. Corresponds to the
1186         * {@code claim_types_supported} metadata field.
1187         *
1188         * @param claimTypes The supported claim types, {@code null} if not
1189         *                   specified.
1190         */
1191        public void setClaimTypes(final List<ClaimType> claimTypes) {
1192
1193                this.claimTypes = claimTypes;
1194        }
1195
1196
1197        /**
1198         * Gets the supported claims names. Corresponds to the 
1199         * {@code claims_supported} metadata field.
1200         *
1201         * @return The supported claims names, {@code null} if not specified.
1202         */
1203        public List<String> getClaims() {
1204
1205                return claims;
1206        }
1207
1208
1209        /**
1210         * Sets the supported claims names. Corresponds to the
1211         * {@code claims_supported} metadata field.
1212         *
1213         * @param claims The supported claims names, {@code null} if not
1214         *               specified.
1215         */
1216        public void setClaims(final List<String> claims) {
1217
1218                this.claims = claims;
1219        }
1220        
1221        
1222        /**
1223         * Gets the supported claims locales. Corresponds to the
1224         * {@code claims_locales_supported} metadata field.
1225         * 
1226         * @return The supported claims locales, {@code null} if not specified.
1227         */
1228        public List<LangTag> getClaimsLocales() {
1229                
1230                return claimsLocales;
1231        }
1232
1233
1234        /**
1235         * Sets the supported claims locales. Corresponds to the
1236         * {@code claims_locales_supported} metadata field.
1237         *
1238         * @param claimsLocales The supported claims locales, {@code null} if
1239         *                      not specified.
1240         */
1241        public void setClaimLocales(final List<LangTag> claimsLocales) {
1242
1243                this.claimsLocales = claimsLocales;
1244        }
1245        
1246        
1247        /**
1248         * Gets the supported UI locales. Corresponds to the 
1249         * {@code ui_locales_supported} metadata field.
1250         * 
1251         * @return The supported UI locales, {@code null} if not specified.
1252         */
1253        public List<LangTag> getUILocales() {
1254                
1255                return uiLocales;
1256        }
1257
1258
1259        /**
1260         * Sets the supported UI locales. Corresponds to the
1261         * {@code ui_locales_supported} metadata field.
1262         *
1263         * @param uiLocales The supported UI locales, {@code null} if not
1264         *                  specified.
1265         */
1266        public void setUILocales(final List<LangTag> uiLocales) {
1267
1268                this.uiLocales = uiLocales;
1269        }
1270
1271
1272        /**
1273         * Gets the service documentation URI. Corresponds to the
1274         * {@code service_documentation} metadata field.
1275         *
1276         * @return The service documentation URI, {@code null} if not
1277         *         specified.
1278         */
1279        public URI getServiceDocsURI() {
1280
1281                return serviceDocsURI;
1282        }
1283
1284
1285        /**
1286         * Sets the service documentation URI. Corresponds to the
1287         * {@code service_documentation} metadata field.
1288         *
1289         * @param serviceDocsURI The service documentation URI, {@code null} if
1290         *                       not specified.
1291         */
1292        public void setServiceDocsURI(final URI serviceDocsURI) {
1293
1294                this.serviceDocsURI = serviceDocsURI;
1295        }
1296        
1297        
1298        /**
1299         * Gets the provider's policy regarding relying party use of data.
1300         * Corresponds to the {@code op_policy_uri} metadata field.
1301         * 
1302         * @return The policy URI, {@code null} if not specified.
1303         */
1304        public URI getPolicyURI() {
1305                
1306                return policyURI;
1307        }
1308
1309
1310        /**
1311         * Sets the provider's policy regarding relying party use of data.
1312         * Corresponds to the {@code op_policy_uri} metadata field.
1313         *
1314         * @param policyURI The policy URI, {@code null} if not specified.
1315         */
1316        public void setPolicyURI(final URI policyURI) {
1317
1318                this.policyURI = policyURI;
1319        }
1320        
1321        
1322        /**
1323         * Gets the provider's terms of service. Corresponds to the 
1324         * {@code op_tos_uri} metadata field.
1325         * 
1326         * @return The terms of service URI, {@code null} if not specified.
1327         */
1328        public URI getTermsOfServiceURI() {
1329                
1330                return tosURI;
1331        }
1332
1333
1334        /**
1335         * Sets the provider's terms of service. Corresponds to the
1336         * {@code op_tos_uri} metadata field.
1337         *
1338         * @param tosURI The terms of service URI, {@code null} if not
1339         *               specified.
1340         */
1341        public void setTermsOfServiceURI(final URI tosURI) {
1342
1343                this.tosURI = tosURI;
1344        }
1345        
1346        
1347        /**
1348         * Gets the support for the {@code claims} authorisation request
1349         * parameter. Corresponds to the {@code claims_parameter_supported} 
1350         * metadata field.
1351         * 
1352         * @return {@code true} if the {@code claim} parameter is supported,
1353         *         else {@code false}.
1354         */
1355        public boolean supportsClaimsParam() {
1356                
1357                return claimsParamSupported;
1358        }
1359
1360
1361        /**
1362         * Sets the support for the {@code claims} authorisation request
1363         * parameter. Corresponds to the {@code claims_parameter_supported}
1364         * metadata field.
1365         *
1366         * @param claimsParamSupported {@code true} if the {@code claim}
1367         *                             parameter is supported, else
1368         *                             {@code false}.
1369         */
1370        public void setSupportsClaimsParams(final boolean claimsParamSupported) {
1371
1372                this.claimsParamSupported = claimsParamSupported;
1373        }
1374        
1375        
1376        /**
1377         * Gets the support for the {@code request} authorisation request
1378         * parameter. Corresponds to the {@code request_parameter_supported}
1379         * metadata field.
1380         * 
1381         * @return {@code true} if the {@code reqeust} parameter is supported,
1382         *         else {@code false}.
1383         */
1384        public boolean supportsRequestParam() {
1385                
1386                return requestParamSupported;
1387        }
1388
1389
1390        /**
1391         * Sets the support for the {@code request} authorisation request
1392         * parameter. Corresponds to the {@code request_parameter_supported}
1393         * metadata field.
1394         *
1395         * @param requestParamSupported {@code true} if the {@code reqeust}
1396         *                              parameter is supported, else
1397         *                              {@code false}.
1398         */
1399        public void setSupportsRequestParam(final boolean requestParamSupported) {
1400
1401                this.requestParamSupported = requestParamSupported;
1402        }
1403        
1404        
1405        /**
1406         * Gets the support for the {@code request_uri} authorisation request
1407         * parameter. Corresponds the {@code request_uri_parameter_supported}
1408         * metadata field.
1409         * 
1410         * @return {@code true} if the {@code request_uri} parameter is
1411         *         supported, else {@code false}.
1412         */
1413        public boolean supportsRequestURIParam() {
1414                
1415                return requestURIParamSupported;
1416        }
1417
1418
1419        /**
1420         * Sets the support for the {@code request_uri} authorisation request
1421         * parameter. Corresponds the {@code request_uri_parameter_supported}
1422         * metadata field.
1423         *
1424         * @param requestURIParamSupported {@code true} if the
1425         *                                 {@code request_uri} parameter is
1426         *                                 supported, else {@code false}.
1427         */
1428        public void setSupportsRequestURIParam(final boolean requestURIParamSupported) {
1429
1430                this.requestURIParamSupported = requestURIParamSupported;
1431        }
1432        
1433        
1434        /**
1435         * Gets the requirement for the {@code request_uri} parameter 
1436         * pre-registration. Corresponds to the 
1437         * {@code require_request_uri_registration} metadata field.
1438         * 
1439         * @return {@code true} if the {@code request_uri} parameter values
1440         *         must be pre-registered, else {@code false}.
1441         */
1442        public boolean requiresRequestURIRegistration() {
1443                
1444                return requireRequestURIReg;
1445        }
1446
1447
1448        /**
1449         * Sets the requirement for the {@code request_uri} parameter
1450         * pre-registration. Corresponds to the
1451         * {@code require_request_uri_registration} metadata field.
1452         *
1453         * @param requireRequestURIReg {@code true} if the {@code request_uri}
1454         *                             parameter values must be pre-registered,
1455         *                             else {@code false}.
1456         */
1457        public void setRequiresRequestURIRegistration(final boolean requireRequestURIReg) {
1458
1459                this.requireRequestURIReg = requireRequestURIReg;
1460        }
1461        
1462        
1463        /**
1464         * Gets the support for front-channel logout. Corresponds to the
1465         * {@code frontchannel_logout_supported} metadata field.
1466         *
1467         * @return {@code true} if front-channel logout is supported, else
1468         *         {@code false}.
1469         */
1470        public boolean supportsFrontChannelLogout() {
1471                
1472                return frontChannelLogoutSupported;
1473        }
1474        
1475        
1476        /**
1477         * Sets the support for front-channel logout. Corresponds to the
1478         * {@code frontchannel_logout_supported} metadata field.
1479         *
1480         * @param frontChannelLogoutSupported {@code true} if front-channel
1481         *                                    logout is supported, else
1482         *                                    {@code false}.
1483         */
1484        public void setSupportsFrontChannelLogout(final boolean frontChannelLogoutSupported) {
1485        
1486                this.frontChannelLogoutSupported = frontChannelLogoutSupported;
1487        }
1488        
1489        
1490        /**
1491         * Gets the support for front-channel logout with a session ID.
1492         * Corresponds to the {@code frontchannel_logout_session_supported}
1493         * metadata field.
1494         *
1495         * @return {@code true} if front-channel logout with a session ID is
1496         *         supported, else {@code false}.
1497         */
1498        public boolean supportsFrontChannelLogoutSession() {
1499                
1500                return frontChannelLogoutSessionSupported;
1501        }
1502        
1503        
1504        /**
1505         * Sets the support for front-channel logout with a session ID.
1506         * Corresponds to the {@code frontchannel_logout_session_supported}
1507         * metadata field.
1508         *
1509         * @param frontChannelLogoutSessionSupported {@code true} if
1510         *                                           front-channel logout with
1511         *                                           a session ID is supported,
1512         *                                           else {@code false}.
1513         */
1514        public void setSupportsFrontChannelLogoutSession(final boolean frontChannelLogoutSessionSupported) {
1515        
1516                this.frontChannelLogoutSessionSupported = frontChannelLogoutSessionSupported;
1517        }
1518        
1519        
1520        /**
1521         * Gets the support for back-channel logout. Corresponds to the
1522         * {@code backchannel_logout_supported} metadata field.
1523         *
1524         * @return {@code true} if back-channel logout is supported, else
1525         *         {@code false}.
1526         */
1527        public boolean supportsBackChannelLogout() {
1528                
1529                return backChannelLogoutSupported;
1530        }
1531        
1532        
1533        /**
1534         * Sets the support for back-channel logout. Corresponds to the
1535         * {@code backchannel_logout_supported} metadata field.
1536         *
1537         * @param backChannelLogoutSupported {@code true} if back-channel
1538         *                                   logout is supported, else
1539         *                                   {@code false}.
1540         */
1541        public void setSupportsBackChannelLogout(final boolean backChannelLogoutSupported) {
1542        
1543                this.backChannelLogoutSupported = backChannelLogoutSupported;
1544        }
1545        
1546        
1547        /**
1548         * Gets the support for back-channel logout with a session ID.
1549         * Corresponds to the {@code backchannel_logout_session_supported}
1550         * metadata field.
1551         *
1552         * @return {@code true} if back-channel logout with a session ID is
1553         *         supported, else {@code false}.
1554         */
1555        public boolean supportsBackChannelLogoutSession() {
1556                
1557                return backChannelLogoutSessionSupported;
1558        }
1559        
1560        
1561        /**
1562         * Sets the support for back-channel logout with a session ID.
1563         * Corresponds to the {@code backchannel_logout_session_supported}
1564         * metadata field.
1565         *
1566         * @param backChannelLogoutSessionSupported {@code true} if
1567         *                                          back-channel logout with a
1568         *                                          session ID is supported,
1569         *                                          else {@code false}.
1570         */
1571        public void setSupportsBackChannelLogoutSession(final boolean backChannelLogoutSessionSupported) {
1572                
1573                this.backChannelLogoutSessionSupported = backChannelLogoutSessionSupported;
1574        }
1575
1576
1577        /**
1578         * Gets the specified custom (not registered) parameter.
1579         *
1580         * @param name The parameter name. Must not be {@code null}.
1581         *
1582         * @return The parameter value, {@code null} if not specified.
1583         */
1584        public Object getCustomParameter(final String name) {
1585
1586                return customParameters.get(name);
1587        }
1588
1589
1590        /**
1591         * Gets the specified custom (not registered) URI parameter.
1592         *
1593         * @param name The parameter name. Must not be {@code null}.
1594         *
1595         * @return The parameter URI value, {@code null} if not specified.
1596         */
1597        public URI getCustomURIParameter(final String name) {
1598
1599                try {
1600                        return JSONObjectUtils.getURI(customParameters, name);
1601                } catch (ParseException e) {
1602                        return null;
1603                }
1604        }
1605
1606
1607        /**
1608         * Sets the specified custom (not registered) parameter.
1609         *
1610         * @param name  The parameter name. Must not be {@code null}.
1611         * @param value The parameter value, {@code null} if not specified.
1612         */
1613        public void setCustomParameter(final String name, final Object value) {
1614
1615                if (REGISTERED_PARAMETER_NAMES.contains(name)) {
1616                        throw new IllegalArgumentException("The " + name + " parameter is registered");
1617                }
1618
1619                customParameters.put(name, value);
1620        }
1621
1622
1623        /**
1624         * Gets the custom (not registered) parameters.
1625         *
1626         * @return The custom parameters, empty JSON object if none.
1627         */
1628        public JSONObject getCustomParameters() {
1629
1630                return customParameters;
1631        }
1632
1633
1634        /**
1635         * Applies the OpenID Connect provider metadata defaults where no
1636         * values have been specified.
1637         *
1638         * <ul>
1639         *     <li>The response modes default to {@code ["query", "fragment"]}.
1640         *     <li>The grant types default to {@code ["authorization_code",
1641         *         "implicit"]}.
1642         *     <li>The token endpoint authentication methods default to
1643         *         {@code ["client_secret_basic"]}.
1644         *     <li>The claim types default to {@code ["normal]}.
1645         * </ul>
1646         */
1647        public void applyDefaults() {
1648
1649                if (rms == null) {
1650                        rms = new ArrayList<>(2);
1651                        rms.add(ResponseMode.QUERY);
1652                        rms.add(ResponseMode.FRAGMENT);
1653                }
1654
1655                if (gts == null) {
1656                        gts = new ArrayList<>(2);
1657                        gts.add(GrantType.AUTHORIZATION_CODE);
1658                        gts.add(GrantType.IMPLICIT);
1659                }
1660
1661                if (claimTypes == null) {
1662                        claimTypes = new ArrayList<>(1);
1663                        claimTypes.add(ClaimType.NORMAL);
1664                }
1665        }
1666
1667
1668        /**
1669         * Returns the JSON object representation of this OpenID Connect
1670         * provider metadata.
1671         *
1672         * @return The JSON object representation.
1673         */
1674        public JSONObject toJSONObject() {
1675
1676                JSONObject o = new OrderedJSONObject();
1677
1678                // Mandatory fields
1679
1680                o.put("issuer", issuer.getValue());
1681
1682                List<String> stringList = new ArrayList<>(subjectTypes.size());
1683
1684                for (SubjectType st: subjectTypes)
1685                        stringList.add(st.toString());
1686
1687                o.put("subject_types_supported", stringList);
1688
1689                o.put("jwks_uri", jwkSetURI.toString());
1690
1691                // Optional fields
1692
1693                if (authzEndpoint != null)
1694                        o.put("authorization_endpoint", authzEndpoint.toString());
1695
1696                if (tokenEndpoint != null)
1697                        o.put("token_endpoint", tokenEndpoint.toString());
1698
1699                if (userInfoEndpoint != null)
1700                        o.put("userinfo_endpoint", userInfoEndpoint.toString());
1701
1702                if (regEndpoint != null)
1703                        o.put("registration_endpoint", regEndpoint.toString());
1704                
1705                if (introspectionEndpoint != null)
1706                        o.put("introspection_endpoint", introspectionEndpoint.toString());
1707                
1708                if (revocationEndpoint != null)
1709                        o.put("revocation_endpoint", revocationEndpoint.toString());
1710
1711                if (checkSessionIframe != null)
1712                        o.put("check_session_iframe", checkSessionIframe.toString());
1713
1714                if (endSessionEndpoint != null)
1715                        o.put("end_session_endpoint", endSessionEndpoint.toString());
1716
1717                if (scope != null)
1718                        o.put("scopes_supported", scope.toStringList());
1719
1720                if (rts != null) {
1721
1722                        stringList = new ArrayList<>(rts.size());
1723
1724                        for (ResponseType rt: rts)
1725                                stringList.add(rt.toString());
1726
1727                        o.put("response_types_supported", stringList);
1728                }
1729
1730                if (rms != null) {
1731
1732                        stringList = new ArrayList<>(rms.size());
1733
1734                        for (ResponseMode rm: rms)
1735                                stringList.add(rm.getValue());
1736
1737                        o.put("response_modes_supported", stringList);
1738                }
1739
1740                if (gts != null) {
1741
1742                        stringList = new ArrayList<>(gts.size());
1743
1744                        for (GrantType gt: gts)
1745                                stringList.add(gt.toString());
1746
1747                        o.put("grant_types_supported", stringList);
1748                }
1749
1750                if (codeChallengeMethods != null) {
1751
1752                        stringList = new ArrayList<>(codeChallengeMethods.size());
1753
1754                        for (CodeChallengeMethod m: codeChallengeMethods)
1755                                stringList.add(m.getValue());
1756
1757                        o.put("code_challenge_methods_supported", stringList);
1758                }
1759
1760                if (acrValues != null) {
1761
1762                        stringList = new ArrayList<>(acrValues.size());
1763
1764                        for (ACR acr: acrValues)
1765                                stringList.add(acr.getValue());
1766
1767                        o.put("acr_values_supported", stringList);
1768                }
1769
1770
1771                if (tokenEndpointAuthMethods != null) {
1772
1773                        stringList = new ArrayList<>(tokenEndpointAuthMethods.size());
1774
1775                        for (ClientAuthenticationMethod m: tokenEndpointAuthMethods)
1776                                stringList.add(m.getValue());
1777
1778                        o.put("token_endpoint_auth_methods_supported", stringList);
1779                }
1780
1781                if (tokenEndpointJWSAlgs != null) {
1782
1783                        stringList = new ArrayList<>(tokenEndpointJWSAlgs.size());
1784
1785                        for (JWSAlgorithm alg: tokenEndpointJWSAlgs)
1786                                stringList.add(alg.getName());
1787
1788                        o.put("token_endpoint_auth_signing_alg_values_supported", stringList);
1789                }
1790
1791                if (requestObjectJWSAlgs != null) {
1792
1793                        stringList = new ArrayList<>(requestObjectJWSAlgs.size());
1794
1795                        for (JWSAlgorithm alg: requestObjectJWSAlgs)
1796                                stringList.add(alg.getName());
1797
1798                        o.put("request_object_signing_alg_values_supported", stringList);
1799                }
1800
1801                if (requestObjectJWEAlgs != null) {
1802
1803                        stringList = new ArrayList<>(requestObjectJWEAlgs.size());
1804
1805                        for (JWEAlgorithm alg: requestObjectJWEAlgs)
1806                                stringList.add(alg.getName());
1807
1808                        o.put("request_object_encryption_alg_values_supported", stringList);
1809                }
1810
1811                if (requestObjectJWEEncs != null) {
1812
1813                        stringList = new ArrayList<>(requestObjectJWEEncs.size());
1814
1815                        for (EncryptionMethod m: requestObjectJWEEncs)
1816                                stringList.add(m.getName());
1817
1818                        o.put("request_object_encryption_enc_values_supported", stringList);
1819                }
1820
1821                if (idTokenJWSAlgs != null) {
1822
1823                        stringList = new ArrayList<>(idTokenJWSAlgs.size());
1824
1825                        for (JWSAlgorithm alg: idTokenJWSAlgs)
1826                                stringList.add(alg.getName());
1827
1828                        o.put("id_token_signing_alg_values_supported", stringList);
1829                }
1830
1831                if (idTokenJWEAlgs != null) {
1832
1833                        stringList = new ArrayList<>(idTokenJWEAlgs.size());
1834
1835                        for (JWEAlgorithm alg: idTokenJWEAlgs)
1836                                stringList.add(alg.getName());
1837
1838                        o.put("id_token_encryption_alg_values_supported", stringList);
1839                }
1840
1841                if (idTokenJWEEncs != null) {
1842
1843                        stringList = new ArrayList<>(idTokenJWEEncs.size());
1844
1845                        for (EncryptionMethod m: idTokenJWEEncs)
1846                                stringList.add(m.getName());
1847
1848                        o.put("id_token_encryption_enc_values_supported", stringList);
1849                }
1850
1851                if (userInfoJWSAlgs != null) {
1852
1853                        stringList = new ArrayList<>(userInfoJWSAlgs.size());
1854
1855                        for (JWSAlgorithm alg: userInfoJWSAlgs)
1856                                stringList.add(alg.getName());
1857
1858                        o.put("userinfo_signing_alg_values_supported", stringList);
1859                }
1860
1861                if (userInfoJWEAlgs != null) {
1862
1863                        stringList = new ArrayList<>(userInfoJWEAlgs.size());
1864
1865                        for (JWEAlgorithm alg: userInfoJWEAlgs)
1866                                stringList.add(alg.getName());
1867
1868                        o.put("userinfo_encryption_alg_values_supported", stringList);
1869                }
1870
1871                if (userInfoJWEEncs != null) {
1872
1873                        stringList = new ArrayList<>(userInfoJWEEncs.size());
1874
1875                        for (EncryptionMethod m: userInfoJWEEncs)
1876                                stringList.add(m.getName());
1877
1878                        o.put("userinfo_encryption_enc_values_supported", stringList);
1879                }
1880
1881                if (displays != null) {
1882
1883                        stringList = new ArrayList<>(displays.size());
1884
1885                        for (Display d: displays)
1886                                stringList.add(d.toString());
1887
1888                        o.put("display_values_supported", stringList);
1889                }
1890
1891                if (claimTypes != null) {
1892
1893                        stringList = new ArrayList<>(claimTypes.size());
1894
1895                        for (ClaimType ct: claimTypes)
1896                                stringList.add(ct.toString());
1897
1898                        o.put("claim_types_supported", stringList);
1899                }
1900
1901                if (claims != null)
1902                        o.put("claims_supported", claims);
1903
1904                if (claimsLocales != null) {
1905
1906                        stringList = new ArrayList<>(claimsLocales.size());
1907
1908                        for (LangTag l: claimsLocales)
1909                                stringList.add(l.toString());
1910
1911                        o.put("claims_locales_supported", stringList);
1912                }
1913
1914                if (uiLocales != null) {
1915
1916                        stringList = new ArrayList<>(uiLocales.size());
1917
1918                        for (LangTag l: uiLocales)
1919                                stringList.add(l.toString());
1920
1921                        o.put("ui_locales_supported", stringList);
1922                }
1923
1924                if (serviceDocsURI != null)
1925                        o.put("service_documentation", serviceDocsURI.toString());
1926
1927                if (policyURI != null)
1928                        o.put("op_policy_uri", policyURI.toString());
1929
1930                if (tosURI != null)
1931                        o.put("op_tos_uri", tosURI.toString());
1932
1933                o.put("claims_parameter_supported", claimsParamSupported);
1934
1935                o.put("request_parameter_supported", requestParamSupported);
1936
1937                o.put("request_uri_parameter_supported", requestURIParamSupported);
1938
1939                o.put("require_request_uri_registration", requireRequestURIReg);
1940                
1941                // optional front and back-channel logout
1942                o.put("frontchannel_logout_supported", frontChannelLogoutSupported);
1943                
1944                if (frontChannelLogoutSupported) {
1945                        o.put("frontchannel_logout_session_supported", frontChannelLogoutSessionSupported);
1946                }
1947                
1948                o.put("backchannel_logout_supported", backChannelLogoutSupported);
1949                
1950                if (backChannelLogoutSupported) {
1951                        o.put("backchannel_logout_session_supported", backChannelLogoutSessionSupported);
1952                }
1953
1954                // Append any custom (not registered) parameters
1955                o.putAll(customParameters);
1956
1957                return o;
1958        }
1959
1960
1961
1962        /**
1963         * Parses an OpenID Connect provider metadata from the specified JSON 
1964         * object.
1965         *
1966         * @param jsonObject The JSON object to parse. Must not be 
1967         *                   {@code null}.
1968         *
1969         * @return The OpenID Connect provider metadata.
1970         *
1971         * @throws ParseException If the JSON object couldn't be parsed to an
1972         *                        OpenID Connect provider metadata.
1973         */
1974        public static OIDCProviderMetadata parse(final JSONObject jsonObject)
1975                throws ParseException {
1976
1977                // Parse issuer and subject_types_supported first
1978                
1979                List<SubjectType> subjectTypes = new ArrayList<>();
1980                
1981                for (String v: JSONObjectUtils.getStringArray(jsonObject, "subject_types_supported")) {
1982                        subjectTypes.add(SubjectType.parse(v));
1983                }
1984                
1985                Issuer issuer = new Issuer(JSONObjectUtils.getURI(jsonObject, "issuer").toString());
1986
1987                URI jwkSetURI = JSONObjectUtils.getURI(jsonObject, "jwks_uri");
1988                
1989                
1990                OIDCProviderMetadata op = new OIDCProviderMetadata(issuer, Collections.unmodifiableList(subjectTypes), jwkSetURI);
1991
1992                // Endpoints
1993                if (jsonObject.get("authorization_endpoint") != null)
1994                        op.authzEndpoint = JSONObjectUtils.getURI(jsonObject, "authorization_endpoint");
1995
1996                if (jsonObject.get("token_endpoint") != null)
1997                        op.tokenEndpoint = JSONObjectUtils.getURI(jsonObject, "token_endpoint");
1998
1999                if (jsonObject.get("userinfo_endpoint") != null)
2000                        op.userInfoEndpoint = JSONObjectUtils.getURI(jsonObject, "userinfo_endpoint");
2001                
2002                if (jsonObject.get("registration_endpoint") != null)
2003                        op.regEndpoint = JSONObjectUtils.getURI(jsonObject, "registration_endpoint");
2004                
2005                if (jsonObject.get("introspection_endpoint") != null)
2006                        op.introspectionEndpoint = JSONObjectUtils.getURI(jsonObject, "introspection_endpoint");
2007                
2008                if (jsonObject.get("revocation_endpoint") != null)
2009                        op.revocationEndpoint = JSONObjectUtils.getURI(jsonObject, "revocation_endpoint");
2010                
2011                if (jsonObject.get("check_session_iframe") != null)
2012                        op.checkSessionIframe = JSONObjectUtils.getURI(jsonObject, "check_session_iframe");
2013                
2014                if (jsonObject.get("end_session_endpoint") != null)
2015                        op.endSessionEndpoint = JSONObjectUtils.getURI(jsonObject, "end_session_endpoint");
2016
2017                // OIDC capabilities
2018                if (jsonObject.get("scopes_supported") != null) {
2019
2020                        op.scope = new Scope();
2021
2022                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "scopes_supported")) {
2023
2024                                if (v != null)
2025                                        op.scope.add(new Scope.Value(v));
2026                        }
2027                }
2028
2029                if (jsonObject.get("response_types_supported") != null) {
2030
2031                        op.rts = new ArrayList<>();
2032
2033                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "response_types_supported")) {
2034
2035                                if (v != null)
2036                                        op.rts.add(ResponseType.parse(v));
2037                        }
2038                }
2039
2040                if (jsonObject.get("response_modes_supported") != null) {
2041
2042                        op.rms = new ArrayList<>();
2043
2044                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "response_modes_supported")) {
2045
2046                                if (v != null)
2047                                        op.rms.add(new ResponseMode(v));
2048                        }
2049                }
2050                
2051                if (jsonObject.get("grant_types_supported") != null) {
2052                        
2053                        op.gts = new ArrayList<>();
2054                        
2055                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "grant_types_supported")) {
2056                                
2057                                if (v != null)
2058                                        op.gts.add(GrantType.parse(v));
2059                        }
2060                }
2061
2062                if (jsonObject.get("code_challenge_methods_supported") != null) {
2063
2064                        op.codeChallengeMethods = new ArrayList<>();
2065
2066                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "code_challenge_methods_supported")) {
2067
2068                                if (v != null)
2069                                        op.codeChallengeMethods.add(CodeChallengeMethod.parse(v));
2070                        }
2071                }
2072
2073                if (jsonObject.get("acr_values_supported") != null) {
2074
2075                        op.acrValues = new ArrayList<>();
2076
2077                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "acr_values_supported")) {
2078
2079                                if (v != null)
2080                                        op.acrValues.add(new ACR(v));
2081                        }
2082                }
2083
2084                if (jsonObject.get("token_endpoint_auth_methods_supported") != null) {
2085                        
2086                        op.tokenEndpointAuthMethods = new ArrayList<>();
2087                        
2088                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "token_endpoint_auth_methods_supported")) {
2089                                
2090                                if (v != null)
2091                                        op.tokenEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
2092                        }
2093                }
2094                
2095                if (jsonObject.get("token_endpoint_auth_signing_alg_values_supported") != null) {
2096                        
2097                        op.tokenEndpointJWSAlgs = new ArrayList<>();
2098                        
2099                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "token_endpoint_auth_signing_alg_values_supported")) {
2100
2101                                if (v != null && v.equals(Algorithm.NONE.getName()))
2102                                        throw new ParseException("The none algorithm is not accepted");
2103                                
2104                                if (v != null)
2105                                        op.tokenEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
2106                        }
2107                }
2108                
2109                
2110                // OpenID Connect request object
2111
2112                if (jsonObject.get("request_object_signing_alg_values_supported") != null) {
2113
2114                        op.requestObjectJWSAlgs = new ArrayList<>();
2115
2116                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_signing_alg_values_supported")) {
2117
2118                                if (v != null)
2119                                        op.requestObjectJWSAlgs.add(JWSAlgorithm.parse(v));
2120                        }
2121                }
2122
2123
2124                if (jsonObject.get("request_object_encryption_alg_values_supported") != null) {
2125
2126                        op.requestObjectJWEAlgs = new ArrayList<>();
2127
2128                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_encryption_alg_values_supported")) {
2129
2130                                if (v != null)
2131                                        op.requestObjectJWEAlgs.add(JWEAlgorithm.parse(v));
2132                        }
2133                }
2134
2135
2136                if (jsonObject.get("request_object_encryption_enc_values_supported") != null) {
2137
2138                        op.requestObjectJWEEncs = new ArrayList<>();
2139
2140                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_encryption_enc_values_supported")) {
2141
2142                                if (v != null)
2143                                        op.requestObjectJWEEncs.add(EncryptionMethod.parse(v));
2144                        }
2145                }
2146                
2147                
2148                // ID token
2149
2150                if (jsonObject.get("id_token_signing_alg_values_supported") != null) {
2151
2152                        op.idTokenJWSAlgs = new ArrayList<>();
2153
2154                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_signing_alg_values_supported")) {
2155
2156                                if (v != null)
2157                                        op.idTokenJWSAlgs.add(JWSAlgorithm.parse(v));
2158                        }
2159                }
2160
2161
2162                if (jsonObject.get("id_token_encryption_alg_values_supported") != null) {
2163
2164                        op.idTokenJWEAlgs = new ArrayList<>();
2165
2166                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_encryption_alg_values_supported")) {
2167
2168                                if (v != null)
2169                                        op.idTokenJWEAlgs.add(JWEAlgorithm.parse(v));
2170                        }
2171                }
2172
2173
2174                if (jsonObject.get("id_token_encryption_enc_values_supported") != null) {
2175
2176                        op.idTokenJWEEncs = new ArrayList<>();
2177
2178                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_encryption_enc_values_supported")) {
2179
2180                                if (v != null)
2181                                        op.idTokenJWEEncs.add(EncryptionMethod.parse(v));
2182                        }
2183                }
2184
2185                // UserInfo
2186
2187                if (jsonObject.get("userinfo_signing_alg_values_supported") != null) {
2188
2189                        op.userInfoJWSAlgs = new ArrayList<>();
2190
2191                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_signing_alg_values_supported")) {
2192
2193                                if (v != null)
2194                                        op.userInfoJWSAlgs.add(JWSAlgorithm.parse(v));
2195                        }
2196                }
2197
2198
2199                if (jsonObject.get("userinfo_encryption_alg_values_supported") != null) {
2200
2201                        op.userInfoJWEAlgs = new ArrayList<>();
2202
2203                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_encryption_alg_values_supported")) {
2204
2205                                if (v != null)
2206                                        op.userInfoJWEAlgs.add(JWEAlgorithm.parse(v));
2207                        }
2208                }
2209
2210
2211                if (jsonObject.get("userinfo_encryption_enc_values_supported") != null) {
2212
2213                        op.userInfoJWEEncs = new ArrayList<>();
2214
2215                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_encryption_enc_values_supported")) {
2216
2217                                        if (v != null)
2218                                                op.userInfoJWEEncs.add(EncryptionMethod.parse(v));
2219                        }
2220                }
2221
2222                
2223                // Misc
2224
2225                if (jsonObject.get("display_values_supported") != null) {
2226
2227                        op.displays = new ArrayList<>();
2228
2229                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "display_values_supported")) {
2230
2231                                if (v != null)
2232                                        op.displays.add(Display.parse(v));
2233                        }
2234                }
2235                
2236                if (jsonObject.get("claim_types_supported") != null) {
2237                        
2238                        op.claimTypes = new ArrayList<>();
2239                        
2240                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "claim_types_supported")) {
2241                                
2242                                if (v != null)
2243                                        op.claimTypes.add(ClaimType.parse(v));
2244                        }
2245                }
2246
2247
2248                if (jsonObject.get("claims_supported") != null) {
2249
2250                        op.claims = new ArrayList<>();
2251
2252                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "claims_supported")) {
2253
2254                                if (v != null)
2255                                        op.claims.add(v);
2256                        }
2257                }
2258                
2259                if (jsonObject.get("claims_locales_supported") != null) {
2260                        
2261                        op.claimsLocales = new ArrayList<>();
2262                        
2263                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "claims_locales_supported")) {
2264                                
2265                                if (v != null) {
2266                                        
2267                                        try {
2268                                                op.claimsLocales.add(LangTag.parse(v));
2269                                        
2270                                        } catch (LangTagException e) {
2271                                                
2272                                                throw new ParseException("Invalid claims_locales_supported field: " + e.getMessage(), e);
2273                                        }
2274                                }
2275                        }
2276                }
2277                
2278                if (jsonObject.get("ui_locales_supported") != null) {
2279                        
2280                        op.uiLocales = new ArrayList<>();
2281                        
2282                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "ui_locales_supported")) {
2283                                
2284                                if (v != null) {
2285                                        
2286                                        try {
2287                                                op.uiLocales.add(LangTag.parse(v));
2288                                        
2289                                        } catch (LangTagException e) {
2290                                                
2291                                                throw new ParseException("Invalid ui_locales_supported field: " + e.getMessage(), e);
2292                                        }
2293                                }
2294                        }
2295                }
2296
2297
2298                if (jsonObject.get("service_documentation") != null)
2299                        op.serviceDocsURI = JSONObjectUtils.getURI(jsonObject, "service_documentation");
2300                
2301                if (jsonObject.get("op_policy_uri") != null)
2302                        op.policyURI = JSONObjectUtils.getURI(jsonObject, "op_policy_uri");
2303                
2304                if (jsonObject.get("op_tos_uri") != null)
2305                        op.tosURI = JSONObjectUtils.getURI(jsonObject, "op_tos_uri");
2306                
2307                if (jsonObject.get("claims_parameter_supported") != null)
2308                        op.claimsParamSupported = JSONObjectUtils.getBoolean(jsonObject, "claims_parameter_supported");
2309                
2310                if (jsonObject.get("request_parameter_supported") != null)
2311                        op.requestParamSupported = JSONObjectUtils.getBoolean(jsonObject, "request_parameter_supported");
2312                
2313                if (jsonObject.get("request_uri_parameter_supported") != null)
2314                        op.requestURIParamSupported = JSONObjectUtils.getBoolean(jsonObject, "request_uri_parameter_supported");
2315                
2316                if (jsonObject.get("require_request_uri_registration") != null)
2317                        op.requireRequestURIReg = JSONObjectUtils.getBoolean(jsonObject, "require_request_uri_registration");
2318                
2319                // optional front and back-channel logout
2320                if (jsonObject.get("frontchannel_logout_supported") != null)
2321                        op.frontChannelLogoutSupported = JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_supported");
2322                
2323                if (op.frontChannelLogoutSupported && jsonObject.get("frontchannel_logout_session_supported") != null)
2324                        op.frontChannelLogoutSessionSupported = JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_supported");
2325                
2326                if (jsonObject.get("backchannel_logout_supported") != null)
2327                        op.backChannelLogoutSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_supported");
2328                
2329                if (op.frontChannelLogoutSupported && jsonObject.get("backchannel_logout_session_supported") != null)
2330                        op.backChannelLogoutSessionSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_supported");
2331                
2332                // Parse custom (not registered) parameters
2333                JSONObject customParams = new JSONObject(jsonObject);
2334                customParams.keySet().removeAll(REGISTERED_PARAMETER_NAMES);
2335                for (Map.Entry<String,Object> customEntry: customParams.entrySet()) {
2336                        op.setCustomParameter(customEntry.getKey(), customEntry.getValue());
2337                }
2338
2339                return op;
2340        }
2341
2342
2343        /**
2344         * Parses an OpenID Connect provider metadata from the specified JSON 
2345         * object string.
2346         *
2347         * @param s The JSON object sting to parse. Must not be {@code null}.
2348         *
2349         * @return The OpenID Connect provider metadata.
2350         *
2351         * @throws ParseException If the JSON object string couldn't be parsed
2352         *                        to an OpenID Connect provider metadata.
2353         */
2354        public static OIDCProviderMetadata parse(final String s)
2355                throws ParseException {
2356
2357                return parse(JSONObjectUtils.parse(s));
2358        }
2359}