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