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