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