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