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