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