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