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