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