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                // OpenID Federation 1.0
1714                
1715                if (organizationName != null) {
1716                        o.put("organization_name", organizationName);
1717                }
1718
1719                if (signedJWKSetURI != null) {
1720                        o.put("signed_jwks_uri", signedJWKSetURI.toString());
1721                }
1722
1723                if (jwkSet != null) {
1724                        o.put("jwks", JSONObjectUtils.toJSONObject(jwkSet.toPublicJWKSet())); // prevent private keys from leaking
1725                }
1726                
1727                if (CollectionUtils.isNotEmpty(clientRegistrationTypes)) {
1728                        
1729                        o.put("client_registration_types_supported", Identifier.toStringList(clientRegistrationTypes));
1730                        
1731                        if (clientRegistrationTypes.contains(ClientRegistrationType.AUTOMATIC) && MapUtils.isNotEmpty(clientRegistrationAuthMethods)) {
1732                                JSONObject map = new JSONObject();
1733                                for (Map.Entry<EndpointName,List<ClientAuthenticationMethod>> en: getClientRegistrationAuthnMethods().entrySet()) {
1734                                        List<String> methodNames = new LinkedList<>();
1735                                        for (ClientAuthenticationMethod method: en.getValue()) {
1736                                                methodNames.add(method.getValue());
1737                                        }
1738                                        map.put(en.getKey().getValue(), methodNames);
1739                                }
1740                                o.put("request_authentication_methods_supported", map);
1741                        }
1742                        
1743                        if (clientRegistrationTypes.contains(ClientRegistrationType.AUTOMATIC) && CollectionUtils.isNotEmpty(clientRegistrationAuthJWSAlgs)) {
1744                                
1745                                stringList = new ArrayList<>(clientRegistrationAuthJWSAlgs.size());
1746                                
1747                                for (JWSAlgorithm alg: clientRegistrationAuthJWSAlgs)
1748                                        stringList.add(alg.getName());
1749                                
1750                                o.put("request_authentication_signing_alg_values_supported", stringList);
1751                        }
1752                        
1753                        if (clientRegistrationTypes.contains(ClientRegistrationType.EXPLICIT) && federationRegistrationEndpoint != null) {
1754                                o.put("federation_registration_endpoint", federationRegistrationEndpoint.toString());
1755                        } else {
1756                                o.remove("federation_registration_endpoint");
1757                        }
1758                }
1759
1760                // Append any custom (not registered) parameters
1761                o.putAll(customParameters);
1762                
1763                return o;
1764        }
1765        
1766        
1767        /**
1768         * Parses an OAuth 2.0 Authorisation Server metadata from the specified
1769         * JSON object.
1770         *
1771         * @param jsonObject The JSON object to parse. Must not be
1772         *                   {@code null}.
1773         *
1774         * @return The OAuth 2.0 Authorisation Server metadata.
1775         *
1776         * @throws ParseException If the JSON object couldn't be parsed to an
1777         *                        OAuth 2.0 Authorisation Server metadata.
1778         */
1779        public static AuthorizationServerMetadata parse(final JSONObject jsonObject)
1780                throws ParseException {
1781                
1782                // Parse issuer and subject_types_supported first
1783                
1784                Issuer issuer = new Issuer(JSONObjectUtils.getURI(jsonObject, "issuer").toString());
1785
1786                AuthorizationServerEndpointMetadata asEndpoints = AuthorizationServerEndpointMetadata.parse(jsonObject);
1787                
1788                AuthorizationServerMetadata as;
1789                
1790                try {
1791                        as = new AuthorizationServerMetadata(issuer); // validates issuer syntax
1792                } catch (IllegalArgumentException e) {
1793                        throw new ParseException(e.getMessage(), e);
1794                }
1795                
1796                // Endpoints
1797                as.setAuthorizationEndpointURI(asEndpoints.getAuthorizationEndpointURI());
1798                as.setTokenEndpointURI(asEndpoints.getTokenEndpointURI());
1799                as.setRegistrationEndpointURI(asEndpoints.getRegistrationEndpointURI());
1800                as.setIntrospectionEndpointURI(asEndpoints.getIntrospectionEndpointURI());
1801                as.setRevocationEndpointURI(asEndpoints.getRevocationEndpointURI());
1802                as.setRequestObjectEndpoint(asEndpoints.getRequestObjectEndpoint());
1803                as.setPushedAuthorizationRequestEndpointURI(asEndpoints.getPushedAuthorizationRequestEndpointURI());
1804                as.setDeviceAuthorizationEndpointURI(asEndpoints.getDeviceAuthorizationEndpointURI());
1805                as.setBackChannelAuthenticationEndpointURI(asEndpoints.getBackChannelAuthenticationEndpointURI());
1806                as.jwkSetURI = JSONObjectUtils.getURI(jsonObject, "jwks_uri", null);
1807                
1808                // AS capabilities
1809                if (jsonObject.get("scopes_supported") != null) {
1810                        
1811                        as.scope = new Scope();
1812                        
1813                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "scopes_supported")) {
1814                                
1815                                if (v != null)
1816                                        as.scope.add(new Scope.Value(v));
1817                        }
1818                }
1819                
1820                if (jsonObject.get("response_types_supported") != null) {
1821                        
1822                        as.rts = new ArrayList<>();
1823                        
1824                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "response_types_supported")) {
1825                                
1826                                if (v != null)
1827                                        as.rts.add(ResponseType.parse(v));
1828                        }
1829                }
1830                
1831                if (jsonObject.get("response_modes_supported") != null) {
1832                        
1833                        as.rms = new ArrayList<>();
1834                        
1835                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "response_modes_supported")) {
1836                                
1837                                if (v != null)
1838                                        as.rms.add(new ResponseMode(v));
1839                        }
1840                }
1841                
1842                if (jsonObject.get("grant_types_supported") != null) {
1843                        
1844                        as.gts = new ArrayList<>();
1845                        
1846                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "grant_types_supported")) {
1847                                
1848                                if (v != null)
1849                                        as.gts.add(GrantType.parse(v));
1850                        }
1851                }
1852                
1853                if (jsonObject.get("code_challenge_methods_supported") != null) {
1854                        
1855                        as.codeChallengeMethods = new ArrayList<>();
1856                        
1857                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "code_challenge_methods_supported")) {
1858                                
1859                                if (v != null)
1860                                        as.codeChallengeMethods.add(CodeChallengeMethod.parse(v));
1861                        }
1862                }
1863                
1864                if (jsonObject.get("token_endpoint_auth_methods_supported") != null) {
1865                        
1866                        as.tokenEndpointAuthMethods = new ArrayList<>();
1867                        
1868                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "token_endpoint_auth_methods_supported")) {
1869                                
1870                                if (v != null)
1871                                        as.tokenEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
1872                        }
1873                }
1874                
1875                if (jsonObject.get("token_endpoint_auth_signing_alg_values_supported") != null) {
1876                        
1877                        as.tokenEndpointJWSAlgs = new ArrayList<>();
1878                        
1879                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "token_endpoint_auth_signing_alg_values_supported")) {
1880                                
1881                                if (v != null && v.equals(Algorithm.NONE.getName()))
1882                                        throw new ParseException("The none algorithm is not accepted");
1883                                
1884                                if (v != null)
1885                                        as.tokenEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
1886                        }
1887                }
1888                
1889                if (jsonObject.get("introspection_endpoint_auth_methods_supported") != null) {
1890                        
1891                        as.introspectionEndpointAuthMethods = new ArrayList<>();
1892                        
1893                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "introspection_endpoint_auth_methods_supported")) {
1894                                
1895                                if (v != null)
1896                                        as.introspectionEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
1897                        }
1898                }
1899                
1900                if (jsonObject.get("introspection_endpoint_auth_signing_alg_values_supported") != null) {
1901                        
1902                        as.introspectionEndpointJWSAlgs = new ArrayList<>();
1903                        
1904                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "introspection_endpoint_auth_signing_alg_values_supported")) {
1905                                
1906                                if (v != null && v.equals(Algorithm.NONE.getName()))
1907                                        throw new ParseException("The none algorithm is not accepted");
1908                                
1909                                if (v != null)
1910                                        as.introspectionEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
1911                        }
1912                }
1913                
1914                if (jsonObject.get("revocation_endpoint_auth_methods_supported") != null) {
1915                        
1916                        as.revocationEndpointAuthMethods = new ArrayList<>();
1917                        
1918                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "revocation_endpoint_auth_methods_supported")) {
1919                                
1920                                if (v != null)
1921                                        as.revocationEndpointAuthMethods.add(ClientAuthenticationMethod.parse(v));
1922                        }
1923                }
1924                
1925                if (jsonObject.get("revocation_endpoint_auth_signing_alg_values_supported") != null) {
1926                        
1927                        as.revocationEndpointJWSAlgs = new ArrayList<>();
1928                        
1929                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "revocation_endpoint_auth_signing_alg_values_supported")) {
1930                                
1931                                if (v != null && v.equals(Algorithm.NONE.getName()))
1932                                        throw new ParseException("The none algorithm is not accepted");
1933                                
1934                                if (v != null)
1935                                        as.revocationEndpointJWSAlgs.add(JWSAlgorithm.parse(v));
1936                        }
1937                }
1938                
1939                
1940                // Request object
1941                if (jsonObject.get("request_object_signing_alg_values_supported") != null) {
1942                        
1943                        as.requestObjectJWSAlgs = new ArrayList<>();
1944                        
1945                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_signing_alg_values_supported")) {
1946                                
1947                                if (v != null)
1948                                        as.requestObjectJWSAlgs.add(JWSAlgorithm.parse(v));
1949                        }
1950                }
1951                
1952                
1953                if (jsonObject.get("request_object_encryption_alg_values_supported") != null) {
1954                        
1955                        as.requestObjectJWEAlgs = new ArrayList<>();
1956                        
1957                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_encryption_alg_values_supported")) {
1958                                
1959                                if (v != null)
1960                                        as.requestObjectJWEAlgs.add(JWEAlgorithm.parse(v));
1961                        }
1962                }
1963                
1964                
1965                if (jsonObject.get("request_object_encryption_enc_values_supported") != null) {
1966                        
1967                        as.requestObjectJWEEncs = new ArrayList<>();
1968                        
1969                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "request_object_encryption_enc_values_supported")) {
1970                                
1971                                if (v != null)
1972                                        as.requestObjectJWEEncs.add(EncryptionMethod.parse(v));
1973                        }
1974                }
1975                
1976                
1977                // Misc
1978                
1979                if (jsonObject.get("ui_locales_supported") != null) {
1980                        
1981                        as.uiLocales = new ArrayList<>();
1982                        
1983                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "ui_locales_supported")) {
1984                                
1985                                if (v != null) {
1986                                        
1987                                        try {
1988                                                as.uiLocales.add(LangTag.parse(v));
1989                                                
1990                                        } catch (LangTagException e) {
1991                                                
1992                                                throw new ParseException("Invalid ui_locales_supported field: " + e.getMessage(), e);
1993                                        }
1994                                }
1995                        }
1996                }
1997                
1998                if (jsonObject.get("service_documentation") != null) {
1999                        try {
2000                                as.setServiceDocsURI(JSONObjectUtils.getURI(jsonObject, "service_documentation"));
2001                        } catch (IllegalArgumentException e) {
2002                                throw new ParseException("Illegal service_documentation parameter: " + e.getMessage());
2003                        }
2004                }
2005                
2006                if (jsonObject.get("op_policy_uri") != null) {
2007                        try {
2008                                as.setPolicyURI(JSONObjectUtils.getURI(jsonObject, "op_policy_uri"));
2009                        } catch (IllegalArgumentException e) {
2010                                throw new ParseException("Illegal op_policy_uri parameter: " + e.getMessage());
2011                        }
2012                }
2013                
2014                if (jsonObject.get("op_tos_uri") != null) {
2015                        try {
2016                                as.setTermsOfServiceURI(JSONObjectUtils.getURI(jsonObject, "op_tos_uri"));
2017                        } catch (IllegalArgumentException e) {
2018                                throw new ParseException("Illegal op_tos_uri parameter: " + e.getMessage());
2019                        }
2020                }
2021                
2022                if (jsonObject.get("request_parameter_supported") != null)
2023                        as.requestParamSupported = JSONObjectUtils.getBoolean(jsonObject, "request_parameter_supported");
2024                
2025                if (jsonObject.get("request_uri_parameter_supported") != null)
2026                        as.requestURIParamSupported = JSONObjectUtils.getBoolean(jsonObject, "request_uri_parameter_supported");
2027                
2028                if (jsonObject.get("require_request_uri_registration") != null)
2029                        as.requireRequestURIReg = JSONObjectUtils.getBoolean(jsonObject, "require_request_uri_registration");
2030                
2031                if (jsonObject.get("authorization_response_iss_parameter_supported") != null)
2032                        as.authzResponseIssParameterSupported = JSONObjectUtils.getBoolean(jsonObject, "authorization_response_iss_parameter_supported");
2033                
2034                if (jsonObject.get("mtls_endpoint_aliases") != null)
2035                        as.mtlsEndpointAliases = AuthorizationServerEndpointMetadata.parse(JSONObjectUtils.getJSONObject(jsonObject, "mtls_endpoint_aliases"));
2036                
2037                if (jsonObject.get("tls_client_certificate_bound_access_tokens") != null)
2038                        as.tlsClientCertificateBoundAccessTokens = JSONObjectUtils.getBoolean(jsonObject, "tls_client_certificate_bound_access_tokens");
2039                
2040                // DPoP
2041                if (jsonObject.get("dpop_signing_alg_values_supported") != null)  {
2042                        
2043                        as.dPoPJWSAlgs = new ArrayList<>();
2044                        
2045                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "dpop_signing_alg_values_supported")) {
2046                                
2047                                if (v != null)
2048                                        as.dPoPJWSAlgs.add(JWSAlgorithm.parse(v));
2049                        }
2050                }
2051                
2052                // JARM
2053                if (jsonObject.get("authorization_signing_alg_values_supported") != null) {
2054                        
2055                        as.authzJWSAlgs = new ArrayList<>();
2056                        
2057                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_signing_alg_values_supported")) {
2058                                
2059                                if (v != null)
2060                                        as.authzJWSAlgs.add(JWSAlgorithm.parse(v));
2061                        }
2062                }
2063                
2064                
2065                if (jsonObject.get("authorization_encryption_alg_values_supported") != null) {
2066                        
2067                        as.authzJWEAlgs = new ArrayList<>();
2068                        
2069                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_encryption_alg_values_supported")) {
2070                                
2071                                if (v != null)
2072                                        as.authzJWEAlgs.add(JWEAlgorithm.parse(v));
2073                        }
2074                }
2075                
2076                
2077                if (jsonObject.get("authorization_encryption_enc_values_supported") != null) {
2078                        
2079                        as.authzJWEEncs = new ArrayList<>();
2080                        
2081                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_encryption_enc_values_supported")) {
2082                                
2083                                if (v != null)
2084                                        as.authzJWEEncs.add(EncryptionMethod.parse(v));
2085                        }
2086                }
2087                
2088                // PAR
2089                if (jsonObject.get("require_pushed_authorization_requests") != null) {
2090                        as.requiresPushedAuthorizationRequests(JSONObjectUtils.getBoolean(jsonObject, "require_pushed_authorization_requests"));
2091                }
2092
2093                // RAR
2094                if (jsonObject.get("authorization_details_types_supported") != null) {
2095
2096                        as.authzTypes = new ArrayList<>();
2097
2098                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "authorization_details_types_supported")) {
2099
2100                                if (StringUtils.isNotBlank(v)) {
2101                                        as.authzTypes.add(new AuthorizationType(v));
2102                                }
2103                        }
2104                }
2105                
2106                // Incremental authz
2107                if (jsonObject.get("incremental_authz_types_supported") != null) {
2108                        
2109                        as.incrementalAuthzTypes = new ArrayList<>();
2110                        
2111                        for (String v: JSONObjectUtils.getStringArray(jsonObject, "incremental_authz_types_supported")) {
2112                                
2113                                if (v != null) {
2114                                        ClientType clientType;
2115                                        try {
2116                                                clientType = ClientType.valueOf(v.toUpperCase());
2117                                        } catch (IllegalArgumentException e) {
2118                                                throw new ParseException("Illegal client type in incremental_authz_types_supported field: " + v);
2119                                        }
2120                                        as.incrementalAuthzTypes.add(clientType);
2121                                }
2122                        }
2123                }
2124                
2125                // CIBA
2126                if (jsonObject.get("backchannel_token_delivery_modes_supported") != null) {
2127                        
2128                        as.backChannelTokenDeliveryModes = new ArrayList<>();
2129
2130                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "backchannel_token_delivery_modes_supported")) {
2131
2132                                if (v != null)
2133                                        as.backChannelTokenDeliveryModes.add(BackChannelTokenDeliveryMode.parse(v));
2134                        }
2135                }
2136
2137                if (jsonObject.get("backchannel_authentication_request_signing_alg_values_supported") != null) {
2138                        
2139                        as.backChannelAuthRequestJWSAlgs = new ArrayList<>();
2140
2141                        for (String v : JSONObjectUtils.getStringArray(jsonObject, "backchannel_authentication_request_signing_alg_values_supported")) {
2142
2143                                if (v != null)
2144                                        as.backChannelAuthRequestJWSAlgs.add(JWSAlgorithm.parse(v));
2145                        }
2146                }
2147                
2148                if (jsonObject.get("backchannel_user_code_parameter_supported") != null) {
2149                        as.backChannelUserCodeSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_user_code_parameter_supported");
2150                }
2151                
2152                // prompt=create
2153                if (jsonObject.get("prompt_values_supported") != null) {
2154                        
2155                        as.promptTypes = new ArrayList<>();
2156                        for (String v: JSONObjectUtils.getStringList(jsonObject, "prompt_values_supported")) {
2157                                
2158                                if (v != null)
2159                                        as.promptTypes.add(Prompt.Type.parse(v));
2160                        }
2161                }
2162                
2163                // OIDC Federation 1.0
2164                as.signedJWKSetURI = JSONObjectUtils.getURI(jsonObject, "signed_jwks_uri", null);
2165
2166                if (jsonObject.get("jwks") != null) {
2167                        try {
2168                                as.jwkSet = JWKSet.parse(JSONObjectUtils.getJSONObject(jsonObject, "jwks"));
2169                        } catch (java.text.ParseException e) {
2170                                throw new ParseException(e.getMessage(), e);
2171                        }
2172                }
2173
2174                if (jsonObject.get("client_registration_types_supported") != null) {
2175                        
2176                        as.clientRegistrationTypes = new LinkedList<>();
2177                        for (String v : JSONObjectUtils.getStringList(jsonObject, "client_registration_types_supported")) {
2178                                as.clientRegistrationTypes.add(new ClientRegistrationType(v));
2179                        }
2180                        
2181                        if (jsonObject.get("request_authentication_methods_supported") != null) {
2182                                Map<EndpointName, List<ClientAuthenticationMethod>> requestAuthMethods = new HashMap<>();
2183                                JSONObject spec = JSONObjectUtils.getJSONObject(jsonObject, "request_authentication_methods_supported");
2184                                // authorization_endpoint or RAR
2185                                for (String endpointName : spec.keySet()) {
2186                                        List<String> methodNames = JSONObjectUtils.getStringList(spec, endpointName, Collections.<String>emptyList());
2187                                        List<ClientAuthenticationMethod> authMethods = new LinkedList<>();
2188                                        for (String name : methodNames) {
2189                                                authMethods.add(ClientAuthenticationMethod.parse(name));
2190                                        }
2191                                        requestAuthMethods.put(new EndpointName(endpointName), authMethods);
2192                                }
2193                                as.setClientRegistrationAuthnMethods(requestAuthMethods);
2194                        }
2195                        
2196                        if (jsonObject.get("request_authentication_signing_alg_values_supported") != null) {
2197                                as.clientRegistrationAuthJWSAlgs = new ArrayList<>();
2198                                
2199                                for (String v : JSONObjectUtils.getStringArray(jsonObject, "request_authentication_signing_alg_values_supported")) {
2200                                        
2201                                        if (v != null)
2202                                                as.clientRegistrationAuthJWSAlgs.add(JWSAlgorithm.parse(v));
2203                                }
2204                        }
2205                        
2206                        as.federationRegistrationEndpoint = JSONObjectUtils.getURI(jsonObject, "federation_registration_endpoint", null);
2207                }
2208                
2209                as.organizationName = JSONObjectUtils.getString(jsonObject, "organization_name", null);
2210                
2211                // Parse custom (not registered) parameters
2212                JSONObject customParams = new JSONObject(jsonObject);
2213                customParams.keySet().removeAll(REGISTERED_PARAMETER_NAMES);
2214                for (Map.Entry<String,Object> customEntry: customParams.entrySet()) {
2215                        as.setCustomParameter(customEntry.getKey(), customEntry.getValue());
2216                }
2217                
2218                return as;
2219        }
2220        
2221        
2222        /**
2223         * Parses an OAuth 2.0 Authorisation Server metadata from the specified
2224         * JSON object string.
2225         *
2226         * @param s The JSON object sting to parse. Must not be {@code null}.
2227         *
2228         * @return The OAuth 2.0 Authorisation Server metadata.
2229         *
2230         * @throws ParseException If the JSON object string couldn't be parsed
2231         *                        to an OAuth 2.0 Authorisation Server
2232         *                        metadata.
2233         */
2234        public static AuthorizationServerMetadata parse(final String s)
2235                throws ParseException {
2236                
2237                return parse(JSONObjectUtils.parse(s));
2238        }
2239        
2240        
2241        /**
2242         * Resolves the OAuth 2.0 authorisation server metadata URL for the
2243         * specified issuer.
2244         *
2245         * @param issuer The issuer. Must represent a valid HTTPS or HTTP URL.
2246         *               Must not be {@code null}.
2247         *
2248         * @return The OAuth 2.0 authorisation server metadata URL.
2249         *
2250         * @throws GeneralException If the issuer is invalid.
2251         */
2252        public static URL resolveURL(final Issuer issuer)
2253                throws GeneralException {
2254                
2255                try {
2256                        URL issuerURL = new URL(issuer.getValue());
2257                        
2258                        // Validate but don't insist on HTTPS
2259                        if (issuerURL.getQuery() != null && ! issuerURL.getQuery().trim().isEmpty()) {
2260                                throw new GeneralException("The issuer must not contain a query component");
2261                        }
2262                        
2263                        if (issuerURL.getPath() != null && issuerURL.getPath().endsWith("/")) {
2264                                return new URL(issuerURL + ".well-known/oauth-authorization-server");
2265                        } else {
2266                                return new URL(issuerURL + "/.well-known/oauth-authorization-server");
2267                        }
2268                        
2269                } catch (MalformedURLException e) {
2270                        throw new GeneralException("The issuer is not a valid URL", e);
2271                }
2272        }
2273        
2274        
2275        /**
2276         * Resolves the OAuth 2.0 authorisation server metadata for the
2277         * specified issuer. The metadata is downloaded by HTTP GET from
2278         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2279         *
2280         * @param issuer The issuer. Must represent a valid HTTPS or HTTP URL.
2281         *               Must not be {@code null}.
2282         *
2283         * @return The OAuth 2.0 authorisation server metadata.
2284         *
2285         * @throws GeneralException On invalid issuer or metadata.
2286         * @throws IOException      On an HTTP exception.
2287         */
2288        public static AuthorizationServerMetadata resolve(final Issuer issuer)
2289                throws GeneralException, IOException {
2290                
2291                return resolve(issuer, null, 0, 0);
2292        }
2293
2294
2295        /**
2296         * Resolves the OAuth 2.0 authorisation server metadata for the
2297         * specified issuer. The metadata is downloaded by HTTP GET from
2298         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2299         *
2300         * @param issuer     The issuer. Must represent a valid HTTPS or HTTP
2301         *                   URL. Must not be {@code null}.
2302         * @param altBaseURL Alternative base URL to use instead of the issuer
2303         *                   URL, when the issuer URL is not resolvable or
2304         *                   accessible. When {@code null} the issuer URL is
2305         *                   used as the base URL.
2306         *
2307         * @return The OAuth 2.0 authorisation server metadata.
2308         *
2309         * @throws GeneralException On invalid issuer or metadata.
2310         * @throws IOException      On an HTTP exception.
2311         */
2312        public static AuthorizationServerMetadata resolve(final Issuer issuer, final URL altBaseURL)
2313                throws GeneralException, IOException {
2314
2315                return resolve(issuer, altBaseURL, 0, 0);
2316        }
2317
2318
2319        /**
2320         * Resolves the OAuth 2.0 authorisation server metadata for the
2321         * specified issuer. The metadata is downloaded by HTTP GET from
2322         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2323         *
2324         * @param issuer         The issuer. Must represent a valid HTTPS or
2325         *                       HTTP URL. Must not be {@code null}.
2326         * @param connectTimeout The HTTP connect timeout, in milliseconds.
2327         *                       Zero implies no timeout. Must not be negative.
2328         * @param readTimeout    The HTTP response read timeout, in
2329         *                       milliseconds. Zero implies no timeout. Must
2330         *                       not be negative.
2331         *
2332         * @return The OAuth 2.0 authorisation server metadata.
2333         *
2334         * @throws GeneralException On invalid issuer or metadata.
2335         * @throws IOException      On an HTTP exception.
2336         */
2337        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2338                                                          final int connectTimeout,
2339                                                          final int readTimeout)
2340                throws GeneralException, IOException {
2341
2342                HTTPRequestConfigurator requestConfigurator = new HTTPRequestConfigurator() {
2343                        @Override
2344                        public void configure(HTTPRequest httpRequest) {
2345                                httpRequest.setConnectTimeout(connectTimeout);
2346                                httpRequest.setReadTimeout(readTimeout);
2347                        }
2348                };
2349
2350                return resolve(issuer, requestConfigurator);
2351        }
2352
2353
2354        /**
2355         * Resolves the OAuth 2.0 authorisation server metadata for the
2356         * specified issuer. The metadata is downloaded by HTTP GET from
2357         * {@code [issuer-url]/.well-known/oauth-authorization-server}.
2358         *
2359         * @param issuer         The issuer. Must represent a valid HTTPS or
2360         *                       HTTP URL. Must not be {@code null}.
2361         * @param altBaseURL     Alternative base URL to use instead of the
2362         *                       issuer URL, when the issuer URL is not
2363         *                       resolvable or accessible. When {@code null}
2364         *                       the issuer URL is used as the base URL.
2365         * @param connectTimeout The HTTP connect timeout, in milliseconds.
2366         *                       Zero implies no timeout. Must not be negative.
2367         * @param readTimeout    The HTTP response read timeout, in
2368         *                       milliseconds. Zero implies no timeout. Must
2369         *                       not be negative.
2370         *
2371         * @return The OAuth 2.0 authorisation server metadata.
2372         *
2373         * @throws GeneralException On invalid issuer or metadata.
2374         * @throws IOException      On an HTTP exception.
2375         */
2376        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2377                                                          final URL altBaseURL,
2378                                                          final int connectTimeout,
2379                                                          final int readTimeout)
2380                throws GeneralException, IOException {
2381
2382                HTTPRequestConfigurator requestConfigurator = new HTTPRequestConfigurator() {
2383                        @Override
2384                        public void configure(HTTPRequest httpRequest) {
2385                                httpRequest.setConnectTimeout(connectTimeout);
2386                                httpRequest.setReadTimeout(readTimeout);
2387                        }
2388                };
2389
2390                return resolve(issuer, altBaseURL, requestConfigurator);
2391        }
2392
2393
2394        /**
2395         * Resolves the OAuth 2.0 authorisation server metadata for the
2396         * specified issuer. The metadata is downloaded by HTTP GET from
2397         * {@code [issuer-url]/.well-known/oauth-authorization-server}, using
2398         * the specified HTTP request configurator.
2399         *
2400         * @param issuer              The issuer. Must represent a valid HTTPS
2401         *                            or HTTP URL. Must not be {@code null}.
2402         * @param requestConfigurator An {@link HTTPRequestConfigurator}
2403         *                            instance to perform additional
2404         *                            {@link HTTPRequest} configuration. Must
2405         *                            not be {@code null}.
2406         *
2407         * @return The OAuth 2.0 authorisation server metadata.
2408         *
2409         * @throws GeneralException On invalid issuer or metadata.
2410         * @throws IOException      On an HTTP exception.
2411         */
2412        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2413                                                          final HTTPRequestConfigurator requestConfigurator)
2414                throws GeneralException, IOException {
2415
2416                return resolve(issuer, null, requestConfigurator);
2417        }
2418
2419
2420        /**
2421         * Resolves the OAuth 2.0 authorisation server metadata for the
2422         * specified issuer. The metadata is downloaded by HTTP GET from
2423         * {@code [issuer-url]/.well-known/oauth-authorization-server}, using
2424         * the specified HTTP request configurator.
2425         *
2426         * @param issuer              The issuer. Must represent a valid HTTPS
2427         *                            or HTTP URL. Must not be {@code null}.
2428         * @param altBaseURL          Alternative base URL to use instead of
2429         *                            the issuer URL, when the issuer URL is
2430         *                            not resolvable or accessible. When
2431         *                            {@code null} the issuer URL is used as
2432         *                            the base URL.
2433         * @param requestConfigurator An {@link HTTPRequestConfigurator}
2434         *                            instance to perform additional
2435         *                            {@link HTTPRequest} configuration. Must
2436         *                            not be {@code null}.
2437         *
2438         * @return The OAuth 2.0 authorisation server metadata.
2439         *
2440         * @throws GeneralException On invalid issuer or metadata.
2441         * @throws IOException      On an HTTP exception.
2442         */
2443        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2444                                                          final URL altBaseURL,
2445                                                          final HTTPRequestConfigurator requestConfigurator)
2446                throws GeneralException, IOException {
2447
2448                return resolve(
2449                        issuer,
2450                        altBaseURL,
2451                        new HTTPRequestModifier() {
2452                                @Override
2453                                public HTTPRequest modify(HTTPRequest httpRequest) {
2454                                        requestConfigurator.configure(httpRequest);
2455                                        return httpRequest;
2456                                }
2457                        },
2458                        false);
2459        }
2460
2461
2462        /**
2463         * Resolves the OAuth 2.0 authorisation server metadata for the
2464         * specified issuer. The metadata is downloaded by HTTP GET from
2465         * {@code [issuer-url]/.well-known/oauth-authorization-server}, using
2466         * the specified HTTP request modifier.
2467         *
2468         * @param issuer              The issuer. Must represent a valid HTTPS
2469         *                            or HTTP URL. Must not be {@code null}.
2470         * @param altBaseURL          Alternative base URL to use instead of
2471         *                            the issuer URL, when the issuer URL is
2472         *                            not resolvable or accessible. When
2473         *                            {@code null} the issuer URL is used as
2474         *                            the base URL.
2475         * @param requestModifier     An {@link HTTPRequestModifier} to perform
2476         *                            additional {@link HTTPRequest}
2477         *                            configuration. Must not be {@code null}.
2478         * @param ignoreTrailingSlash If {@code true} compares the issuer URL
2479         *                            to the issuer in the authorisation server
2480         *                            metadata ignoring any trailing slashes.
2481         *
2482         * @return The OAuth 2.0 authorisation server metadata.
2483         *
2484         * @throws GeneralException On invalid issuer or metadata.
2485         * @throws IOException      On an HTTP exception.
2486         */
2487        public static AuthorizationServerMetadata resolve(final Issuer issuer,
2488                                                          final URL altBaseURL,
2489                                                          final HTTPRequestModifier requestModifier,
2490                                                          final boolean ignoreTrailingSlash)
2491                throws GeneralException, IOException {
2492
2493                URL configURL = resolveURL(altBaseURL != null ? new Issuer(altBaseURL.toString()) : issuer);
2494
2495                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, configURL);
2496                httpRequest = requestModifier.modify(httpRequest);
2497
2498                HTTPResponse httpResponse = httpRequest.send();
2499
2500                if (httpResponse.getStatusCode() != 200) {
2501                        throw new IOException("Couldn't download OAuth 2.0 Authorization Server metadata from " + configURL +
2502                                ": Status code " + httpResponse.getStatusCode());
2503                }
2504
2505                JSONObject jsonObject = httpResponse.getBodyAsJSONObject();
2506
2507                AuthorizationServerMetadata as = AuthorizationServerMetadata.parse(jsonObject);
2508
2509                if (ignoreTrailingSlash ? ! issuer.equalsIgnoreTrailingSlash(as.getIssuer()) : ! issuer.equals(as.getIssuer())) {
2510                        throw new GeneralException("The returned issuer doesn't match the expected: " + as.getIssuer());
2511                }
2512
2513                return as;
2514        }
2515}