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