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