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