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