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