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