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