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