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.client;
019
020
021import java.net.URI;
022import java.net.URISyntaxException;
023import java.util.*;
024
025import com.nimbusds.oauth2.sdk.*;
026import net.minidev.json.JSONArray;
027import net.minidev.json.JSONObject;
028
029import com.nimbusds.jose.EncryptionMethod;
030import com.nimbusds.jose.JWEAlgorithm;
031import com.nimbusds.jose.JWSAlgorithm;
032import com.nimbusds.jose.JWSObject;
033import com.nimbusds.jose.jwk.JWKSet;
034import com.nimbusds.jwt.SignedJWT;
035import com.nimbusds.langtag.LangTag;
036import com.nimbusds.langtag.LangTagUtils;
037import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
038import com.nimbusds.oauth2.sdk.ciba.BackChannelTokenDeliveryMode;
039import com.nimbusds.oauth2.sdk.id.Identifier;
040import com.nimbusds.oauth2.sdk.id.SoftwareID;
041import com.nimbusds.oauth2.sdk.id.SoftwareVersion;
042import com.nimbusds.oauth2.sdk.util.CollectionUtils;
043import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
044import com.nimbusds.oauth2.sdk.util.URIUtils;
045import com.nimbusds.openid.connect.sdk.federation.registration.ClientRegistrationType;
046
047
048/**
049 * Client metadata.
050 * 
051 * <p>Example client metadata, serialised to a JSON object:
052 * 
053 * <pre>
054 * {
055 *  "redirect_uris"              : ["https://client.example.org/callback",
056 *                                  "https://client.example.org/callback2"],
057 *  "client_name"                : "My Example Client",
058 *  "client_name#ja-Jpan-JP"     : "\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
059 *  "token_endpoint_auth_method" : "client_secret_basic",
060 *  "scope"                      : "read write dolphin",
061 *  "logo_uri"                   : "https://client.example.org/logo.png",
062 *  "jwks_uri"                   : "https://client.example.org/my_public_keys.jwks"
063 * }
064 * </pre>
065 * 
066 * <p>Related specifications:
067 *
068 * <ul>
069 *     <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591), section
070 *         2.
071 *     <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound
072 *         Access Tokens (RFC 8705), sections 2.1.2 and 3.4.
073 *     <li>Financial-grade API: JWT Secured Authorization Response Mode for
074 *         OAuth 2.0 (JARM).
075 *     <li>OAuth 2.0 Pushed Authorization Requests (RFC 9126)
076 *     <li>OpenID Connect Client Initiated Backchannel Authentication Flow -
077 *         Core 1.0
078 *     <li>OpenID Connect Federation 1.0 (draft 22)
079 * </ul>
080 */
081public class ClientMetadata {
082
083
084        /**
085         * The registered parameter names.
086         */
087        private static final Set<String> REGISTERED_PARAMETER_NAMES;
088        
089        
090        /**
091         * Prohibited URI schemes in redirection URIs. See
092         * https://security.lauritz-holtmann.de/post/sso-security-redirect-uri/.
093         */
094        public static final Set<String> PROHIBITED_REDIRECT_URI_SCHEMES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("data", "javascript", "vbscript")));
095
096
097        static {
098                Set<String> p = new HashSet<>();
099
100                p.add("redirect_uris");
101                p.add("scope");
102                p.add("response_types");
103                p.add("grant_types");
104                p.add("contacts");
105                p.add("client_name");
106                p.add("logo_uri");
107                p.add("client_uri");
108                p.add("policy_uri");
109                p.add("tos_uri");
110                p.add("token_endpoint_auth_method");
111                p.add("token_endpoint_auth_signing_alg");
112                p.add("jwks_uri");
113                p.add("jwks");
114                p.add("request_uris");
115                p.add("request_object_signing_alg");
116                p.add("request_object_encryption_alg");
117                p.add("request_object_encryption_enc");
118                p.add("require_pushed_authorization_requests");
119                p.add("software_id");
120                p.add("software_version");
121                p.add("software_statement");
122                p.add("tls_client_certificate_bound_access_tokens");
123                p.add("tls_client_auth_subject_dn");
124                p.add("tls_client_auth_san_dns");
125                p.add("tls_client_auth_san_uri");
126                p.add("tls_client_auth_san_ip");
127                p.add("tls_client_auth_san_email");
128                p.add("authorization_signed_response_alg");
129                p.add("authorization_encrypted_response_alg");
130                p.add("authorization_encrypted_response_enc");
131                
132                // CIBA
133                p.add("backchannel_token_delivery_mode");
134                p.add("backchannel_client_notification_endpoint");
135                p.add("backchannel_authentication_request_signing_alg");
136                p.add("backchannel_user_code_parameter");
137                
138                // OIDC federation
139                p.add("organization_name");
140                p.add("signed_jwks_uri");
141                p.add("client_registration_types");
142
143                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
144        }
145        
146        
147        /**
148         * Redirect URIs.
149         */
150        private Set<URI> redirectURIs;
151
152
153        /**
154         * The client OAuth 2.0 scope.
155         */
156        private Scope scope;
157
158
159        /**
160         * The expected OAuth 2.0 response types.
161         */
162        private Set<ResponseType> responseTypes;
163
164
165        /**
166         * The expected OAuth 2.0 grant types.
167         */
168        private Set<GrantType> grantTypes;
169
170
171        /**
172         * Administrator email contacts for the client.
173         */
174        private List<String> contacts;
175
176
177        /**
178         * The client name.
179         */
180        private final Map<LangTag,String> nameEntries;
181
182
183        /**
184         * The client application logo.
185         */
186        private final Map<LangTag,URI> logoURIEntries;
187
188
189        /**
190         * The client URI entries.
191         */
192        private final Map<LangTag,URI> uriEntries;
193
194
195        /**
196         * The client policy for use of end-user data.
197         */
198        private final Map<LangTag,URI> policyURIEntries;
199
200
201        /**
202         * The client terms of service.
203         */
204        private final Map<LangTag,URI> tosURIEntries;
205
206
207        /**
208         * Token endpoint authentication method.
209         */
210        private ClientAuthenticationMethod authMethod;
211
212
213        /**
214         * The JSON Web Signature (JWS) algorithm required for
215         * {@code private_key_jwt} and {@code client_secret_jwt}
216         * authentication at the Token endpoint.
217         */
218        private JWSAlgorithm authJWSAlg;
219
220
221        /**
222         * URI for this client's JSON Web Key (JWK) set containing key(s) that
223         * are used in signing requests to the server and key(s) for encrypting
224         * responses.
225         */
226        private URI jwkSetURI;
227
228
229        /**
230         * URI for this client's signed JSON Web Key (JWK) set containing
231         * key(s) that are used in signing requests to the server and key(s)
232         * for encrypting responses. Intended for use in OpenID Connect
233         * Federation 1.0.
234         */
235        private URI signedJWKSetURI;
236
237
238        /**
239         * Client's JSON Web Key (JWK) set containing key(s) that are used in
240         * signing requests to the server and key(s) for encrypting responses.
241         * Intended as an alternative to {@link #jwkSetURI} for native clients.
242         */
243        private JWKSet jwkSet;
244        
245        
246        /**
247         * Pre-registered request object URIs.
248         */
249        private Set<URI> requestObjectURIs;
250        
251        
252        /**
253         * The JSON Web Signature (JWS) algorithm required for request objects
254         * sent by this client.
255         */
256        private JWSAlgorithm requestObjectJWSAlg;
257        
258        
259        /**
260         * The JSON Web Encryption (JWE) algorithm required for request objects
261         * sent by this client.
262         */
263        private JWEAlgorithm requestObjectJWEAlg;
264        
265        
266        /**
267         * The JSON Web Encryption (JWE) method required for request objects
268         * sent by this client.
269         */
270        private EncryptionMethod requestObjectJWEEnc;
271
272
273        /**
274         * Identifier for the OAuth 2.0 client software.
275         */
276        private SoftwareID softwareID;
277
278
279        /**
280         * Version identifier for the OAuth 2.0 client software.
281         */
282        private SoftwareVersion softwareVersion;
283        
284        
285        /**
286         * Signed software statement.
287         */
288        private SignedJWT softwareStatement;
289        
290        
291        /**
292         * Preference for TLS client certificate bound access tokens.
293         */
294        private boolean tlsClientCertificateBoundAccessTokens = false;
295        
296        
297        /**
298         * The expected subject distinguished name (DN) of the client X.509
299         * certificate the in mutual TLS authentication.
300         */
301        private String tlsClientAuthSubjectDN = null;
302        
303        
304        /**
305         * The expected dNSName SAN entry in the X.509 certificate, which
306         * the OAuth client will use in mutual TLS authentication.
307         */
308        private String tlsClientAuthSanDNS = null;
309        
310        
311        /**
312         * The expected uniformResourceIdentifier SAN entry in the X.509
313         * certificate, which the OAuth client will use in mutual TLS
314         * authentication.
315         */
316        private String tlsClientAuthSanURI = null;
317        
318        
319        /**
320         * The expected iPAddress SAN entry in the X.509 certificate, which
321         * the OAuth client will use in mutual TLS authentication.
322         */
323        private String tlsClientAuthSanIP = null;
324        
325        
326        /**
327         * The expected rfc822Name SAN entry in the X.509 certificate, which
328         * the OAuth client will use in mutual TLS authentication.
329         */
330        private String tlsClientAuthSanEmail = null;
331        
332        
333        /**
334         * The JWS algorithm for JWT-encoded authorisation responses.
335         */
336        private JWSAlgorithm authzJWSAlg;
337        
338        
339        /**
340         * The JWE algorithm for JWT-encoded authorisation responses.
341         */
342        private JWEAlgorithm authzJWEAlg;
343        
344        
345        /**
346         * The encryption method for JWT-encoded authorisation responses.
347         */
348        private EncryptionMethod authzJWEEnc;
349        
350        
351        /**
352         * If {@code true} PAR is required, else not.
353         */
354        private boolean requirePAR = false;
355        
356        
357        /**
358         * The CIBA token delivery mode.
359         */
360        private BackChannelTokenDeliveryMode backChannelTokenDeliveryMode;
361        
362        
363        /**
364         * The CIBA client notification endpoint for the ping or push token
365         * delivery modes.
366         */
367        private URI backChannelClientNotificationEndpoint;
368        
369        
370        /**
371         * The JWS algorithm for signed CIBA requests.
372         */
373        private JWSAlgorithm backChannelAuthRequestJWSAlg;
374        
375        
376        /**
377         * Support for the {@code user_code} CIBA request parameter.
378         */
379        private boolean backChannelUserCodeParam = false;
380        
381        
382        /**
383         * The supported OpenID Connect Federation 1.0 client registration
384         * types.
385         */
386        private List<ClientRegistrationType> clientRegistrationTypes;
387        
388        
389        /**
390         * The organisation name in OpenID Connect Federation 1.0.
391         */
392        private String organizationName;
393
394
395        /**
396         * The custom metadata fields.
397         */
398        private JSONObject customFields;
399
400
401        /**
402         * Creates a new OAuth 2.0 client metadata instance.
403         */
404        public ClientMetadata() {
405
406                nameEntries = new HashMap<>();
407                logoURIEntries = new HashMap<>();
408                uriEntries = new HashMap<>();
409                policyURIEntries = new HashMap<>();
410                tosURIEntries = new HashMap<>();
411                customFields = new JSONObject();
412        }
413
414
415        /**
416         * Creates a shallow copy of the specified OAuth 2.0 client metadata
417         * instance.
418         *
419         * @param metadata The client metadata to copy. Must not be
420         *                 {@code null}.
421         */
422        public ClientMetadata(final ClientMetadata metadata) {
423
424                redirectURIs = metadata.getRedirectionURIs();
425                scope = metadata.getScope();
426                responseTypes = metadata.getResponseTypes();
427                grantTypes = metadata.getGrantTypes();
428                contacts = metadata.getEmailContacts();
429                nameEntries = metadata.getNameEntries();
430                logoURIEntries = metadata.getLogoURIEntries();
431                uriEntries = metadata.getURIEntries();
432                policyURIEntries = metadata.getPolicyURIEntries();
433                tosURIEntries = metadata.getTermsOfServiceURIEntries();
434                authMethod = metadata.getTokenEndpointAuthMethod();
435                authJWSAlg = metadata.getTokenEndpointAuthJWSAlg();
436                jwkSetURI = metadata.getJWKSetURI();
437                signedJWKSetURI = metadata.getSignedJWKSetURI();
438                jwkSet = metadata.getJWKSet();
439                requestObjectURIs = metadata.getRequestObjectURIs();
440                requestObjectJWSAlg = metadata.getRequestObjectJWSAlg();
441                requestObjectJWEAlg = metadata.getRequestObjectJWEAlg();
442                requestObjectJWEEnc = metadata.getRequestObjectJWEEnc();
443                softwareID = metadata.getSoftwareID();
444                softwareVersion = metadata.getSoftwareVersion();
445                softwareStatement = metadata.getSoftwareStatement();
446                tlsClientCertificateBoundAccessTokens = metadata.getTLSClientCertificateBoundAccessTokens();
447                tlsClientAuthSubjectDN = metadata.getTLSClientAuthSubjectDN();
448                tlsClientAuthSanDNS = metadata.getTLSClientAuthSanDNS();
449                tlsClientAuthSanURI = metadata.getTLSClientAuthSanURI();
450                tlsClientAuthSanIP = metadata.getTLSClientAuthSanIP();
451                tlsClientAuthSanEmail = metadata.getTLSClientAuthSanEmail();
452                authzJWSAlg = metadata.getAuthorizationJWSAlg();
453                authzJWEAlg = metadata.getAuthorizationJWEAlg();
454                authzJWEEnc = metadata.getAuthorizationJWEEnc();
455                requirePAR = metadata.requiresPushedAuthorizationRequests();
456                backChannelTokenDeliveryMode = metadata.getBackChannelTokenDeliveryMode();
457                backChannelClientNotificationEndpoint = metadata.getBackChannelClientNotificationEndpoint();
458                backChannelAuthRequestJWSAlg = metadata.getBackChannelAuthRequestJWSAlg();
459                backChannelUserCodeParam = metadata.supportsBackChannelUserCodeParam();
460                clientRegistrationTypes = metadata.getClientRegistrationTypes();
461                organizationName = metadata.getOrganizationName();
462                customFields = metadata.getCustomFields();
463        }
464
465
466        /**
467         * Gets the registered (standard) OAuth 2.0 client metadata parameter
468         * names.
469         *
470         * @return The registered parameter names, as an unmodifiable set.
471         */
472        public static Set<String> getRegisteredParameterNames() {
473
474                return REGISTERED_PARAMETER_NAMES;
475        }
476
477
478        /**
479         * Gets the redirection URIs for this client. Corresponds to the
480         * {@code redirect_uris} client metadata field.
481         *
482         * @return The redirection URIs, {@code null} if not specified.
483         */
484        public Set<URI> getRedirectionURIs() {
485
486                return redirectURIs;
487        }
488        
489        
490        /**
491         * Gets one of the redirection URIs for this client. Corresponds to the
492         * {@code redirect_uris} client metadata field.
493         *
494         * @return The redirection URI, {@code null} if not specified.
495         */
496        public URI getRedirectionURI() {
497                
498                if (redirectURIs != null && ! redirectURIs.isEmpty()) {
499                        return redirectURIs.iterator().next();
500                } else {
501                        return null;
502                }
503        }
504
505
506        /**
507         * Gets the redirection URIs for this client as strings. Corresponds to
508         * the {@code redirect_uris} client metadata field.
509         *
510         * <p>This short-hand method is intended to enable string-based URI
511         * comparison.
512         *
513         * @return The redirection URIs as strings, {@code null} if not
514         *         specified.
515         */
516        public Set<String> getRedirectionURIStrings() {
517
518                if (redirectURIs == null)
519                        return null;
520
521                Set<String> uriStrings = new HashSet<>();
522
523                for (URI uri: redirectURIs)
524                        uriStrings.add(uri.toString());
525
526                return uriStrings;
527        }
528
529
530        /**
531         * Sets the redirection URIs for this client. Corresponds to the
532         * {@code redirect_uris} client metadata field.
533         *
534         * @param redirectURIs The redirection URIs, {@code null} if not
535         *                     specified. Valid redirection URIs must not
536         *                     contain a fragment.
537         */
538        public void setRedirectionURIs(final Set<URI> redirectURIs) {
539
540                if (redirectURIs != null) {
541                        // check URIs
542                        for (URI uri: redirectURIs) {
543                                if (uri == null) {
544                                        throw new IllegalArgumentException("The redirect_uri must not be null");
545                                }
546                                if (uri.getFragment() != null) {
547                                        throw new IllegalArgumentException("The redirect_uri must not contain fragment");
548                                }
549                                URIUtils.ensureSchemeIsNotProhibited(uri, PROHIBITED_REDIRECT_URI_SCHEMES);
550                        }
551                        this.redirectURIs = Collections.unmodifiableSet(redirectURIs);
552                } else {
553                        this.redirectURIs = null;
554                }
555        }
556
557
558        /**
559         * Sets a single redirection URI for this client. Corresponds to the
560         * {@code redirect_uris} client metadata field.
561         *
562         * @param redirectURI The redirection URIs, {@code null} if not
563         *                    specified. A valid redirection URI must not
564         *                    contain a fragment.
565         */
566        public void setRedirectionURI(final URI redirectURI) {
567
568                setRedirectionURIs(redirectURI != null ? Collections.singleton(redirectURI) : null);
569        }
570
571
572        /**
573         * Gets the scope values that the client can use when requesting access
574         * tokens. Corresponds to the {@code scope} client metadata field.
575         *
576         * @return The scope, {@code null} if not specified.
577         */
578        public Scope getScope() {
579
580                return scope;
581        }
582
583
584        /**
585         * Checks if the scope matadata field is set and contains the specified
586         * scope value.
587         *
588         * @param scopeValue The scope value. Must not be {@code null}.
589         *
590         * @return {@code true} if the scope value is contained, else
591         *         {@code false}.
592         */
593        public boolean hasScopeValue(final Scope.Value scopeValue) {
594
595                return scope != null && scope.contains(scopeValue);
596        }
597
598
599        /**
600         * Sets the scope values that the client can use when requesting access
601         * tokens. Corresponds to the {@code scope} client metadata field.
602         *
603         * @param scope The scope, {@code null} if not specified.
604         */
605        public void setScope(final Scope scope) {
606
607                this.scope = scope;
608        }
609
610
611        /**
612         * Gets the expected OAuth 2.0 response types. Corresponds to the
613         * {@code response_types} client metadata field.
614         *
615         * @return The response types, {@code null} if not specified.
616         */
617        public Set<ResponseType> getResponseTypes() {
618
619                return responseTypes;
620        }
621
622
623        /**
624         * Sets the expected OAuth 2.0 response types. Corresponds to the
625         * {@code response_types} client metadata field.
626         *
627         * @param responseTypes The response types, {@code null} if not
628         *                      specified.
629         */
630        public void setResponseTypes(final Set<ResponseType> responseTypes) {
631
632                this.responseTypes = responseTypes;
633        }
634
635
636        /**
637         * Gets the expected OAuth 2.0 grant types. Corresponds to the
638         * {@code grant_types} client metadata field.
639         *
640         * @return The grant types, {@code null} if not specified.
641         */
642        public Set<GrantType> getGrantTypes() {
643
644                return grantTypes;
645        }
646
647
648        /**
649         * Sets the expected OAuth 2.0 grant types. Corresponds to the
650         * {@code grant_types} client metadata field.
651         *
652         * @param grantTypes The grant types, {@code null} if not specified.
653         */
654        public void setGrantTypes(final Set<GrantType> grantTypes) {
655
656                this.grantTypes = grantTypes;
657        }
658
659
660        /**
661         * Gets the administrator email contacts for the client. Corresponds to
662         * the {@code contacts} client metadata field.
663         *
664         * @return The administrator email contacts, {@code null} if not
665         *         specified.
666         */
667        public List<String> getEmailContacts() {
668
669                return contacts;
670        }
671
672
673        /**
674         * Sets the administrator email contacts for the client. Corresponds to
675         * the {@code contacts} client metadata field.
676         *
677         * @param contacts The administrator email contacts, {@code null} if
678         *                 not specified.
679         */
680        public void setEmailContacts(final List<String> contacts) {
681
682                this.contacts = contacts;
683        }
684
685
686        /**
687         * Gets the client name. Corresponds to the {@code client_name} client
688         * metadata field, with no language tag.
689         *
690         * @return The client name, {@code null} if not specified.
691         */
692        public String getName() {
693
694                return getName(null);
695        }
696
697
698        /**
699         * Gets the client name. Corresponds to the {@code client_name} client
700         * metadata field, with an optional language tag.
701         *
702         * @param langTag The language tag of the entry, {@code null} to get
703         *                the non-tagged entry.
704         *
705         * @return The client name, {@code null} if not specified.
706         */
707        public String getName(final LangTag langTag) {
708
709                return nameEntries.get(langTag);
710        }
711
712
713        /**
714         * Gets the client name entries. Corresponds to the {@code client_name}
715         * client metadata field.
716         *
717         * @return The client name entries, empty map if none.
718         */
719        public Map<LangTag,String> getNameEntries() {
720
721                return nameEntries;
722        }
723
724
725        /**
726         * Sets the client name. Corresponds to the {@code client_name} client
727         * metadata field, with no language tag.
728         *
729         * @param name The client name, {@code null} if not specified.
730         */
731        public void setName(final String name) {
732
733                nameEntries.put(null, name);
734        }
735
736
737        /**
738         * Sets the client name. Corresponds to the {@code client_name} client
739         * metadata field, with an optional language tag.
740         *
741         * @param name    The client name. Must not be {@code null}.
742         * @param langTag The language tag, {@code null} if not specified.
743         */
744        public void setName(final String name, final LangTag langTag) {
745
746                nameEntries.put(langTag, name);
747        }
748
749
750        /**
751         * Gets the client application logo. Corresponds to the
752         * {@code logo_uri} client metadata field, with no language
753         * tag.
754         *
755         * @return The logo URI, {@code null} if not specified.
756         */
757        public URI getLogoURI() {
758
759                return getLogoURI(null);
760        }
761
762
763        /**
764         * Gets the client application logo. Corresponds to the
765         * {@code logo_uri} client metadata field, with an optional
766         * language tag.
767         *
768         * @param langTag The language tag, {@code null} if not specified.
769         *
770         * @return The logo URI, {@code null} if not specified.
771         */
772        public URI getLogoURI(final LangTag langTag) {
773
774                return logoURIEntries.get(langTag);
775        }
776
777
778        /**
779         * Gets the client application logo entries. Corresponds to the
780         * {@code logo_uri} client metadata field.
781         *
782         * @return The logo URI entries, empty map if none.
783         */
784        public Map<LangTag,URI> getLogoURIEntries() {
785
786                return logoURIEntries;
787        }
788
789
790        /**
791         * Sets the client application logo. Corresponds to the
792         * {@code logo_uri} client metadata field, with no language
793         * tag.
794         *
795         * @param logoURI The logo URI, {@code null} if not specified.
796         */
797        public void setLogoURI(final URI logoURI) {
798
799                logoURIEntries.put(null, logoURI);
800        }
801
802
803        /**
804         * Sets the client application logo. Corresponds to the
805         * {@code logo_uri} client metadata field, with an optional
806         * language tag.
807         *
808         * @param logoURI The logo URI. Must not be {@code null}.
809         * @param langTag The language tag, {@code null} if not specified.
810         */
811        public void setLogoURI(final URI logoURI, final LangTag langTag) {
812
813                logoURIEntries.put(langTag, logoURI);
814        }
815
816
817        /**
818         * Gets the client home page. Corresponds to the {@code client_uri}
819         * client metadata field, with no language tag.
820         *
821         * @return The client URI, {@code null} if not specified.
822         */
823        public URI getURI() {
824
825                return getURI(null);
826        }
827
828
829        /**
830         * Gets the client home page. Corresponds to the {@code client_uri}
831         * client metadata field, with an optional language tag.
832         *
833         * @param langTag The language tag, {@code null} if not specified.
834         *
835         * @return The client URI, {@code null} if not specified.
836         */
837        public URI getURI(final LangTag langTag) {
838
839                return uriEntries.get(langTag);
840        }
841
842
843        /**
844         * Gets the client home page entries. Corresponds to the
845         * {@code client_uri} client metadata field.
846         *
847         * @return The client URI entries, empty map if none.
848         */
849        public Map<LangTag,URI> getURIEntries() {
850
851                return uriEntries;
852        }
853
854
855        /**
856         * Sets the client home page. Corresponds to the {@code client_uri}
857         * client metadata field, with no language tag.
858         *
859         * @param uri The client URI, {@code null} if not specified. The URI
860         *            scheme must be https or http.
861         */
862        public void setURI(final URI uri) {
863
864                URIUtils.ensureSchemeIsHTTPSorHTTP(uri);
865                uriEntries.put(null, uri);
866        }
867
868
869        /**
870         * Sets the client home page. Corresponds to the {@code client_uri}
871         * client metadata field, with an optional language tag.
872         *
873         * @param uri     The URI. The URI scheme must be https or http. Must
874         *                not be {@code null}.
875         * @param langTag The language tag, {@code null} if not specified.
876         */
877        public void setURI(final URI uri, final LangTag langTag) {
878                
879                URIUtils.ensureSchemeIsHTTPSorHTTP(uri);
880                uriEntries.put(langTag, uri);
881        }
882
883
884        /**
885         * Gets the client policy for use of end-user data. Corresponds to the
886         * {@code policy_uri} client metadata field, with no language
887         * tag.
888         *
889         * @return The policy URI, {@code null} if not specified.
890         */
891        public URI getPolicyURI() {
892
893                return getPolicyURI(null);
894        }
895
896
897        /**
898         * Gets the client policy for use of end-user data. Corresponds to the
899         * {@code policy_uri} client metadata field, with an optional
900         * language tag.
901         *
902         * @param langTag The language tag, {@code null} if not specified.
903         *
904         * @return The policy URI, {@code null} if not specified.
905         */
906        public URI getPolicyURI(final LangTag langTag) {
907
908                return policyURIEntries.get(langTag);
909        }
910
911
912        /**
913         * Gets the client policy entries for use of end-user data.
914         * Corresponds to the {@code policy_uri} client metadata field.
915         *
916         * @return The policy URI entries, empty map if none.
917         */
918        public Map<LangTag,URI> getPolicyURIEntries() {
919
920                return policyURIEntries;
921        }
922
923
924        /**
925         * Sets the client policy for use of end-user data. Corresponds to the
926         * {@code policy_uri} client metadata field, with no language
927         * tag.
928         *
929         * @param policyURI The policy URI, {@code null} if not specified. The
930         *                  URI scheme must be https or http.
931         */
932        public void setPolicyURI(final URI policyURI) {
933
934                URIUtils.ensureSchemeIsHTTPSorHTTP(policyURI);
935                policyURIEntries.put(null, policyURI);
936        }
937
938
939        /**
940         * Sets the client policy for use of end-user data. Corresponds to the
941         * {@code policy_uri} client metadata field, with an optional
942         * language tag.
943         *
944         * @param policyURI The policy URI. The URI scheme must be https or
945         *                  http. Must not be {@code null}.
946         * @param langTag   The language tag, {@code null} if not specified.
947         */
948        public void setPolicyURI(final URI policyURI, final LangTag langTag) {
949
950                URIUtils.ensureSchemeIsHTTPSorHTTP(policyURI);
951                policyURIEntries.put(langTag, policyURI);
952        }
953
954
955        /**
956         * Gets the client's terms of service. Corresponds to the
957         * {@code tos_uri} client metadata field, with no language
958         * tag.
959         *
960         * @return The terms of service URI, {@code null} if not specified.
961         */
962        public URI getTermsOfServiceURI() {
963
964                return getTermsOfServiceURI(null);
965        }
966
967
968        /**
969         * Gets the client's terms of service. Corresponds to the
970         * {@code tos_uri} client metadata field, with an optional
971         * language tag.
972         *
973         * @param langTag The language tag, {@code null} if not specified.
974         *
975         * @return The terms of service URI, {@code null} if not specified.
976         */
977        public URI getTermsOfServiceURI(final LangTag langTag) {
978
979                return tosURIEntries.get(langTag);
980        }
981
982
983        /**
984         * Gets the client's terms of service entries. Corresponds to the
985         * {@code tos_uri} client metadata field.
986         *
987         * @return The terms of service URI entries, empty map if none.
988         */
989        public Map<LangTag,URI> getTermsOfServiceURIEntries() {
990
991                return tosURIEntries;
992        }
993
994
995        /**
996         * Sets the client's terms of service. Corresponds to the
997         * {@code tos_uri} client metadata field, with no language
998         * tag.
999         *
1000         * @param tosURI The terms of service URI, {@code null} if not
1001         *               specified. The URI scheme must be https or http.
1002         */
1003        public void setTermsOfServiceURI(final URI tosURI) {
1004
1005                URIUtils.ensureSchemeIsHTTPSorHTTP(tosURI);
1006                tosURIEntries.put(null, tosURI);
1007        }
1008
1009
1010        /**
1011         * Sets the client's terms of service. Corresponds to the
1012         * {@code tos_uri} client metadata field, with an optional
1013         * language tag.
1014         *
1015         * @param tosURI  The terms of service URI. The URI scheme must not be
1016         *                https or http. Must not be {@code null}.
1017         * @param langTag The language tag, {@code null} if not specified.
1018         */
1019        public void setTermsOfServiceURI(final URI tosURI, final LangTag langTag) {
1020                
1021                URIUtils.ensureSchemeIsHTTPSorHTTP(tosURI);
1022                tosURIEntries.put(langTag, tosURI);
1023        }
1024
1025
1026        /**
1027         * Gets the Token endpoint authentication method. Corresponds to the
1028         * {@code token_endpoint_auth_method} client metadata field.
1029         *
1030         * @return The Token endpoint authentication method, {@code null} if
1031         *         not specified.
1032         */
1033        public ClientAuthenticationMethod getTokenEndpointAuthMethod() {
1034
1035                return authMethod;
1036        }
1037
1038
1039        /**
1040         * Sets the Token endpoint authentication method. Corresponds to the
1041         * {@code token_endpoint_auth_method} client metadata field.
1042         *
1043         * @param authMethod The Token endpoint authentication  method,
1044         *                   {@code null} if not specified.
1045         */
1046        public void setTokenEndpointAuthMethod(final ClientAuthenticationMethod authMethod) {
1047
1048                this.authMethod = authMethod;
1049        }
1050
1051
1052        /**
1053         * Gets the JSON Web Signature (JWS) algorithm required for
1054         * {@code private_key_jwt} and {@code client_secret_jwt}
1055         * authentication at the Token endpoint. Corresponds to the
1056         * {@code token_endpoint_auth_signing_alg} client metadata field.
1057         *
1058         * @return The JWS algorithm, {@code null} if not specified.
1059         */
1060        public JWSAlgorithm getTokenEndpointAuthJWSAlg() {
1061
1062                return authJWSAlg;
1063        }
1064
1065
1066        /**
1067         * Sets the JSON Web Signature (JWS) algorithm required for
1068         * {@code private_key_jwt} and {@code client_secret_jwt}
1069         * authentication at the Token endpoint. Corresponds to the
1070         * {@code token_endpoint_auth_signing_alg} client metadata field.
1071         *
1072         * @param authJWSAlg The JWS algorithm, {@code null} if not specified.
1073         */
1074        public void setTokenEndpointAuthJWSAlg(final JWSAlgorithm authJWSAlg) {
1075
1076                this.authJWSAlg = authJWSAlg;
1077        }
1078
1079
1080        /**
1081         * Gets the URI for this client's JSON Web Key (JWK) set containing
1082         * key(s) that are used in signing requests to the server and key(s)
1083         * for encrypting responses. Corresponds to the {@code jwks_uri} client
1084         * metadata field.
1085         *
1086         * @return The JWK set URI, {@code null} if not specified.
1087         */
1088        public URI getJWKSetURI() {
1089
1090                return jwkSetURI;
1091        }
1092
1093
1094        /**
1095         * Sets the URI for this client's JSON Web Key (JWK) set containing
1096         * key(s) that are used in signing requests to the server and key(s)
1097         * for encrypting responses. Corresponds to the {@code jwks_uri} client
1098         * metadata field.
1099         *
1100         * @param jwkSetURI The JWK set URI, {@code null} if not specified.
1101         */
1102        public void setJWKSetURI(final URI jwkSetURI) {
1103
1104                this.jwkSetURI = jwkSetURI;
1105        }
1106
1107
1108        /**
1109         * Gets the URI for this client's signed JSON Web Key (JWK) set
1110         * containing key(s) that are used in signing requests to the server
1111         * and key(s) for encrypting responses. Corresponds to the
1112         * {@code signed_jwks_uri} client metadata field. Intended for use in
1113         * OpenID Connect Federation 1.0.
1114         *
1115         * @return The signed JWK set URI, {@code null} if not specified.
1116         */
1117        public URI getSignedJWKSetURI() {
1118
1119                return signedJWKSetURI;
1120        }
1121
1122
1123        /**
1124         * Sets the URI for this client's signed JSON Web Key (JWK) set
1125         * containing key(s) that are used in signing requests to the server
1126         * and key(s) for encrypting responses. Corresponds to the
1127         * {@code signed_jwks_uri} client metadata field. Intended for use in
1128         * OpenID Connect Federation 1.0.
1129         *
1130         * @param signedJWKSetURI The signed JWK set URI, {@code null} if not
1131         *                        specified.
1132         */
1133        public void setSignedJWKSetURI(final URI signedJWKSetURI) {
1134
1135                this.signedJWKSetURI = signedJWKSetURI;
1136        }
1137
1138
1139        /**
1140         * Gets this client's JSON Web Key (JWK) set containing key(s) that are
1141         * used in signing requests to the server and key(s) for encrypting
1142         * responses. Intended as an alternative to {@link #getJWKSetURI} for
1143         * native clients. Corresponds to the {@code jwks} client metadata
1144         * field.
1145         *
1146         * @return The JWK set, {@code null} if not specified.
1147         */
1148        public JWKSet getJWKSet() {
1149
1150                return jwkSet;
1151        }
1152
1153
1154        /**
1155         * Sets this client's JSON Web Key (JWK) set containing key(s) that are
1156         * used in signing requests to the server and key(s) for encrypting
1157         * responses. Intended as an alternative to {@link #getJWKSetURI} for
1158         * native clients. Corresponds to the {@code jwks} client metadata
1159         * field.
1160         *
1161         * @param jwkSet The JWK set, {@code null} if not specified.
1162         */
1163        public void setJWKSet(final JWKSet jwkSet) {
1164
1165                this.jwkSet = jwkSet;
1166        }
1167        
1168        
1169        /**
1170         * Gets the pre-registered request object URIs. Corresponds to the
1171         * {@code request_uris} client metadata field.
1172         *
1173         * @return The request object URIs, {@code null} if not specified.
1174         */
1175        public Set<URI> getRequestObjectURIs() {
1176                
1177                return requestObjectURIs;
1178        }
1179        
1180        
1181        /**
1182         * Sets the pre-registered request object URIs. Corresponds to the
1183         * {@code request_uris} client metadata field.
1184         *
1185         * @param requestObjectURIs The request object URIs, {@code null} if
1186         *                          not specified.
1187         */
1188        public void setRequestObjectURIs(final Set<URI> requestObjectURIs) {
1189                
1190                this.requestObjectURIs = requestObjectURIs;
1191        }
1192        
1193        
1194        /**
1195         * Gets the JSON Web Signature (JWS) algorithm required for request
1196         * objects sent by this client. Corresponds to the
1197         * {@code request_object_signing_alg} client metadata field.
1198         *
1199         * @return The JWS algorithm, {@code null} if not specified.
1200         */
1201        public JWSAlgorithm getRequestObjectJWSAlg() {
1202                
1203                return requestObjectJWSAlg;
1204        }
1205        
1206        
1207        /**
1208         * Sets the JSON Web Signature (JWS) algorithm required for request
1209         * objects sent by this client. Corresponds to the
1210         * {@code request_object_signing_alg} client metadata field.
1211         *
1212         * @param requestObjectJWSAlg The JWS algorithm, {@code null} if not
1213         *                            specified.
1214         */
1215        public void setRequestObjectJWSAlg(final JWSAlgorithm requestObjectJWSAlg) {
1216                
1217                this.requestObjectJWSAlg = requestObjectJWSAlg;
1218        }
1219        
1220        
1221        /**
1222         * Gets the JSON Web Encryption (JWE) algorithm required for request
1223         * objects sent by this client. Corresponds to the
1224         * {@code request_object_encryption_alg} client metadata field.
1225         *
1226         * @return The JWE algorithm, {@code null} if not specified.
1227         */
1228        public JWEAlgorithm getRequestObjectJWEAlg() {
1229                
1230                return requestObjectJWEAlg;
1231        }
1232        
1233        
1234        /**
1235         * Sets the JSON Web Encryption (JWE) algorithm required for request
1236         * objects sent by this client. Corresponds to the
1237         * {@code request_object_encryption_alg} client metadata field.
1238         *
1239         * @param requestObjectJWEAlg The JWE algorithm, {@code null} if not
1240         *                            specified.
1241         */
1242        public void setRequestObjectJWEAlg(final JWEAlgorithm requestObjectJWEAlg) {
1243                
1244                this.requestObjectJWEAlg = requestObjectJWEAlg;
1245        }
1246        
1247        
1248        /**
1249         * Gets the JSON Web Encryption (JWE) method required for request
1250         * objects sent by this client. Corresponds to the
1251         * {@code request_object_encryption_enc} client metadata field.
1252         *
1253         * @return The JWE method, {@code null} if not specified.
1254         */
1255        public EncryptionMethod getRequestObjectJWEEnc() {
1256                
1257                return requestObjectJWEEnc;
1258        }
1259        
1260        
1261        /**
1262         * Sets the JSON Web Encryption (JWE) method required for request
1263         * objects sent by this client. Corresponds to the
1264         * {@code request_object_encryption_enc} client metadata field.
1265         *
1266         * @param requestObjectJWEEnc The JWE method, {@code null} if not
1267         *                            specified.
1268         */
1269        public void setRequestObjectJWEEnc(final EncryptionMethod requestObjectJWEEnc) {
1270                
1271                this.requestObjectJWEEnc = requestObjectJWEEnc;
1272        }
1273
1274
1275        /**
1276         * Gets the identifier for the OAuth 2.0 client software. Corresponds
1277         * to the {@code software_id} client metadata field.
1278         *
1279         * @return The software identifier, {@code null} if not specified.
1280         */
1281        public SoftwareID getSoftwareID() {
1282
1283                return softwareID;
1284        }
1285
1286
1287        /**
1288         * Sets the identifier for the OAuth 2.0 client software. Corresponds
1289         * to the {@code software_id} client metadata field.
1290         *
1291         * @param softwareID The software identifier, {@code null} if not
1292         *                   specified.
1293         */
1294        public void setSoftwareID(final SoftwareID softwareID) {
1295
1296                this.softwareID = softwareID;
1297        }
1298
1299
1300        /**
1301         * Gets the version identifier for the OAuth 2.0 client software.
1302         * Corresponds to the {@code software_version} client metadata field.
1303         *
1304         * @return The version identifier, {@code null} if not specified.
1305         */
1306        public SoftwareVersion getSoftwareVersion() {
1307
1308                return softwareVersion;
1309        }
1310
1311
1312        /**
1313         * Sets the version identifier for the OAuth 2.0 client software.
1314         * Corresponds to the {@code software_version} client metadata field.
1315         *
1316         * @param softwareVersion The version identifier, {@code null} if not
1317         *                        specified.
1318         */
1319        public void setSoftwareVersion(final SoftwareVersion softwareVersion) {
1320
1321                this.softwareVersion = softwareVersion;
1322        }
1323        
1324        
1325        /**
1326         * Gets the software statement. Corresponds to the
1327         * {@code software_statement} client metadata field.
1328         *
1329         * @return The signed software statement, {@code null} if not
1330         *         specified.
1331         */
1332        public SignedJWT getSoftwareStatement() {
1333                
1334                return softwareStatement;
1335        }
1336        
1337        
1338        /**
1339         * Sets the software statement. Corresponds to the
1340         * {@code software_statement} client metadata field.
1341         *
1342         * @param softwareStatement The signed software statement, {@code null}
1343         *                          if not specified.
1344         */
1345        public void setSoftwareStatement(final SignedJWT softwareStatement) {
1346                
1347                if (softwareStatement != null && softwareStatement.getState().equals(JWSObject.State.UNSIGNED)) {
1348                        throw new IllegalArgumentException("The software statement must be signed");
1349                }
1350                
1351                this.softwareStatement = softwareStatement;
1352        }
1353        
1354        
1355        /**
1356         * Sets the preference for TLS client certificate bound access tokens.
1357         * Corresponds to the
1358         * {@code tls_client_certificate_bound_access_tokens} client metadata
1359         * field.
1360         *
1361         * @return {@code true} indicates a preference for TLS client
1362         *         certificate bound access tokens, {@code false} if none.
1363         */
1364        public boolean getTLSClientCertificateBoundAccessTokens() {
1365                
1366                return tlsClientCertificateBoundAccessTokens;
1367        }
1368        
1369        
1370        /**
1371         * Gets the preference for TLS client certificate bound access tokens.
1372         * Corresponds to the
1373         * {@code tls_client_certificate_bound_access_tokens} client metadata
1374         * field.
1375         *
1376         * @param tlsClientCertBoundTokens {@code true} indicates a preference
1377         *                                 for TLS client certificate bound
1378         *                                 access tokens, {@code false} if
1379         *                                 none.
1380         */
1381        public void setTLSClientCertificateBoundAccessTokens(final boolean tlsClientCertBoundTokens) {
1382                
1383                tlsClientCertificateBoundAccessTokens = tlsClientCertBoundTokens;
1384        }
1385        
1386        
1387        /**
1388         * Sets the preference for TLS client certificate bound access tokens.
1389         * Corresponds to the
1390         * {@code tls_client_certificate_bound_access_tokens} client metadata
1391         * field.
1392         *
1393         * @return {@code true} indicates a preference for TLS client
1394         *         certificate bound access tokens, {@code false} if none.
1395         */
1396        @Deprecated
1397        public boolean getMutualTLSSenderConstrainedAccessTokens() {
1398                
1399                return tlsClientCertificateBoundAccessTokens;
1400        }
1401        
1402        
1403        /**
1404         * Gets the preference for TLS client certificate bound access tokens.
1405         * Corresponds to the
1406         * {@code tls_client_certificate_bound_access_tokens} client metadata
1407         * field.
1408         *
1409         * @param tlsSenderAccessTokens {@code true} indicates a preference for
1410         *                              TLS client certificate bound access
1411         *                              tokens, {@code false} if none.
1412         */
1413        @Deprecated
1414        public void setMutualTLSSenderConstrainedAccessTokens(final boolean tlsSenderAccessTokens) {
1415                
1416                tlsClientCertificateBoundAccessTokens = tlsSenderAccessTokens;
1417        }
1418        
1419        
1420        /**
1421         * Gets the expected subject distinguished name (DN) of the client
1422         * X.509 certificate in mutual TLS authentication. Corresponds to the
1423         * {@code tls_client_auth_subject_dn} client metadata field.
1424         *
1425         * @return The expected subject distinguished name (DN) of the client
1426         *         X.509 certificate, {@code null} if not specified.
1427         */
1428        public String getTLSClientAuthSubjectDN() {
1429                
1430                return tlsClientAuthSubjectDN;
1431        }
1432        
1433        
1434        /**
1435         * Sets the expected subject distinguished name (DN) of the client
1436         * X.509 certificate in mutual TLS authentication. Corresponds to the
1437         * {@code tls_client_auth_subject_dn} client metadata field.
1438         *
1439         * @param subjectDN The expected subject distinguished name (DN) of the
1440         *                  client X.509 certificate, {@code null} if not
1441         *                  specified.
1442         */
1443        public void setTLSClientAuthSubjectDN(final String subjectDN) {
1444                
1445                this.tlsClientAuthSubjectDN = subjectDN;
1446        }
1447        
1448        
1449        /**
1450         * Gets the expected dNSName SAN entry in the X.509 certificate, which
1451         * the OAuth client will use in mutual TLS authentication. Corresponds
1452         * to the {@code tls_client_auth_san_dns} client metadata field.
1453         *
1454         * @return The expected dNSName SAN entry in the X.509 certificate,
1455         *         {@code null} if not specified.
1456         */
1457        public String getTLSClientAuthSanDNS() {
1458                
1459                return tlsClientAuthSanDNS;
1460        }
1461        
1462        
1463        /**
1464         * Sets the expected dNSName SAN entry in the X.509 certificate, which
1465         * the OAuth client will use in mutual TLS authentication. Corresponds
1466         * to the {@code tls_client_auth_san_dns} client metadata field.
1467         *
1468         * @param dns The expected dNSName SAN entry in the X.509 certificate,
1469         *            {@code null} if not specified.
1470         */
1471        public void setTLSClientAuthSanDNS(final String dns) {
1472                
1473                this.tlsClientAuthSanDNS = dns;
1474        }
1475        
1476        
1477        /**
1478         * Gets the expected uniformResourceIdentifier SAN entry in the X.509
1479         * certificate, which the OAuth client will use in mutual TLS
1480         * authentication. Corresponds to the {@code tls_client_auth_san_uri}
1481         * client metadata field.
1482         *
1483         * @return The expected uniformResourceIdentifier SAN entry in the X.509
1484         *         certificate, {@code null} if not specified.
1485         */
1486        public String getTLSClientAuthSanURI() {
1487                
1488                return tlsClientAuthSanURI;
1489        }
1490        
1491        
1492        /**
1493         * Sets the expected uniformResourceIdentifier SAN entry in the X.509
1494         * certificate, which the OAuth client will use in mutual TLS
1495         * authentication. Corresponds to the {@code tls_client_auth_san_uri}
1496         * client metadata field.
1497         *
1498         * @param uri The expected uniformResourceIdentifier SAN entry in the X.509
1499         *            certificate, {@code null} if not specified.
1500         */
1501        public void setTLSClientAuthSanURI(final String uri) {
1502                
1503                this.tlsClientAuthSanURI = uri;
1504        }
1505        
1506        
1507        /**
1508         * Gets the expected iPAddress SAN entry in the X.509 certificate, which
1509         * the OAuth client will use in mutual TLS authentication. Corresponds
1510         * to the {@code tls_client_auth_san_ip} client metadata field.
1511         *
1512         * @return The expected iPAddress SAN entry in the X.509 certificate,
1513         *         {@code null} if not specified.
1514         */
1515        public String getTLSClientAuthSanIP() {
1516                
1517                return tlsClientAuthSanIP;
1518        }
1519        
1520        
1521        /**
1522         * Sets the expected iPAddress SAN entry in the X.509 certificate, which
1523         * the OAuth client will use in mutual TLS authentication. Corresponds
1524         * to the {@code tls_client_auth_san_ip} client metadata field.
1525         *
1526         * @param ip The expected iPAddress SAN entry in the X.509
1527         *           certificate, {@code null} if not specified.
1528         */
1529        public void setTLSClientAuthSanIP(final String ip) {
1530                
1531                this.tlsClientAuthSanIP = ip;
1532        }
1533        
1534        
1535        /**
1536         * Gets the expected rfc822Name SAN entry in the X.509 certificate, which
1537         * the OAuth client will use in mutual TLS authentication. Corresponds
1538         * to the {@code tls_client_auth_san_email} client metadata field.
1539         *
1540         * @return The expected rfc822Name SAN entry in the X.509 certificate,
1541         *         {@code null} if not specified.
1542         */
1543        public String getTLSClientAuthSanEmail() {
1544                
1545                return tlsClientAuthSanEmail;
1546        }
1547        
1548        
1549        /**
1550         * Sets the expected rfc822Name SAN entry in the X.509 certificate, which
1551         * the OAuth client will use in mutual TLS authentication. Corresponds
1552         * to the {@code tls_client_auth_san_email} client metadata field.
1553         *
1554         * @param email The expected rfc822Name SAN entry in the X.509
1555         *              certificate, {@code null} if not specified.
1556         */
1557        public void setTLSClientAuthSanEmail(final String email) {
1558                
1559                this.tlsClientAuthSanEmail = email;
1560        }
1561        
1562        
1563        /**
1564         * Ensures that for {@code tls_client_auth} a certificate field for the
1565         * subject is specified. See
1566         * https://www.rfc-editor.org/rfc/rfc8705.html#section-2.1.2
1567         */
1568        private void ensureExactlyOneCertSubjectFieldForTLSClientAuth()
1569                throws IllegalStateException {
1570                
1571                if (! ClientAuthenticationMethod.TLS_CLIENT_AUTH.equals(getTokenEndpointAuthMethod())) {
1572                        // Not tls_client_auth, ignore
1573                        return;
1574                }
1575                
1576                if (tlsClientAuthSubjectDN == null && tlsClientAuthSanDNS == null && tlsClientAuthSanURI == null && tlsClientAuthSanIP == null && tlsClientAuthSanEmail == null) {
1577                        throw new IllegalStateException("A certificate field must be specified to indicate the subject in tls_client_auth: " +
1578                                "tls_client_auth_subject_dn, tls_client_auth_san_dns, tls_client_auth_san_uri, tls_client_auth_san_ip or tls_client_auth_san_email");
1579                }
1580                
1581                String exceptionMessage = "Exactly one certificate field must be specified to indicate the subject in tls_client_auth: " +
1582                        "tls_client_auth_subject_dn, tls_client_auth_san_dns, tls_client_auth_san_uri, tls_client_auth_san_ip or tls_client_auth_san_email";
1583                
1584                if (tlsClientAuthSubjectDN != null) {
1585                        if (tlsClientAuthSanDNS != null || tlsClientAuthSanURI != null || tlsClientAuthSanIP != null || tlsClientAuthSanEmail != null) {
1586                                throw new IllegalStateException(exceptionMessage);
1587                        }
1588                }
1589                
1590                if (tlsClientAuthSanDNS != null) {
1591                        if (tlsClientAuthSanURI != null || tlsClientAuthSanIP != null || tlsClientAuthSanEmail != null) {
1592                                throw new IllegalStateException(exceptionMessage);
1593                        }
1594                }
1595                
1596                if (tlsClientAuthSanURI != null) {
1597                        if (tlsClientAuthSanIP != null || tlsClientAuthSanEmail != null) {
1598                                throw new IllegalStateException(exceptionMessage);
1599                        }
1600                }
1601                
1602                if (tlsClientAuthSanIP != null) {
1603                        if (tlsClientAuthSanEmail != null) {
1604                                throw new IllegalStateException(exceptionMessage);
1605                        }
1606                }
1607        }
1608        
1609        
1610        /**
1611         * Gets the JWS algorithm for JWT-encoded authorisation responses.
1612         * Corresponds to the {@code authorization_signed_response_alg} client
1613         * metadata field.
1614         *
1615         * @return The JWS algorithm, {@code null} if not specified.
1616         */
1617        public JWSAlgorithm getAuthorizationJWSAlg() {
1618                
1619                return authzJWSAlg;
1620        }
1621        
1622        
1623        /**
1624         * Sets the JWS algorithm for JWT-encoded authorisation responses.
1625         * Corresponds to the {@code authorization_signed_response_alg} client
1626         * metadata field.
1627         *
1628         * @param authzJWSAlg The JWS algorithm, {@code null} if not specified.
1629         *                    Must not be {@code "none"}.
1630         */
1631        public void setAuthorizationJWSAlg(final JWSAlgorithm authzJWSAlg) {
1632                
1633                if (new JWSAlgorithm("none").equals(authzJWSAlg)) {
1634                        // Prevent passing none as JWS alg
1635                        throw new IllegalArgumentException("The JWS algorithm must not be \"none\"");
1636                }
1637                
1638                this.authzJWSAlg = authzJWSAlg;
1639        }
1640        
1641        
1642        /**
1643         * Gets the JWE algorithm for JWT-encoded authorisation responses.
1644         * Corresponds to the {@code authorization_encrypted_response_alg}
1645         * client metadata field.
1646         *
1647         * @return The JWE algorithm, {@code null} if not specified.
1648         */
1649        public JWEAlgorithm getAuthorizationJWEAlg() {
1650                
1651                return authzJWEAlg;
1652        }
1653        
1654        
1655        /**
1656         * Sets the JWE algorithm for JWT-encoded authorisation responses.
1657         * Corresponds to the {@code authorization_encrypted_response_alg}
1658         * client metadata field.
1659         *
1660         * @param authzJWEAlg The JWE algorithm, {@code null} if not specified.
1661         */
1662        public void setAuthorizationJWEAlg(final JWEAlgorithm authzJWEAlg) {
1663                
1664                this.authzJWEAlg = authzJWEAlg;
1665        }
1666        
1667        
1668        /**
1669         * Sets the encryption method for JWT-encoded authorisation responses.
1670         * Corresponds to the {@code authorization_encrypted_response_enc}
1671         * client metadata field.
1672         *
1673         * @return The encryption method, {@code null} if specified.
1674         */
1675        public EncryptionMethod getAuthorizationJWEEnc() {
1676                
1677                return authzJWEEnc;
1678        }
1679        
1680        
1681        /**
1682         * Sets the encryption method for JWT-encoded authorisation responses.
1683         * Corresponds to the {@code authorization_encrypted_response_enc}
1684         * client metadata field.
1685         *
1686         * @param authzJWEEnc The encryption method, {@code null} if specified.
1687         */
1688        public void setAuthorizationJWEEnc(final EncryptionMethod authzJWEEnc) {
1689                
1690                this.authzJWEEnc = authzJWEEnc;
1691        }
1692        
1693        
1694        /**
1695         * Gets the requirement for pushed authorisation requests (PAR).
1696         * Corresponds to the {@code pushed_authorization_request_endpoint}
1697         * client metadata field.
1698         *
1699         * @return {@code true} if PAR is required, else {@code false}.
1700         */
1701        public boolean requiresPushedAuthorizationRequests() {
1702                
1703                return requirePAR;
1704        }
1705        
1706        
1707        /**
1708         * Sets the requirement for pushed authorisation requests (PAR).
1709         * Corresponds to the {@code pushed_authorization_request_endpoint}
1710         * client metadata field.
1711         *
1712         * @param requirePAR {@code true} if PAR is required, else
1713         *                   {@code false}.
1714         */
1715        public void requiresPushedAuthorizationRequests(final boolean requirePAR) {
1716                
1717                this.requirePAR = requirePAR;
1718        }
1719        
1720        
1721        /**
1722         * Gets the CIBA token delivery mode. Corresponds to the
1723         * {@code backchannel_token_delivery_mode} metadata field.
1724         *
1725         * @return The CIBA token delivery mode, {@code null} if not
1726         *         specified.
1727         */
1728        public BackChannelTokenDeliveryMode getBackChannelTokenDeliveryMode() {
1729                
1730                return backChannelTokenDeliveryMode;
1731        }
1732        
1733        
1734        /**
1735         * Sets the CIBA token delivery mode. Corresponds to the
1736         * {@code backchannel_token_delivery_mode} metadata field.
1737         *
1738         * @param backChannelTokenDeliveryMode The CIBA token delivery mode,
1739         *                                     {@code null} if not specified.
1740         */
1741        public void setBackChannelTokenDeliveryMode(final BackChannelTokenDeliveryMode backChannelTokenDeliveryMode) {
1742                
1743                this.backChannelTokenDeliveryMode = backChannelTokenDeliveryMode;
1744        }
1745        
1746        
1747        /**
1748         * Gets the CIBA client notification endpoint URI for the ping or push
1749         * delivery modes. Corresponds to the
1750         * {@code backchannel_client_notification_endpoint} metadata field.
1751         *
1752         * @return The CIBA client notification endpoint URI, {@code null} if
1753         *         not specified.
1754         */
1755        public URI getBackChannelClientNotificationEndpoint() {
1756                
1757                return backChannelClientNotificationEndpoint;
1758        }
1759        
1760        
1761        /**
1762         * Sets the CIBA client notification endpoint URI for the ping or push
1763         * delivery modes. Corresponds to the
1764         * {@code backchannel_client_notification_endpoint} metadata field.
1765         *
1766         * @param backChannelClientNotificationEndpoint The CIBA client
1767         *                                              notification endpoint
1768         *                                              URI, {@code null} if
1769         *                                              not specified.
1770         */
1771        public void setBackChannelClientNotificationEndpoint(final URI backChannelClientNotificationEndpoint) {
1772                
1773                this.backChannelClientNotificationEndpoint = backChannelClientNotificationEndpoint;
1774        }
1775        
1776        
1777        /**
1778         * Gets the JWS algorithm for CIBA requests. Corresponds to the
1779         * {@code backchannel_authentication_request_signing_alg} metadata
1780         * field.
1781         *
1782         * @return The JWS algorithm for CIBA requests, {@code null} if not
1783         *         specified.
1784         */
1785        public JWSAlgorithm getBackChannelAuthRequestJWSAlg() {
1786                
1787                return backChannelAuthRequestJWSAlg;
1788        }
1789        
1790        
1791        /**
1792         * Sets the JWS algorithm for CIBA requests. Corresponds to the
1793         * {@code backchannel_authentication_request_signing_alg} metadata
1794         * field.
1795         *
1796         * @param backChannelAuthRequestJWSAlg The JWS algorithm for CIBA
1797         *                                     requests, {@code null} if not
1798         *                                     specified.
1799         */
1800        public void setBackChannelAuthRequestJWSAlg(final JWSAlgorithm backChannelAuthRequestJWSAlg) {
1801                
1802                this.backChannelAuthRequestJWSAlg = backChannelAuthRequestJWSAlg;
1803        }
1804        
1805        
1806        /**
1807         * Gets the support for the {@code user_code} CIBA request parameter.
1808         * Corresponds to the {@code backchannel_user_code_parameter} metadata
1809         * field.
1810         *
1811         * @return {@code true} if the {@code user_code} parameter is
1812         *         supported, else {@code false}.
1813         */
1814        public boolean supportsBackChannelUserCodeParam() {
1815                
1816                return backChannelUserCodeParam;
1817        }
1818        
1819        
1820        /**
1821         * Sets the support for the {@code user_code} CIBA request parameter.
1822         * Corresponds to the {@code backchannel_user_code_parameter} metadata
1823         * field.
1824         *
1825         * @param backChannelUserCodeParam {@code true} if the
1826         *                                 {@code user_code} parameter is
1827         *                                 supported, else {@code false}.
1828         */
1829        public void setSupportsBackChannelUserCodeParam(final boolean backChannelUserCodeParam) {
1830                
1831                this.backChannelUserCodeParam = backChannelUserCodeParam;
1832        }
1833        
1834        
1835        /**
1836         * Gets the supported OpenID Connect Federation 1.0 client registration
1837         * types. Corresponds to the {@code client_registration_types} metadata
1838         * field.
1839         *
1840         * @return The supported registration types, {@code null} if not
1841         *         specified.
1842         */
1843        public List<ClientRegistrationType> getClientRegistrationTypes() {
1844                
1845                return clientRegistrationTypes;
1846        }
1847        
1848        
1849        /**
1850         * Sets the supported OpenID Connect Federation 1.0 client registration
1851         * types. Corresponds to the {@code client_registration_types} metadata
1852         * field.
1853         *
1854         * @param regTypes The supported registration types, {@code null} if
1855         *                 not specified.
1856         */
1857        public void setClientRegistrationTypes(final List<ClientRegistrationType> regTypes) {
1858                
1859                this.clientRegistrationTypes = regTypes;
1860        }
1861        
1862        
1863        /**
1864         * Gets the organisation name in OpenID Connect Federation 1.0.
1865         * Corresponds to the {@code organization_name} metadata field.
1866         *
1867         * @return The organisation name, {@code null} if not specified.
1868         */
1869        public String getOrganizationName() {
1870                
1871                return organizationName;
1872        }
1873        
1874        
1875        /**
1876         * Sets the organisation name in OpenID Connect Federation 1.0.
1877         * Corresponds to the {@code organization_name} metadata field.
1878         *
1879         * @param organizationName The organisation name, {@code null} if not
1880         *                         specified.
1881         */
1882        public void setOrganizationName(final String organizationName) {
1883                
1884                this.organizationName = organizationName;
1885        }
1886        
1887        
1888        /**
1889         * Gets the specified custom metadata field.
1890         *
1891         * @param name The field name. Must not be {@code null}.
1892         *
1893         * @return The field value, typically serialisable to a JSON entity,
1894         *         {@code null} if none.
1895         */
1896        public Object getCustomField(final String name) {
1897
1898                return customFields.get(name);
1899        }
1900
1901
1902        /**
1903         * Gets the custom metadata fields.
1904         *
1905         * @return The custom metadata fields, as a JSON object, empty object
1906         *         if none.
1907         */
1908        public JSONObject getCustomFields() {
1909
1910                return customFields;
1911        }
1912
1913
1914        /**
1915         * Sets the specified custom metadata field.
1916         *
1917         * @param name  The field name. Must not be {@code null}.
1918         * @param value The field value. Should serialise to a JSON entity.
1919         */
1920        public void setCustomField(final String name, final Object value) {
1921
1922                customFields.put(name, value);
1923        }
1924
1925
1926        /**
1927         * Sets the custom metadata fields.
1928         *
1929         * @param customFields The custom metadata fields, as a JSON object,
1930         *                     empty object if none. Must not be {@code null}.
1931         */
1932        public void setCustomFields(final JSONObject customFields) {
1933
1934                if (customFields == null)
1935                        throw new IllegalArgumentException("The custom fields JSON object must not be null");
1936
1937                this.customFields = customFields;
1938        }
1939
1940        
1941        /**
1942         * Applies the client metadata defaults where no values have been
1943         * specified.
1944         *
1945         * <ul>
1946         *     <li>The response types default to {@code ["code"]}.
1947         *     <li>The grant types default to {@code ["authorization_code"]}.
1948         *     <li>The client authentication method defaults to
1949         *         "client_secret_basic", unless the grant type is "implicit"
1950         *         only.
1951         *     <li>The encryption method for JWT-encoded authorisation
1952         *         responses defaults to {@code A128CBC-HS256} if a JWE
1953         *         algorithm is set.
1954         * </ul>
1955         */
1956        public void applyDefaults() {
1957
1958                if (responseTypes == null) {
1959                        responseTypes = new HashSet<>();
1960                        responseTypes.add(ResponseType.getDefault());
1961                }
1962
1963                if (grantTypes == null) {
1964                        grantTypes = new HashSet<>();
1965                        grantTypes.add(GrantType.AUTHORIZATION_CODE);
1966                }
1967
1968                if (authMethod == null) {
1969
1970                        if (grantTypes.contains(GrantType.IMPLICIT) && grantTypes.size() == 1) {
1971                                authMethod = ClientAuthenticationMethod.NONE;
1972                        } else {
1973                                authMethod = ClientAuthenticationMethod.getDefault();
1974                        }
1975                }
1976                
1977                if (authzJWEAlg != null && authzJWEEnc == null) {
1978                        authzJWEEnc = EncryptionMethod.A128CBC_HS256;
1979                }
1980        }
1981
1982
1983        /**
1984         * Returns the JSON object representation of this client metadata,
1985         * including any custom fields.
1986         *
1987         * @return The JSON object.
1988         */
1989        public JSONObject toJSONObject() {
1990
1991                return toJSONObject(true);
1992        }
1993
1994
1995        /**
1996         * Returns the JSON object representation of this client metadata.
1997         *
1998         * @param includeCustomFields {@code true} to include any custom
1999         *                            metadata fields, {@code false} to omit
2000         *                            them.
2001         *
2002         * @return The JSON object.
2003         */
2004        public JSONObject toJSONObject(final boolean includeCustomFields) {
2005
2006                ensureExactlyOneCertSubjectFieldForTLSClientAuth();
2007                
2008                JSONObject o;
2009
2010                if (includeCustomFields)
2011                        o = new JSONObject(customFields);
2012                else
2013                        o = new JSONObject();
2014
2015
2016                if (redirectURIs != null)
2017                        o.put("redirect_uris", URIUtils.toStringList(redirectURIs));
2018
2019
2020                if (scope != null)
2021                        o.put("scope", scope.toString());
2022
2023
2024                if (responseTypes != null) {
2025
2026                        JSONArray rtList = new JSONArray();
2027
2028                        for (ResponseType rt: responseTypes)
2029                                rtList.add(rt.toString());
2030
2031                        o.put("response_types", rtList);
2032                }
2033
2034
2035                if (grantTypes != null) {
2036
2037                        JSONArray grantList = new JSONArray();
2038
2039                        for (GrantType grant: grantTypes)
2040                                grantList.add(grant.toString());
2041
2042                        o.put("grant_types", grantList);
2043                }
2044
2045
2046                if (contacts != null) {
2047                        o.put("contacts", contacts);
2048                }
2049
2050
2051                if (! nameEntries.isEmpty()) {
2052
2053                        for (Map.Entry<LangTag,String> entry: nameEntries.entrySet()) {
2054
2055                                LangTag langTag = entry.getKey();
2056                                String name = entry.getValue();
2057
2058                                if (name == null)
2059                                        continue;
2060
2061                                if (langTag == null)
2062                                        o.put("client_name", entry.getValue());
2063                                else
2064                                        o.put("client_name#" + langTag, entry.getValue());
2065                        }
2066                }
2067
2068
2069                if (! logoURIEntries.isEmpty()) {
2070
2071                        for (Map.Entry<LangTag,URI> entry: logoURIEntries.entrySet()) {
2072
2073                                LangTag langTag = entry.getKey();
2074                                URI uri = entry.getValue();
2075
2076                                if (uri == null)
2077                                        continue;
2078
2079                                if (langTag == null)
2080                                        o.put("logo_uri", entry.getValue().toString());
2081                                else
2082                                        o.put("logo_uri#" + langTag, entry.getValue().toString());
2083                        }
2084                }
2085
2086
2087                if (! uriEntries.isEmpty()) {
2088
2089                        for (Map.Entry<LangTag,URI> entry: uriEntries.entrySet()) {
2090
2091                                LangTag langTag = entry.getKey();
2092                                URI uri = entry.getValue();
2093
2094                                if (uri == null)
2095                                        continue;
2096
2097                                if (langTag == null)
2098                                        o.put("client_uri", entry.getValue().toString());
2099                                else
2100                                        o.put("client_uri#" + langTag, entry.getValue().toString());
2101                        }
2102                }
2103
2104
2105                if (! policyURIEntries.isEmpty()) {
2106
2107                        for (Map.Entry<LangTag,URI> entry: policyURIEntries.entrySet()) {
2108
2109                                LangTag langTag = entry.getKey();
2110                                URI uri = entry.getValue();
2111
2112                                if (uri == null)
2113                                        continue;
2114
2115                                if (langTag == null)
2116                                        o.put("policy_uri", entry.getValue().toString());
2117                                else
2118                                        o.put("policy_uri#" + langTag, entry.getValue().toString());
2119                        }
2120                }
2121
2122
2123                if (! tosURIEntries.isEmpty()) {
2124
2125                        for (Map.Entry<LangTag,URI> entry: tosURIEntries.entrySet()) {
2126
2127                                LangTag langTag = entry.getKey();
2128                                URI uri = entry.getValue();
2129
2130                                if (uri == null)
2131                                        continue;
2132
2133                                if (langTag == null)
2134                                        o.put("tos_uri", entry.getValue().toString());
2135                                else
2136                                        o.put("tos_uri#" + langTag, entry.getValue().toString());
2137                        }
2138                }
2139
2140
2141                if (authMethod != null)
2142                        o.put("token_endpoint_auth_method", authMethod.toString());
2143
2144
2145                if (authJWSAlg != null)
2146                        o.put("token_endpoint_auth_signing_alg", authJWSAlg.getName());
2147
2148
2149                if (jwkSetURI != null)
2150                        o.put("jwks_uri", jwkSetURI.toString());
2151
2152
2153                if (jwkSet != null)
2154                        o.put("jwks", JSONObjectUtils.toJSONObject(jwkSet.toPublicJWKSet())); // prevent private keys from leaking
2155                
2156                
2157                if (requestObjectURIs != null)
2158                        o.put("request_uris", URIUtils.toStringList(requestObjectURIs));
2159                
2160                if (requestObjectJWSAlg != null)
2161                        o.put("request_object_signing_alg", requestObjectJWSAlg.getName());
2162                
2163                if (requestObjectJWEAlg != null)
2164                        o.put("request_object_encryption_alg", requestObjectJWEAlg.getName());
2165                
2166                if (requestObjectJWEEnc != null)
2167                        o.put("request_object_encryption_enc", requestObjectJWEEnc.getName());
2168
2169
2170                if (softwareID != null)
2171                        o.put("software_id", softwareID.getValue());
2172
2173                if (softwareVersion != null)
2174                        o.put("software_version", softwareVersion.getValue());
2175                
2176                if (softwareStatement != null)
2177                        o.put("software_statement", softwareStatement.serialize());
2178                
2179                if (getTLSClientCertificateBoundAccessTokens()) {
2180                        o.put("tls_client_certificate_bound_access_tokens", tlsClientCertificateBoundAccessTokens);
2181                }
2182                
2183                if (tlsClientAuthSubjectDN != null)
2184                        o.put("tls_client_auth_subject_dn", tlsClientAuthSubjectDN);
2185                
2186                if (tlsClientAuthSanDNS != null)
2187                        o.put("tls_client_auth_san_dns", tlsClientAuthSanDNS);
2188                
2189                if (tlsClientAuthSanURI != null)
2190                        o.put("tls_client_auth_san_uri", tlsClientAuthSanURI);
2191                
2192                if (tlsClientAuthSanIP != null)
2193                        o.put("tls_client_auth_san_ip", tlsClientAuthSanIP);
2194                
2195                if (tlsClientAuthSanEmail != null)
2196                        o.put("tls_client_auth_san_email", tlsClientAuthSanEmail);
2197                
2198                if (authzJWSAlg != null) {
2199                        o.put("authorization_signed_response_alg", authzJWSAlg.getName());
2200                }
2201                
2202                if (authzJWEAlg != null) {
2203                        o.put("authorization_encrypted_response_alg", authzJWEAlg.getName());
2204                }
2205                
2206                if (authzJWEEnc != null) {
2207                        o.put("authorization_encrypted_response_enc", authzJWEEnc.getName());
2208                }
2209                
2210                // PAR
2211                if (requirePAR) {
2212                        o.put("require_pushed_authorization_requests", true);
2213                }
2214                
2215                // CIBA
2216                
2217                if (backChannelTokenDeliveryMode != null) {
2218                        o.put("backchannel_token_delivery_mode", backChannelTokenDeliveryMode.getValue());
2219                }
2220                
2221                if (backChannelClientNotificationEndpoint != null) {
2222                        o.put("backchannel_client_notification_endpoint", backChannelClientNotificationEndpoint.toString());
2223                }
2224                
2225                if (backChannelAuthRequestJWSAlg != null) {
2226                        o.put("backchannel_authentication_request_signing_alg", backChannelAuthRequestJWSAlg.getName());
2227                }
2228                
2229                if (backChannelUserCodeParam) {
2230                        o.put("backchannel_user_code_parameter", true);
2231                }
2232                
2233                // Federation
2234                if (CollectionUtils.isNotEmpty(clientRegistrationTypes)) {
2235                        o.put("client_registration_types", Identifier.toStringList(clientRegistrationTypes));
2236                }
2237                if (organizationName != null) {
2238                        o.put("organization_name", organizationName);
2239                }
2240                if (signedJWKSetURI != null) {
2241                        o.put("signed_jwks_uri", signedJWKSetURI.toString());
2242                }
2243
2244                return o;
2245        }
2246        
2247        
2248        @Override
2249        public String toString() {
2250                return toJSONObject().toJSONString();
2251        }
2252        
2253        
2254        /**
2255         * Parses an client metadata instance from the specified JSON object.
2256         *
2257         * @param jsonObject The JSON object to parse. Must not be
2258         *                   {@code null}.
2259         *
2260         * @return The client metadata.
2261         *
2262         * @throws ParseException If the JSON object couldn't be parsed to a
2263         *                        client metadata instance.
2264         */
2265        public static ClientMetadata parse(final JSONObject jsonObject)
2266                throws ParseException {
2267
2268                // Copy JSON object, then parse
2269                return parseFromModifiableJSONObject(new JSONObject(jsonObject));
2270        }
2271
2272
2273        /**
2274         * Parses an client metadata instance from the specified JSON object.
2275         *
2276         * @param jsonObject The JSON object to parse, will be modified by
2277         *                   the parse routine. Must not be {@code null}.
2278         *
2279         * @return The client metadata.
2280         *
2281         * @throws ParseException If the JSON object couldn't be parsed to a
2282         *                        client metadata instance.
2283         */
2284        private static ClientMetadata parseFromModifiableJSONObject(final JSONObject jsonObject)
2285                throws ParseException {
2286
2287                ClientMetadata metadata = new ClientMetadata();
2288
2289                if (jsonObject.get("redirect_uris") != null) {
2290
2291                        Set<URI> redirectURIs = new LinkedHashSet<>();
2292
2293                        for (String uriString: JSONObjectUtils.getStringArray(jsonObject, "redirect_uris")) {
2294                                URI uri;
2295                                try {
2296                                        uri = new URI(uriString);
2297                                } catch (URISyntaxException e) {
2298                                        throw new ParseException("Invalid redirect_uris parameter: " + e.getMessage(), RegistrationError.INVALID_REDIRECT_URI.appendDescription(": " + e.getMessage()));
2299                                }
2300                                redirectURIs.add(uri);
2301                        }
2302                        try {
2303                                metadata.setRedirectionURIs(redirectURIs);
2304                        } catch (IllegalArgumentException e) {
2305                                throw new ParseException("Invalid redirect_uris parameter: " + e.getMessage(), RegistrationError.INVALID_REDIRECT_URI.appendDescription(": " + e.getMessage()));
2306                        }
2307                        jsonObject.remove("redirect_uris");
2308                }
2309
2310                try {
2311
2312                        if (jsonObject.get("scope") != null) {
2313                                metadata.setScope(Scope.parse(JSONObjectUtils.getString(jsonObject, "scope")));
2314                                jsonObject.remove("scope");
2315                        }
2316
2317
2318                        if (jsonObject.get("response_types") != null) {
2319
2320                                Set<ResponseType> responseTypes = new LinkedHashSet<>();
2321
2322                                for (String rt : JSONObjectUtils.getStringArray(jsonObject, "response_types")) {
2323
2324                                        responseTypes.add(ResponseType.parse(rt));
2325                                }
2326
2327                                metadata.setResponseTypes(responseTypes);
2328                                jsonObject.remove("response_types");
2329                        }
2330
2331
2332                        if (jsonObject.get("grant_types") != null) {
2333
2334                                Set<GrantType> grantTypes = new LinkedHashSet<>();
2335
2336                                for (String grant : JSONObjectUtils.getStringArray(jsonObject, "grant_types")) {
2337
2338                                        grantTypes.add(GrantType.parse(grant));
2339                                }
2340
2341                                metadata.setGrantTypes(grantTypes);
2342                                jsonObject.remove("grant_types");
2343                        }
2344
2345
2346                        if (jsonObject.get("contacts") != null) {
2347                                metadata.setEmailContacts(JSONObjectUtils.getStringList(jsonObject, "contacts"));
2348                                jsonObject.remove("contacts");
2349                        }
2350
2351
2352                        // Find lang-tagged client_name params
2353                        Map<LangTag, Object> matches = LangTagUtils.find("client_name", jsonObject);
2354
2355                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2356
2357                                try {
2358                                        metadata.setName((String) entry.getValue(), entry.getKey());
2359
2360                                } catch (ClassCastException e) {
2361
2362                                        throw new ParseException("Invalid client_name (language tag) parameter");
2363                                }
2364
2365                                removeMember(jsonObject, "client_name", entry.getKey());
2366                        }
2367
2368
2369                        matches = LangTagUtils.find("logo_uri", jsonObject);
2370
2371                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2372
2373                                if (entry.getValue() == null) continue;
2374                                
2375                                try {
2376                                        metadata.setLogoURI(new URI((String) entry.getValue()), entry.getKey());
2377                                } catch (Exception e) {
2378                                        throw new ParseException("Invalid logo_uri (language tag) parameter");
2379                                }
2380
2381                                removeMember(jsonObject, "logo_uri", entry.getKey());
2382                        }
2383
2384
2385                        matches = LangTagUtils.find("client_uri", jsonObject);
2386
2387                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2388                                
2389                                if (entry.getValue() == null) continue;
2390
2391                                try {
2392                                        metadata.setURI(new URI((String) entry.getValue()), entry.getKey());
2393                                } catch (Exception e) {
2394                                        throw new ParseException("Invalid client_uri (language tag) parameter: " + e.getMessage());
2395                                }
2396
2397                                removeMember(jsonObject, "client_uri", entry.getKey());
2398                        }
2399
2400
2401                        matches = LangTagUtils.find("policy_uri", jsonObject);
2402
2403                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2404                                
2405                                if (entry.getValue() == null) continue;
2406
2407                                try {
2408                                        metadata.setPolicyURI(new URI((String) entry.getValue()), entry.getKey());
2409                                } catch (Exception e) {
2410                                        throw new ParseException("Invalid policy_uri (language tag) parameter: " + e.getMessage());
2411                                }
2412
2413                                removeMember(jsonObject, "policy_uri", entry.getKey());
2414                        }
2415
2416
2417                        matches = LangTagUtils.find("tos_uri", jsonObject);
2418
2419                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2420                                
2421                                if (entry.getValue() == null) continue;
2422
2423                                try {
2424                                        metadata.setTermsOfServiceURI(new URI((String) entry.getValue()), entry.getKey());
2425                                } catch (Exception e) {
2426                                        throw new ParseException("Invalid tos_uri (language tag) parameter: " + e.getMessage());
2427                                }
2428
2429                                removeMember(jsonObject, "tos_uri", entry.getKey());
2430                        }
2431
2432
2433                        if (jsonObject.get("token_endpoint_auth_method") != null) {
2434                                metadata.setTokenEndpointAuthMethod(ClientAuthenticationMethod.parse(
2435                                        JSONObjectUtils.getString(jsonObject, "token_endpoint_auth_method")));
2436
2437                                jsonObject.remove("token_endpoint_auth_method");
2438                        }
2439
2440
2441                        if (jsonObject.get("token_endpoint_auth_signing_alg") != null) {
2442                                metadata.setTokenEndpointAuthJWSAlg(JWSAlgorithm.parse(
2443                                        JSONObjectUtils.getString(jsonObject, "token_endpoint_auth_signing_alg")));
2444
2445                                jsonObject.remove("token_endpoint_auth_signing_alg");
2446                        }
2447
2448
2449                        if (jsonObject.get("jwks_uri") != null) {
2450                                metadata.setJWKSetURI(JSONObjectUtils.getURI(jsonObject, "jwks_uri"));
2451                                jsonObject.remove("jwks_uri");
2452                        }
2453
2454                        if (jsonObject.get("jwks") != null) {
2455
2456                                try {
2457                                        metadata.setJWKSet(JWKSet.parse(JSONObjectUtils.getJSONObject(jsonObject, "jwks")));
2458
2459                                } catch (java.text.ParseException e) {
2460                                        throw new ParseException("Illegal JWK set: " + e.getMessage(), e);
2461                                }
2462
2463                                jsonObject.remove("jwks");
2464                        }
2465                        
2466                        if (jsonObject.get("request_uris") != null) {
2467                                
2468                                Set<URI> requestURIs = new LinkedHashSet<>();
2469                                
2470                                for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "request_uris")) {
2471                                        
2472                                        try {
2473                                                requestURIs.add(new URI(uriString));
2474                                                
2475                                        } catch (URISyntaxException e) {
2476                                                
2477                                                throw new ParseException("Invalid request_uris parameter");
2478                                        }
2479                                }
2480                                
2481                                metadata.setRequestObjectURIs(requestURIs);
2482                                jsonObject.remove("request_uris");
2483                        }
2484                        
2485                        if (jsonObject.get("request_object_signing_alg") != null) {
2486                                metadata.setRequestObjectJWSAlg(JWSAlgorithm.parse(
2487                                        JSONObjectUtils.getString(jsonObject, "request_object_signing_alg")));
2488                                
2489                                jsonObject.remove("request_object_signing_alg");
2490                        }
2491                        
2492                        if (jsonObject.get("request_object_encryption_alg") != null) {
2493                                metadata.setRequestObjectJWEAlg(JWEAlgorithm.parse(
2494                                        JSONObjectUtils.getString(jsonObject, "request_object_encryption_alg")));
2495                                
2496                                jsonObject.remove("request_object_encryption_alg");
2497                        }
2498                        
2499                        if (jsonObject.get("request_object_encryption_enc") != null) {
2500                                metadata.setRequestObjectJWEEnc(EncryptionMethod.parse(
2501                                        JSONObjectUtils.getString(jsonObject, "request_object_encryption_enc")));
2502                                
2503                                jsonObject.remove("request_object_encryption_enc");
2504                        }
2505
2506                        if (jsonObject.get("software_id") != null) {
2507                                metadata.setSoftwareID(new SoftwareID(JSONObjectUtils.getString(jsonObject, "software_id")));
2508                                jsonObject.remove("software_id");
2509                        }
2510
2511                        if (jsonObject.get("software_version") != null) {
2512                                // Normalize to string, in non-compliant OB profiles
2513                                metadata.setSoftwareVersion(new SoftwareVersion(jsonObject.get("software_version").toString()));
2514                                jsonObject.remove("software_version");
2515                        }
2516                        
2517                        if (jsonObject.get("software_statement") != null) {
2518                                try {
2519                                        metadata.setSoftwareStatement(SignedJWT.parse(JSONObjectUtils.getString(jsonObject, "software_statement")));
2520                                } catch (java.text.ParseException e) {
2521                                        throw new ParseException("Invalid software_statement JWT: " + e.getMessage());
2522                                }
2523                                jsonObject.remove("software_statement");
2524                        }
2525                        
2526                        if (jsonObject.get("tls_client_certificate_bound_access_tokens") != null) {
2527                                metadata.setTLSClientCertificateBoundAccessTokens(JSONObjectUtils.getBoolean(jsonObject, "tls_client_certificate_bound_access_tokens"));
2528                                jsonObject.remove("tls_client_certificate_bound_access_tokens");
2529                        }
2530                        
2531                        if (jsonObject.get("tls_client_auth_subject_dn") != null) {
2532                                metadata.setTLSClientAuthSubjectDN(JSONObjectUtils.getString(jsonObject, "tls_client_auth_subject_dn"));
2533                                jsonObject.remove("tls_client_auth_subject_dn");
2534                        }
2535                        
2536                        if (jsonObject.get("tls_client_auth_san_dns") != null) {
2537                                metadata.setTLSClientAuthSanDNS(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_dns"));
2538                                jsonObject.remove("tls_client_auth_san_dns");
2539                        }
2540                        
2541                        if (jsonObject.get("tls_client_auth_san_uri") != null) {
2542                                metadata.setTLSClientAuthSanURI(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_uri"));
2543                                jsonObject.remove("tls_client_auth_san_uri");
2544                        }
2545                        
2546                        if (jsonObject.get("tls_client_auth_san_ip") != null) {
2547                                metadata.setTLSClientAuthSanIP(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_ip"));
2548                                jsonObject.remove("tls_client_auth_san_ip");
2549                        }
2550                        
2551                        if (jsonObject.get("tls_client_auth_san_email") != null) {
2552                                metadata.setTLSClientAuthSanEmail(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_email"));
2553                                jsonObject.remove("tls_client_auth_san_email");
2554                        }
2555                        
2556                        metadata.ensureExactlyOneCertSubjectFieldForTLSClientAuth();
2557                        
2558                        if (jsonObject.get("authorization_signed_response_alg") != null) {
2559                                metadata.setAuthorizationJWSAlg(JWSAlgorithm.parse(JSONObjectUtils.getString(jsonObject, "authorization_signed_response_alg")));
2560                                jsonObject.remove("authorization_signed_response_alg");
2561                        }
2562                        
2563                        if (jsonObject.get("authorization_encrypted_response_alg") != null) {
2564                                metadata.setAuthorizationJWEAlg(JWEAlgorithm.parse(JSONObjectUtils.getString(jsonObject, "authorization_encrypted_response_alg")));
2565                                jsonObject.remove("authorization_encrypted_response_alg");
2566                        }
2567                        
2568                        if (jsonObject.get("authorization_encrypted_response_enc") != null) {
2569                                metadata.setAuthorizationJWEEnc(EncryptionMethod.parse(JSONObjectUtils.getString(jsonObject, "authorization_encrypted_response_enc")));
2570                                jsonObject.remove("authorization_encrypted_response_enc");
2571                        }
2572                        
2573                        // PAR
2574                        if (jsonObject.get("require_pushed_authorization_requests") != null) {
2575                                metadata.requiresPushedAuthorizationRequests(JSONObjectUtils.getBoolean(jsonObject, "require_pushed_authorization_requests"));
2576                                jsonObject.remove("require_pushed_authorization_requests");
2577                        }
2578                        
2579                        // CIBA
2580                        
2581                        if (jsonObject.get("backchannel_token_delivery_mode") != null) {
2582                                metadata.setBackChannelTokenDeliveryMode(BackChannelTokenDeliveryMode.parse(JSONObjectUtils.getString(jsonObject, "backchannel_token_delivery_mode")));
2583                                jsonObject.remove("backchannel_token_delivery_mode");
2584                        }
2585                        
2586                        if (jsonObject.get("backchannel_client_notification_endpoint") != null) {
2587                                metadata.setBackChannelClientNotificationEndpoint(JSONObjectUtils.getURI(jsonObject, "backchannel_client_notification_endpoint"));
2588                                jsonObject.remove("backchannel_client_notification_endpoint");
2589                        }
2590                        
2591                        if (jsonObject.get("backchannel_authentication_request_signing_alg") != null) {
2592                                metadata.setBackChannelAuthRequestJWSAlg(JWSAlgorithm.parse(JSONObjectUtils.getString(jsonObject, "backchannel_authentication_request_signing_alg")));
2593                                jsonObject.remove("backchannel_authentication_request_signing_alg");
2594                        }
2595                        
2596                        if (jsonObject.get("backchannel_user_code_parameter") != null) {
2597                                metadata.setSupportsBackChannelUserCodeParam(JSONObjectUtils.getBoolean(jsonObject, "backchannel_user_code_parameter"));
2598                                jsonObject.remove("backchannel_user_code_parameter");
2599                        }
2600                        
2601                        
2602                        // Federation
2603                        
2604                        if (jsonObject.get("client_registration_types") != null) {
2605                                List<ClientRegistrationType> types = new LinkedList<>();
2606                                for (String v: JSONObjectUtils.getStringList(jsonObject, "client_registration_types")) {
2607                                        types.add(new ClientRegistrationType(v));
2608                                }
2609                                metadata.setClientRegistrationTypes(types);
2610                                jsonObject.remove("client_registration_types");
2611                        }
2612                        
2613                        if (jsonObject.get("organization_name") != null) {
2614                                metadata.setOrganizationName(JSONObjectUtils.getString(jsonObject, "organization_name"));
2615                                jsonObject.remove("organization_name");
2616                        }
2617                        
2618                        if (jsonObject.get("signed_jwks_uri") != null) {
2619                                metadata.setSignedJWKSetURI(JSONObjectUtils.getURI(jsonObject, "signed_jwks_uri"));
2620                                jsonObject.remove("signed_jwks_uri");
2621                        }
2622
2623                } catch (ParseException | IllegalStateException e) {
2624                        // Insert client_client_metadata error code so that it
2625                        // can be reported back to the client if we have a
2626                        // registration event
2627                        throw new ParseException(
2628                                e.getMessage(),
2629                                RegistrationError.INVALID_CLIENT_METADATA.appendDescription(ErrorObject.removeIllegalChars(": " + e.getMessage())),
2630                                e.getCause()
2631                        );
2632                }
2633
2634                // Remove any remaining top-level client information fields
2635                for (String paramName: ClientInformation.getRegisteredParameterNames()) {
2636                        jsonObject.remove(paramName);
2637                }
2638                // The remaining fields are custom
2639                metadata.customFields = jsonObject;
2640
2641                return metadata;
2642        }
2643
2644
2645        /**
2646         * Removes a JSON object member with the specified base name and
2647         * optional language tag.
2648         *
2649         * @param jsonObject The JSON object. Must not be {@code null}.
2650         * @param name       The base member name. Must not be {@code null}.
2651         * @param langTag    The language tag, {@code null} if none.
2652         */
2653        private static void removeMember(final JSONObject jsonObject, final String name, final LangTag langTag) {
2654
2655                if (langTag == null)
2656                        jsonObject.remove(name);
2657                else
2658                        jsonObject.remove(name + "#" + langTag);
2659        }
2660}