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