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                ensureExactlyOneCertSubjectFieldForTLSClientAuth();
1817                
1818                JSONObject o;
1819
1820                if (includeCustomFields)
1821                        o = new JSONObject(customFields);
1822                else
1823                        o = new JSONObject();
1824
1825
1826                if (redirectURIs != null) {
1827
1828                        JSONArray uriList = new JSONArray();
1829
1830                        for (URI uri: redirectURIs)
1831                                uriList.add(uri.toString());
1832
1833                        o.put("redirect_uris", uriList);
1834                }
1835
1836
1837                if (scope != null)
1838                        o.put("scope", scope.toString());
1839
1840
1841                if (responseTypes != null) {
1842
1843                        JSONArray rtList = new JSONArray();
1844
1845                        for (ResponseType rt: responseTypes)
1846                                rtList.add(rt.toString());
1847
1848                        o.put("response_types", rtList);
1849                }
1850
1851
1852                if (grantTypes != null) {
1853
1854                        JSONArray grantList = new JSONArray();
1855
1856                        for (GrantType grant: grantTypes)
1857                                grantList.add(grant.toString());
1858
1859                        o.put("grant_types", grantList);
1860                }
1861
1862
1863                if (contacts != null) {
1864                        o.put("contacts", contacts);
1865                }
1866
1867
1868                if (! nameEntries.isEmpty()) {
1869
1870                        for (Map.Entry<LangTag,String> entry: nameEntries.entrySet()) {
1871
1872                                LangTag langTag = entry.getKey();
1873                                String name = entry.getValue();
1874
1875                                if (name == null)
1876                                        continue;
1877
1878                                if (langTag == null)
1879                                        o.put("client_name", entry.getValue());
1880                                else
1881                                        o.put("client_name#" + langTag, entry.getValue());
1882                        }
1883                }
1884
1885
1886                if (! logoURIEntries.isEmpty()) {
1887
1888                        for (Map.Entry<LangTag,URI> entry: logoURIEntries.entrySet()) {
1889
1890                                LangTag langTag = entry.getKey();
1891                                URI uri = entry.getValue();
1892
1893                                if (uri == null)
1894                                        continue;
1895
1896                                if (langTag == null)
1897                                        o.put("logo_uri", entry.getValue().toString());
1898                                else
1899                                        o.put("logo_uri#" + langTag, entry.getValue().toString());
1900                        }
1901                }
1902
1903
1904                if (! uriEntries.isEmpty()) {
1905
1906                        for (Map.Entry<LangTag,URI> entry: uriEntries.entrySet()) {
1907
1908                                LangTag langTag = entry.getKey();
1909                                URI uri = entry.getValue();
1910
1911                                if (uri == null)
1912                                        continue;
1913
1914                                if (langTag == null)
1915                                        o.put("client_uri", entry.getValue().toString());
1916                                else
1917                                        o.put("client_uri#" + langTag, entry.getValue().toString());
1918                        }
1919                }
1920
1921
1922                if (! policyURIEntries.isEmpty()) {
1923
1924                        for (Map.Entry<LangTag,URI> entry: policyURIEntries.entrySet()) {
1925
1926                                LangTag langTag = entry.getKey();
1927                                URI uri = entry.getValue();
1928
1929                                if (uri == null)
1930                                        continue;
1931
1932                                if (langTag == null)
1933                                        o.put("policy_uri", entry.getValue().toString());
1934                                else
1935                                        o.put("policy_uri#" + langTag, entry.getValue().toString());
1936                        }
1937                }
1938
1939
1940                if (! tosURIEntries.isEmpty()) {
1941
1942                        for (Map.Entry<LangTag,URI> entry: tosURIEntries.entrySet()) {
1943
1944                                LangTag langTag = entry.getKey();
1945                                URI uri = entry.getValue();
1946
1947                                if (uri == null)
1948                                        continue;
1949
1950                                if (langTag == null)
1951                                        o.put("tos_uri", entry.getValue().toString());
1952                                else
1953                                        o.put("tos_uri#" + langTag, entry.getValue().toString());
1954                        }
1955                }
1956
1957
1958                if (authMethod != null)
1959                        o.put("token_endpoint_auth_method", authMethod.toString());
1960
1961
1962                if (authJWSAlg != null)
1963                        o.put("token_endpoint_auth_signing_alg", authJWSAlg.getName());
1964
1965
1966                if (jwkSetURI != null)
1967                        o.put("jwks_uri", jwkSetURI.toString());
1968
1969
1970                if (jwkSet != null)
1971                        o.put("jwks", jwkSet.toJSONObject(true)); // prevent private keys from leaking
1972                
1973                
1974                if (requestObjectURIs != null) {
1975                        
1976                        JSONArray uriList = new JSONArray();
1977                        
1978                        for (URI uri: requestObjectURIs)
1979                                uriList.add(uri.toString());
1980                        
1981                        o.put("request_uris", uriList);
1982                }
1983                
1984                
1985                if (requestObjectJWSAlg != null)
1986                        o.put("request_object_signing_alg", requestObjectJWSAlg.getName());
1987                
1988                if (requestObjectJWEAlg != null)
1989                        o.put("request_object_encryption_alg", requestObjectJWEAlg.getName());
1990                
1991                if (requestObjectJWEEnc != null)
1992                        o.put("request_object_encryption_enc", requestObjectJWEEnc.getName());
1993
1994
1995                if (softwareID != null)
1996                        o.put("software_id", softwareID.getValue());
1997
1998                if (softwareVersion != null)
1999                        o.put("software_version", softwareVersion.getValue());
2000                
2001                if (softwareStatement != null)
2002                        o.put("software_statement", softwareStatement.serialize());
2003                
2004                if (getTLSClientCertificateBoundAccessTokens()) {
2005                        o.put("tls_client_certificate_bound_access_tokens", tlsClientCertificateBoundAccessTokens);
2006                }
2007                
2008                if (tlsClientAuthSubjectDN != null)
2009                        o.put("tls_client_auth_subject_dn", tlsClientAuthSubjectDN);
2010                
2011                if (tlsClientAuthSanDNS != null)
2012                        o.put("tls_client_auth_san_dns", tlsClientAuthSanDNS);
2013                
2014                if (tlsClientAuthSanURI != null)
2015                        o.put("tls_client_auth_san_uri", tlsClientAuthSanURI);
2016                
2017                if (tlsClientAuthSanIP != null)
2018                        o.put("tls_client_auth_san_ip", tlsClientAuthSanIP);
2019                
2020                if (tlsClientAuthSanEmail != null)
2021                        o.put("tls_client_auth_san_email", tlsClientAuthSanEmail);
2022                
2023                if (authzJWSAlg != null) {
2024                        o.put("authorization_signed_response_alg", authzJWSAlg.getName());
2025                }
2026                
2027                if (authzJWEAlg != null) {
2028                        o.put("authorization_encrypted_response_alg", authzJWEAlg.getName());
2029                }
2030                
2031                if (authzJWEEnc != null) {
2032                        o.put("authorization_encrypted_response_enc", authzJWEEnc.getName());
2033                }
2034                
2035                // PAR
2036                if (requirePAR) {
2037                        o.put("require_pushed_authorization_requests", true);
2038                }
2039                
2040                // Federation
2041                
2042                if (CollectionUtils.isNotEmpty(clientRegistrationTypes)) {
2043                        o.put("client_registration_types", Identifier.toStringList(clientRegistrationTypes));
2044                        o.put("federation_type", Identifier.toStringList(clientRegistrationTypes)); // TODO deprecated
2045                }
2046                if (organizationName != null) {
2047                        o.put("organization_name", organizationName);
2048                }
2049
2050                return o;
2051        }
2052        
2053        
2054        @Override
2055        public String toString() {
2056                return toJSONObject().toJSONString();
2057        }
2058        
2059        
2060        /**
2061         * Parses an client metadata instance from the specified JSON object.
2062         *
2063         * @param jsonObject The JSON object to parse. Must not be
2064         *                   {@code null}.
2065         *
2066         * @return The client metadata.
2067         *
2068         * @throws ParseException If the JSON object couldn't be parsed to a
2069         *                        client metadata instance.
2070         */
2071        public static ClientMetadata parse(final JSONObject jsonObject)
2072                throws ParseException {
2073
2074                // Copy JSON object, then parse
2075                return parseFromModifiableJSONObject(new JSONObject(jsonObject));
2076        }
2077
2078
2079        /**
2080         * Parses an client metadata instance from the specified JSON object.
2081         *
2082         * @param jsonObject The JSON object to parse, will be modified by
2083         *                   the parse routine. Must not be {@code null}.
2084         *
2085         * @return The client metadata.
2086         *
2087         * @throws ParseException If the JSON object couldn't be parsed to a
2088         *                        client metadata instance.
2089         */
2090        private static ClientMetadata parseFromModifiableJSONObject(final JSONObject jsonObject)
2091                throws ParseException {
2092
2093                ClientMetadata metadata = new ClientMetadata();
2094
2095                if (jsonObject.get("redirect_uris") != null) {
2096
2097                        Set<URI> redirectURIs = new LinkedHashSet<>();
2098
2099                        for (String uriString: JSONObjectUtils.getStringArray(jsonObject, "redirect_uris")) {
2100                                URI uri;
2101                                try {
2102                                        uri = new URI(uriString);
2103                                } catch (URISyntaxException e) {
2104                                        throw new ParseException("Invalid \"redirect_uris\" parameter: " + e.getMessage(), RegistrationError.INVALID_REDIRECT_URI.appendDescription(": " + e.getMessage()));
2105                                }
2106                                redirectURIs.add(uri);
2107                        }
2108                        try {
2109                                metadata.setRedirectionURIs(redirectURIs);
2110                        } catch (IllegalArgumentException e) {
2111                                throw new ParseException("Invalid \"redirect_uris\" parameter: " + e.getMessage(), RegistrationError.INVALID_REDIRECT_URI.appendDescription(": " + e.getMessage()));
2112                        }
2113                        jsonObject.remove("redirect_uris");
2114                }
2115
2116                try {
2117
2118                        if (jsonObject.get("scope") != null) {
2119                                metadata.setScope(Scope.parse(JSONObjectUtils.getString(jsonObject, "scope")));
2120                                jsonObject.remove("scope");
2121                        }
2122
2123
2124                        if (jsonObject.get("response_types") != null) {
2125
2126                                Set<ResponseType> responseTypes = new LinkedHashSet<>();
2127
2128                                for (String rt : JSONObjectUtils.getStringArray(jsonObject, "response_types")) {
2129
2130                                        responseTypes.add(ResponseType.parse(rt));
2131                                }
2132
2133                                metadata.setResponseTypes(responseTypes);
2134                                jsonObject.remove("response_types");
2135                        }
2136
2137
2138                        if (jsonObject.get("grant_types") != null) {
2139
2140                                Set<GrantType> grantTypes = new LinkedHashSet<>();
2141
2142                                for (String grant : JSONObjectUtils.getStringArray(jsonObject, "grant_types")) {
2143
2144                                        grantTypes.add(GrantType.parse(grant));
2145                                }
2146
2147                                metadata.setGrantTypes(grantTypes);
2148                                jsonObject.remove("grant_types");
2149                        }
2150
2151
2152                        if (jsonObject.get("contacts") != null) {
2153                                metadata.setEmailContacts(JSONObjectUtils.getStringList(jsonObject, "contacts"));
2154                                jsonObject.remove("contacts");
2155                        }
2156
2157
2158                        // Find lang-tagged client_name params
2159                        Map<LangTag, Object> matches = LangTagUtils.find("client_name", jsonObject);
2160
2161                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2162
2163                                try {
2164                                        metadata.setName((String) entry.getValue(), entry.getKey());
2165
2166                                } catch (ClassCastException e) {
2167
2168                                        throw new ParseException("Invalid \"client_name\" (language tag) parameter");
2169                                }
2170
2171                                removeMember(jsonObject, "client_name", entry.getKey());
2172                        }
2173
2174
2175                        matches = LangTagUtils.find("logo_uri", jsonObject);
2176
2177                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2178
2179                                if (entry.getValue() == null) continue;
2180                                
2181                                try {
2182                                        metadata.setLogoURI(new URI((String) entry.getValue()), entry.getKey());
2183                                } catch (Exception e) {
2184                                        throw new ParseException("Invalid \"logo_uri\" (language tag) parameter");
2185                                }
2186
2187                                removeMember(jsonObject, "logo_uri", entry.getKey());
2188                        }
2189
2190
2191                        matches = LangTagUtils.find("client_uri", jsonObject);
2192
2193                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2194                                
2195                                if (entry.getValue() == null) continue;
2196
2197                                try {
2198                                        metadata.setURI(new URI((String) entry.getValue()), entry.getKey());
2199                                } catch (Exception e) {
2200                                        throw new ParseException("Invalid \"client_uri\" (language tag) parameter: " + e.getMessage());
2201                                }
2202
2203                                removeMember(jsonObject, "client_uri", entry.getKey());
2204                        }
2205
2206
2207                        matches = LangTagUtils.find("policy_uri", jsonObject);
2208
2209                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2210                                
2211                                if (entry.getValue() == null) continue;
2212
2213                                try {
2214                                        metadata.setPolicyURI(new URI((String) entry.getValue()), entry.getKey());
2215                                } catch (Exception e) {
2216                                        throw new ParseException("Invalid \"policy_uri\" (language tag) parameter: " + e.getMessage());
2217                                }
2218
2219                                removeMember(jsonObject, "policy_uri", entry.getKey());
2220                        }
2221
2222
2223                        matches = LangTagUtils.find("tos_uri", jsonObject);
2224
2225                        for (Map.Entry<LangTag, Object> entry : matches.entrySet()) {
2226                                
2227                                if (entry.getValue() == null) continue;
2228
2229                                try {
2230                                        metadata.setTermsOfServiceURI(new URI((String) entry.getValue()), entry.getKey());
2231                                } catch (Exception e) {
2232                                        throw new ParseException("Invalid \"tos_uri\" (language tag) parameter: " + e.getMessage());
2233                                }
2234
2235                                removeMember(jsonObject, "tos_uri", entry.getKey());
2236                        }
2237
2238
2239                        if (jsonObject.get("token_endpoint_auth_method") != null) {
2240                                metadata.setTokenEndpointAuthMethod(ClientAuthenticationMethod.parse(
2241                                        JSONObjectUtils.getString(jsonObject, "token_endpoint_auth_method")));
2242
2243                                jsonObject.remove("token_endpoint_auth_method");
2244                        }
2245
2246
2247                        if (jsonObject.get("token_endpoint_auth_signing_alg") != null) {
2248                                metadata.setTokenEndpointAuthJWSAlg(JWSAlgorithm.parse(
2249                                        JSONObjectUtils.getString(jsonObject, "token_endpoint_auth_signing_alg")));
2250
2251                                jsonObject.remove("token_endpoint_auth_signing_alg");
2252                        }
2253
2254
2255                        if (jsonObject.get("jwks_uri") != null) {
2256                                metadata.setJWKSetURI(JSONObjectUtils.getURI(jsonObject, "jwks_uri"));
2257                                jsonObject.remove("jwks_uri");
2258                        }
2259
2260                        if (jsonObject.get("jwks") != null) {
2261
2262                                try {
2263                                        metadata.setJWKSet(JWKSet.parse(JSONObjectUtils.getJSONObject(jsonObject, "jwks")));
2264
2265                                } catch (java.text.ParseException e) {
2266                                        throw new ParseException(e.getMessage(), e);
2267                                }
2268
2269                                jsonObject.remove("jwks");
2270                        }
2271                        
2272                        if (jsonObject.get("request_uris") != null) {
2273                                
2274                                Set<URI> requestURIs = new LinkedHashSet<>();
2275                                
2276                                for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "request_uris")) {
2277                                        
2278                                        try {
2279                                                requestURIs.add(new URI(uriString));
2280                                                
2281                                        } catch (URISyntaxException e) {
2282                                                
2283                                                throw new ParseException("Invalid \"request_uris\" parameter");
2284                                        }
2285                                }
2286                                
2287                                metadata.setRequestObjectURIs(requestURIs);
2288                                jsonObject.remove("request_uris");
2289                        }
2290                        
2291                        if (jsonObject.get("request_object_signing_alg") != null) {
2292                                metadata.setRequestObjectJWSAlg(JWSAlgorithm.parse(
2293                                        JSONObjectUtils.getString(jsonObject, "request_object_signing_alg")));
2294                                
2295                                jsonObject.remove("request_object_signing_alg");
2296                        }
2297                        
2298                        if (jsonObject.get("request_object_encryption_alg") != null) {
2299                                metadata.setRequestObjectJWEAlg(JWEAlgorithm.parse(
2300                                        JSONObjectUtils.getString(jsonObject, "request_object_encryption_alg")));
2301                                
2302                                jsonObject.remove("request_object_encryption_alg");
2303                        }
2304                        
2305                        if (jsonObject.get("request_object_encryption_enc") != null) {
2306                                metadata.setRequestObjectJWEEnc(EncryptionMethod.parse(
2307                                        JSONObjectUtils.getString(jsonObject, "request_object_encryption_enc")));
2308                                
2309                                jsonObject.remove("request_object_encryption_enc");
2310                        }
2311
2312                        if (jsonObject.get("software_id") != null) {
2313                                metadata.setSoftwareID(new SoftwareID(JSONObjectUtils.getString(jsonObject, "software_id")));
2314                                jsonObject.remove("software_id");
2315                        }
2316
2317                        if (jsonObject.get("software_version") != null) {
2318                                metadata.setSoftwareVersion(new SoftwareVersion(JSONObjectUtils.getString(jsonObject, "software_version")));
2319                                jsonObject.remove("software_version");
2320                        }
2321                        
2322                        if (jsonObject.get("software_statement") != null) {
2323                                try {
2324                                        metadata.setSoftwareStatement(SignedJWT.parse(JSONObjectUtils.getString(jsonObject, "software_statement")));
2325                                } catch (java.text.ParseException e) {
2326                                        throw new ParseException("Invalid software_statement JWT: " + e.getMessage());
2327                                }
2328                                jsonObject.remove("software_statement");
2329                        }
2330                        
2331                        if (jsonObject.get("tls_client_certificate_bound_access_tokens") != null) {
2332                                metadata.setTLSClientCertificateBoundAccessTokens(JSONObjectUtils.getBoolean(jsonObject, "tls_client_certificate_bound_access_tokens"));
2333                                jsonObject.remove("tls_client_certificate_bound_access_tokens");
2334                        }
2335                        
2336                        if (jsonObject.get("tls_client_auth_subject_dn") != null) {
2337                                metadata.setTLSClientAuthSubjectDN(JSONObjectUtils.getString(jsonObject, "tls_client_auth_subject_dn"));
2338                                jsonObject.remove("tls_client_auth_subject_dn");
2339                        }
2340                        
2341                        if (jsonObject.get("tls_client_auth_san_dns") != null) {
2342                                metadata.setTLSClientAuthSanDNS(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_dns"));
2343                                jsonObject.remove("tls_client_auth_san_dns");
2344                        }
2345                        
2346                        if (jsonObject.get("tls_client_auth_san_uri") != null) {
2347                                metadata.setTLSClientAuthSanURI(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_uri"));
2348                                jsonObject.remove("tls_client_auth_san_uri");
2349                        }
2350                        
2351                        if (jsonObject.get("tls_client_auth_san_ip") != null) {
2352                                metadata.setTLSClientAuthSanIP(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_ip"));
2353                                jsonObject.remove("tls_client_auth_san_ip");
2354                        }
2355                        
2356                        if (jsonObject.get("tls_client_auth_san_email") != null) {
2357                                metadata.setTLSClientAuthSanEmail(JSONObjectUtils.getString(jsonObject, "tls_client_auth_san_email"));
2358                                jsonObject.remove("tls_client_auth_san_email");
2359                        }
2360                        
2361                        metadata.ensureExactlyOneCertSubjectFieldForTLSClientAuth();
2362                        
2363                        if (jsonObject.get("authorization_signed_response_alg") != null) {
2364                                metadata.setAuthorizationJWSAlg(JWSAlgorithm.parse(JSONObjectUtils.getString(jsonObject, "authorization_signed_response_alg")));
2365                                jsonObject.remove("authorization_signed_response_alg");
2366                        }
2367                        
2368                        if (jsonObject.get("authorization_encrypted_response_alg") != null) {
2369                                metadata.setAuthorizationJWEAlg(JWEAlgorithm.parse(JSONObjectUtils.getString(jsonObject, "authorization_encrypted_response_alg")));
2370                                jsonObject.remove("authorization_encrypted_response_alg");
2371                        }
2372                        
2373                        if (jsonObject.get("authorization_encrypted_response_enc") != null) {
2374                                metadata.setAuthorizationJWEEnc(EncryptionMethod.parse(JSONObjectUtils.getString(jsonObject, "authorization_encrypted_response_enc")));
2375                                jsonObject.remove("authorization_encrypted_response_enc");
2376                        }
2377                        
2378                        // PAR
2379                        if (jsonObject.get("require_pushed_authorization_requests") != null) {
2380                                metadata.requiresPushedAuthorizationRequests(JSONObjectUtils.getBoolean(jsonObject, "require_pushed_authorization_requests"));
2381                                jsonObject.remove("require_pushed_authorization_requests");
2382                        }
2383                        
2384                        // Federation
2385                        
2386                        if (jsonObject.get("client_registration_types") != null) {
2387                                List<ClientRegistrationType> types = new LinkedList<>();
2388                                for (String v: JSONObjectUtils.getStringList(jsonObject, "client_registration_types")) {
2389                                        types.add(new ClientRegistrationType(v));
2390                                }
2391                                metadata.setClientRegistrationTypes(types);
2392                                jsonObject.remove("client_registration_types");
2393                        } else if (jsonObject.get("federation_type") != null) {
2394                                // TODO deprecated
2395                                List<ClientRegistrationType> types = new LinkedList<>();
2396                                for (String v: JSONObjectUtils.getStringList(jsonObject, "federation_type")) {
2397                                        types.add(new ClientRegistrationType(v));
2398                                }
2399                                metadata.setClientRegistrationTypes(types);
2400                                jsonObject.remove("federation_type");
2401                        }
2402                        
2403                        if (jsonObject.get("organization_name") != null) {
2404                                metadata.setOrganizationName(JSONObjectUtils.getString(jsonObject, "organization_name"));
2405                                jsonObject.remove("organization_name");
2406                        }
2407
2408                } catch (ParseException | IllegalStateException e) {
2409                        // Insert client_client_metadata error code so that it
2410                        // can be reported back to the client if we have a
2411                        // registration event
2412                        throw new ParseException(e.getMessage(), RegistrationError.INVALID_CLIENT_METADATA.appendDescription(": " + e.getMessage()), e.getCause());
2413                }
2414
2415                // The remaining fields are custom
2416                metadata.customFields = jsonObject;
2417
2418                return metadata;
2419        }
2420
2421
2422        /**
2423         * Removes a JSON object member with the specified base name and
2424         * optional language tag.
2425         *
2426         * @param jsonObject The JSON object. Must not be {@code null}.
2427         * @param name       The base member name. Must not be {@code null}.
2428         * @param langTag    The language tag, {@code null} if none.
2429         */
2430        private static void removeMember(final JSONObject jsonObject, final String name, final LangTag langTag) {
2431
2432                if (langTag == null)
2433                        jsonObject.remove(name);
2434                else
2435                        jsonObject.remove(name + "#" + langTag);
2436        }
2437}