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