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.URL;
025import java.util.*;
026
027import net.minidev.json.JSONObject;
028
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.GeneralException;
035import com.nimbusds.oauth2.sdk.ParseException;
036import com.nimbusds.oauth2.sdk.as.AuthorizationServerEndpointMetadata;
037import com.nimbusds.oauth2.sdk.as.AuthorizationServerMetadata;
038import com.nimbusds.oauth2.sdk.http.HTTPRequest;
039import com.nimbusds.oauth2.sdk.http.HTTPResponse;
040import com.nimbusds.oauth2.sdk.id.Identifier;
041import com.nimbusds.oauth2.sdk.id.Issuer;
042import com.nimbusds.oauth2.sdk.util.CollectionUtils;
043import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
044import com.nimbusds.openid.connect.sdk.Display;
045import com.nimbusds.openid.connect.sdk.SubjectType;
046import com.nimbusds.openid.connect.sdk.assurance.evidences.IDDocumentType;
047import com.nimbusds.openid.connect.sdk.assurance.evidences.IdentityEvidenceType;
048import com.nimbusds.openid.connect.sdk.assurance.IdentityTrustFramework;
049import com.nimbusds.openid.connect.sdk.assurance.evidences.IdentityVerificationMethod;
050import com.nimbusds.openid.connect.sdk.claims.ACR;
051import com.nimbusds.openid.connect.sdk.claims.ClaimType;
052import com.nimbusds.openid.connect.sdk.federation.FederationType;
053
054
055/**
056 * OpenID Provider (OP) metadata.
057 *
058 * <p>Related specifications:
059 *
060 * <ul>
061 *     <li>OpenID Connect Discovery 1.0, section 3.
062 *     <li>OpenID Connect Session Management 1.0, section 2.1 (draft 28).
063 *     <li>OpenID Connect Front-Channel Logout 1.0, section 3 (draft 02).
064 *     <li>OpenID Connect Back-Channel Logout 1.0, section 2.1 (draft 04).
065 *     <li>OpenID Connect for Identity Assurance 1.0 (draft 08).
066 *     <li>OpenID Connect Federation 1.0 (draft 10).
067 *     <li>OAuth 2.0 Authorization Server Metadata (RFC 8414)
068 *     <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound
069 *         Access Tokens (RFC 8705)
070 *     <li>Financial-grade API: JWT Secured Authorization Response Mode for
071 *         OAuth 2.0 (JARM)
072 * </ul>
073 */
074public class OIDCProviderMetadata extends AuthorizationServerMetadata {
075
076
077        /**
078         * The registered parameter names.
079         */
080        private static final Set<String> REGISTERED_PARAMETER_NAMES;
081
082
083        static {
084                Set<String> p = new HashSet<>(AuthorizationServerMetadata.getRegisteredParameterNames());
085                p.addAll(OIDCProviderEndpointMetadata.getRegisteredParameterNames());
086                p.add("check_session_iframe");
087                p.add("end_session_endpoint");
088                p.add("acr_values_supported");
089                p.add("subject_types_supported");
090                p.add("id_token_signing_alg_values_supported");
091                p.add("id_token_encryption_alg_values_supported");
092                p.add("id_token_encryption_enc_values_supported");
093                p.add("userinfo_signing_alg_values_supported");
094                p.add("userinfo_encryption_alg_values_supported");
095                p.add("userinfo_encryption_enc_values_supported");
096                p.add("display_values_supported");
097                p.add("claim_types_supported");
098                p.add("claims_supported");
099                p.add("claims_locales_supported");
100                p.add("claims_parameter_supported");
101                p.add("backchannel_logout_supported");
102                p.add("backchannel_logout_session_supported");
103                p.add("frontchannel_logout_supported");
104                p.add("frontchannel_logout_session_supported");
105                p.add("verified_claims_supported");
106                p.add("trust_frameworks_supported");
107                p.add("evidence_supported");
108                p.add("id_documents_supported");
109                p.add("id_documents_verification_methods_supported");
110                p.add("claims_in_verified_claims_supported");
111                p.add("federation_types_supported");
112                p.add("organization_name");
113                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
114        }
115
116
117        /**
118         * The UserInfo endpoint.
119         */
120        private URI userInfoEndpoint;
121        
122        
123        /**
124         * The cross-origin check session iframe.
125         */
126        private URI checkSessionIframe;
127        
128        
129        /**
130         * The logout endpoint.
131         */
132        private URI endSessionEndpoint;
133
134
135        /**
136         * The supported ACRs.
137         */
138        private List<ACR> acrValues;
139
140
141        /**
142         * The supported subject types.
143         */
144        private final List<SubjectType> subjectTypes;
145
146
147        /**
148         * The supported ID token JWS algorithms.
149         */
150        private List<JWSAlgorithm> idTokenJWSAlgs;
151
152
153        /**
154         * The supported ID token JWE algorithms.
155         */
156        private List<JWEAlgorithm> idTokenJWEAlgs;
157
158
159        /**
160         * The supported ID token encryption methods.
161         */
162        private List<EncryptionMethod> idTokenJWEEncs;
163
164
165        /**
166         * The supported UserInfo JWS algorithms.
167         */
168        private List<JWSAlgorithm> userInfoJWSAlgs;
169
170
171        /**
172         * The supported UserInfo JWE algorithms.
173         */
174        private List<JWEAlgorithm> userInfoJWEAlgs;
175
176
177        /**
178         * The supported UserInfo encryption methods.
179         */
180        private List<EncryptionMethod> userInfoJWEEncs;
181
182
183        /**
184         * The supported displays.
185         */
186        private List<Display> displays;
187        
188        
189        /**
190         * The supported claim types.
191         */
192        private List<ClaimType> claimTypes;
193
194
195        /**
196         * The supported claims names.
197         */
198        private List<String> claims;
199        
200        
201        /**
202         * The supported claims locales.
203         */
204        private List<LangTag> claimsLocales;
205        
206        
207        /**
208         * If {@code true} the {@code claims} parameter is supported, else not.
209         */
210        private boolean claimsParamSupported = false;
211        
212        
213        /**
214         * If {@code true} the {@code frontchannel_logout_supported} parameter
215         * is set, else not.
216         */
217        private boolean frontChannelLogoutSupported = false;
218        
219        
220        /**
221         * If {@code true} the {@code frontchannel_logout_session_supported}
222         * parameter is set, else not.
223         */
224        private boolean frontChannelLogoutSessionSupported = false;
225        
226        
227        /**
228         * If {@code true} the {@code backchannel_logout_supported} parameter
229         * is set, else not.
230         */
231        private boolean backChannelLogoutSupported = false;
232        
233        
234        /**
235         * If {@code true} the {@code backchannel_logout_session_supported}
236         * parameter is set, else not.
237         */
238        private boolean backChannelLogoutSessionSupported = false;
239        
240        
241        /**
242         * If {@code true} verified claims are supported.
243         */
244        private boolean verifiedClaimsSupported = false;
245        
246        
247        /**
248         * The supported trust frameworks.
249         */
250        private List<IdentityTrustFramework> trustFrameworks;
251        
252        
253        /**
254         * The supported identity evidence types.
255         */
256        private List<IdentityEvidenceType> evidenceTypes;
257        
258        
259        /**
260         * The supported identity documents.
261         */
262        private List<IDDocumentType> idDocuments;
263        
264        
265        /**
266         * The supported identity verification methods.
267         */
268        private List<IdentityVerificationMethod> idVerificationMethods;
269        
270        
271        /**
272         * The supported verified claims.
273         */
274        private List<String> verifiedClaims;
275        
276        
277        /**
278         * The supported federation types.
279         */
280        private List<FederationType> federationTypes;
281        
282        
283        /**
284         * The organisation name (in federation).
285         */
286        private String organizationName;
287        
288        
289        /**
290         * The federation registration endpoint.
291         */
292        private URI federationRegistrationEndpoint;
293
294
295        /**
296         * Creates a new OpenID Connect provider metadata instance.
297         * 
298         * @param issuer       The issuer identifier. Must be an URI using the
299         *                     https scheme with no query or fragment 
300         *                     component. Must not be {@code null}.
301         * @param subjectTypes The supported subject types. At least one must
302         *                     be specified. Must not be {@code null}.
303         * @param jwkSetURI    The JWK set URI. Must not be {@code null}.
304         */
305        public OIDCProviderMetadata(final Issuer issuer,
306                                    final List<SubjectType> subjectTypes,
307                                    final URI jwkSetURI) {
308        
309                super(issuer);
310                
311                if (subjectTypes.size() < 1)
312                        throw new IllegalArgumentException("At least one supported subject type must be specified");
313                
314                this.subjectTypes = subjectTypes;
315
316                if (jwkSetURI == null)
317                        throw new IllegalArgumentException("The public JWK set URI must not be null");
318
319                setJWKSetURI(jwkSetURI);
320                
321                // Default OpenID Connect setting is supported
322                setSupportsRequestURIParam(true);
323        }
324        
325        
326        @Override
327        public void setMtlsEndpointAliases(AuthorizationServerEndpointMetadata mtlsEndpointAliases) {
328        
329                if (mtlsEndpointAliases != null && !(mtlsEndpointAliases instanceof OIDCProviderEndpointMetadata)) {
330                        // convert the provided endpoints to OIDC
331                        super.setMtlsEndpointAliases(new OIDCProviderEndpointMetadata(mtlsEndpointAliases));
332                } else {
333                        super.setMtlsEndpointAliases(mtlsEndpointAliases);
334                }
335        }
336        
337        @Override
338        public OIDCProviderEndpointMetadata getMtlsEndpointAliases() {
339        
340                return (OIDCProviderEndpointMetadata) super.getMtlsEndpointAliases();
341        }
342
343
344        /**
345         * Gets the registered OpenID Connect provider metadata parameter
346         * names.
347         *
348         * @return The registered OpenID Connect provider metadata parameter
349         *         names, as an unmodifiable set.
350         */
351        public static Set<String> getRegisteredParameterNames() {
352
353                return REGISTERED_PARAMETER_NAMES;
354        }
355
356
357        /**
358         * Gets the UserInfo endpoint URI. Corresponds the
359         * {@code userinfo_endpoint} metadata field.
360         *
361         * @return The UserInfo endpoint URI, {@code null} if not specified.
362         */
363        public URI getUserInfoEndpointURI() {
364
365                return userInfoEndpoint;
366        }
367
368
369        /**
370         * Sets the UserInfo endpoint URI. Corresponds the
371         * {@code userinfo_endpoint} metadata field.
372         *
373         * @param userInfoEndpoint The UserInfo endpoint URI, {@code null} if
374         *                         not specified.
375         */
376        public void setUserInfoEndpointURI(final URI userInfoEndpoint) {
377
378                this.userInfoEndpoint = userInfoEndpoint;
379        }
380        
381        
382        /**
383         * Gets the cross-origin check session iframe URI. Corresponds to the
384         * {@code check_session_iframe} metadata field.
385         * 
386         * @return The check session iframe URI, {@code null} if not specified.
387         */
388        public URI getCheckSessionIframeURI() {
389                
390                return checkSessionIframe;
391        }
392
393
394        /**
395         * Sets the cross-origin check session iframe URI. Corresponds to the
396         * {@code check_session_iframe} metadata field.
397         *
398         * @param checkSessionIframe The check session iframe URI, {@code null}
399         *                           if not specified.
400         */
401        public void setCheckSessionIframeURI(final URI checkSessionIframe) {
402
403                this.checkSessionIframe = checkSessionIframe;
404        }
405        
406        
407        /**
408         * Gets the logout endpoint URI. Corresponds to the
409         * {@code end_session_endpoint} metadata field.
410         * 
411         * @return The logoout endpoint URI, {@code null} if not specified.
412         */
413        public URI getEndSessionEndpointURI() {
414                
415                return endSessionEndpoint;
416        }
417
418
419        /**
420         * Sets the logout endpoint URI. Corresponds to the
421         * {@code end_session_endpoint} metadata field.
422         *
423         * @param endSessionEndpoint The logoout endpoint URI, {@code null} if
424         *                           not specified.
425         */
426        public void setEndSessionEndpointURI(final URI endSessionEndpoint) {
427
428                this.endSessionEndpoint = endSessionEndpoint;
429        }
430
431        /**
432         * Gets the supported Authentication Context Class References (ACRs).
433         * Corresponds to the {@code acr_values_supported} metadata field.
434         *
435         * @return The supported ACRs, {@code null} if not specified.
436         */
437        public List<ACR> getACRs() {
438
439                return acrValues;
440        }
441
442
443        /**
444         * Sets the supported Authentication Context Class References (ACRs).
445         * Corresponds to the {@code acr_values_supported} metadata field.
446         *
447         * @param acrValues The supported ACRs, {@code null} if not specified.
448         */
449        public void setACRs(final List<ACR> acrValues) {
450
451                this.acrValues = acrValues;
452        }
453
454
455        /**
456         * Gets the supported subject types. Corresponds to the
457         * {@code subject_types_supported} metadata field.
458         *
459         * @return The supported subject types.
460         */
461        public List<SubjectType> getSubjectTypes() {
462
463                return subjectTypes;
464        }
465
466
467        /**
468         * Gets the supported JWS algorithms for ID tokens. Corresponds to the 
469         * {@code id_token_signing_alg_values_supported} metadata field.
470         *
471         * @return The supported JWS algorithms, {@code null} if not specified.
472         */
473        public List<JWSAlgorithm> getIDTokenJWSAlgs() {
474
475                return idTokenJWSAlgs;
476        }
477
478
479        /**
480         * Sets the supported JWS algorithms for ID tokens. Corresponds to the
481         * {@code id_token_signing_alg_values_supported} metadata field.
482         *
483         * @param idTokenJWSAlgs The supported JWS algorithms, {@code null} if
484         *                       not specified.
485         */
486        public void setIDTokenJWSAlgs(final List<JWSAlgorithm> idTokenJWSAlgs) {
487
488                this.idTokenJWSAlgs = idTokenJWSAlgs;
489        }
490
491
492        /**
493         * Gets the supported JWE algorithms for ID tokens. Corresponds to the 
494         * {@code id_token_encryption_alg_values_supported} metadata field.
495         *
496         * @return The supported JWE algorithms, {@code null} if not specified.
497         */
498        public List<JWEAlgorithm> getIDTokenJWEAlgs() {
499
500                return idTokenJWEAlgs;
501        }
502
503
504        /**
505         * Sets the supported JWE algorithms for ID tokens. Corresponds to the
506         * {@code id_token_encryption_alg_values_supported} metadata field.
507         *
508         * @param idTokenJWEAlgs The supported JWE algorithms, {@code null} if
509         *                       not specified.
510         */
511        public void setIDTokenJWEAlgs(final List<JWEAlgorithm> idTokenJWEAlgs) {
512
513                this.idTokenJWEAlgs = idTokenJWEAlgs;
514        }
515
516
517        /**
518         * Gets the supported encryption methods for ID tokens. Corresponds to 
519         * the {@code id_token_encryption_enc_values_supported} metadata field.
520         *
521         * @return The supported encryption methods, {@code null} if not 
522         *         specified.
523         */
524        public List<EncryptionMethod> getIDTokenJWEEncs() {
525
526                return idTokenJWEEncs;
527        }
528
529
530        /**
531         * Sets the supported encryption methods for ID tokens. Corresponds to
532         * the {@code id_token_encryption_enc_values_supported} metadata field.
533         *
534         * @param idTokenJWEEncs The supported encryption methods, {@code null}
535         *                       if not specified.
536         */
537        public void setIDTokenJWEEncs(final List<EncryptionMethod> idTokenJWEEncs) {
538
539                this.idTokenJWEEncs = idTokenJWEEncs;
540        }
541
542
543        /**
544         * Gets the supported JWS algorithms for UserInfo JWTs. Corresponds to 
545         * the {@code userinfo_signing_alg_values_supported} metadata field.
546         *
547         * @return The supported JWS algorithms, {@code null} if not specified.
548         */
549        public List<JWSAlgorithm> getUserInfoJWSAlgs() {
550
551                return userInfoJWSAlgs;
552        }
553
554
555        /**
556         * Sets the supported JWS algorithms for UserInfo JWTs. Corresponds to
557         * the {@code userinfo_signing_alg_values_supported} metadata field.
558         *
559         * @param userInfoJWSAlgs The supported JWS algorithms, {@code null} if
560         *                        not specified.
561         */
562        public void setUserInfoJWSAlgs(final List<JWSAlgorithm> userInfoJWSAlgs) {
563
564                this.userInfoJWSAlgs = userInfoJWSAlgs;
565        }
566
567
568        /**
569         * Gets the supported JWE algorithms for UserInfo JWTs. Corresponds to 
570         * the {@code userinfo_encryption_alg_values_supported} metadata field.
571         *
572         * @return The supported JWE algorithms, {@code null} if not specified.
573         */
574        public List<JWEAlgorithm> getUserInfoJWEAlgs() {
575
576                return userInfoJWEAlgs;
577        }
578
579
580        /**
581         * Sets the supported JWE algorithms for UserInfo JWTs. Corresponds to
582         * the {@code userinfo_encryption_alg_values_supported} metadata field.
583         *
584         * @param userInfoJWEAlgs The supported JWE algorithms, {@code null} if
585         *                        not specified.
586         */
587        public void setUserInfoJWEAlgs(final List<JWEAlgorithm> userInfoJWEAlgs) {
588
589                this.userInfoJWEAlgs = userInfoJWEAlgs;
590        }
591
592
593        /**
594         * Gets the supported encryption methods for UserInfo JWTs. Corresponds 
595         * to the {@code userinfo_encryption_enc_values_supported} metadata 
596         * field.
597         *
598         * @return The supported encryption methods, {@code null} if not 
599         *         specified.
600         */
601        public List<EncryptionMethod> getUserInfoJWEEncs() {
602
603                return userInfoJWEEncs;
604        }
605
606
607        /**
608         * Sets the supported encryption methods for UserInfo JWTs. Corresponds
609         * to the {@code userinfo_encryption_enc_values_supported} metadata
610         * field.
611         *
612         * @param userInfoJWEEncs The supported encryption methods,
613         *                        {@code null} if not specified.
614         */
615        public void setUserInfoJWEEncs(final List<EncryptionMethod> userInfoJWEEncs) {
616
617                this.userInfoJWEEncs = userInfoJWEEncs;
618        }
619
620
621        /**
622         * Gets the supported displays. Corresponds to the 
623         * {@code display_values_supported} metadata field.
624         *
625         * @return The supported displays, {@code null} if not specified.
626         */
627        public List<Display> getDisplays() {
628
629                return displays;
630        }
631
632
633        /**
634         * Sets the supported displays. Corresponds to the
635         * {@code display_values_supported} metadata field.
636         *
637         * @param displays The supported displays, {@code null} if not
638         *                 specified.
639         */
640        public void setDisplays(final List<Display> displays) {
641
642                this.displays = displays;
643        }
644        
645        
646        /**
647         * Gets the supported claim types. Corresponds to the 
648         * {@code claim_types_supported} metadata field.
649         * 
650         * @return The supported claim types, {@code null} if not specified.
651         */
652        public List<ClaimType> getClaimTypes() {
653                
654                return claimTypes;
655        }
656
657
658        /**
659         * Sets the supported claim types. Corresponds to the
660         * {@code claim_types_supported} metadata field.
661         *
662         * @param claimTypes The supported claim types, {@code null} if not
663         *                   specified.
664         */
665        public void setClaimTypes(final List<ClaimType> claimTypes) {
666
667                this.claimTypes = claimTypes;
668        }
669
670
671        /**
672         * Gets the supported claims names. Corresponds to the 
673         * {@code claims_supported} metadata field.
674         *
675         * @return The supported claims names, {@code null} if not specified.
676         */
677        public List<String> getClaims() {
678
679                return claims;
680        }
681
682
683        /**
684         * Sets the supported claims names. Corresponds to the
685         * {@code claims_supported} metadata field.
686         *
687         * @param claims The supported claims names, {@code null} if not
688         *               specified.
689         */
690        public void setClaims(final List<String> claims) {
691
692                this.claims = claims;
693        }
694        
695        
696        /**
697         * Gets the supported claims locales. Corresponds to the
698         * {@code claims_locales_supported} metadata field.
699         * 
700         * @return The supported claims locales, {@code null} if not specified.
701         */
702        public List<LangTag> getClaimsLocales() {
703                
704                return claimsLocales;
705        }
706
707
708        /**
709         * Sets the supported claims locales. Corresponds to the
710         * {@code claims_locales_supported} metadata field.
711         *
712         * @param claimsLocales The supported claims locales, {@code null} if
713         *                      not specified.
714         */
715        public void setClaimLocales(final List<LangTag> claimsLocales) {
716
717                this.claimsLocales = claimsLocales;
718        }
719        
720        
721        /**
722         * Gets the support for the {@code claims} authorisation request
723         * parameter. Corresponds to the {@code claims_parameter_supported} 
724         * metadata field.
725         * 
726         * @return {@code true} if the {@code claim} parameter is supported,
727         *         else {@code false}.
728         */
729        public boolean supportsClaimsParam() {
730                
731                return claimsParamSupported;
732        }
733
734
735        /**
736         * Sets the support for the {@code claims} authorisation request
737         * parameter. Corresponds to the {@code claims_parameter_supported}
738         * metadata field.
739         *
740         * @param claimsParamSupported {@code true} if the {@code claim}
741         *                             parameter is supported, else
742         *                             {@code false}.
743         */
744        public void setSupportsClaimsParams(final boolean claimsParamSupported) {
745
746                this.claimsParamSupported = claimsParamSupported;
747        }
748        
749        
750        /**
751         * Gets the support for front-channel logout. Corresponds to the
752         * {@code frontchannel_logout_supported} metadata field.
753         *
754         * @return {@code true} if front-channel logout is supported, else
755         *         {@code false}.
756         */
757        public boolean supportsFrontChannelLogout() {
758                
759                return frontChannelLogoutSupported;
760        }
761        
762        
763        /**
764         * Sets the support for front-channel logout. Corresponds to the
765         * {@code frontchannel_logout_supported} metadata field.
766         *
767         * @param frontChannelLogoutSupported {@code true} if front-channel
768         *                                    logout is supported, else
769         *                                    {@code false}.
770         */
771        public void setSupportsFrontChannelLogout(final boolean frontChannelLogoutSupported) {
772        
773                this.frontChannelLogoutSupported = frontChannelLogoutSupported;
774        }
775        
776        
777        /**
778         * Gets the support for front-channel logout with a session ID.
779         * Corresponds to the {@code frontchannel_logout_session_supported}
780         * metadata field.
781         *
782         * @return {@code true} if front-channel logout with a session ID is
783         *         supported, else {@code false}.
784         */
785        public boolean supportsFrontChannelLogoutSession() {
786                
787                return frontChannelLogoutSessionSupported;
788        }
789        
790        
791        /**
792         * Sets the support for front-channel logout with a session ID.
793         * Corresponds to the {@code frontchannel_logout_session_supported}
794         * metadata field.
795         *
796         * @param frontChannelLogoutSessionSupported {@code true} if
797         *                                           front-channel logout with
798         *                                           a session ID is supported,
799         *                                           else {@code false}.
800         */
801        public void setSupportsFrontChannelLogoutSession(final boolean frontChannelLogoutSessionSupported) {
802        
803                this.frontChannelLogoutSessionSupported = frontChannelLogoutSessionSupported;
804        }
805        
806        
807        /**
808         * Gets the support for back-channel logout. Corresponds to the
809         * {@code backchannel_logout_supported} metadata field.
810         *
811         * @return {@code true} if back-channel logout is supported, else
812         *         {@code false}.
813         */
814        public boolean supportsBackChannelLogout() {
815                
816                return backChannelLogoutSupported;
817        }
818        
819        
820        /**
821         * Sets the support for back-channel logout. Corresponds to the
822         * {@code backchannel_logout_supported} metadata field.
823         *
824         * @param backChannelLogoutSupported {@code true} if back-channel
825         *                                   logout is supported, else
826         *                                   {@code false}.
827         */
828        public void setSupportsBackChannelLogout(final boolean backChannelLogoutSupported) {
829        
830                this.backChannelLogoutSupported = backChannelLogoutSupported;
831        }
832        
833        
834        /**
835         * Gets the support for back-channel logout with a session ID.
836         * Corresponds to the {@code backchannel_logout_session_supported}
837         * metadata field.
838         *
839         * @return {@code true} if back-channel logout with a session ID is
840         *         supported, else {@code false}.
841         */
842        public boolean supportsBackChannelLogoutSession() {
843                
844                return backChannelLogoutSessionSupported;
845        }
846        
847        
848        /**
849         * Sets the support for back-channel logout with a session ID.
850         * Corresponds to the {@code backchannel_logout_session_supported}
851         * metadata field.
852         *
853         * @param backChannelLogoutSessionSupported {@code true} if
854         *                                          back-channel logout with a
855         *                                          session ID is supported,
856         *                                          else {@code false}.
857         */
858        public void setSupportsBackChannelLogoutSession(final boolean backChannelLogoutSessionSupported) {
859                
860                this.backChannelLogoutSessionSupported = backChannelLogoutSessionSupported;
861        }
862        
863        
864        /**
865         * Gets support for verified claims. Corresponds to the
866         * {@code verified_claims_supported} metadata field.
867         *
868         * @return {@code true} if verified claims are supported, else
869         *         {@code false}.
870         */
871        public boolean supportsVerifiedClaims() {
872                
873                return verifiedClaimsSupported;
874        }
875        
876        
877        /**
878         * Sets support for verified claims. Corresponds to the
879         * {@code verified_claims_supported} metadata field.
880         *
881         * @param verifiedClaimsSupported {@code true} if verified claims are
882         *                                supported, else {@code false}.
883         */
884        public void setSupportsVerifiedClaims(final boolean verifiedClaimsSupported) {
885                
886                this.verifiedClaimsSupported = verifiedClaimsSupported;
887        }
888        
889        
890        /**
891         * Gets the supported identity trust frameworks. Corresponds to the
892         * {@code trust_frameworks_supported} metadata field.
893         *
894         * @return The supported identity trust frameworks, {@code null} if not
895         *         specified.
896         */
897        public List<IdentityTrustFramework> getIdentityTrustFrameworks() {
898                return trustFrameworks;
899        }
900        
901        
902        /**
903         * Sets the supported identity trust frameworks. Corresponds to the
904         * {@code trust_frameworks_supported} metadata field.
905         *
906         * @param trustFrameworks The supported identity trust frameworks,
907         *                        {@code null} if not specified.
908         */
909        public void setIdentityTrustFrameworks(final List<IdentityTrustFramework> trustFrameworks) {
910                this.trustFrameworks = trustFrameworks;
911        }
912        
913        
914        /**
915         * Gets the supported identity evidence types. Corresponds to the
916         * {@code evidence_supported} metadata field.
917         *
918         * @return The supported identity evidence types, {@code null} if not
919         *         specified.
920         */
921        public List<IdentityEvidenceType> getIdentityEvidenceTypes() {
922                return evidenceTypes;
923        }
924        
925        
926        /**
927         * Sets the supported identity evidence types. Corresponds to the
928         * {@code evidence_supported} metadata field.
929         *
930         * @param evidenceTypes The supported identity evidence types,
931         *                      {@code null} if not specified.
932         */
933        public void setIdentityEvidenceTypes(final List<IdentityEvidenceType> evidenceTypes) {
934                this.evidenceTypes = evidenceTypes;
935        }
936        
937        
938        /**
939         * Gets the supported identity document types. Corresponds to the
940         * {@code id_documents_supported} metadata field.
941         *
942         * @return The supported identity documents types, {@code null}
943         *         if not specified.
944         */
945        public List<IDDocumentType> getIdentityDocumentTypes() {
946                return idDocuments;
947        }
948        
949        
950        /**
951         * Sets the supported identity document types. Corresponds to the
952         * {@code id_documents_supported} metadata field.
953         *
954         * @param idDocuments The supported identity document types,
955         *                    {@code null} if not specified.
956         */
957        public void setIdentityDocumentTypes(List<IDDocumentType> idDocuments) {
958                this.idDocuments = idDocuments;
959        }
960        
961        
962        /**
963         * Gets the supported identity verification methods. Corresponds to the
964         * {@code id_documents_verification_methods_supported} metadata field.
965         *
966         * @return The supported identity verification methods, {@code null}
967         *         if not specified.
968         */
969        public List<IdentityVerificationMethod> getIdentityVerificationMethods() {
970                return idVerificationMethods;
971        }
972        
973        
974        /**
975         * Sets the supported identity verification methods. Corresponds to the
976         * {@code id_documents_verification_methods_supported} metadata field.
977         *
978         * @param idVerificationMethods The supported identity verification
979         *                              methods, {@code null} if not specified.
980         */
981        public void setIdentityVerificationMethods(final List<IdentityVerificationMethod> idVerificationMethods) {
982                this.idVerificationMethods = idVerificationMethods;
983        }
984        
985        
986        /**
987         * Gets the supported verified claims names. Corresponds to the
988         * {@code claims_in_verified_claims_supported} metadata field.
989         *
990         * @return The supported verified claims names, {@code null} if not
991         *         specified.
992         */
993        public List<String> getVerifiedClaims() {
994                return verifiedClaims;
995        }
996        
997        
998        /**
999         * Sets the supported verified claims names. Corresponds to the
1000         * {@code claims_in_verified_claims_supported} metadata field.
1001         *
1002         * @param verifiedClaims The supported verified claims names,
1003         *                       {@code null} if not specified.
1004         */
1005        public void setVerifiedClaims(final List<String> verifiedClaims) {
1006                this.verifiedClaims = verifiedClaims;
1007        }
1008        
1009        
1010        /**
1011         * Gets the supported federation types. Corresponds to the
1012         * {@code federation_types_supported} metadata field.
1013         *
1014         * @return The supported federation types, {@code null} if not
1015         *         specified.
1016         */
1017        public List<FederationType> getFederationTypes() {
1018                return federationTypes;
1019        }
1020        
1021        
1022        /**
1023         * Sets the supported federation types. Corresponds to the
1024         * {@code federation_types_supported} metadata field.
1025         *
1026         * @param federationTypes The supported federation types, {@code null}
1027         *                        if not specified.
1028         */
1029        public void setFederationTypes(final List<FederationType> federationTypes) {
1030                this.federationTypes = federationTypes;
1031        }
1032        
1033        
1034        /**
1035         * Gets the organisation name (in federation). Corresponds to the
1036         * {@code organization_name} metadata field.
1037         *
1038         * @return The organisation name, {@code null} if not specified.
1039         */
1040        public String getOrganizationName() {
1041                return organizationName;
1042        }
1043        
1044        
1045        /**
1046         * Sets the organisation name (in federation). Corresponds to the
1047         * {@code organization_name} metadata field.
1048         *
1049         * @param organizationName The organisation name, {@code null} if not
1050         *                         specified.
1051         */
1052        public void setOrganizationName(final String organizationName) {
1053                this.organizationName = organizationName;
1054        }
1055        
1056        
1057        /**
1058         * Gets the federation registration endpoint URI. Corresponds to the
1059         * {@code federation_registration_endpoint} metadata field.
1060         *
1061         * @return The federation registration endpoint URI, {@code null} if
1062         *         not specified.
1063         */
1064        public URI getFederationRegistrationEndpointURI() {
1065                
1066                return federationRegistrationEndpoint;
1067        }
1068        
1069        
1070        /**
1071         * Sets the federation registration endpoint URI. Corresponds to the
1072         * {@code federation_registration_endpoint} metadata field.
1073         *
1074         * @param federationRegistrationEndpoint The federation registration
1075         *                                       endpoint URI, {@code null} if
1076         *                                       not specified.
1077         */
1078        public void setFederationRegistrationEndpointURI(final URI federationRegistrationEndpoint) {
1079                
1080                this.federationRegistrationEndpoint = federationRegistrationEndpoint;
1081        }
1082        
1083        
1084        /**
1085         * Applies the OpenID Provider metadata defaults where no values have
1086         * been specified.
1087         *
1088         * <ul>
1089         *     <li>The response modes default to {@code ["query", "fragment"]}.
1090         *     <li>The grant types default to {@code ["authorization_code",
1091         *         "implicit"]}.
1092         *     <li>The token endpoint authentication methods default to
1093         *         {@code ["client_secret_basic"]}.
1094         *     <li>The claim types default to {@code ["normal]}.
1095         * </ul>
1096         */
1097        public void applyDefaults() {
1098
1099                super.applyDefaults();
1100
1101                if (claimTypes == null) {
1102                        claimTypes = new ArrayList<>(1);
1103                        claimTypes.add(ClaimType.NORMAL);
1104                }
1105        }
1106
1107
1108        /**
1109         * Returns the JSON object representation of this OpenID Connect
1110         * provider metadata.
1111         *
1112         * @return The JSON object representation.
1113         */
1114        public JSONObject toJSONObject() {
1115
1116                JSONObject o = super.toJSONObject();
1117
1118                // Mandatory fields
1119
1120                List<String> stringList = new ArrayList<>(subjectTypes.size());
1121
1122                for (SubjectType st: subjectTypes)
1123                        stringList.add(st.toString());
1124
1125                o.put("subject_types_supported", stringList);
1126
1127                // Optional fields
1128
1129                if (userInfoEndpoint != null)
1130                        o.put("userinfo_endpoint", userInfoEndpoint.toString());
1131
1132                if (checkSessionIframe != null)
1133                        o.put("check_session_iframe", checkSessionIframe.toString());
1134
1135                if (endSessionEndpoint != null)
1136                        o.put("end_session_endpoint", endSessionEndpoint.toString());
1137
1138                if (acrValues != null) {
1139                        o.put("acr_values_supported", Identifier.toStringList(acrValues));
1140                }
1141
1142                if (idTokenJWSAlgs != null) {
1143
1144                        stringList = new ArrayList<>(idTokenJWSAlgs.size());
1145
1146                        for (JWSAlgorithm alg: idTokenJWSAlgs)
1147                                stringList.add(alg.getName());
1148
1149                        o.put("id_token_signing_alg_values_supported", stringList);
1150                }
1151
1152                if (idTokenJWEAlgs != null) {
1153
1154                        stringList = new ArrayList<>(idTokenJWEAlgs.size());
1155
1156                        for (JWEAlgorithm alg: idTokenJWEAlgs)
1157                                stringList.add(alg.getName());
1158
1159                        o.put("id_token_encryption_alg_values_supported", stringList);
1160                }
1161
1162                if (idTokenJWEEncs != null) {
1163
1164                        stringList = new ArrayList<>(idTokenJWEEncs.size());
1165
1166                        for (EncryptionMethod m: idTokenJWEEncs)
1167                                stringList.add(m.getName());
1168
1169                        o.put("id_token_encryption_enc_values_supported", stringList);
1170                }
1171
1172                if (userInfoJWSAlgs != null) {
1173
1174                        stringList = new ArrayList<>(userInfoJWSAlgs.size());
1175
1176                        for (JWSAlgorithm alg: userInfoJWSAlgs)
1177                                stringList.add(alg.getName());
1178
1179                        o.put("userinfo_signing_alg_values_supported", stringList);
1180                }
1181
1182                if (userInfoJWEAlgs != null) {
1183
1184                        stringList = new ArrayList<>(userInfoJWEAlgs.size());
1185
1186                        for (JWEAlgorithm alg: userInfoJWEAlgs)
1187                                stringList.add(alg.getName());
1188
1189                        o.put("userinfo_encryption_alg_values_supported", stringList);
1190                }
1191
1192                if (userInfoJWEEncs != null) {
1193
1194                        stringList = new ArrayList<>(userInfoJWEEncs.size());
1195
1196                        for (EncryptionMethod m: userInfoJWEEncs)
1197                                stringList.add(m.getName());
1198
1199                        o.put("userinfo_encryption_enc_values_supported", stringList);
1200                }
1201
1202                if (displays != null) {
1203
1204                        stringList = new ArrayList<>(displays.size());
1205
1206                        for (Display d: displays)
1207                                stringList.add(d.toString());
1208
1209                        o.put("display_values_supported", stringList);
1210                }
1211
1212                if (claimTypes != null) {
1213
1214                        stringList = new ArrayList<>(claimTypes.size());
1215
1216                        for (ClaimType ct: claimTypes)
1217                                stringList.add(ct.toString());
1218
1219                        o.put("claim_types_supported", stringList);
1220                }
1221
1222                if (claims != null)
1223                        o.put("claims_supported", claims);
1224
1225                if (claimsLocales != null) {
1226
1227                        stringList = new ArrayList<>(claimsLocales.size());
1228
1229                        for (LangTag l: claimsLocales)
1230                                stringList.add(l.toString());
1231
1232                        o.put("claims_locales_supported", stringList);
1233                }
1234
1235                if (claimsParamSupported) {
1236                        o.put("claims_parameter_supported", true);
1237                }
1238                
1239                if (supportsRequestURIParam()) {
1240                        // default true
1241                        o.remove("request_uri_parameter_supported");
1242                } else {
1243                        o.put("request_uri_parameter_supported", false);
1244                }
1245                
1246                // optional front and back-channel logout
1247                if (frontChannelLogoutSupported) {
1248                        o.put("frontchannel_logout_supported", true);
1249                }
1250                
1251                if (frontChannelLogoutSupported) {
1252                        o.put("frontchannel_logout_session_supported", frontChannelLogoutSessionSupported);
1253                }
1254                
1255                if (backChannelLogoutSupported) {
1256                        o.put("backchannel_logout_supported", true);
1257                }
1258                
1259                if (backChannelLogoutSupported) {
1260                        o.put("backchannel_logout_session_supported", backChannelLogoutSessionSupported);
1261                }
1262                
1263                // identity assurance
1264                
1265                if (verifiedClaimsSupported) {
1266                        o.put("verified_claims_supported", true);
1267                        if (trustFrameworks != null) {
1268                                o.put("trust_frameworks_supported", Identifier.toStringList(trustFrameworks));
1269                        }
1270                        if (evidenceTypes != null) {
1271                                o.put("evidence_supported", Identifier.toStringList(evidenceTypes));
1272                        }
1273                        if (idDocuments != null) {
1274                                o.put("id_documents_supported", Identifier.toStringList(idDocuments));
1275                        }
1276                        if (idVerificationMethods != null) {
1277                                o.put("id_documents_verification_methods_supported", Identifier.toStringList(idVerificationMethods));
1278                        }
1279                        if (verifiedClaims != null) {
1280                                o.put("claims_in_verified_claims_supported", verifiedClaims);
1281                        }
1282                }
1283                
1284                // federation
1285                
1286                if (CollectionUtils.isNotEmpty(federationTypes)) {
1287                        o.put("federation_types_supported", Identifier.toStringList(federationTypes));
1288                }
1289                if (organizationName != null) {
1290                        o.put("organization_name", organizationName);
1291                }
1292                if (federationRegistrationEndpoint != null) {
1293                        o.put("federation_registration_endpoint", federationRegistrationEndpoint.toString());
1294                }
1295                
1296                return o;
1297        }
1298        
1299        
1300        /**
1301         * Parses an OpenID Provider metadata from the specified JSON object.
1302         *
1303         * @param jsonObject The JSON object to parse. Must not be 
1304         *                   {@code null}.
1305         *
1306         * @return The OpenID Provider metadata.
1307         *
1308         * @throws ParseException If the JSON object couldn't be parsed to an
1309         *                        OpenID Provider metadata.
1310         */
1311        public static OIDCProviderMetadata parse(final JSONObject jsonObject)
1312                throws ParseException {
1313                
1314                AuthorizationServerMetadata as = AuthorizationServerMetadata.parse(jsonObject);
1315
1316                List<SubjectType> subjectTypes = new ArrayList<>();
1317                for (String v: JSONObjectUtils.getStringArray(jsonObject, "subject_types_supported")) {
1318                        subjectTypes.add(SubjectType.parse(v));
1319                }
1320                
1321                OIDCProviderMetadata op = new OIDCProviderMetadata(
1322                        as.getIssuer(),
1323                        Collections.unmodifiableList(subjectTypes),
1324                        as.getJWKSetURI());
1325
1326                // Endpoints
1327                op.setAuthorizationEndpointURI(as.getAuthorizationEndpointURI());
1328                op.setTokenEndpointURI(as.getTokenEndpointURI());
1329                op.setRegistrationEndpointURI(as.getRegistrationEndpointURI());
1330                op.setIntrospectionEndpointURI(as.getIntrospectionEndpointURI());
1331                op.setRevocationEndpointURI(as.getRevocationEndpointURI());
1332                op.setRequestObjectEndpoint(as.getRequestObjectEndpoint());
1333                op.setPushedAuthorizationRequestEndpointURI(as.getPushedAuthorizationRequestEndpointURI());
1334                op.userInfoEndpoint = JSONObjectUtils.getURI(jsonObject, "userinfo_endpoint", null);
1335                op.checkSessionIframe = JSONObjectUtils.getURI(jsonObject, "check_session_iframe", null);
1336                op.endSessionEndpoint = JSONObjectUtils.getURI(jsonObject, "end_session_endpoint", null);
1337
1338                // Capabilities
1339                op.setScopes(as.getScopes());
1340                op.setResponseTypes(as.getResponseTypes());
1341                op.setResponseModes(as.getResponseModes());
1342                op.setGrantTypes(as.getGrantTypes());
1343                
1344                op.setTokenEndpointAuthMethods(as.getTokenEndpointAuthMethods());
1345                op.setTokenEndpointJWSAlgs(as.getTokenEndpointJWSAlgs());
1346                
1347                op.setIntrospectionEndpointAuthMethods(as.getIntrospectionEndpointAuthMethods());
1348                op.setIntrospectionEndpointJWSAlgs(as.getIntrospectionEndpointJWSAlgs());
1349                
1350                op.setRevocationEndpointAuthMethods(as.getRevocationEndpointAuthMethods());
1351                op.setRevocationEndpointJWSAlgs(as.getRevocationEndpointJWSAlgs());
1352                
1353                op.setRequestObjectJWSAlgs(as.getRequestObjectJWSAlgs());
1354                op.setRequestObjectJWEAlgs(as.getRequestObjectJWEAlgs());
1355                op.setRequestObjectJWEEncs(as.getRequestObjectJWEEncs());
1356                
1357                op.setSupportsRequestParam(as.supportsRequestParam());
1358                op.setSupportsRequestURIParam(as.supportsRequestURIParam());
1359                op.setRequiresRequestURIRegistration(as.requiresRequestURIRegistration());
1360                
1361                op.setCodeChallengeMethods(as.getCodeChallengeMethods());
1362
1363                if (jsonObject.get("acr_values_supported") != null) {
1364
1365                        op.acrValues = new ArrayList<>();
1366
1367                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "acr_values_supported")) {
1368
1369                                if (v != null)
1370                                        op.acrValues.add(new ACR(v));
1371                        }
1372                }
1373                
1374                // ID token
1375
1376                if (jsonObject.get("id_token_signing_alg_values_supported") != null) {
1377
1378                        op.idTokenJWSAlgs = new ArrayList<>();
1379
1380                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_signing_alg_values_supported")) {
1381
1382                                if (v != null)
1383                                        op.idTokenJWSAlgs.add(JWSAlgorithm.parse(v));
1384                        }
1385                }
1386
1387
1388                if (jsonObject.get("id_token_encryption_alg_values_supported") != null) {
1389
1390                        op.idTokenJWEAlgs = new ArrayList<>();
1391
1392                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_encryption_alg_values_supported")) {
1393
1394                                if (v != null)
1395                                        op.idTokenJWEAlgs.add(JWEAlgorithm.parse(v));
1396                        }
1397                }
1398
1399
1400                if (jsonObject.get("id_token_encryption_enc_values_supported") != null) {
1401
1402                        op.idTokenJWEEncs = new ArrayList<>();
1403
1404                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_encryption_enc_values_supported")) {
1405
1406                                if (v != null)
1407                                        op.idTokenJWEEncs.add(EncryptionMethod.parse(v));
1408                        }
1409                }
1410
1411                // UserInfo
1412
1413                if (jsonObject.get("userinfo_signing_alg_values_supported") != null) {
1414
1415                        op.userInfoJWSAlgs = new ArrayList<>();
1416
1417                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_signing_alg_values_supported")) {
1418
1419                                if (v != null)
1420                                        op.userInfoJWSAlgs.add(JWSAlgorithm.parse(v));
1421                        }
1422                }
1423
1424
1425                if (jsonObject.get("userinfo_encryption_alg_values_supported") != null) {
1426
1427                        op.userInfoJWEAlgs = new ArrayList<>();
1428
1429                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_encryption_alg_values_supported")) {
1430
1431                                if (v != null)
1432                                        op.userInfoJWEAlgs.add(JWEAlgorithm.parse(v));
1433                        }
1434                }
1435
1436
1437                if (jsonObject.get("userinfo_encryption_enc_values_supported") != null) {
1438
1439                        op.userInfoJWEEncs = new ArrayList<>();
1440
1441                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_encryption_enc_values_supported")) {
1442
1443                                        if (v != null)
1444                                                op.userInfoJWEEncs.add(EncryptionMethod.parse(v));
1445                        }
1446                }
1447
1448                
1449                // Misc
1450
1451                if (jsonObject.get("display_values_supported") != null) {
1452
1453                        op.displays = new ArrayList<>();
1454
1455                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "display_values_supported")) {
1456
1457                                if (v != null)
1458                                        op.displays.add(Display.parse(v));
1459                        }
1460                }
1461                
1462                if (jsonObject.get("claim_types_supported") != null) {
1463                        
1464                        op.claimTypes = new ArrayList<>();
1465                        
1466                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "claim_types_supported")) {
1467                                
1468                                if (v != null)
1469                                        op.claimTypes.add(ClaimType.parse(v));
1470                        }
1471                }
1472
1473
1474                if (jsonObject.get("claims_supported") != null) {
1475
1476                        op.claims = new ArrayList<>();
1477
1478                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "claims_supported")) {
1479
1480                                if (v != null)
1481                                        op.claims.add(v);
1482                        }
1483                }
1484                
1485                if (jsonObject.get("claims_locales_supported") != null) {
1486                        
1487                        op.claimsLocales = new ArrayList<>();
1488                        
1489                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "claims_locales_supported")) {
1490                                
1491                                if (v != null) {
1492                                        
1493                                        try {
1494                                                op.claimsLocales.add(LangTag.parse(v));
1495                                        
1496                                        } catch (LangTagException e) {
1497                                                
1498                                                throw new ParseException("Invalid claims_locales_supported field: " + e.getMessage(), e);
1499                                        }
1500                                }
1501                        }
1502                }
1503                
1504                op.setUILocales(as.getUILocales());
1505                op.setServiceDocsURI(as.getServiceDocsURI());
1506                op.setPolicyURI(as.getPolicyURI());
1507                op.setTermsOfServiceURI(as.getTermsOfServiceURI());
1508                
1509                if (jsonObject.get("claims_parameter_supported") != null)
1510                        op.claimsParamSupported = JSONObjectUtils.getBoolean(jsonObject, "claims_parameter_supported");
1511                
1512                if (jsonObject.get("request_uri_parameter_supported") == null) {
1513                        op.setSupportsRequestURIParam(true);
1514                }
1515                
1516                // Optional front and back-channel logout
1517                if (jsonObject.get("frontchannel_logout_supported") != null)
1518                        op.frontChannelLogoutSupported = JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_supported");
1519                
1520                if (op.frontChannelLogoutSupported && jsonObject.get("frontchannel_logout_session_supported") != null)
1521                        op.frontChannelLogoutSessionSupported = JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_supported");
1522                
1523                if (jsonObject.get("backchannel_logout_supported") != null)
1524                        op.backChannelLogoutSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_supported");
1525                
1526                if (op.frontChannelLogoutSupported && jsonObject.get("backchannel_logout_session_supported") != null)
1527                        op.backChannelLogoutSessionSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_supported");
1528                
1529                if (jsonObject.get("mtls_endpoint_aliases") != null)
1530                        op.setMtlsEndpointAliases(OIDCProviderEndpointMetadata.parse(JSONObjectUtils.getJSONObject(jsonObject, "mtls_endpoint_aliases")));
1531                
1532                op.setSupportsTLSClientCertificateBoundAccessTokens(as.supportsTLSClientCertificateBoundAccessTokens());
1533                
1534                // JARM
1535                op.setAuthorizationJWSAlgs(as.getAuthorizationJWSAlgs());
1536                op.setAuthorizationJWEAlgs(as.getAuthorizationJWEAlgs());
1537                op.setAuthorizationJWEEncs(as.getAuthorizationJWEEncs());
1538                
1539                // OpenID Connect for Identity Assurance 1.0
1540                if (jsonObject.get("verified_claims_supported") != null) {
1541                        op.verifiedClaimsSupported = JSONObjectUtils.getBoolean(jsonObject, "verified_claims_supported");
1542                        if (op.verifiedClaimsSupported) {
1543                                if (jsonObject.get("trust_frameworks_supported") != null) {
1544                                        op.trustFrameworks = new LinkedList<>();
1545                                        for (String v : JSONObjectUtils.getStringList(jsonObject, "trust_frameworks_supported")) {
1546                                                op.trustFrameworks.add(new IdentityTrustFramework(v));
1547                                        }
1548                                }
1549                                if (jsonObject.get("evidence_supported") != null) {
1550                                        op.evidenceTypes = new LinkedList<>();
1551                                        for (String v: JSONObjectUtils.getStringList(jsonObject, "evidence_supported")) {
1552                                                op.evidenceTypes.add(new IdentityEvidenceType(v));
1553                                        }
1554                                }
1555                                if (jsonObject.get("id_documents_supported") != null) {
1556                                        op.idDocuments = new LinkedList<>();
1557                                        for (String v: JSONObjectUtils.getStringList(jsonObject, "id_documents_supported")) {
1558                                                op.idDocuments.add(new IDDocumentType(v));
1559                                        }
1560                                }
1561                                if (jsonObject.get("id_documents_verification_methods_supported") != null) {
1562                                        op.idVerificationMethods = new LinkedList<>();
1563                                        for (String v: JSONObjectUtils.getStringList(jsonObject, "id_documents_verification_methods_supported")) {
1564                                                op.idVerificationMethods.add(new IdentityVerificationMethod(v));
1565                                        }
1566                                }
1567                                if (jsonObject.get("claims_in_verified_claims_supported") != null) {
1568                                        op.verifiedClaims = JSONObjectUtils.getStringList(jsonObject, "claims_in_verified_claims_supported");
1569                                }
1570                        }
1571                }
1572                
1573                // Federation
1574                
1575                if (jsonObject.get("federation_types_supported") != null) {
1576                        op.federationTypes = new LinkedList<>();
1577                        for (String v: JSONObjectUtils.getStringList(jsonObject, "federation_types_supported")) {
1578                                op.federationTypes.add(new FederationType(v));
1579                        }
1580                }
1581                
1582                op.organizationName = JSONObjectUtils.getString(jsonObject, "organization_name", null);
1583                
1584                op.federationRegistrationEndpoint = JSONObjectUtils.getURI(jsonObject, "federation_registration_endpoint", null);
1585                
1586                // Parse custom (not registered) parameters
1587                for (Map.Entry<String,?> entry: as.getCustomParameters().entrySet()) {
1588                        if (REGISTERED_PARAMETER_NAMES.contains(entry.getKey()))
1589                                continue; // skip
1590                        op.setCustomParameter(entry.getKey(), entry.getValue());
1591                }
1592
1593                return op;
1594        }
1595
1596
1597        /**
1598         * Parses an OpenID Provider metadata from the specified JSON object
1599         * string.
1600         *
1601         * @param s The JSON object sting to parse. Must not be {@code null}.
1602         *
1603         * @return The OpenID Provider metadata.
1604         *
1605         * @throws ParseException If the JSON object string couldn't be parsed
1606         *                        to an OpenID Provider metadata.
1607         */
1608        public static OIDCProviderMetadata parse(final String s)
1609                throws ParseException {
1610
1611                return parse(JSONObjectUtils.parse(s));
1612        }
1613        
1614        
1615        /**
1616         * Resolves OpenID Provider metadata URL from the specified issuer
1617         * identifier.
1618         *
1619         * @param issuer The OpenID Provider issuer identifier. Must represent
1620         *               a valid HTTPS or HTTP URL. Must not be {@code null}.
1621         *
1622         * @return The OpenID Provider metadata URL.
1623         *
1624         * @throws GeneralException If the issuer identifier is invalid.
1625         */
1626        public static URL resolveURL(final Issuer issuer)
1627                throws GeneralException {
1628                
1629                try {
1630                        URL issuerURL = new URL(issuer.getValue());
1631                        
1632                        // Validate but don't insist on HTTPS, see
1633                        // http://openid.net/specs/openid-connect-core-1_0.html#Terminology
1634                        if (issuerURL.getQuery() != null && ! issuerURL.getQuery().trim().isEmpty()) {
1635                                throw new GeneralException("The issuer identifier must not contain a query component");
1636                        }
1637                        
1638                        if (issuerURL.getPath() != null && issuerURL.getPath().endsWith("/")) {
1639                                return new URL(issuerURL + ".well-known/openid-configuration");
1640                        } else {
1641                                return new URL(issuerURL + "/.well-known/openid-configuration");
1642                        }
1643                        
1644                } catch (MalformedURLException e) {
1645                        throw new GeneralException("The issuer identifier doesn't represent a valid URL: " + e.getMessage(), e);
1646                }
1647        }
1648        
1649        
1650        /**
1651         * Resolves OpenID Provider metadata from the specified issuer
1652         * identifier. The metadata is downloaded by HTTP GET from
1653         * {@code [issuer-url]/.well-known/openid-configuration}.
1654         *
1655         * @param issuer The OpenID Provider issuer identifier. Must represent
1656         *               a valid HTTPS or HTTP URL. Must not be {@code null}.
1657         *
1658         * @return The OpenID Provider metadata.
1659         *
1660         * @throws GeneralException If the issuer identifier or the downloaded
1661         *                          metadata are invalid.
1662         * @throws IOException      On a HTTP exception.
1663         */
1664        public static OIDCProviderMetadata resolve(final Issuer issuer)
1665                throws GeneralException, IOException {
1666                
1667                return resolve(issuer, 0, 0);
1668        }
1669        
1670        
1671        /**
1672         * Resolves OpenID Provider metadata from the specified issuer
1673         * identifier. The metadata is downloaded by HTTP GET from
1674         * {@code [issuer-url]/.well-known/openid-configuration}, using the
1675         * specified HTTP timeouts.
1676         *
1677         * @param issuer         The issuer identifier. Must represent a valid
1678         *                       HTTPS or HTTP URL. Must not be {@code null}.
1679         * @param connectTimeout The HTTP connect timeout, in milliseconds.
1680         *                       Zero implies no timeout. Must not be negative.
1681         * @param readTimeout    The HTTP response read timeout, in
1682         *                       milliseconds. Zero implies no timeout. Must
1683         *                       not be negative.
1684         *
1685         * @return The OpenID Provider metadata.
1686         *
1687         * @throws GeneralException If the issuer identifier or the downloaded
1688         *                          metadata are invalid.
1689         * @throws IOException      On a HTTP exception.
1690         */
1691        public static OIDCProviderMetadata resolve(final Issuer issuer,
1692                                                   final int connectTimeout,
1693                                                   final int readTimeout)
1694                throws GeneralException, IOException {
1695                
1696                URL configURL = resolveURL(issuer);
1697                
1698                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, configURL);
1699                httpRequest.setConnectTimeout(connectTimeout);
1700                httpRequest.setReadTimeout(readTimeout);
1701                
1702                HTTPResponse httpResponse = httpRequest.send();
1703                
1704                if (httpResponse.getStatusCode() != 200) {
1705                        throw new IOException("Couldn't download OpenID Provider metadata from " + configURL +
1706                                ": Status code " + httpResponse.getStatusCode());
1707                }
1708                
1709                JSONObject jsonObject = httpResponse.getContentAsJSONObject();
1710                
1711                OIDCProviderMetadata op = OIDCProviderMetadata.parse(jsonObject);
1712                
1713                if (! issuer.equals(op.getIssuer())) {
1714                        throw new GeneralException("The returned issuer doesn't match the expected: " + op.getIssuer());
1715                }
1716                
1717                return op;
1718        }
1719}