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