001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk.as;
019
020
021import com.nimbusds.jose.Algorithm;
022import com.nimbusds.jose.EncryptionMethod;
023import com.nimbusds.jose.JWEAlgorithm;
024import com.nimbusds.jose.JWSAlgorithm;
025import com.nimbusds.jose.jwk.JWKSet;
026import com.nimbusds.langtag.LangTag;
027import com.nimbusds.langtag.LangTagException;
028import com.nimbusds.oauth2.sdk.*;
029import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
030import com.nimbusds.oauth2.sdk.ciba.BackChannelTokenDeliveryMode;
031import com.nimbusds.oauth2.sdk.client.ClientType;
032import com.nimbusds.oauth2.sdk.http.HTTPRequest;
033import com.nimbusds.oauth2.sdk.http.HTTPRequestConfigurator;
034import com.nimbusds.oauth2.sdk.http.HTTPRequestModifier;
035import com.nimbusds.oauth2.sdk.http.HTTPResponse;
036import com.nimbusds.oauth2.sdk.id.Identifier;
037import com.nimbusds.oauth2.sdk.id.Issuer;
038import com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod;
039import com.nimbusds.oauth2.sdk.rar.AuthorizationType;
040import com.nimbusds.oauth2.sdk.util.*;
041import com.nimbusds.openid.connect.sdk.Prompt;
042import com.nimbusds.openid.connect.sdk.federation.registration.ClientRegistrationType;
043import com.nimbusds.openid.connect.sdk.op.EndpointName;
044import net.minidev.json.JSONObject;
045
046import java.io.IOException;
047import java.net.MalformedURLException;
048import java.net.URI;
049import java.net.URISyntaxException;
050import java.net.URL;
051import java.util.*;
052
053
054/**
055 * OAuth 2.0 Authorisation Server (AS) metadata.
056 *
057 * <p>Related specifications:
058 *
059 * <ul>
060 *     <li>OAuth 2.0 Authorization Server Metadata (RFC 8414)
061 *     <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound
062 *         Access Tokens (RFC 8705)
063 *     <li>OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer
064 *         (DPoP) (RFC 9449)
065 *     <li>Financial-grade API: JWT Secured Authorization Response Mode for
066 *         OAuth 2.0 (JARM)
067 *     <li>OAuth 2.0 Authorization Server Issuer Identification (RFC 9207)
068 *     <li>Financial-grade API - Part 2: Read and Write API Security Profile
069 *     <li>OAuth 2.0 Pushed Authorization Requests (RFC 9126)
070 *     <li>OAuth 2.0 Rich Authorization Requests (RFC 9396)
071 *     <li>OAuth 2.0 Device Authorization Grant (RFC 8628)
072 *     <li>OpenID Connect Client Initiated Backchannel Authentication Flow -
073 *         Core 1.0
074 *     <li>OAuth 2.0 Incremental Authorization
075 *         (draft-ietf-oauth-incremental-authz)
076 *     <li>Initiating User Registration via OpenID Connect 1.0
077 *     <li>OpenID Connect Federation 1.0
078 * </ul>
079 */
080public class AuthorizationServerMetadata extends AuthorizationServerEndpointMetadata implements ReadOnlyAuthorizationServerMetadata {
081
082        /**
083         * The registered parameter names.
084         */
085        private static final Set<String> REGISTERED_PARAMETER_NAMES;
086
087        static {
088                Set<String> p = new HashSet<>(AuthorizationServerEndpointMetadata.getRegisteredParameterNames());
089                p.add("issuer");
090                p.add("jwks_uri");
091                p.add("scopes_supported");
092                p.add("response_types_supported");
093                p.add("response_modes_supported");
094                p.add("grant_types_supported");
095                p.add("code_challenge_methods_supported");
096                p.add("token_endpoint_auth_methods_supported");
097                p.add("token_endpoint_auth_signing_alg_values_supported");
098                p.add("request_parameter_supported");
099                p.add("request_uri_parameter_supported");
100                p.add("require_request_uri_registration");
101                p.add("request_object_signing_alg_values_supported");
102                p.add("request_object_encryption_alg_values_supported");
103                p.add("request_object_encryption_enc_values_supported");
104                p.add("ui_locales_supported");
105                p.add("service_documentation");
106                p.add("op_policy_uri");
107                p.add("op_tos_uri");
108                p.add("introspection_endpoint_auth_methods_supported");
109                p.add("introspection_endpoint_auth_signing_alg_values_supported");
110                p.add("revocation_endpoint_auth_methods_supported");
111                p.add("revocation_endpoint_auth_signing_alg_values_supported");
112                p.add("mtls_endpoint_aliases");
113                p.add("tls_client_certificate_bound_access_tokens");
114                p.add("dpop_signing_alg_values_supported");
115                p.add("authorization_signing_alg_values_supported");
116                p.add("authorization_encryption_alg_values_supported");
117                p.add("authorization_encryption_enc_values_supported");
118                p.add("require_pushed_authorization_requests");
119                p.add("authorization_details_types_supported");
120                p.add("incremental_authz_types_supported");
121                p.add("authorization_response_iss_parameter_supported");
122                p.add("backchannel_token_delivery_modes_supported");
123                p.add("backchannel_authentication_request_signing_alg_values_supported");
124                p.add("backchannel_user_code_parameter_supported");
125                p.add("prompt_values_supported");
126                p.add("organization_name");
127                p.add("jwks");
128                p.add("signed_jwks_uri");
129                p.add("client_registration_types_supported");
130                p.add("request_authentication_methods_supported");
131                p.add("request_authentication_signing_alg_values_supported");
132                p.add("federation_registration_endpoint");
133                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
134        }
135        
136        
137        /**
138         * Gets the registered OpenID Connect provider metadata parameter
139         * names.
140         *
141         * @return The registered OpenID Connect provider metadata parameter
142         *         names, as an unmodifiable set.
143         */
144        public static Set<String> getRegisteredParameterNames() {
145                
146                return REGISTERED_PARAMETER_NAMES;
147        }
148        
149        
150        /**
151         * The issuer.
152         */
153        private final Issuer issuer;
154        
155        
156        /**
157         * The JWK set URI.
158         */
159        private URI jwkSetURI;
160        
161        
162        /**
163         * The supported scope values.
164         */
165        private Scope scope;
166        
167        
168        /**
169         * The supported response types.
170         */
171        private List<ResponseType> rts;
172        
173        
174        /**
175         * The supported response modes.
176         */
177        private List<ResponseMode> rms;
178        
179        
180        /**
181         * The supported grant types.
182         */
183        private List<GrantType> gts;
184        
185        
186        /**
187         * The supported code challenge methods for PKCE.
188         */
189        private List<CodeChallengeMethod> codeChallengeMethods;
190        
191        
192        /**
193         * The supported token endpoint authentication methods.
194         */
195        private List<ClientAuthenticationMethod> tokenEndpointAuthMethods;
196        
197        
198        /**
199         * The supported JWS algorithms for the {@code private_key_jwt} and
200         * {@code client_secret_jwt} token endpoint authentication methods.
201         */
202        private List<JWSAlgorithm> tokenEndpointJWSAlgs;
203        
204        
205        /**
206         * The supported introspection endpoint authentication methods.
207         */
208        private List<ClientAuthenticationMethod> introspectionEndpointAuthMethods;
209        
210        
211        /**
212         * The supported JWS algorithms for the {@code private_key_jwt} and
213         * {@code client_secret_jwt} introspection endpoint authentication
214         * methods.
215         */
216        private List<JWSAlgorithm> introspectionEndpointJWSAlgs;
217        
218        
219        /**
220         * The supported revocation endpoint authentication methods.
221         */
222        private List<ClientAuthenticationMethod> revocationEndpointAuthMethods;
223        
224        
225        /**
226         * The supported JWS algorithms for the {@code private_key_jwt} and
227         * {@code client_secret_jwt} revocation endpoint authentication
228         * methods.
229         */
230        private List<JWSAlgorithm> revocationEndpointJWSAlgs;
231        
232        
233        /**
234         * The supported JWS algorithms for request objects.
235         */
236        private List<JWSAlgorithm> requestObjectJWSAlgs;
237        
238        
239        /**
240         * The supported JWE algorithms for request objects.
241         */
242        private List<JWEAlgorithm> requestObjectJWEAlgs;
243        
244        
245        /**
246         * The supported encryption methods for request objects.
247         */
248        private List<EncryptionMethod> requestObjectJWEEncs;
249        
250        
251        /**
252         * If {@code true} the {@code request} parameter is supported, else
253         * not.
254         */
255        private boolean requestParamSupported = false;
256        
257        
258        /**
259         * If {@code true} the {@code request_uri} parameter is supported, else
260         * not.
261         */
262        private boolean requestURIParamSupported = false;
263        
264        
265        /**
266         * If {@code true} the {@code request_uri} parameters must be
267         * pre-registered with the provider, else not.
268         */
269        private boolean requireRequestURIReg = false;
270        
271        
272        /**
273         * If {@code true} the {@code iss} authorisation response is supported,
274         * else not.
275         */
276        private boolean authzResponseIssParameterSupported = false;
277        
278        
279        /**
280         * The supported UI locales.
281         */
282        private List<LangTag> uiLocales;
283        
284        
285        /**
286         * The service documentation URI.
287         */
288        private URI serviceDocsURI;
289        
290        
291        /**
292         * The provider's policy regarding relying party use of data.
293         */
294        private URI policyURI;
295        
296        
297        /**
298         * The provider's terms of service.
299         */
300        private URI tosURI;
301        
302        
303        /**
304         * Aliases for endpoints with mutial TLS authentication.
305         */
306        private AuthorizationServerEndpointMetadata mtlsEndpointAliases;
307        
308        
309        /**
310         * If {@code true} the
311         * {@code tls_client_certificate_bound_access_tokens} if set, else
312         * not.
313         */
314        private boolean tlsClientCertificateBoundAccessTokens = false;
315        
316        
317        /**
318         * The supported JWS algorithms for DPoP.
319         */
320        private List<JWSAlgorithm> dPoPJWSAlgs;
321        
322        
323        /**
324         * The supported JWS algorithms for JWT-encoded authorisation
325         * responses.
326         */
327        private List<JWSAlgorithm> authzJWSAlgs;
328        
329        
330        /**
331         * The supported JWE algorithms for JWT-encoded authorisation
332         * responses.
333         */
334        private List<JWEAlgorithm> authzJWEAlgs;
335        
336        
337        /**
338         * The supported encryption methods for JWT-encoded authorisation
339         * responses.
340         */
341        private List<EncryptionMethod> authzJWEEncs;
342        
343        
344        /**
345         * If {@code true} PAR is required, else not.
346         */
347        private boolean requirePAR = false;
348
349
350        /**
351         * The supported authorisation details types.
352         */
353        private List<AuthorizationType> authzTypes;
354        
355        
356        /**
357         * The supported OAuth 2.0 client types for incremental authorisation.
358         */
359        private List<ClientType> incrementalAuthzTypes;
360
361        
362        /**
363         * The supported CIBA token delivery modes.
364         */
365        private List<BackChannelTokenDeliveryMode> backChannelTokenDeliveryModes;
366        
367        
368        /**
369         * The supported JWS algorithms for CIBA requests. If omitted signed
370         * authentication requests are not supported.
371         */
372        private List<JWSAlgorithm> backChannelAuthRequestJWSAlgs;
373
374        
375        /**
376         * If {@code true} the CIBA {@code user_code} parameter is supported,
377         * else not.
378         */
379        private boolean backChannelUserCodeSupported = false;
380        
381        
382        /**
383         * The supported prompt types.
384         */
385        private List<Prompt.Type> promptTypes;
386        
387        
388        /**
389         * The organisation name (OpenID Connect Federation 1.0).
390         */
391        private String organizationName;
392        
393        
394        /**
395         * The OP JWK set (OpenID Connect Federation 1.0).
396         */
397        private JWKSet jwkSet;
398        
399        
400        /**
401         * The signed OP JWK set (OpenID Connect Federation 1.0).
402         */
403        private URI signedJWKSetURI;
404        
405        
406        /**
407         * The supported OpenID Connect Federation 1.0 client registration
408         * types.
409         */
410        private List<ClientRegistrationType> clientRegistrationTypes;
411        
412        
413        /**
414         * The supported request authentication methods for automatic OpenID
415         * Connect Federation 1.0 client registration.
416         */
417        private Map<EndpointName,List<ClientAuthenticationMethod>> clientRegistrationAuthMethods;
418        
419        
420        /**
421         * The supported JWS algorithms for authenticating automatic OpenID
422         * Connect Federation 1.0 client registration requests.
423         */
424        private List<JWSAlgorithm> clientRegistrationAuthJWSAlgs;
425        
426        
427        /**
428         * The OpenID Connect Federation 1.0 registration endpoint.
429         */
430        private URI federationRegistrationEndpoint;
431        
432        
433        /**
434         * Custom (not-registered) parameters.
435         */
436        private final JSONObject customParameters = new JSONObject();
437        
438        
439        /**
440         * Creates a new OAuth 2.0 Authorisation Server (AS) metadata instance.
441         *
442         * @param issuer The issuer identifier. Must be a URI using the https
443         *               scheme with no query or fragment component. Must not
444         *               be {@code null}.
445         */
446        public AuthorizationServerMetadata(final Issuer issuer) {
447                
448                URI uri;
449                try {
450                        uri = new URI(issuer.getValue());
451                } catch (URISyntaxException e) {
452                        throw new IllegalArgumentException("The issuer identifier must be a URI: " + e.getMessage(), e);
453                }
454                
455                if (uri.getRawQuery() != null)
456                        throw new IllegalArgumentException("The issuer URI must be without a query component");
457                
458                if (uri.getRawFragment() != null)
459                        throw new IllegalArgumentException("The issuer URI must be without a fragment component");
460                
461                this.issuer = issuer;
462        }
463        
464        
465        @Override
466        public Issuer getIssuer() {
467                return issuer;
468        }
469        
470        
471        @Override
472        public URI getJWKSetURI() {
473                return jwkSetURI;
474        }
475        
476        
477        /**
478         * Sets the JSON Web Key (JWT) set URI. Corresponds to the
479         * {@code jwks_uri} metadata field.
480         *
481         * @param jwkSetURI The JWK set URI, {@code null} if not specified.
482         */
483        public void setJWKSetURI(final URI jwkSetURI) {
484                this.jwkSetURI = jwkSetURI;
485        }
486        
487        
488        @Override
489        public Scope getScopes() {
490                return scope;
491        }
492        
493        
494        /**
495         * Sets the supported scope values. Corresponds to the
496         * {@code scopes_supported} metadata field.
497         *
498         * @param scope The supported scope values, {@code null} if not
499         *              specified.
500         */
501        public void setScopes(final Scope scope) {
502                this.scope = scope;
503        }
504        
505        
506        @Override
507        public List<ResponseType> getResponseTypes() {
508                return rts;
509        }
510        
511        
512        /**
513         * Sets the supported response type values. Corresponds to the
514         * {@code response_types_supported} metadata field.
515         *
516         * @param rts The supported response type values, {@code null} if not
517         *            specified.
518         */
519        public void setResponseTypes(final List<ResponseType> rts) {
520                this.rts = rts;
521        }
522        
523        
524        @Override
525        public List<ResponseMode> getResponseModes() {
526                return rms;
527        }
528        
529        
530        /**
531         * Sets the supported response mode values. Corresponds to the
532         * {@code response_modes_supported}.
533         *
534         * @param rms The supported response mode values, {@code null} if not
535         *            specified.
536         */
537        public void setResponseModes(final List<ResponseMode> rms) {
538                this.rms = rms;
539        }
540        
541        
542        @Override
543        public List<GrantType> getGrantTypes() {
544                return gts;
545        }
546        
547        
548        /**
549         * Sets the supported OAuth 2.0 grant types. Corresponds to the
550         * {@code grant_types_supported} metadata field.
551         *
552         * @param gts The supported grant types, {@code null} if not specified.
553         */
554        public void setGrantTypes(final List<GrantType> gts) {
555                this.gts = gts;
556        }
557        
558        
559        @Override
560        public List<CodeChallengeMethod> getCodeChallengeMethods() {
561                return codeChallengeMethods;
562        }
563        
564        
565        /**
566         * Gets the supported authorisation code challenge methods for PKCE.
567         * Corresponds to the {@code code_challenge_methods_supported} metadata
568         * field.
569         *
570         * @param codeChallengeMethods The supported code challenge methods,
571         *                             {@code null} if not specified.
572         */
573        public void setCodeChallengeMethods(final List<CodeChallengeMethod> codeChallengeMethods) {
574                this.codeChallengeMethods = codeChallengeMethods;
575        }
576        
577        
578        @Override
579        public List<ClientAuthenticationMethod> getTokenEndpointAuthMethods() {
580                return tokenEndpointAuthMethods;
581        }
582        
583        
584        /**
585         * Sets the supported token endpoint authentication methods.
586         * Corresponds to the {@code token_endpoint_auth_methods_supported}
587         * metadata field.
588         *
589         * @param authMethods The supported token endpoint authentication
590         *                    methods, {@code null} if not specified.
591         */
592        public void setTokenEndpointAuthMethods(final List<ClientAuthenticationMethod> authMethods) {
593                this.tokenEndpointAuthMethods = authMethods;
594        }
595        
596        
597        @Override
598        public List<JWSAlgorithm> getTokenEndpointJWSAlgs() {
599                return tokenEndpointJWSAlgs;
600        }
601        
602        
603        /**
604         * Sets the supported JWS algorithms for the {@code private_key_jwt}
605         * and {@code client_secret_jwt} token endpoint authentication methods.
606         * Corresponds to the
607         * {@code token_endpoint_auth_signing_alg_values_supported} metadata
608         * field.
609         *
610         * @param jwsAlgs The supported JWS algorithms, {@code null} if not
611         *                specified. Must not contain the {@code none}
612         *                algorithm.
613         */
614        public void setTokenEndpointJWSAlgs(final List<JWSAlgorithm> jwsAlgs) {
615                if (jwsAlgs != null && jwsAlgs.contains(Algorithm.NONE))
616                        throw new IllegalArgumentException("The \"none\" algorithm is not accepted");
617                
618                this.tokenEndpointJWSAlgs = jwsAlgs;
619        }
620        
621        
622        @Override
623        public List<ClientAuthenticationMethod> getIntrospectionEndpointAuthMethods() {
624                return introspectionEndpointAuthMethods;
625        }
626        
627        
628        /**
629         * Sets the supported introspection endpoint authentication methods.
630         * Corresponds to the
631         * {@code introspection_endpoint_auth_methods_supported} metadata
632         * field.
633         *
634         * @param authMethods The supported introspection endpoint
635         *                    authentication methods, {@code null} if not
636         *                    specified.
637         */
638        public void setIntrospectionEndpointAuthMethods(final List<ClientAuthenticationMethod> authMethods) {
639                this.introspectionEndpointAuthMethods = authMethods;
640        }
641        
642        
643        @Override
644        public List<JWSAlgorithm> getIntrospectionEndpointJWSAlgs() {
645                return introspectionEndpointJWSAlgs;
646        }
647        
648        
649        /**
650         * Sets the supported JWS algorithms for the {@code private_key_jwt}
651         * and {@code client_secret_jwt} introspection endpoint authentication
652         * methods. Corresponds to the
653         * {@code introspection_endpoint_auth_signing_alg_values_supported}
654         * metadata field.
655         *
656         * @param jwsAlgs The supported JWS algorithms, {@code null} if not
657         *                specified. Must not contain the {@code none}
658         *                algorithm.
659         */
660        public void setIntrospectionEndpointJWSAlgs(final List<JWSAlgorithm> jwsAlgs) {
661                
662                if (jwsAlgs != null && jwsAlgs.contains(Algorithm.NONE))
663                        throw new IllegalArgumentException("The \"none\" algorithm is not accepted");
664                
665                introspectionEndpointJWSAlgs = jwsAlgs;
666        }
667        
668        
669        @Override
670        public List<ClientAuthenticationMethod> getRevocationEndpointAuthMethods() {
671                return revocationEndpointAuthMethods;
672        }
673        
674        
675        /**
676         * Sets the supported revocation endpoint authentication methods.
677         * Corresponds to the
678         * {@code revocation_endpoint_auth_methods_supported} metadata field.
679         *
680         * @param authMethods The supported revocation endpoint authentication
681         *                    methods, {@code null} if not specified.
682         */
683        public void setRevocationEndpointAuthMethods(final List<ClientAuthenticationMethod> authMethods) {
684                revocationEndpointAuthMethods = authMethods;
685        }
686        
687        
688        @Override
689        public List<JWSAlgorithm> getRevocationEndpointJWSAlgs() {
690                return revocationEndpointJWSAlgs;
691        }
692        
693        
694        /**
695         * Sets the supported JWS algorithms for the {@code private_key_jwt}
696         * and {@code client_secret_jwt} revocation endpoint authentication
697         * methods. Corresponds to the
698         * {@code revocation_endpoint_auth_signing_alg_values_supported}
699         * metadata field.
700         *
701         * @param jwsAlgs The supported JWS algorithms, {@code null} if not
702         *                specified. Must not contain the {@code none}
703         *                algorithm.
704         */
705        public void setRevocationEndpointJWSAlgs(final List<JWSAlgorithm> jwsAlgs) {
706                
707                if (jwsAlgs != null && jwsAlgs.contains(Algorithm.NONE))
708                        throw new IllegalArgumentException("The \"none\" algorithm is not accepted");
709                
710                revocationEndpointJWSAlgs = jwsAlgs;
711        }
712        
713        
714        @Override
715        public List<JWSAlgorithm> getRequestObjectJWSAlgs() {
716                return requestObjectJWSAlgs;
717        }
718        
719        
720        /**
721         * Sets the supported JWS algorithms for request objects. Corresponds
722         * to the {@code request_object_signing_alg_values_supported} metadata
723         * field.
724         *
725         * @param requestObjectJWSAlgs The supported JWS algorithms,
726         *                             {@code null} if not specified.
727         */
728        public void setRequestObjectJWSAlgs(final List<JWSAlgorithm> requestObjectJWSAlgs) {
729                this.requestObjectJWSAlgs = requestObjectJWSAlgs;
730        }
731        
732        
733        @Override
734        public List<JWEAlgorithm> getRequestObjectJWEAlgs() {
735                return requestObjectJWEAlgs;
736        }
737        
738        
739        /**
740         * Sets the supported JWE algorithms for request objects. Corresponds
741         * to the {@code request_object_encryption_alg_values_supported}
742         * metadata field.
743         *
744         * @param requestObjectJWEAlgs The supported JWE algorithms,
745         *                            {@code null} if not specified.
746         */
747        public void setRequestObjectJWEAlgs(final List<JWEAlgorithm> requestObjectJWEAlgs) {
748                this.requestObjectJWEAlgs = requestObjectJWEAlgs;
749        }
750        
751        
752        @Override
753        public List<EncryptionMethod> getRequestObjectJWEEncs() {
754                return requestObjectJWEEncs;
755        }
756        
757        
758        /**
759         * Sets the supported encryption methods for request objects.
760         * Corresponds to the
761         * {@code request_object_encryption_enc_values_supported} metadata
762         * field.
763         *
764         * @param requestObjectJWEEncs The supported encryption methods,
765         *                             {@code null} if not specified.
766         */
767        public void setRequestObjectJWEEncs(final List<EncryptionMethod> requestObjectJWEEncs) {
768                this.requestObjectJWEEncs = requestObjectJWEEncs;
769        }
770        
771        
772        @Override
773        public boolean supportsRequestParam() {
774                return requestParamSupported;
775        }
776        
777        
778        /**
779         * Sets the support for the {@code request} authorisation request
780         * parameter. Corresponds to the {@code request_parameter_supported}
781         * metadata field.
782         *
783         * @param requestParamSupported {@code true} if the {@code reqeust}
784         *                              parameter is supported, else
785         *                              {@code false}.
786         */
787        public void setSupportsRequestParam(final boolean requestParamSupported) {
788                this.requestParamSupported = requestParamSupported;
789        }
790        
791        
792        @Override
793        public boolean supportsRequestURIParam() {
794                return requestURIParamSupported;
795        }
796        
797        
798        /**
799         * Sets the support for the {@code request_uri} authorisation request
800         * parameter. Corresponds to the
801         * {@code request_uri_parameter_supported} metadata field.
802         *
803         * @param requestURIParamSupported {@code true} if the
804         *                                 {@code request_uri} parameter is
805         *                                 supported, else {@code false}.
806         */
807        public void setSupportsRequestURIParam(final boolean requestURIParamSupported) {
808                this.requestURIParamSupported = requestURIParamSupported;
809        }
810        
811        
812        @Override
813        public boolean requiresRequestURIRegistration() {
814                return requireRequestURIReg;
815        }
816        
817        
818        /**
819         * Sets the requirement for the {@code request_uri} parameter
820         * pre-registration. Corresponds to the
821         * {@code require_request_uri_registration} metadata field.
822         *
823         * @param requireRequestURIReg {@code true} if the {@code request_uri}
824         *                             parameter values must be pre-registered,
825         *                             else {@code false}.
826         */
827        public void setRequiresRequestURIRegistration(final boolean requireRequestURIReg) {
828                this.requireRequestURIReg = requireRequestURIReg;
829        }
830        
831        
832        @Override
833        public boolean supportsAuthorizationResponseIssuerParam() {
834                return authzResponseIssParameterSupported;
835        }
836        
837        
838        /**
839         * Sets the support for the {@code iss} authorisation response
840         * parameter. Corresponds to the
841         * {@code authorization_response_iss_parameter_supported} metadata
842         * field.
843         *
844         * @param authzResponseIssParameterSupported {@code true} if the
845         *                                           {@code iss} authorisation
846         *                                           response parameter is
847         *                                           provided, else
848         *                                           {@code false}.
849         */
850        public void setSupportsAuthorizationResponseIssuerParam(final boolean authzResponseIssParameterSupported) {
851                this.authzResponseIssParameterSupported = authzResponseIssParameterSupported;
852        }
853        
854        
855        @Override
856        public List<LangTag> getUILocales() {
857                return uiLocales;
858        }
859        
860        
861        /**
862         * Sets the supported UI locales. Corresponds to the
863         * {@code ui_locales_supported} metadata field.
864         *
865         * @param uiLocales The supported UI locales, {@code null} if not
866         *                  specified.
867         */
868        public void setUILocales(final List<LangTag> uiLocales) {
869                this.uiLocales = uiLocales;
870        }
871        
872        
873        @Override
874        public URI getServiceDocsURI() {
875                return serviceDocsURI;
876        }
877        
878        
879        /**
880         * Sets the service documentation URI. Corresponds to the
881         * {@code service_documentation} metadata field.
882         *
883         * @param serviceDocsURI The service documentation URI, {@code null} if
884         *                       not specified. The URI scheme must be https or
885         *                       http.
886         */
887        public void setServiceDocsURI(final URI serviceDocsURI) {
888                URIUtils.ensureSchemeIsHTTPSorHTTP(serviceDocsURI);
889                this.serviceDocsURI = serviceDocsURI;
890        }
891        
892        
893        @Override
894        public URI getPolicyURI() {
895                return policyURI;
896        }
897        
898        
899        /**
900         * Sets the provider's policy regarding relying party use of data.
901         * Corresponds to the {@code op_policy_uri} metadata field.
902         *
903         * @param policyURI The policy URI, {@code null} if not specified. The
904         *                  URI scheme must be https or http.
905         */
906        public void setPolicyURI(final URI policyURI) {
907                URIUtils.ensureSchemeIsHTTPSorHTTP(policyURI);
908                this.policyURI = policyURI;
909        }
910        
911        
912        @Override
913        public URI getTermsOfServiceURI() {
914                return tosURI;
915        }
916        
917        
918        /**
919         * Sets the provider's terms of service. Corresponds to the
920         * {@code op_tos_uri} metadata field.
921         *
922         * @param tosURI The terms of service URI, {@code null} if not
923         *               specified. The URI scheme must be https or http.
924         */
925        public void setTermsOfServiceURI(final URI tosURI) {
926                URIUtils.ensureSchemeIsHTTPSorHTTP(tosURI);
927                this.tosURI = tosURI;
928        }
929        
930        
931        @Override
932        public ReadOnlyAuthorizationServerEndpointMetadata getReadOnlyMtlsEndpointAliases() {
933                return getMtlsEndpointAliases();
934        }
935        
936        
937        /**
938         * Gets the aliases for communication with mutual TLS. Corresponds to
939         * the {@code mtls_endpoint_aliases} metadata field.
940         *
941         * @return The aliases for communication with mutual TLS, {@code null}
942         *         when no aliases are defined.
943         */
944        public AuthorizationServerEndpointMetadata getMtlsEndpointAliases() {
945                return mtlsEndpointAliases;
946        }
947        
948        
949        /**
950         * Sets the aliases for communication with mutual TLS. Corresponds to the
951         * {@code mtls_endpoint_aliases} metadata field.
952         * 
953         * @param mtlsEndpointAliases The aliases for communication with mutual
954         *                            TLS, or {@code null} when no aliases are
955         *                            defined.
956         */
957        public void setMtlsEndpointAliases(AuthorizationServerEndpointMetadata mtlsEndpointAliases) {
958                this.mtlsEndpointAliases = mtlsEndpointAliases;
959        }
960        
961        
962        @Override
963        public boolean supportsTLSClientCertificateBoundAccessTokens() {
964                return tlsClientCertificateBoundAccessTokens;
965        }
966        
967        
968        /**
969         * Sets the support for TLS client certificate bound access tokens.
970         * Corresponds to the
971         * {@code tls_client_certificate_bound_access_tokens} metadata field.
972         *
973         * @param tlsClientCertBoundTokens {@code true} if TLS client
974         *                                 certificate bound access tokens are
975         *                                 supported, else {@code false}.
976         */
977        public void setSupportsTLSClientCertificateBoundAccessTokens(final boolean tlsClientCertBoundTokens) {
978                tlsClientCertificateBoundAccessTokens = tlsClientCertBoundTokens;
979        }
980        
981        
982        @Override
983        @Deprecated
984        public boolean supportsMutualTLSSenderConstrainedAccessTokens() {
985                return supportsTLSClientCertificateBoundAccessTokens();
986        }
987        
988        
989        /**
990         * Sets the support for TLS client certificate bound access tokens.
991         * Corresponds to the
992         * {@code tls_client_certificate_bound_access_tokens} metadata field.
993         *
994         * @param mutualTLSSenderConstrainedAccessTokens {@code true} if TLS
995         *                                               client certificate
996         *                                               bound access tokens
997         *                                               are supported, else
998         *                                               {@code false}.
999         */
1000        @Deprecated
1001        public void setSupportsMutualTLSSenderConstrainedAccessTokens(final boolean mutualTLSSenderConstrainedAccessTokens) {
1002                setSupportsTLSClientCertificateBoundAccessTokens(mutualTLSSenderConstrainedAccessTokens);
1003        }
1004        
1005        
1006        @Override
1007        public List<JWSAlgorithm> getDPoPJWSAlgs() {
1008                return dPoPJWSAlgs;
1009        }
1010        
1011        
1012        /**
1013         * Sets the supported JWS algorithms for Demonstrating
1014         * Proof-of-Possession at the Application Layer (DPoP). Corresponds to
1015         * the "dpop_signing_alg_values_supported" metadata field.
1016         *
1017         * @param dPoPJWSAlgs The supported JWS algorithms for DPoP,
1018         *                    {@code null} if none.
1019         */
1020        public void setDPoPJWSAlgs(final List<JWSAlgorithm> dPoPJWSAlgs) {
1021                this.dPoPJWSAlgs = dPoPJWSAlgs;
1022        }
1023        
1024        
1025        @Override
1026        public List<JWSAlgorithm> getAuthorizationJWSAlgs() {
1027                return authzJWSAlgs;
1028        }
1029        
1030        
1031        /**
1032         * Sets the supported JWS algorithms for JWT-encoded authorisation
1033         * responses. Corresponds to the
1034         * {@code authorization_signing_alg_values_supported} metadata field.
1035         *
1036         * @param authzJWSAlgs The supported JWS algorithms, {@code null} if
1037         *                     not specified.
1038         */
1039        public void setAuthorizationJWSAlgs(final List<JWSAlgorithm> authzJWSAlgs) {
1040                this.authzJWSAlgs = authzJWSAlgs;
1041        }
1042        
1043        
1044        @Override
1045        public List<JWEAlgorithm> getAuthorizationJWEAlgs() {
1046                return authzJWEAlgs;
1047        }
1048        
1049        
1050        /**
1051         * Sets the supported JWE algorithms for JWT-encoded authorisation
1052         * responses. Corresponds to the
1053         * {@code authorization_encryption_alg_values_supported} metadata
1054         * field.
1055         *
1056         * @param authzJWEAlgs The supported JWE algorithms, {@code null} if
1057         *                     not specified.
1058         */
1059        public void setAuthorizationJWEAlgs(final List<JWEAlgorithm> authzJWEAlgs) {
1060                this.authzJWEAlgs = authzJWEAlgs;
1061        }
1062        
1063        
1064        @Override
1065        public List<EncryptionMethod> getAuthorizationJWEEncs() {
1066                return authzJWEEncs;
1067        }
1068        
1069        
1070        /**
1071         * Sets the supported encryption methods for JWT-encoded authorisation
1072         * responses. Corresponds to the
1073         * {@code authorization_encryption_enc_values_supported} metadata
1074         * field.
1075         *
1076         * @param authzJWEEncs The supported encryption methods, {@code null}
1077         *                     if not specified.
1078         */
1079        public void setAuthorizationJWEEncs(final List<EncryptionMethod> authzJWEEncs) {
1080                this.authzJWEEncs = authzJWEEncs;
1081        }
1082        
1083        
1084        @Override
1085        public boolean requiresPushedAuthorizationRequests() {
1086                return requirePAR;
1087        }
1088        
1089        
1090        /**
1091         * Sets the requirement for pushed authorisation requests (PAR).
1092         * Corresponds to the {@code pushed_authorization_request_endpoint}
1093         * metadata field.
1094         *
1095         * @param requirePAR {@code true} if PAR is required, else
1096         *                   {@code false}.
1097         */
1098        public void requiresPushedAuthorizationRequests(final boolean requirePAR) {
1099                this.requirePAR = requirePAR;
1100        }
1101
1102
1103        @Override
1104        public List<AuthorizationType> getAuthorizationDetailsTypes() {
1105                return authzTypes;
1106        }
1107
1108
1109        /**
1110         * Sets the supported authorisation details types for Rich
1111         * Authorisation Requests (RAR). Corresponds to the
1112         * {@code authorization_details_types_supported} metadata field.
1113         *
1114         * @param authzTypes The supported authorisation types, {@code null} if
1115         *                   not specified.
1116         */
1117        public void setAuthorizationDetailsTypes(final List<AuthorizationType> authzTypes) {
1118                this.authzTypes = authzTypes;
1119        }
1120
1121
1122        @Override
1123        public List<ClientType> getIncrementalAuthorizationTypes() {
1124                return incrementalAuthzTypes;
1125        }
1126        
1127        
1128        /**
1129         * Sets the supported OAuth 2.0 client types for incremental
1130         * authorisation. Corresponds to the
1131         * {@code incremental_authz_types_supported} metadata field.
1132         *
1133         * @param incrementalAuthzTypes The supported client types for
1134         *                              incremental authorisation, {@code null}
1135         *                              if not specified.
1136         */
1137        public void setIncrementalAuthorizationTypes(final List<ClientType> incrementalAuthzTypes) {
1138                this.incrementalAuthzTypes = incrementalAuthzTypes;
1139        }
1140        
1141        
1142        @Override
1143        public List<BackChannelTokenDeliveryMode> getBackChannelTokenDeliveryModes() {
1144                return backChannelTokenDeliveryModes;
1145        }
1146        
1147        
1148        /**
1149         * Sets the supported CIBA token delivery modes. Corresponds to the
1150         * {@code backchannel_token_delivery_modes_supported} metadata field.
1151         *
1152         * @param backChannelTokenDeliveryModes The CIBA token delivery modes,
1153         *                                      {@code null} if not specified.
1154         */
1155        public void setBackChannelTokenDeliveryModes(final List<BackChannelTokenDeliveryMode> backChannelTokenDeliveryModes) {
1156                this.backChannelTokenDeliveryModes = backChannelTokenDeliveryModes;
1157        }
1158        
1159        @Override
1160        public List<JWSAlgorithm> getBackChannelAuthenticationRequestJWSAlgs() {
1161                return backChannelAuthRequestJWSAlgs;
1162        }
1163        
1164        /**
1165         * Gets the supported JWS algorithms for CIBA requests. Corresponds to
1166         * the {@code backchannel_authentication_request_signing_alg_values_supported}
1167         * metadata field.
1168         *
1169         * @param backChannelAuthRequestJWSAlgs The supported JWS algorithms,
1170         *                                      {@code null} if not specified.
1171         */
1172        public void setBackChannelAuthenticationRequestJWSAlgs(final List<JWSAlgorithm> backChannelAuthRequestJWSAlgs) {
1173                this.backChannelAuthRequestJWSAlgs = backChannelAuthRequestJWSAlgs;
1174        }
1175        
1176        
1177        @Override
1178        public boolean supportsBackChannelUserCodeParam() {
1179                return backChannelUserCodeSupported;
1180        }
1181        
1182        
1183        /**
1184         * Sets the support for the {@code user_code} CIBA request parameter.
1185         * Corresponds to the {@code backchannel_user_code_parameter_supported}
1186         * metadata field.
1187         *
1188         * @param backChannelUserCodeSupported {@code true} if the
1189         *                                     {@code user_code} parameter is
1190         *                                     supported, else {@code false}.
1191         */
1192        public void setSupportsBackChannelUserCodeParam(final boolean backChannelUserCodeSupported) {
1193                this.backChannelUserCodeSupported = backChannelUserCodeSupported;
1194        }
1195        
1196        
1197        @Override
1198        public List<Prompt.Type> getPromptTypes() {
1199                return promptTypes;
1200        }
1201        
1202        
1203        /**
1204         * Sets the supported {@link Prompt.Type prompt types}. Corresponds to
1205         * the {@code prompt_values_supported} metadata field.
1206         *
1207         * @param promptTypes The supported prompt types, {@code null} if not
1208         *                    specified.
1209         */
1210        public void setPromptTypes(final List<Prompt.Type> promptTypes) {
1211                this.promptTypes = promptTypes;
1212        }
1213        
1214        
1215        @Override
1216        public String getOrganizationName() {
1217                return organizationName;
1218        }
1219        
1220        
1221        /**
1222         * Sets the organisation name (in federation). Corresponds to the
1223         * {@code organization_name} metadata field.
1224         *
1225         * @param organizationName The organisation name, {@code null} if not
1226         *                         specified.
1227         */
1228        public void setOrganizationName(final String organizationName) {
1229                this.organizationName = organizationName;
1230        }
1231        
1232        
1233        @Override
1234        public JWKSet getJWKSet() {
1235                return jwkSet;
1236        }
1237        
1238        
1239        /**
1240         * Sets the JWK set (OpenID Connect Federation 1.0). Corresponds to the
1241         * {@code jwks} metadata field.
1242         *
1243         * @param jwkSet The JWK set, {@code null} if not specified.
1244         */
1245        public void setJWKSet(final JWKSet jwkSet) {
1246                this.jwkSet = jwkSet;
1247        }
1248        
1249        
1250        @Override
1251        public URI getSignedJWKSetURI() {
1252                return signedJWKSetURI;
1253        }
1254        
1255        
1256        /**
1257         * Sets the signed JWK set URI (OpenID Connect Federation 1.0).
1258         * Corresponds to the {@code signed_jwks_uri} metadata field.
1259         *
1260         * @param signedJWKSetURI The signed JWK set URI, {@code null} if not
1261         *                        specified.
1262         */
1263        public void setSignedJWKSetURI(final URI signedJWKSetURI) {
1264                this.signedJWKSetURI = signedJWKSetURI;
1265        }
1266        
1267        
1268        @Override
1269        public List<ClientRegistrationType> getClientRegistrationTypes() {
1270                return clientRegistrationTypes;
1271        }
1272        
1273        
1274        /**
1275         * Sets the supported federation client registration types. Corresponds
1276         * to the {@code client_registration_types_supported} metadata field.
1277         *
1278         * @param clientRegistrationTypes The supported client registration
1279         *                                types, {@code null} if not specified.
1280         */
1281        public void setClientRegistrationTypes(final List<ClientRegistrationType> clientRegistrationTypes) {
1282                this.clientRegistrationTypes = clientRegistrationTypes;
1283        }
1284        
1285        
1286        @Override
1287        public Map<EndpointName, List<ClientAuthenticationMethod>> getClientRegistrationAuthnMethods() {
1288                return clientRegistrationAuthMethods;
1289        }
1290        
1291        
1292        /**
1293         * Sets the supported request authentication methods for automatic
1294         * OpenID Connect Federation 1.0 client registration. Corresponds to
1295         * the {@code request_authentication_methods_supported} field.
1296         *
1297         * @param methods The supported request authentication methods for
1298         *                automatic federation client registration,
1299         *                {@code null} if not specified.
1300         */
1301        public void setClientRegistrationAuthnMethods(final Map<EndpointName,List<ClientAuthenticationMethod>> methods) {
1302                clientRegistrationAuthMethods = methods;
1303        }
1304        
1305        
1306        @Override
1307        public List<JWSAlgorithm> getClientRegistrationAuthnJWSAlgs() {
1308                return clientRegistrationAuthJWSAlgs;
1309        }
1310        
1311        
1312        /**
1313         * Sets the supported JWS algorithms for authenticating automatic
1314         * OpenID Connect Federation 1.0 client registration requests.
1315         * Corresponds to the
1316         * {@code request_authentication_signing_alg_values_supported}.
1317         *
1318         * @param jwsAlgs The supported JWS algorithms, {@code null} if
1319         *                       not specified.
1320         */
1321        public void setClientRegistrationAuthnJWSAlgs(final List<JWSAlgorithm> jwsAlgs) {
1322                clientRegistrationAuthJWSAlgs = jwsAlgs;
1323        }
1324        
1325        
1326        @Override
1327        public URI getFederationRegistrationEndpointURI() {
1328                return federationRegistrationEndpoint;
1329        }
1330        
1331        
1332        /**
1333         * Sets the federation registration endpoint URI. Corresponds to the
1334         * {@code federation_registration_endpoint} metadata field.
1335         *
1336         * @param federationRegistrationEndpoint The federation registration
1337         *                                       endpoint URI, {@code null} if
1338         *                                       not specified.
1339         */
1340        public void setFederationRegistrationEndpointURI(final URI federationRegistrationEndpoint) {
1341                this.federationRegistrationEndpoint = federationRegistrationEndpoint;
1342        }
1343        
1344        
1345        @Override
1346        public Object getCustomParameter(final String name) {
1347                
1348                return customParameters.get(name);
1349        }
1350        
1351        
1352        @Override
1353        public URI getCustomURIParameter(final String name) {
1354                
1355                try {
1356                        return JSONObjectUtils.getURI(customParameters, name, null);
1357                } catch (ParseException e) {
1358                        return null;
1359                }
1360        }
1361        
1362        
1363        /**
1364         * Sets the specified custom (not registered) parameter.
1365         *
1366         * @param name  The parameter name. Must not be {@code null}.
1367         * @param value The parameter value, {@code null} if not specified.
1368         */
1369        public void setCustomParameter(final String name, final Object value) {
1370                
1371                if (REGISTERED_PARAMETER_NAMES.contains(name)) {
1372                        throw new IllegalArgumentException("The " + name + " parameter is registered");
1373                }
1374                
1375                customParameters.put(name, value);
1376        }
1377        
1378        
1379        @Override
1380        public JSONObject getCustomParameters() {
1381                
1382                return customParameters;
1383        }
1384        
1385        
1386        /**
1387         * Applies the OAuth 2.0 Authorisation Server metadata defaults where
1388         * no values have been specified.
1389         *
1390         * <ul>
1391         *     <li>The response modes default to {@code ["query", "fragment"]}.
1392         *     <li>The grant types default to {@code ["authorization_code",
1393         *         "implicit"]}.
1394         *     <li>The token endpoint authentication methods default to
1395         *         {@code ["client_secret_basic"]}.
1396         * </ul>
1397         */
1398        public void applyDefaults() {
1399                
1400                if (rms == null) {
1401                        rms = new ArrayList<>(2);
1402                        rms.add(ResponseMode.QUERY);
1403                        rms.add(ResponseMode.FRAGMENT);
1404                }
1405                
1406                if (gts == null) {
1407                        gts = new ArrayList<>(2);
1408                        gts.add(GrantType.AUTHORIZATION_CODE);
1409                        gts.add(GrantType.IMPLICIT);
1410                }
1411                
1412                if (tokenEndpointAuthMethods == null) {
1413                        tokenEndpointAuthMethods = new ArrayList<>();
1414                        tokenEndpointAuthMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
1415                }
1416        }
1417        
1418        
1419        @Override
1420        public JSONObject toJSONObject() {
1421                JSONObject o = super.toJSONObject();
1422                
1423                // Mandatory fields
1424                o.put("issuer", issuer.getValue());
1425                
1426                
1427                // Optional fields
1428                if (jwkSetURI != null)
1429                        o.put("jwks_uri", jwkSetURI.toString());
1430                
1431                if (scope != null)
1432                        o.put("scopes_supported", scope.toStringList());
1433                
1434                List<String> stringList;
1435                
1436                if (rts != null) {
1437                        
1438                        stringList = new ArrayList<>(rts.size());
1439                        
1440                        for (ResponseType rt: rts)
1441                                stringList.add(rt.toString());
1442                        
1443                        o.put("response_types_supported", stringList);
1444                }
1445                
1446                if (rms != null) {
1447                        
1448                        stringList = new ArrayList<>(rms.size());
1449                        
1450                        for (ResponseMode rm: rms)
1451                                stringList.add(rm.getValue());
1452                        
1453                        o.put("response_modes_supported", stringList);
1454                }
1455                
1456                if (gts != null) {
1457                        
1458                        stringList = new ArrayList<>(gts.size());
1459                        
1460                        for (GrantType gt: gts)
1461                                stringList.add(gt.toString());
1462                        
1463                        o.put("grant_types_supported", stringList);
1464                }
1465                
1466                if (codeChallengeMethods != null) {
1467                        
1468                        stringList = new ArrayList<>(codeChallengeMethods.size());
1469                        
1470                        for (CodeChallengeMethod m: codeChallengeMethods)
1471                                stringList.add(m.getValue());
1472                        
1473                        o.put("code_challenge_methods_supported", stringList);
1474                }
1475                
1476                
1477                if (tokenEndpointAuthMethods != null) {
1478                        
1479                        stringList = new ArrayList<>(tokenEndpointAuthMethods.size());
1480                        
1481                        for (ClientAuthenticationMethod m: tokenEndpointAuthMethods)
1482                                stringList.add(m.getValue());
1483                        
1484                        o.put("token_endpoint_auth_methods_supported", stringList);
1485                }
1486                
1487                if (tokenEndpointJWSAlgs != null) {
1488                        
1489                        stringList = new ArrayList<>(tokenEndpointJWSAlgs.size());
1490                        
1491                        for (JWSAlgorithm alg: tokenEndpointJWSAlgs)
1492                                stringList.add(alg.getName());
1493                        
1494                        o.put("token_endpoint_auth_signing_alg_values_supported", stringList);
1495                }
1496                
1497                if (introspectionEndpointAuthMethods != null) {
1498                        
1499                        stringList = new ArrayList<>(introspectionEndpointAuthMethods.size());
1500                        
1501                        for (ClientAuthenticationMethod m: introspectionEndpointAuthMethods)
1502                                stringList.add(m.getValue());
1503                        
1504                        o.put("introspection_endpoint_auth_methods_supported", stringList);
1505                }
1506                
1507                if (introspectionEndpointJWSAlgs != null) {
1508                        
1509                        stringList = new ArrayList<>(introspectionEndpointJWSAlgs.size());
1510                        
1511                        for (JWSAlgorithm alg: introspectionEndpointJWSAlgs)
1512                                stringList.add(alg.getName());
1513                        
1514                        o.put("introspection_endpoint_auth_signing_alg_values_supported", stringList);
1515                }
1516                
1517                if (revocationEndpointAuthMethods != null) {
1518                        
1519                        stringList = new ArrayList<>(revocationEndpointAuthMethods.size());
1520                        
1521                        for (ClientAuthenticationMethod m: revocationEndpointAuthMethods)
1522                                stringList.add(m.getValue());
1523                        
1524                        o.put("revocation_endpoint_auth_methods_supported", stringList);
1525                }
1526                
1527                if (revocationEndpointJWSAlgs != null) {
1528                        
1529                        stringList = new ArrayList<>(revocationEndpointJWSAlgs.size());
1530                        
1531                        for (JWSAlgorithm alg: revocationEndpointJWSAlgs)
1532                                stringList.add(alg.getName());
1533                        
1534                        o.put("revocation_endpoint_auth_signing_alg_values_supported", stringList);
1535                }
1536                
1537                if (requestObjectJWSAlgs != null) {
1538                        
1539                        stringList = new ArrayList<>(requestObjectJWSAlgs.size());
1540                        
1541                        for (JWSAlgorithm alg: requestObjectJWSAlgs)
1542                                stringList.add(alg.getName());
1543                        
1544                        o.put("request_object_signing_alg_values_supported", stringList);
1545                }
1546                
1547                if (requestObjectJWEAlgs != null) {
1548                        
1549                        stringList = new ArrayList<>(requestObjectJWEAlgs.size());
1550                        
1551                        for (JWEAlgorithm alg: requestObjectJWEAlgs)
1552                                stringList.add(alg.getName());
1553                        
1554                        o.put("request_object_encryption_alg_values_supported", stringList);
1555                }
1556                
1557                if (requestObjectJWEEncs != null) {
1558                        
1559                        stringList = new ArrayList<>(requestObjectJWEEncs.size());
1560                        
1561                        for (EncryptionMethod m: requestObjectJWEEncs)
1562                                stringList.add(m.getName());
1563                        
1564                        o.put("request_object_encryption_enc_values_supported", stringList);
1565                }
1566                
1567                if (uiLocales != null) {
1568                        
1569                        stringList = new ArrayList<>(uiLocales.size());
1570                        
1571                        for (LangTag l: uiLocales)
1572                                stringList.add(l.toString());
1573                        
1574                        o.put("ui_locales_supported", stringList);
1575                }
1576                
1577                if (serviceDocsURI != null)
1578                        o.put("service_documentation", serviceDocsURI.toString());
1579                
1580                if (policyURI != null)
1581                        o.put("op_policy_uri", policyURI.toString());
1582                
1583                if (tosURI != null)
1584                        o.put("op_tos_uri", tosURI.toString());
1585                
1586                if (requestParamSupported) {
1587                        o.put("request_parameter_supported", true);
1588                }
1589                
1590                if (requestURIParamSupported) {
1591                        o.put("request_uri_parameter_supported", true);
1592                }
1593                
1594                if (requireRequestURIReg) {
1595                        o.put("require_request_uri_registration", true);
1596                }
1597                
1598                if (authzResponseIssParameterSupported) {
1599                        o.put("authorization_response_iss_parameter_supported", true);
1600                }
1601                
1602                if (mtlsEndpointAliases != null)
1603                        o.put("mtls_endpoint_aliases", mtlsEndpointAliases.toJSONObject());
1604                
1605                if (tlsClientCertificateBoundAccessTokens) {
1606                        o.put("tls_client_certificate_bound_access_tokens", true);
1607                }
1608                
1609                // DPoP
1610                if (dPoPJWSAlgs != null) {
1611                        
1612                        stringList = new ArrayList<>(dPoPJWSAlgs.size());
1613                        
1614                        for (JWSAlgorithm alg: dPoPJWSAlgs)
1615                                stringList.add(alg.getName());
1616                        
1617                        o.put("dpop_signing_alg_values_supported", stringList);
1618                }
1619                
1620                // JARM
1621                if (authzJWSAlgs != null) {
1622                        
1623                        stringList = new ArrayList<>(authzJWSAlgs.size());
1624                        
1625                        for (JWSAlgorithm alg: authzJWSAlgs)
1626                                stringList.add(alg.getName());
1627                        
1628                        o.put("authorization_signing_alg_values_supported", stringList);
1629                }
1630                
1631                if (authzJWEAlgs != null) {
1632                        
1633                        stringList = new ArrayList<>(authzJWEAlgs.size());
1634                        
1635                        for (JWEAlgorithm alg: authzJWEAlgs)
1636                                stringList.add(alg.getName());
1637                        
1638                        o.put("authorization_encryption_alg_values_supported", stringList);
1639                }
1640                
1641                if (authzJWEEncs != null) {
1642                        
1643                        stringList = new ArrayList<>(authzJWEEncs.size());
1644                        
1645                        for (EncryptionMethod m: authzJWEEncs)
1646                                stringList.add(m.getName());
1647                        
1648                        o.put("authorization_encryption_enc_values_supported", stringList);
1649                }
1650                
1651                // PAR
1652                if (requirePAR) {
1653                        o.put("require_pushed_authorization_requests", true);
1654                }
1655
1656                // RAR
1657                if (authzTypes != null) {
1658                        o.put("authorization_details_types_supported", Identifier.toStringList(authzTypes));
1659                }
1660                
1661                // Incremental authz
1662                if (CollectionUtils.isNotEmpty(incrementalAuthzTypes)) {
1663                        stringList = new ArrayList<>(incrementalAuthzTypes.size());
1664                        for (ClientType clientType: incrementalAuthzTypes) {
1665                                if (clientType != null) {
1666                                        stringList.add(clientType.name().toLowerCase());
1667                                }
1668                        }
1669                        o.put("incremental_authz_types_supported", stringList);
1670                }
1671                
1672                // CIBA
1673                if (backChannelTokenDeliveryModes != null) {
1674                        
1675                        stringList = new ArrayList<>(backChannelTokenDeliveryModes.size());
1676                        
1677                        for (BackChannelTokenDeliveryMode mode: backChannelTokenDeliveryModes) {
1678                                if (mode != null) {
1679                                        stringList.add(mode.getValue());
1680                                }
1681                        }
1682                        
1683                        o.put("backchannel_token_delivery_modes_supported", stringList);
1684                }
1685                
1686                if (backChannelAuthRequestJWSAlgs != null) {
1687                        
1688                        stringList = new ArrayList<>(backChannelAuthRequestJWSAlgs.size());
1689                        
1690                        for (JWSAlgorithm alg : backChannelAuthRequestJWSAlgs) {
1691                                if (alg != null) {
1692                                        stringList.add(alg.getName());
1693                                }
1694                        }
1695                        
1696                        o.put("backchannel_authentication_request_signing_alg_values_supported", stringList);
1697                }
1698                
1699                if (backChannelUserCodeSupported) {
1700                        o.put("backchannel_user_code_parameter_supported", true);
1701                }
1702                
1703                
1704                // Prompt=create
1705                if (promptTypes != null) {
1706                        stringList = new ArrayList<>(promptTypes.size());
1707                        for (Prompt.Type type: promptTypes) {
1708                                stringList.add(type.toString());
1709                        }
1710                        o.put("prompt_values_supported", stringList);
1711                }
1712                
1713                // OIDC Federation 1.0
1714                
1715                if (organizationName != null) {
1716                        o.put("organization_name", organizationName);
1717                }
1718                
1719                if (CollectionUtils.isNotEmpty(clientRegistrationTypes)) {
1720                        
1721                        o.put("client_registration_types_supported", Identifier.toStringList(clientRegistrationTypes));
1722                        
1723                        if (jwkSet != null) {
1724                                o.put("jwks", JSONObjectUtils.toJSONObject(jwkSet.toPublicJWKSet())); // prevent private keys from leaking
1725                        } else if (signedJWKSetURI != null) {
1726                                o.put("signed_jwks_uri", signedJWKSetURI.toString());
1727                        }
1728                        
1729                        if (clientRegistrationTypes.contains(ClientRegistrationType.AUTOMATIC) && MapUtils.isNotEmpty(clientRegistrationAuthMethods)) {
1730                                JSONObject map = new JSONObject();
1731                                for (Map.Entry<EndpointName,List<ClientAuthenticationMethod>> en: getClientRegistrationAuthnMethods().entrySet()) {
1732                                        List<String> methodNames = new LinkedList<>();
1733                                        for (ClientAuthenticationMethod method: en.getValue()) {
1734                                                methodNames.add(method.getValue());
1735                                        }
1736                                        map.put(en.getKey().getValue(), methodNames);
1737                                }
1738                                o.put("request_authentication_methods_supported", map);
1739                        }
1740                        
1741                        if (clientRegistrationTypes.contains(ClientRegistrationType.AUTOMATIC) && CollectionUtils.isNotEmpty(clientRegistrationAuthJWSAlgs)) {
1742                                
1743                                stringList = new ArrayList<>(clientRegistrationAuthJWSAlgs.size());
1744                                
1745                                for (JWSAlgorithm alg: clientRegistrationAuthJWSAlgs)
1746                                        stringList.add(alg.getName());
1747                                
1748                                o.put("request_authentication_signing_alg_values_supported", stringList);
1749                        }
1750                        
1751                        if (clientRegistrationTypes.contains(ClientRegistrationType.EXPLICIT) && federationRegistrationEndpoint != null) {
1752                                o.put("federation_registration_endpoint", federationRegistrationEndpoint.toString());
1753                        } else {
1754                                o.remove("federation_registration_endpoint");
1755                        }
1756                }
1757
1758                // Append any custom (not registered) parameters
1759                o.putAll(customParameters);
1760                
1761                return o;
1762        }
1763        
1764        
1765        /**
1766         * Parses an OAuth 2.0 Authorisation Server metadata from the specified
1767         * JSON object.
1768         *
1769         * @param jsonObject The JSON object to parse. Must not be
1770         *                   {@code null}.
1771         *
1772         * @return The OAuth 2.0 Authorisation Server metadata.
1773         *
1774         * @throws ParseException If the JSON object couldn't be parsed to an
1775         *                        OAuth 2.0 Authorisation Server metadata.
1776         */
1777        public static AuthorizationServerMetadata parse(final JSONObject jsonObject)
1778                throws ParseException {
1779                
1780                // Parse issuer and subject_types_supported first
1781                
1782                Issuer issuer = new Issuer(JSONObjectUtils.getURI(jsonObject, "issuer").toString());
1783
1784                AuthorizationServerEndpointMetadata asEndpoints = AuthorizationServerEndpointMetadata.parse(jsonObject);
1785                
1786                AuthorizationServerMetadata as;
1787                
1788                try {
1789                        as = new AuthorizationServerMetadata(issuer); // validates issuer syntax
1790                } catch (IllegalArgumentException e) {
1791                        throw new ParseException(e.getMessage(), e);
1792                }
1793                
1794                // Endpoints
1795                as.setAuthorizationEndpointURI(asEndpoints.getAuthorizationEndpointURI());
1796                as.setTokenEndpointURI(asEndpoints.getTokenEndpointURI());
1797                as.setRegistrationEndpointURI(asEndpoints.getRegistrationEndpointURI());
1798                as.setIntrospectionEndpointURI(asEndpoints.getIntrospectionEndpointURI());
1799                as.setRevocationEndpointURI(asEndpoints.getRevocationEndpointURI());
1800                as.setRequestObjectEndpoint(asEndpoints.getRequestObjectEndpoint());
1801                as.setPushedAuthorizationRequestEndpointURI(asEndpoints.getPushedAuthorizationRequestEndpointURI());
1802                as.setDeviceAuthorizationEndpointURI(asEndpoints.getDeviceAuthorizationEndpointURI());
1803                as.setBackChannelAuthenticationEndpointURI(asEndpoints.getBackChannelAuthenticationEndpointURI());
1804                as.jwkSetURI = JSONObjectUtils.getURI(jsonObject, "jwks_uri", null);
1805                
1806                // AS capabilities
1807                if (jsonObject.get("scopes_supported") != null) {
1808                        
1809                        as.scope = new Scope();
1810                        
1811                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "scopes_supported")) {
1812                                
1813                                if (v != null)
1814                                        as.scope.add(new Scope.Value(v));
1815                        }
1816                }
1817                
1818                if (jsonObject.get("response_types_supported") != null) {
1819                        
1820                        as.rts = new ArrayList<>();
1821                        
1822                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "response_types_supported")) {
1823                                
1824                                if (v != null)
1825                                        as.rts.add(ResponseType.parse(v));
1826                        }
1827                }
1828                
1829                if (jsonObject.get("response_modes_supported") != null) {
1830                        
1831                        as.rms = new ArrayList<>();
1832                        
1833                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "response_modes_supported")) {
1834                                
1835                                if (v != null)
1836                                        as.rms.add(new ResponseMode(v));
1837                        }
1838                }
1839                
1840                if (jsonObject.get("grant_types_supported") != null) {
1841                        
1842                        as.gts = new ArrayList<>();
1843                        
1844                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "grant_types_supported")) {
1845                                
1846                                if (v != null)
1847                                        as.gts.add(GrantType.parse(v));
1848                        }
1849                }
1850                
1851                if (jsonObject.get("code_challenge_methods_supported") != null) {
1852                        
1853                        as.codeChallengeMethods = new ArrayList<>();
1854                        
1855                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "code_challenge_methods_supported")) {
1856                                
1857                                if (v != null)
1858                                        as.codeChallengeMethods.add(CodeChallengeMethod.parse(v));
1859                        }
1860                }
1861                
1862                if (jsonObject.get("token_endpoint_auth_methods_supported") != null) {
1863                        
1864                        as.tokenEndpointAuthMethods = new ArrayList<>();
1865                        
1866                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "token_endpoint_auth_methods_supported")) {
1867                                
1868                                if (v != null)
1869                                        as.tokenEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
1870                        }
1871                }
1872                
1873                if (jsonObject.get("token_endpoint_auth_signing_alg_values_supported") != null) {
1874                        
1875                        as.tokenEndpointJWSAlgs = new ArrayList<>();
1876                        
1877                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "token_endpoint_auth_signing_alg_values_supported")) {
1878                                
1879                                if (v != null && v.equals(Algorithm.NONE.getName()))
1880                                        throw new ParseException("The none algorithm is not accepted");
1881                                
1882                                if (v != null)
1883                                        as.tokenEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
1884                        }
1885                }
1886                
1887                if (jsonObject.get("introspection_endpoint_auth_methods_supported") != null) {
1888                        
1889                        as.introspectionEndpointAuthMethods = new ArrayList<>();
1890                        
1891                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "introspection_endpoint_auth_methods_supported")) {
1892                                
1893                                if (v != null)
1894                                        as.introspectionEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
1895                        }
1896                }
1897                
1898                if (jsonObject.get("introspection_endpoint_auth_signing_alg_values_supported") != null) {
1899                        
1900                        as.introspectionEndpointJWSAlgs = new ArrayList<>();
1901                        
1902                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "introspection_endpoint_auth_signing_alg_values_supported")) {
1903                                
1904                                if (v != null && v.equals(Algorithm.NONE.getName()))
1905                                        throw new ParseException("The none algorithm is not accepted");
1906                                
1907                                if (v != null)
1908                                        as.introspectionEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
1909                        }
1910                }
1911                
1912                if (jsonObject.get("revocation_endpoint_auth_methods_supported") != null) {
1913                        
1914                        as.revocationEndpointAuthMethods = new ArrayList<>();
1915                        
1916                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "revocation_endpoint_auth_methods_supported")) {
1917                                
1918                                if (v != null)
1919                                        as.revocationEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
1920                        }
1921                }
1922                
1923                if (jsonObject.get("revocation_endpoint_auth_signing_alg_values_supported") != null) {
1924                        
1925                        as.revocationEndpointJWSAlgs = new ArrayList<>();
1926                        
1927                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "revocation_endpoint_auth_signing_alg_values_supported")) {
1928                                
1929                                if (v != null && v.equals(Algorithm.NONE.getName()))
1930                                        throw new ParseException("The none algorithm is not accepted");
1931                                
1932                                if (v != null)
1933                                        as.revocationEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
1934                        }
1935                }
1936                
1937                
1938                // Request object
1939                if (jsonObject.get("request_object_signing_alg_values_supported") != null) {
1940                        
1941                        as.requestObjectJWSAlgs = new ArrayList<>();
1942                        
1943                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_signing_alg_values_supported")) {
1944                                
1945                                if (v != null)
1946                                        as.requestObjectJWSAlgs.add(JWSAlgorithm.parse(v));
1947                        }
1948                }
1949                
1950                
1951                if (jsonObject.get("request_object_encryption_alg_values_supported") != null) {
1952                        
1953                        as.requestObjectJWEAlgs = new ArrayList<>();
1954                        
1955                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_encryption_alg_values_supported")) {
1956                                
1957                                if (v != null)
1958                                        as.requestObjectJWEAlgs.add(JWEAlgorithm.parse(v));
1959                        }
1960                }
1961                
1962                
1963                if (jsonObject.get("request_object_encryption_enc_values_supported") != null) {
1964                        
1965                        as.requestObjectJWEEncs = new ArrayList<>();
1966                        
1967                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_encryption_enc_values_supported")) {
1968                                
1969                                if (v != null)
1970                                        as.requestObjectJWEEncs.add(EncryptionMethod.parse(v));
1971                        }
1972                }
1973                
1974                
1975                // Misc
1976                
1977                if (jsonObject.get("ui_locales_supported") != null) {
1978                        
1979                        as.uiLocales = new ArrayList<>();
1980                        
1981                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "ui_locales_supported")) {
1982                                
1983                                if (v != null) {
1984                                        
1985                                        try {
1986                                                as.uiLocales.add(LangTag.parse(v));
1987                                                
1988                                        } catch (LangTagException e) {
1989                                                
1990                                                throw new ParseException("Invalid ui_locales_supported field: " + e.getMessage(), e);
1991                                        }
1992                                }
1993                        }
1994                }
1995                
1996                if (jsonObject.get("service_documentation") != null) {
1997                        try {
1998                                as.setServiceDocsURI(JSONObjectUtils.getURI(jsonObject, "service_documentation"));
1999                        } catch (IllegalArgumentException e) {
2000                                throw new ParseException("Illegal service_documentation parameter: " + e.getMessage());
2001                        }
2002                }
2003                
2004                if (jsonObject.get("op_policy_uri") != null) {
2005                        try {
2006                                as.setPolicyURI(JSONObjectUtils.getURI(jsonObject, "op_policy_uri"));
2007                        } catch (IllegalArgumentException e) {
2008                                throw new ParseException("Illegal op_policy_uri parameter: " + e.getMessage());
2009                        }
2010                }
2011                
2012                if (jsonObject.get("op_tos_uri") != null) {
2013                        try {
2014                                as.setTermsOfServiceURI(JSONObjectUtils.getURI(jsonObject, "op_tos_uri"));
2015                        } catch (IllegalArgumentException e) {
2016                                throw new ParseException("Illegal op_tos_uri parameter: " + e.getMessage());
2017                        }
2018                }
2019                
2020                if (jsonObject.get("request_parameter_supported") != null)
2021                        as.requestParamSupported = JSONObjectUtils.getBoolean(jsonObject, "request_parameter_supported");
2022                
2023                if (jsonObject.get("request_uri_parameter_supported") != null)
2024                        as.requestURIParamSupported = JSONObjectUtils.getBoolean(jsonObject, "request_uri_parameter_supported");
2025                
2026                if (jsonObject.get("require_request_uri_registration") != null)
2027                        as.requireRequestURIReg = JSONObjectUtils.getBoolean(jsonObject, "require_request_uri_registration");
2028                
2029                if (jsonObject.get("authorization_response_iss_parameter_supported") != null)
2030                        as.authzResponseIssParameterSupported = JSONObjectUtils.getBoolean(jsonObject, "authorization_response_iss_parameter_supported");
2031                
2032                if (jsonObject.get("mtls_endpoint_aliases") != null)
2033                        as.mtlsEndpointAliases = AuthorizationServerEndpointMetadata.parse(JSONObjectUtils.getJSONObject(jsonObject, "mtls_endpoint_aliases"));
2034                
2035                if (jsonObject.get("tls_client_certificate_bound_access_tokens") != null)
2036                        as.tlsClientCertificateBoundAccessTokens = JSONObjectUtils.getBoolean(jsonObject, "tls_client_certificate_bound_access_tokens");
2037                
2038                // DPoP
2039                if (jsonObject.get("dpop_signing_alg_values_supported") != null)  {
2040                        
2041                        as.dPoPJWSAlgs = new ArrayList<>();
2042                        
2043                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "dpop_signing_alg_values_supported")) {
2044                                
2045                                if (v != null)
2046                                        as.dPoPJWSAlgs.add(JWSAlgorithm.parse(v));
2047                        }
2048                }
2049                
2050                // JARM
2051                if (jsonObject.get("authorization_signing_alg_values_supported") != null) {
2052                        
2053                        as.authzJWSAlgs = new ArrayList<>();
2054                        
2055                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_signing_alg_values_supported")) {
2056                                
2057                                if (v != null)
2058                                        as.authzJWSAlgs.add(JWSAlgorithm.parse(v));
2059                        }
2060                }
2061                
2062                
2063                if (jsonObject.get("authorization_encryption_alg_values_supported") != null) {
2064                        
2065                        as.authzJWEAlgs = new ArrayList<>();
2066                        
2067                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_encryption_alg_values_supported")) {
2068                                
2069                                if (v != null)
2070                                        as.authzJWEAlgs.add(JWEAlgorithm.parse(v));
2071                        }
2072                }
2073                
2074                
2075                if (jsonObject.get("authorization_encryption_enc_values_supported") != null) {
2076                        
2077                        as.authzJWEEncs = new ArrayList<>();
2078                        
2079                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_encryption_enc_values_supported")) {
2080                                
2081                                if (v != null)
2082                                        as.authzJWEEncs.add(EncryptionMethod.parse(v));
2083                        }
2084                }
2085                
2086                // PAR
2087                if (jsonObject.get("require_pushed_authorization_requests") != null) {
2088                        as.requiresPushedAuthorizationRequests(JSONObjectUtils.getBoolean(jsonObject, "require_pushed_authorization_requests"));
2089                }
2090
2091                // RAR
2092                if (jsonObject.get("authorization_details_types_supported") != null) {
2093
2094                        as.authzTypes = new ArrayList<>();
2095
2096                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_details_types_supported")) {
2097
2098                                if (StringUtils.isNotBlank(v)) {
2099                                        as.authzTypes.add(new AuthorizationType(v));
2100                                }
2101                        }
2102                }
2103                
2104                // Incremental authz
2105                if (jsonObject.get("incremental_authz_types_supported") != null) {
2106                        
2107                        as.incrementalAuthzTypes = new ArrayList<>();
2108                        
2109                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "incremental_authz_types_supported")) {
2110                                
2111                                if (v != null) {
2112                                        ClientType clientType;
2113                                        try {
2114                                                clientType = ClientType.valueOf(v.toUpperCase());
2115                                        } catch (IllegalArgumentException e) {
2116                                                throw new ParseException("Illegal client type in incremental_authz_types_supported field: " + v);
2117                                        }
2118                                        as.incrementalAuthzTypes.add(clientType);
2119                                }
2120                        }
2121                }
2122                
2123                // CIBA
2124                if (jsonObject.get("backchannel_token_delivery_modes_supported") != null) {
2125                        
2126                        as.backChannelTokenDeliveryModes = new ArrayList<>();
2127
2128                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "backchannel_token_delivery_modes_supported")) {
2129
2130                                if (v != null)
2131                                        as.backChannelTokenDeliveryModes.add(BackChannelTokenDeliveryMode.parse(v));
2132                        }
2133                }
2134
2135                if (jsonObject.get("backchannel_authentication_request_signing_alg_values_supported") != null) {
2136                        
2137                        as.backChannelAuthRequestJWSAlgs = new ArrayList<>();
2138
2139                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "backchannel_authentication_request_signing_alg_values_supported")) {
2140
2141                                if (v != null)
2142                                        as.backChannelAuthRequestJWSAlgs.add(JWSAlgorithm.parse(v));
2143                        }
2144                }
2145                
2146                if (jsonObject.get("backchannel_user_code_parameter_supported") != null) {
2147                        as.backChannelUserCodeSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_user_code_parameter_supported");
2148                }
2149                
2150                // prompt=create
2151                if (jsonObject.get("prompt_values_supported") != null) {
2152                        
2153                        as.promptTypes = new ArrayList<>();
2154                        for (String v: JSONObjectUtils.getStringList(jsonObject, "prompt_values_supported")) {
2155                                
2156                                if (v != null)
2157                                        as.promptTypes.add(Prompt.Type.parse(v));
2158                        }
2159                }
2160                
2161                // OIDC Federation 1.0
2162                if (jsonObject.get("client_registration_types_supported") != null) {
2163                        
2164                        as.clientRegistrationTypes = new LinkedList<>();
2165                        for (String v : JSONObjectUtils.getStringList(jsonObject, "client_registration_types_supported")) {
2166                                as.clientRegistrationTypes.add(new ClientRegistrationType(v));
2167                        }
2168                        
2169                        if (jsonObject.get("jwks") != null) {
2170                                try {
2171                                        as.jwkSet = JWKSet.parse(JSONObjectUtils.getJSONObject(jsonObject, "jwks"));
2172                                } catch (java.text.ParseException e) {
2173                                        throw new ParseException(e.getMessage(), e);
2174                                }
2175                        }
2176                        
2177                        as.signedJWKSetURI = JSONObjectUtils.getURI(jsonObject, "signed_jwks_uri", null);
2178                        
2179                        if (jsonObject.get("request_authentication_methods_supported") != null) {
2180                                Map<EndpointName, List<ClientAuthenticationMethod>> requestAuthMethods = new HashMap<>();
2181                                JSONObject spec = JSONObjectUtils.getJSONObject(jsonObject, "request_authentication_methods_supported");
2182                                // authorization_endpoint or RAR
2183                                for (String endpointName : spec.keySet()) {
2184                                        List<String> methodNames = JSONObjectUtils.getStringList(spec, endpointName, Collections.<String>emptyList());
2185                                        List<ClientAuthenticationMethod> authMethods = new LinkedList<>();
2186                                        for (String name : methodNames) {
2187                                                authMethods.add(ClientAuthenticationMethod.parse(name));
2188                                        }
2189                                        requestAuthMethods.put(new EndpointName(endpointName), authMethods);
2190                                }
2191                                as.setClientRegistrationAuthnMethods(requestAuthMethods);
2192                        }
2193                        
2194                        if (jsonObject.get("request_authentication_signing_alg_values_supported") != null) {
2195                                as.clientRegistrationAuthJWSAlgs = new ArrayList<>();
2196                                
2197                                for (String v : JSONObjectUtils.getStringArray(jsonObject, "request_authentication_signing_alg_values_supported")) {
2198                                        
2199                                        if (v != null)
2200                                                as.clientRegistrationAuthJWSAlgs.add(JWSAlgorithm.parse(v));
2201                                }
2202                        }
2203                        
2204                        as.federationRegistrationEndpoint = JSONObjectUtils.getURI(jsonObject, "federation_registration_endpoint", null);
2205                }
2206                
2207                as.organizationName = JSONObjectUtils.getString(jsonObject, "organization_name", null);
2208                
2209                // Parse custom (not registered) parameters
2210                JSONObject customParams = new JSONObject(jsonObject);
2211                customParams.keySet().removeAll(REGISTERED_PARAMETER_NAMES);
2212                for (Map.Entry<String,Object> customEntry: customParams.entrySet()) {
2213                        as.setCustomParameter(customEntry.getKey(), customEntry.getValue());
2214                }
2215                
2216                return as;
2217        }
2218        
2219        
2220        /**
2221         * Parses an OAuth 2.0 Authorisation Server metadata from the specified
2222         * JSON object string.
2223         *
2224         * @param s The JSON object sting to parse. Must not be {@code null}.
2225         *
2226         * @return The OAuth 2.0 Authorisation Server metadata.
2227         *
2228         * @throws ParseException If the JSON object string couldn't be parsed
2229         *                        to an OAuth 2.0 Authorisation Server
2230         *                        metadata.
2231         */
2232        public static AuthorizationServerMetadata parse(final String s)
2233                throws ParseException {
2234                
2235                return parse(JSONObjectUtils.parse(s));
2236        }
2237        
2238        
2239        /**
2240         * Resolves the OAuth 2.0 authorisation server metadata URL for the
2241         * specified issuer.
2242         *
2243         * @param issuer The issuer. Must represent a valid HTTPS or HTTP URL.
2244         *               Must not be {@code null}.
2245         *
2246         * @return The OAuth 2.0 authorisation server metadata URL.
2247         *
2248         * @throws GeneralException If the issuer is invalid.
2249         */
2250        public static URL resolveURL(final Issuer issuer)
2251                throws GeneralException {
2252                
2253                try {
2254                        URL issuerURL = new URL(issuer.getValue());
2255                        
2256                        // Validate but don't insist on HTTPS
2257                        if (issuerURL.getQuery() != null && ! issuerURL.getQuery().trim().isEmpty()) {
2258                                throw new GeneralException("The issuer must not contain a query component");
2259                        }
2260                        
2261                        if (issuerURL.getPath() != null && issuerURL.getPath().endsWith("/")) {
2262                                return new URL(issuerURL + ".well-known/oauth-authorization-server");
2263                        } else {
2264                                return new URL(issuerURL + "/.well-known/oauth-authorization-server");
2265                        }
2266                        
2267                } catch (MalformedURLException e) {
2268                        throw new GeneralException("The issuer is not a valid URL", e);
2269                }
2270        }
2271        
2272        
2273        /**
2274         * Resolves the OAuth 2.0 authorisation server metadata for the
2275         * specified issuer. The metadata is downloaded by HTTP GET from
2276         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2277         *
2278         * @param issuer The issuer. Must represent a valid HTTPS or HTTP URL.
2279         *               Must not be {@code null}.
2280         *
2281         * @return The OAuth 2.0 authorisation server metadata.
2282         *
2283         * @throws GeneralException On invalid issuer or metadata.
2284         * @throws IOException      On an HTTP exception.
2285         */
2286        public static AuthorizationServerMetadata resolve(final Issuer issuer)
2287                throws GeneralException, IOException {
2288                
2289                return resolve(issuer, null, 0, 0);
2290        }
2291
2292
2293        /**
2294         * Resolves the OAuth 2.0 authorisation server metadata for the
2295         * specified issuer. The metadata is downloaded by HTTP GET from
2296         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2297         *
2298         * @param issuer     The issuer. Must represent a valid HTTPS or HTTP
2299         *                   URL. Must not be {@code null}.
2300         * @param altBaseURL Alternative base URL to use instead of the issuer
2301         *                   URL, when the issuer URL is not resolvable or
2302         *                   accessible. When {@code null} the issuer URL is
2303         *                   used as the base URL.
2304         *
2305         * @return The OAuth 2.0 authorisation server metadata.
2306         *
2307         * @throws GeneralException On invalid issuer or metadata.
2308         * @throws IOException      On an HTTP exception.
2309         */
2310        public static AuthorizationServerMetadata resolve(final Issuer issuer, final URL altBaseURL)
2311                throws GeneralException, IOException {
2312
2313                return resolve(issuer, altBaseURL, 0, 0);
2314        }
2315
2316
2317        /**
2318         * Resolves the OAuth 2.0 authorisation server metadata for the
2319         * specified issuer. The metadata is downloaded by HTTP GET from
2320         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2321         *
2322         * @param issuer         The issuer. Must represent a valid HTTPS or
2323         *                       HTTP URL. Must not be {@code null}.
2324         * @param connectTimeout The HTTP connect timeout, in milliseconds.
2325         *                       Zero implies no timeout. Must not be negative.
2326         * @param readTimeout    The HTTP response read timeout, in
2327         *                       milliseconds. Zero implies no timeout. Must
2328         *                       not be negative.
2329         *
2330         * @return The OAuth 2.0 authorisation server metadata.
2331         *
2332         * @throws GeneralException On invalid issuer or metadata.
2333         * @throws IOException      On an HTTP exception.
2334         */
2335        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2336                                                          final int connectTimeout,
2337                                                          final int readTimeout)
2338                throws GeneralException, IOException {
2339
2340                HTTPRequestConfigurator requestConfigurator = new HTTPRequestConfigurator() {
2341                        @Override
2342                        public void configure(HTTPRequest httpRequest) {
2343                                httpRequest.setConnectTimeout(connectTimeout);
2344                                httpRequest.setReadTimeout(readTimeout);
2345                        }
2346                };
2347
2348                return resolve(issuer, requestConfigurator);
2349        }
2350
2351
2352        /**
2353         * Resolves the OAuth 2.0 authorisation server metadata for the
2354         * specified issuer. The metadata is downloaded by HTTP GET from
2355         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2356         *
2357         * @param issuer         The issuer. Must represent a valid HTTPS or
2358         *                       HTTP URL. Must not be {@code null}.
2359         * @param altBaseURL     Alternative base URL to use instead of the
2360         *                       issuer URL, when the issuer URL is not
2361         *                       resolvable or accessible. When {@code null}
2362         *                       the issuer URL is used as the base URL.
2363         * @param connectTimeout The HTTP connect timeout, in milliseconds.
2364         *                       Zero implies no timeout. Must not be negative.
2365         * @param readTimeout    The HTTP response read timeout, in
2366         *                       milliseconds. Zero implies no timeout. Must
2367         *                       not be negative.
2368         *
2369         * @return The OAuth 2.0 authorisation server metadata.
2370         *
2371         * @throws GeneralException On invalid issuer or metadata.
2372         * @throws IOException      On an HTTP exception.
2373         */
2374        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2375                                                          final URL altBaseURL,
2376                                                          final int connectTimeout,
2377                                                          final int readTimeout)
2378                throws GeneralException, IOException {
2379
2380                HTTPRequestConfigurator requestConfigurator = new HTTPRequestConfigurator() {
2381                        @Override
2382                        public void configure(HTTPRequest httpRequest) {
2383                                httpRequest.setConnectTimeout(connectTimeout);
2384                                httpRequest.setReadTimeout(readTimeout);
2385                        }
2386                };
2387
2388                return resolve(issuer, altBaseURL, requestConfigurator);
2389        }
2390
2391
2392        /**
2393         * Resolves the OAuth 2.0 authorisation server metadata for the
2394         * specified issuer. The metadata is downloaded by HTTP GET from
2395         * {@code [issuer-url]/.well-known/oauth-authorization-server}, using
2396         * the specified HTTP request configurator.
2397         *
2398         * @param issuer              The issuer. Must represent a valid HTTPS
2399         *                            or HTTP URL. Must not be {@code null}.
2400         * @param requestConfigurator An {@link HTTPRequestConfigurator}
2401         *                            instance to perform additional
2402         *                            {@link HTTPRequest} configuration. Must
2403         *                            not be {@code null}.
2404         *
2405         * @return The OAuth 2.0 authorisation server metadata.
2406         *
2407         * @throws GeneralException On invalid issuer or metadata.
2408         * @throws IOException      On an HTTP exception.
2409         */
2410        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2411                                                          final HTTPRequestConfigurator requestConfigurator)
2412                throws GeneralException, IOException {
2413
2414                return resolve(issuer, null, requestConfigurator);
2415        }
2416
2417
2418        /**
2419         * Resolves the OAuth 2.0 authorisation server metadata for the
2420         * specified issuer. The metadata is downloaded by HTTP GET from
2421         * {@code [issuer-url]/.well-known/oauth-authorization-server}, using
2422         * the specified HTTP request configurator.
2423         *
2424         * @param issuer              The issuer. Must represent a valid HTTPS
2425         *                            or HTTP URL. Must not be {@code null}.
2426         * @param altBaseURL          Alternative base URL to use instead of
2427         *                            the issuer URL, when the issuer URL is
2428         *                            not resolvable or accessible. When
2429         *                            {@code null} the issuer URL is used as
2430         *                            the base URL.
2431         * @param requestConfigurator An {@link HTTPRequestConfigurator}
2432         *                            instance to perform additional
2433         *                            {@link HTTPRequest} configuration. Must
2434         *                            not be {@code null}.
2435         *
2436         * @return The OAuth 2.0 authorisation server metadata.
2437         *
2438         * @throws GeneralException On invalid issuer or metadata.
2439         * @throws IOException      On an HTTP exception.
2440         */
2441        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2442                                                          final URL altBaseURL,
2443                                                          final HTTPRequestConfigurator requestConfigurator)
2444                throws GeneralException, IOException {
2445
2446                return resolve(
2447                        issuer,
2448                        altBaseURL,
2449                        new HTTPRequestModifier() {
2450                                @Override
2451                                public HTTPRequest modify(HTTPRequest httpRequest) {
2452                                        requestConfigurator.configure(httpRequest);
2453                                        return httpRequest;
2454                                }
2455                        },
2456                        false);
2457        }
2458
2459
2460        /**
2461         * Resolves the OAuth 2.0 authorisation server metadata for the
2462         * specified issuer. The metadata is downloaded by HTTP GET from
2463         * {@code [issuer-url]/.well-known/oauth-authorization-server}, using
2464         * the specified HTTP request modifier.
2465         *
2466         * @param issuer              The issuer. Must represent a valid HTTPS
2467         *                            or HTTP URL. Must not be {@code null}.
2468         * @param altBaseURL          Alternative base URL to use instead of
2469         *                            the issuer URL, when the issuer URL is
2470         *                            not resolvable or accessible. When
2471         *                            {@code null} the issuer URL is used as
2472         *                            the base URL.
2473         * @param requestModifier     An {@link HTTPRequestModifier} to perform
2474         *                            additional {@link HTTPRequest}
2475         *                            configuration. Must not be {@code null}.
2476         * @param ignoreTrailingSlash If {@code true} compares the issuer URL
2477         *                            to the issuer in the authorisation server
2478         *                            metadata ignoring any trailing slashes.
2479         *
2480         * @return The OAuth 2.0 authorisation server metadata.
2481         *
2482         * @throws GeneralException On invalid issuer or metadata.
2483         * @throws IOException      On an HTTP exception.
2484         */
2485        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2486                                                          final URL altBaseURL,
2487                                                          final HTTPRequestModifier requestModifier,
2488                                                          final boolean ignoreTrailingSlash)
2489                throws GeneralException, IOException {
2490
2491                URL configURL = resolveURL(altBaseURL != null ? new Issuer(altBaseURL.toString()) : issuer);
2492
2493                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, configURL);
2494                httpRequest = requestModifier.modify(httpRequest);
2495
2496                HTTPResponse httpResponse = httpRequest.send();
2497
2498                if (httpResponse.getStatusCode() != 200) {
2499                        throw new IOException("Couldn't download OAuth 2.0 Authorization Server metadata from " + configURL +
2500                                ": Status code " + httpResponse.getStatusCode());
2501                }
2502
2503                JSONObject jsonObject = httpResponse.getBodyAsJSONObject();
2504
2505                AuthorizationServerMetadata as = AuthorizationServerMetadata.parse(jsonObject);
2506
2507                if (ignoreTrailingSlash ? ! issuer.equalsIgnoreTrailingSlash(as.getIssuer()) : ! issuer.equals(as.getIssuer())) {
2508                        throw new GeneralException("The returned issuer doesn't match the expected: " + as.getIssuer());
2509                }
2510
2511                return as;
2512        }
2513}