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