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