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