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