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