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.openid.connect.sdk.rp; 019 020 021import java.net.URI; 022import java.net.URISyntaxException; 023import java.util.*; 024 025import net.minidev.json.JSONArray; 026import net.minidev.json.JSONObject; 027 028import com.nimbusds.jose.EncryptionMethod; 029import com.nimbusds.jose.JWEAlgorithm; 030import com.nimbusds.jose.JWSAlgorithm; 031import com.nimbusds.oauth2.sdk.ParseException; 032import com.nimbusds.oauth2.sdk.client.ClientMetadata; 033import com.nimbusds.oauth2.sdk.client.RegistrationError; 034import com.nimbusds.oauth2.sdk.util.CollectionUtils; 035import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 036import com.nimbusds.oauth2.sdk.util.URIUtils; 037import com.nimbusds.openid.connect.sdk.SubjectType; 038import com.nimbusds.openid.connect.sdk.claims.ACR; 039import com.nimbusds.openid.connect.sdk.id.SectorID; 040 041 042/** 043 * OpenID Connect client metadata. 044 * 045 * <p>Related specifications: 046 * 047 * <ul> 048 * <li>OpenID Connect Dynamic Client Registration 1.0, section 2. 049 * <li>OpenID Connect Session Management 1.0, section 5.1.1 (draft 28). 050 * <li>OpenID Connect Front-Channel Logout 1.0, section 2 (draft 02). 051 * <li>OpenID Connect Back-Channel Logout 1.0, section 2.2 (draft 04). 052 * <li>OpenID Connect Federation 1.0 (draft 11). 053 * <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591), section 054 * 2. 055 * <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound 056 * Access Tokens (RFC 8705), sections 2.1.2 and 3.4. 057 * <li>Financial-grade API: JWT Secured Authorization Response Mode for 058 * OAuth 2.0 (JARM) 059 * </ul> 060 */ 061public class OIDCClientMetadata extends ClientMetadata { 062 063 064 /** 065 * The registered parameter names. 066 */ 067 private static final Set<String> REGISTERED_PARAMETER_NAMES; 068 069 070 static { 071 // Start with the base OAuth 2.0 client params 072 Set<String> p = new HashSet<>(ClientMetadata.getRegisteredParameterNames()); 073 074 // OIDC params 075 p.add("application_type"); 076 p.add("subject_type"); 077 p.add("sector_identifier_uri"); 078 p.add("id_token_signed_response_alg"); 079 p.add("id_token_encrypted_response_alg"); 080 p.add("id_token_encrypted_response_enc"); 081 p.add("userinfo_signed_response_alg"); 082 p.add("userinfo_encrypted_response_alg"); 083 p.add("userinfo_encrypted_response_enc"); 084 p.add("default_max_age"); 085 p.add("require_auth_time"); 086 p.add("default_acr_values"); 087 p.add("initiate_login_uri"); 088 089 // OIDC session 090 p.add("post_logout_redirect_uris"); 091 092 // OIDC logout 093 p.add("frontchannel_logout_uri"); 094 p.add("frontchannel_logout_session_required"); 095 p.add("backchannel_logout_uri"); 096 p.add("backchannel_logout_session_required"); 097 098 REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p); 099 } 100 101 102 /** 103 * The client application type. 104 */ 105 private ApplicationType applicationType; 106 107 108 /** 109 * The subject identifier type for responses to this client. 110 */ 111 private SubjectType subjectType; 112 113 114 /** 115 * Sector identifier URI. 116 */ 117 private URI sectorIDURI; 118 119 120 /** 121 * The JSON Web Signature (JWS) algorithm required for the ID Tokens 122 * issued to this client. 123 */ 124 private JWSAlgorithm idTokenJWSAlg; 125 126 127 /** 128 * The JSON Web Encryption (JWE) algorithm required for the ID Tokens 129 * issued to this client. 130 */ 131 private JWEAlgorithm idTokenJWEAlg; 132 133 134 /** 135 * The JSON Web Encryption (JWE) method required for the ID Tokens 136 * issued to this client. 137 */ 138 private EncryptionMethod idTokenJWEEnc; 139 140 141 /** 142 * The JSON Web Signature (JWS) algorithm required for the UserInfo 143 * responses to this client. 144 */ 145 private JWSAlgorithm userInfoJWSAlg; 146 147 148 /** 149 * The JSON Web Encryption (JWE) algorithm required for the UserInfo 150 * responses to this client. 151 */ 152 private JWEAlgorithm userInfoJWEAlg; 153 154 155 /** 156 * The JSON Web Encryption (JWE) method required for the UserInfo 157 * responses to this client. 158 */ 159 private EncryptionMethod userInfoJWEEnc; 160 161 162 /** 163 * The default max authentication age, in seconds. If not specified 0. 164 */ 165 private int defaultMaxAge = -1; 166 167 168 /** 169 * If {@code true} the {@code auth_time} claim in the ID Token is 170 * required by default. 171 */ 172 private boolean requiresAuthTime; 173 174 175 /** 176 * The default Authentication Context Class Reference (ACR) values, by 177 * order of preference. 178 */ 179 private List<ACR> defaultACRs; 180 181 182 /** 183 * Authorisation server initiated login HTTPS URI. 184 */ 185 private URI initiateLoginURI; 186 187 188 /** 189 * Logout redirection URIs. 190 */ 191 private Set<URI> postLogoutRedirectURIs; 192 193 194 /** 195 * Front-channel logout URI. 196 */ 197 private URI frontChannelLogoutURI; 198 199 200 /** 201 * Indicates requirement for a session identifier on front-channel 202 * logout. 203 */ 204 private boolean frontChannelLogoutSessionRequired = false; 205 206 207 /** 208 * Back-channel logout URI. 209 */ 210 private URI backChannelLogoutURI; 211 212 213 /** 214 * Indicates requirement for a session identifier on back-channel 215 * logout. 216 */ 217 private boolean backChannelLogoutSessionRequired = false; 218 219 220 /** 221 * Creates a new OpenID Connect client metadata instance. 222 */ 223 public OIDCClientMetadata() { 224 225 super(); 226 } 227 228 229 /** 230 * Creates a new OpenID Connect client metadata instance from the 231 * specified base OAuth 2.0 client metadata. 232 * 233 * @param metadata The base OAuth 2.0 client metadata. Must not be 234 * {@code null}. 235 */ 236 public OIDCClientMetadata(final ClientMetadata metadata) { 237 238 super(metadata); 239 } 240 241 242 /** 243 * Gets the registered (standard) OpenID Connect client metadata 244 * parameter names. 245 * 246 * @return The registered OpenID Connect parameter names, as an 247 * unmodifiable set. 248 */ 249 public static Set<String> getRegisteredParameterNames() { 250 251 return REGISTERED_PARAMETER_NAMES; 252 } 253 254 255 /** 256 * Gets the client application type. Corresponds to the 257 * {@code application_type} client metadata field. 258 * 259 * @return The client application type, {@code null} if not specified. 260 */ 261 public ApplicationType getApplicationType() { 262 263 return applicationType; 264 } 265 266 267 /** 268 * Sets the client application type. Corresponds to the 269 * {@code application_type} client metadata field. 270 * 271 * @param applicationType The client application type, {@code null} if 272 * not specified. 273 */ 274 public void setApplicationType(final ApplicationType applicationType) { 275 276 this.applicationType = applicationType; 277 } 278 279 280 /** 281 * Gets the subject identifier type for responses to this client. 282 * Corresponds to the {@code subject_type} client metadata field. 283 * 284 * @return The subject identifier type, {@code null} if not specified. 285 */ 286 public SubjectType getSubjectType() { 287 288 return subjectType; 289 } 290 291 292 /** 293 * Sets the subject identifier type for responses to this client. 294 * Corresponds to the {@code subject_type} client metadata field. 295 * 296 * @param subjectType The subject identifier type, {@code null} if not 297 * specified. 298 */ 299 public void setSubjectType(final SubjectType subjectType) { 300 301 this.subjectType = subjectType; 302 } 303 304 305 /** 306 * Gets the sector identifier URI. Corresponds to the 307 * {@code sector_identifier_uri} client metadata field. 308 * 309 * @return The sector identifier URI, {@code null} if not specified. 310 */ 311 public URI getSectorIDURI() { 312 313 return sectorIDURI; 314 } 315 316 317 /** 318 * Sets the sector identifier URI. Corresponds to the 319 * {@code sector_identifier_uri} client metadata field. 320 * 321 * @param sectorIDURI The sector identifier URI, {@code null} if not 322 * specified. 323 */ 324 public void setSectorIDURI(final URI sectorIDURI) { 325 326 if (sectorIDURI != null) { 327 SectorID.ensureHTTPScheme(sectorIDURI); 328 SectorID.ensureHostComponent(sectorIDURI); 329 } 330 331 this.sectorIDURI = sectorIDURI; 332 } 333 334 335 /** 336 * Resolves the sector identifier from the client metadata. 337 * 338 * @return The sector identifier, {@code null} if the subject type is 339 * set to public. 340 * 341 * @throws IllegalStateException If resolution failed due to incomplete 342 * or inconsistent metadata. 343 */ 344 public SectorID resolveSectorID() { 345 346 if (! SubjectType.PAIRWISE.equals(getSubjectType())) { 347 // subject type is not pairwise or null 348 return null; 349 } 350 351 // Check sector identifier URI first 352 if (getSectorIDURI() != null) { 353 return new SectorID(getSectorIDURI()); 354 } 355 356 // Check redirect URIs second 357 if (CollectionUtils.isEmpty(getRedirectionURIs())) { 358 throw new IllegalStateException("Couldn't resolve sector ID: Missing redirect_uris"); 359 } 360 361 if (getRedirectionURIs().size() > 1) { 362 throw new IllegalStateException("Couldn't resolve sector ID: More than one redirect_uri, sector_identifier_uri not specified"); 363 } 364 365 return new SectorID(getRedirectionURIs().iterator().next()); 366 } 367 368 369 /** 370 * Gets the JSON Web Signature (JWS) algorithm required for the ID 371 * Tokens issued to this client. Corresponds to the 372 * {@code id_token_signed_response_alg} client metadata field. 373 * 374 * @return The JWS algorithm, {@code null} if not specified. 375 */ 376 public JWSAlgorithm getIDTokenJWSAlg() { 377 378 return idTokenJWSAlg; 379 } 380 381 382 /** 383 * Sets the JSON Web Signature (JWS) algorithm required for the ID 384 * Tokens issued to this client. Corresponds to the 385 * {@code id_token_signed_response_alg} client metadata field. 386 * 387 * @param idTokenJWSAlg The JWS algorithm, {@code null} if not 388 * specified. 389 */ 390 public void setIDTokenJWSAlg(final JWSAlgorithm idTokenJWSAlg) { 391 392 this.idTokenJWSAlg = idTokenJWSAlg; 393 } 394 395 396 /** 397 * Gets the JSON Web Encryption (JWE) algorithm required for the ID 398 * Tokens issued to this client. Corresponds to the 399 * {@code id_token_encrypted_response_alg} client metadata field. 400 * 401 * @return The JWE algorithm, {@code null} if not specified. 402 */ 403 public JWEAlgorithm getIDTokenJWEAlg() { 404 405 return idTokenJWEAlg; 406 } 407 408 409 /** 410 * Sets the JSON Web Encryption (JWE) algorithm required for the ID 411 * Tokens issued to this client. Corresponds to the 412 * {@code id_token_encrypted_response_alg} client metadata field. 413 * 414 * @param idTokenJWEAlg The JWE algorithm, {@code null} if not 415 * specified. 416 */ 417 public void setIDTokenJWEAlg(final JWEAlgorithm idTokenJWEAlg) { 418 419 this.idTokenJWEAlg = idTokenJWEAlg; 420 } 421 422 423 /** 424 * Gets the JSON Web Encryption (JWE) method required for the ID Tokens 425 * issued to this client. Corresponds to the 426 * {@code id_token_encrypted_response_enc} client metadata field. 427 * 428 * @return The JWE method, {@code null} if not specified. 429 */ 430 public EncryptionMethod getIDTokenJWEEnc() { 431 432 return idTokenJWEEnc; 433 } 434 435 436 /** 437 * Sets the JSON Web Encryption (JWE) method required for the ID Tokens 438 * issued to this client. Corresponds to the 439 * {@code id_token_encrypted_response_enc} client metadata field. 440 * 441 * @param idTokenJWEEnc The JWE method, {@code null} if not specified. 442 */ 443 public void setIDTokenJWEEnc(final EncryptionMethod idTokenJWEEnc) { 444 445 this.idTokenJWEEnc = idTokenJWEEnc; 446 } 447 448 449 /** 450 * Gets the JSON Web Signature (JWS) algorithm required for the 451 * UserInfo responses to this client. Corresponds to the 452 * {@code userinfo_signed_response_alg} client metadata field. 453 * 454 * @return The JWS algorithm, {@code null} if not specified. 455 */ 456 public JWSAlgorithm getUserInfoJWSAlg() { 457 458 return userInfoJWSAlg; 459 } 460 461 462 /** 463 * Sets the JSON Web Signature (JWS) algorithm required for the 464 * UserInfo responses to this client. Corresponds to the 465 * {@code userinfo_signed_response_alg} client metadata field. 466 * 467 * @param userInfoJWSAlg The JWS algorithm, {@code null} if not 468 * specified. 469 */ 470 public void setUserInfoJWSAlg(final JWSAlgorithm userInfoJWSAlg) { 471 472 this.userInfoJWSAlg = userInfoJWSAlg; 473 } 474 475 476 /** 477 * Gets the JSON Web Encryption (JWE) algorithm required for the 478 * UserInfo responses to this client. Corresponds to the 479 * {@code userinfo_encrypted_response_alg} client metadata field. 480 * 481 * @return The JWE algorithm, {@code null} if not specified. 482 */ 483 public JWEAlgorithm getUserInfoJWEAlg() { 484 485 return userInfoJWEAlg; 486 } 487 488 489 /** 490 * Sets the JSON Web Encryption (JWE) algorithm required for the 491 * UserInfo responses to this client. Corresponds to the 492 * {@code userinfo_encrypted_response_alg} client metadata field. 493 * 494 * @param userInfoJWEAlg The JWE algorithm, {@code null} if not 495 * specified. 496 */ 497 public void setUserInfoJWEAlg(final JWEAlgorithm userInfoJWEAlg) { 498 499 this.userInfoJWEAlg = userInfoJWEAlg; 500 } 501 502 503 /** 504 * Gets the JSON Web Encryption (JWE) method required for the UserInfo 505 * responses to this client. Corresponds to the 506 * {@code userinfo_encrypted_response_enc} client metadata field. 507 * 508 * @return The JWE method, {@code null} if not specified. 509 */ 510 public EncryptionMethod getUserInfoJWEEnc() { 511 512 return userInfoJWEEnc; 513 } 514 515 516 /** 517 * Sets the JSON Web Encryption (JWE) method required for the UserInfo 518 * responses to this client. Corresponds to the 519 * {@code userinfo_encrypted_response_enc} client metadata field. 520 * 521 * @param userInfoJWEEnc The JWE method, {@code null} if not specified. 522 */ 523 public void setUserInfoJWEEnc(final EncryptionMethod userInfoJWEEnc) { 524 525 this.userInfoJWEEnc = userInfoJWEEnc; 526 } 527 528 529 /** 530 * Gets the default maximum authentication age. Corresponds to the 531 * {@code default_max_age} client metadata field. 532 * 533 * @return The default max authentication age, in seconds. If not 534 * specified -1. 535 */ 536 public int getDefaultMaxAge() { 537 538 return defaultMaxAge; 539 } 540 541 542 /** 543 * Sets the default maximum authentication age. Corresponds to the 544 * {@code default_max_age} client metadata field. 545 * 546 * @param defaultMaxAge The default max authentication age, in seconds. 547 * If not specified -1. 548 */ 549 public void setDefaultMaxAge(final int defaultMaxAge) { 550 551 this.defaultMaxAge = defaultMaxAge; 552 } 553 554 555 /** 556 * Gets the default requirement for the {@code auth_time} claim in the 557 * ID Token. Corresponds to the {@code require_auth_time} client 558 * metadata field. 559 * 560 * @return If {@code true} the {@code auth_Time} claim in the ID Token 561 * is required by default. 562 */ 563 public boolean requiresAuthTime() { 564 565 return requiresAuthTime; 566 } 567 568 569 /** 570 * Sets the default requirement for the {@code auth_time} claim in the 571 * ID Token. Corresponds to the {@code require_auth_time} client 572 * metadata field. 573 * 574 * @param requiresAuthTime If {@code true} the {@code auth_Time} claim 575 * in the ID Token is required by default. 576 */ 577 public void requiresAuthTime(final boolean requiresAuthTime) { 578 579 this.requiresAuthTime = requiresAuthTime; 580 } 581 582 583 /** 584 * Gets the default Authentication Context Class Reference (ACR) 585 * values. Corresponds to the {@code default_acr_values} client 586 * metadata field. 587 * 588 * @return The default ACR values, by order of preference, 589 * {@code null} if not specified. 590 */ 591 public List<ACR> getDefaultACRs() { 592 593 return defaultACRs; 594 } 595 596 597 /** 598 * Sets the default Authentication Context Class Reference (ACR) 599 * values. Corresponds to the {@code default_acr_values} client 600 * metadata field. 601 * 602 * @param defaultACRs The default ACRs, by order of preference, 603 * {@code null} if not specified. 604 */ 605 public void setDefaultACRs(final List<ACR> defaultACRs) { 606 607 this.defaultACRs = defaultACRs; 608 } 609 610 611 /** 612 * Gets the HTTPS URI that the authorisation server can call to 613 * initiate a login at the client. Corresponds to the 614 * {@code initiate_login_uri} client metadata field. 615 * 616 * @return The login URI, {@code null} if not specified. 617 */ 618 public URI getInitiateLoginURI() { 619 620 return initiateLoginURI; 621 } 622 623 624 /** 625 * Sets the HTTPS URI that the authorisation server can call to 626 * initiate a login at the client. Corresponds to the 627 * {@code initiate_login_uri} client metadata field. 628 * 629 * @param loginURI The login URI, {@code null} if not specified. The 630 * URI scheme must be https. 631 */ 632 public void setInitiateLoginURI(final URI loginURI) { 633 634 URIUtils.ensureSchemeIsHTTPS(loginURI); 635 this.initiateLoginURI = loginURI; 636 } 637 638 639 /** 640 * Gets the post logout redirection URIs. Corresponds to the 641 * {@code post_logout_redirect_uris} client metadata field. 642 * 643 * @return The logout redirection URIs, {@code null} if not specified. 644 */ 645 public Set<URI> getPostLogoutRedirectionURIs() { 646 647 return postLogoutRedirectURIs; 648 } 649 650 651 /** 652 * Sets the post logout redirection URIs. Corresponds to the 653 * {@code post_logout_redirect_uris} client metadata field. 654 * 655 * @param logoutURIs The post logout redirection URIs, {@code null} if 656 * not specified. 657 */ 658 public void setPostLogoutRedirectionURIs(final Set<URI> logoutURIs) { 659 660 if (logoutURIs != null) { 661 for (URI uri: logoutURIs) { 662 URIUtils.ensureSchemeIsNotProhibited(uri, PROHIBITED_REDIRECT_URI_SCHEMES); 663 } 664 } 665 postLogoutRedirectURIs = logoutURIs; 666 } 667 668 669 /** 670 * Gets the front-channel logout URI. Corresponds to the 671 * {@code frontchannel_logout_uri} client metadata field. 672 * 673 * @return The front-channel logout URI, {@code null} if not specified. 674 */ 675 public URI getFrontChannelLogoutURI() { 676 677 return frontChannelLogoutURI; 678 } 679 680 681 /** 682 * Sets the front-channel logout URI. Corresponds to the 683 * {@code frontchannel_logout_uri} client metadata field. 684 * 685 * @param frontChannelLogoutURI The front-channel logout URI, 686 * {@code null} if not specified. The URI 687 * scheme must be https or http. 688 */ 689 public void setFrontChannelLogoutURI(final URI frontChannelLogoutURI) { 690 691 URIUtils.ensureSchemeIsHTTPSorHTTP(frontChannelLogoutURI); 692 this.frontChannelLogoutURI = frontChannelLogoutURI; 693 } 694 695 696 /** 697 * Gets the requirement for a session identifier on front-channel 698 * logout. Corresponds to 699 * the {@code frontchannel_logout_session_required} client metadata 700 * field. 701 * 702 * @return {@code true} if a session identifier is required, else 703 * {@code false}. 704 */ 705 public boolean requiresFrontChannelLogoutSession() { 706 707 return frontChannelLogoutSessionRequired; 708 } 709 710 711 /** 712 * Sets the requirement for a session identifier on front-channel 713 * logout. Corresponds to 714 * the {@code frontchannel_logout_session_required} client metadata 715 * field. 716 * 717 * @param requiresSession {@code true} if a session identifier is 718 * required, else {@code false}. 719 */ 720 public void requiresFrontChannelLogoutSession(boolean requiresSession) { 721 722 frontChannelLogoutSessionRequired = requiresSession; 723 } 724 725 726 /** 727 * Gets the back-channel logout URI. Corresponds to the 728 * {@code backchannel_logout_uri} client metadata field. 729 * 730 * @return The back-channel logout URI, {@code null} if not specified. 731 */ 732 public URI getBackChannelLogoutURI() { 733 734 return backChannelLogoutURI; 735 } 736 737 738 /** 739 * Sets the back-channel logout URI. Corresponds to the 740 * {@code backchannel_logout_uri} client metadata field. 741 * 742 * @param backChannelLogoutURI The back-channel logout URI, 743 * {@code null} if not specified. The URI 744 * scheme must be https or http. 745 */ 746 public void setBackChannelLogoutURI(final URI backChannelLogoutURI) { 747 748 URIUtils.ensureSchemeIsHTTPSorHTTP(backChannelLogoutURI); 749 this.backChannelLogoutURI = backChannelLogoutURI; 750 } 751 752 753 /** 754 * Gets the requirement for a session identifier on back-channel 755 * logout. Corresponds to 756 * the {@code backchannel_logout_session_required} client metadata 757 * field. 758 * 759 * @return {@code true} if a session identifier is required, else 760 * {@code false}. 761 */ 762 public boolean requiresBackChannelLogoutSession() { 763 764 return backChannelLogoutSessionRequired; 765 } 766 767 768 /** 769 * Sets the requirement for a session identifier on back-channel 770 * logout. Corresponds to 771 * the {@code backchannel_logout_session_required} client metadata 772 * field. 773 * 774 * @param requiresSession {@code true} if a session identifier is 775 * required, else {@code false}. 776 */ 777 public void requiresBackChannelLogoutSession(final boolean requiresSession) { 778 779 backChannelLogoutSessionRequired = requiresSession; 780 } 781 782 783 /** 784 * Applies the client metadata defaults where no values have been 785 * specified. 786 * 787 * <ul> 788 * <li>The response types default to {@code ["code"]}. 789 * <li>The grant types default to {@code "authorization_code".} 790 * <li>The client authentication method defaults to 791 * "client_secret_basic". 792 * <li>The application type defaults to 793 * {@link ApplicationType#WEB}. 794 * <li>The ID token JWS algorithm defaults to "RS256". 795 * </ul> 796 */ 797 @Override 798 public void applyDefaults() { 799 800 super.applyDefaults(); 801 802 if (applicationType == null) { 803 applicationType = ApplicationType.WEB; 804 } 805 806 if (idTokenJWSAlg == null) { 807 idTokenJWSAlg = JWSAlgorithm.RS256; 808 } 809 } 810 811 812 @Override 813 public JSONObject toJSONObject(boolean includeCustomFields) { 814 815 JSONObject o = super.toJSONObject(includeCustomFields); 816 817 o.putAll(getCustomFields()); 818 819 if (applicationType != null) 820 o.put("application_type", applicationType.toString()); 821 822 if (subjectType != null) 823 o.put("subject_type", subjectType.toString()); 824 825 826 if (sectorIDURI != null) 827 o.put("sector_identifier_uri", sectorIDURI.toString()); 828 829 830 if (idTokenJWSAlg != null) 831 o.put("id_token_signed_response_alg", idTokenJWSAlg.getName()); 832 833 834 if (idTokenJWEAlg != null) 835 o.put("id_token_encrypted_response_alg", idTokenJWEAlg.getName()); 836 837 838 if (idTokenJWEEnc != null) 839 o.put("id_token_encrypted_response_enc", idTokenJWEEnc.getName()); 840 841 842 if (userInfoJWSAlg != null) 843 o.put("userinfo_signed_response_alg", userInfoJWSAlg.getName()); 844 845 846 if (userInfoJWEAlg != null) 847 o.put("userinfo_encrypted_response_alg", userInfoJWEAlg.getName()); 848 849 850 if (userInfoJWEEnc != null) 851 o.put("userinfo_encrypted_response_enc", userInfoJWEEnc.getName()); 852 853 854 if (defaultMaxAge > 0) 855 o.put("default_max_age", defaultMaxAge); 856 857 858 if (requiresAuthTime()) 859 o.put("require_auth_time", requiresAuthTime); 860 861 862 if (defaultACRs != null) { 863 864 JSONArray acrList = new JSONArray(); 865 acrList.addAll(defaultACRs); 866 o.put("default_acr_values", acrList); 867 } 868 869 870 if (initiateLoginURI != null) 871 o.put("initiate_login_uri", initiateLoginURI.toString()); 872 873 874 if (postLogoutRedirectURIs != null) { 875 876 JSONArray uriList = new JSONArray(); 877 878 for (URI uri: postLogoutRedirectURIs) 879 uriList.add(uri.toString()); 880 881 o.put("post_logout_redirect_uris", uriList); 882 } 883 884 if (frontChannelLogoutURI != null) { 885 o.put("frontchannel_logout_uri", frontChannelLogoutURI.toString()); 886 o.put("frontchannel_logout_session_required", frontChannelLogoutSessionRequired); 887 } 888 889 if (backChannelLogoutURI != null) { 890 o.put("backchannel_logout_uri", backChannelLogoutURI.toString()); 891 o.put("backchannel_logout_session_required", backChannelLogoutSessionRequired); 892 } 893 894 return o; 895 } 896 897 898 /** 899 * Parses an OpenID Connect client metadata instance from the specified 900 * JSON object. 901 * 902 * @param jsonObject The JSON object to parse. Must not be 903 * {@code null}. 904 * 905 * @return The OpenID Connect client metadata. 906 * 907 * @throws ParseException If the JSON object couldn't be parsed to an 908 * OpenID Connect client metadata instance. 909 */ 910 public static OIDCClientMetadata parse(final JSONObject jsonObject) 911 throws ParseException { 912 913 ClientMetadata baseMetadata = ClientMetadata.parse(jsonObject); 914 915 OIDCClientMetadata metadata = new OIDCClientMetadata(baseMetadata); 916 917 // Parse the OIDC-specific fields from the custom OAuth 2.0 dyn 918 // reg fields 919 920 JSONObject oidcFields = baseMetadata.getCustomFields(); 921 922 try { 923 if (jsonObject.get("application_type") != null) { 924 metadata.setApplicationType(JSONObjectUtils.getEnum(jsonObject, "application_type", ApplicationType.class)); 925 oidcFields.remove("application_type"); 926 } 927 928 if (jsonObject.get("subject_type") != null) { 929 metadata.setSubjectType(JSONObjectUtils.getEnum(jsonObject, "subject_type", SubjectType.class)); 930 oidcFields.remove("subject_type"); 931 } 932 933 if (jsonObject.get("sector_identifier_uri") != null) { 934 metadata.setSectorIDURI(JSONObjectUtils.getURI(jsonObject, "sector_identifier_uri")); 935 oidcFields.remove("sector_identifier_uri"); 936 } 937 938 if (jsonObject.get("id_token_signed_response_alg") != null) { 939 metadata.setIDTokenJWSAlg(JWSAlgorithm.parse( 940 JSONObjectUtils.getString(jsonObject, "id_token_signed_response_alg"))); 941 942 oidcFields.remove("id_token_signed_response_alg"); 943 } 944 945 if (jsonObject.get("id_token_encrypted_response_alg") != null) { 946 metadata.setIDTokenJWEAlg(JWEAlgorithm.parse( 947 JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_alg"))); 948 949 oidcFields.remove("id_token_encrypted_response_alg"); 950 } 951 952 if (jsonObject.get("id_token_encrypted_response_enc") != null) { 953 metadata.setIDTokenJWEEnc(EncryptionMethod.parse( 954 JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_enc"))); 955 956 oidcFields.remove("id_token_encrypted_response_enc"); 957 } 958 959 if (jsonObject.get("userinfo_signed_response_alg") != null) { 960 metadata.setUserInfoJWSAlg(JWSAlgorithm.parse( 961 JSONObjectUtils.getString(jsonObject, "userinfo_signed_response_alg"))); 962 963 oidcFields.remove("userinfo_signed_response_alg"); 964 } 965 966 if (jsonObject.get("userinfo_encrypted_response_alg") != null) { 967 metadata.setUserInfoJWEAlg(JWEAlgorithm.parse( 968 JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_alg"))); 969 970 oidcFields.remove("userinfo_encrypted_response_alg"); 971 } 972 973 if (jsonObject.get("userinfo_encrypted_response_enc") != null) { 974 metadata.setUserInfoJWEEnc(EncryptionMethod.parse( 975 JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_enc"))); 976 977 oidcFields.remove("userinfo_encrypted_response_enc"); 978 } 979 980 if (jsonObject.get("default_max_age") != null) { 981 metadata.setDefaultMaxAge(JSONObjectUtils.getInt(jsonObject, "default_max_age")); 982 oidcFields.remove("default_max_age"); 983 } 984 985 if (jsonObject.get("require_auth_time") != null) { 986 metadata.requiresAuthTime(JSONObjectUtils.getBoolean(jsonObject, "require_auth_time")); 987 oidcFields.remove("require_auth_time"); 988 } 989 990 if (jsonObject.get("default_acr_values") != null) { 991 992 List<ACR> acrValues = new LinkedList<>(); 993 994 for (String acrString : JSONObjectUtils.getStringArray(jsonObject, "default_acr_values")) 995 acrValues.add(new ACR(acrString)); 996 997 metadata.setDefaultACRs(acrValues); 998 999 oidcFields.remove("default_acr_values"); 1000 } 1001 1002 if (jsonObject.get("initiate_login_uri") != null) { 1003 try { 1004 metadata.setInitiateLoginURI(JSONObjectUtils.getURI(jsonObject, "initiate_login_uri")); 1005 } catch (IllegalArgumentException e) { 1006 throw new ParseException("Invalid \"initiate_login_uri\" parameter: " + e.getMessage()); 1007 } 1008 oidcFields.remove("initiate_login_uri"); 1009 } 1010 1011 if (jsonObject.get("post_logout_redirect_uris") != null) { 1012 1013 Set<URI> logoutURIs = new LinkedHashSet<>(); 1014 1015 for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "post_logout_redirect_uris")) { 1016 1017 try { 1018 logoutURIs.add(new URI(uriString)); 1019 } catch (URISyntaxException e) { 1020 throw new ParseException("Invalid \"post_logout_redirect_uris\" parameter"); 1021 } 1022 } 1023 1024 try { 1025 metadata.setPostLogoutRedirectionURIs(logoutURIs); 1026 } catch (IllegalArgumentException e) { 1027 throw new ParseException("Invalid \"post_logout_redirect_uris\" parameter: " + e.getMessage()); 1028 } 1029 oidcFields.remove("post_logout_redirect_uris"); 1030 } 1031 1032 if (jsonObject.get("frontchannel_logout_uri") != null) { 1033 1034 try { 1035 metadata.setFrontChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "frontchannel_logout_uri")); 1036 } catch (IllegalArgumentException e) { 1037 throw new ParseException("Invalid \"frontchannel_logout_uri\" parameter: " + e.getMessage()); 1038 } 1039 oidcFields.remove("frontchannel_logout_uri"); 1040 1041 if (jsonObject.get("frontchannel_logout_session_required") != null) { 1042 metadata.requiresFrontChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_required")); 1043 oidcFields.remove("frontchannel_logout_session_required"); 1044 } 1045 } 1046 1047 1048 if (jsonObject.get("backchannel_logout_uri") != null) { 1049 1050 try { 1051 metadata.setBackChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "backchannel_logout_uri")); 1052 } catch (IllegalArgumentException e) { 1053 throw new ParseException("Invalid \"backchannel_logout_uri\" parameter: " + e.getMessage()); 1054 } 1055 oidcFields.remove("backchannel_logout_uri"); 1056 1057 if (jsonObject.get("backchannel_logout_session_required") != null) { 1058 metadata.requiresBackChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_required")); 1059 oidcFields.remove("backchannel_logout_session_required"); 1060 } 1061 } 1062 1063 } catch (ParseException e) { 1064 // Insert client_client_metadata error code so that it 1065 // can be reported back to the client if we have a 1066 // registration event 1067 throw new ParseException(e.getMessage(), RegistrationError.INVALID_CLIENT_METADATA.appendDescription(": " + e.getMessage()), e.getCause()); 1068 } 1069 1070 // The remaining fields are custom 1071 metadata.setCustomFields(oidcFields); 1072 1073 return metadata; 1074 } 1075}