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