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 14). 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 * Creates a shallow copy of the specified OpenID Connect client 244 * metadata instance. 245 * 246 * @param metadata The client metadata to copy. Must not be 247 * {@code null}. 248 */ 249 public OIDCClientMetadata(final OIDCClientMetadata metadata) { 250 251 super(metadata); 252 applicationType = metadata.getApplicationType(); 253 subjectType = metadata.getSubjectType(); 254 sectorIDURI = metadata.getSectorIDURI(); 255 idTokenJWSAlg = metadata.getIDTokenJWSAlg(); 256 idTokenJWEAlg = metadata.getIDTokenJWEAlg(); 257 idTokenJWEEnc = metadata.getIDTokenJWEEnc(); 258 userInfoJWSAlg = metadata.getUserInfoJWSAlg(); 259 userInfoJWEAlg = metadata.getUserInfoJWEAlg(); 260 userInfoJWEEnc = metadata.getUserInfoJWEEnc(); 261 defaultMaxAge = metadata.getDefaultMaxAge(); 262 requiresAuthTime = metadata.requiresAuthTime(); 263 defaultACRs = metadata.getDefaultACRs(); 264 initiateLoginURI = metadata.getInitiateLoginURI(); 265 postLogoutRedirectURIs = metadata.getPostLogoutRedirectionURIs(); 266 frontChannelLogoutURI = metadata.getFrontChannelLogoutURI(); 267 frontChannelLogoutSessionRequired = metadata.requiresFrontChannelLogoutSession(); 268 backChannelLogoutURI = metadata.getBackChannelLogoutURI(); 269 backChannelLogoutSessionRequired = metadata.requiresBackChannelLogoutSession(); 270 } 271 272 273 /** 274 * Gets the registered (standard) OpenID Connect client metadata 275 * parameter names. 276 * 277 * @return The registered OpenID Connect parameter names, as an 278 * unmodifiable set. 279 */ 280 public static Set<String> getRegisteredParameterNames() { 281 282 return REGISTERED_PARAMETER_NAMES; 283 } 284 285 286 /** 287 * Gets the client application type. Corresponds to the 288 * {@code application_type} client metadata field. 289 * 290 * @return The client application type, {@code null} if not specified. 291 */ 292 public ApplicationType getApplicationType() { 293 294 return applicationType; 295 } 296 297 298 /** 299 * Sets the client application type. Corresponds to the 300 * {@code application_type} client metadata field. 301 * 302 * @param applicationType The client application type, {@code null} if 303 * not specified. 304 */ 305 public void setApplicationType(final ApplicationType applicationType) { 306 307 this.applicationType = applicationType; 308 } 309 310 311 /** 312 * Gets the subject identifier type for responses to this client. 313 * Corresponds to the {@code subject_type} client metadata field. 314 * 315 * @return The subject identifier type, {@code null} if not specified. 316 */ 317 public SubjectType getSubjectType() { 318 319 return subjectType; 320 } 321 322 323 /** 324 * Sets the subject identifier type for responses to this client. 325 * Corresponds to the {@code subject_type} client metadata field. 326 * 327 * @param subjectType The subject identifier type, {@code null} if not 328 * specified. 329 */ 330 public void setSubjectType(final SubjectType subjectType) { 331 332 this.subjectType = subjectType; 333 } 334 335 336 /** 337 * Gets the sector identifier URI. Corresponds to the 338 * {@code sector_identifier_uri} client metadata field. 339 * 340 * @return The sector identifier URI, {@code null} if not specified. 341 */ 342 public URI getSectorIDURI() { 343 344 return sectorIDURI; 345 } 346 347 348 /** 349 * Sets the sector identifier URI. Corresponds to the 350 * {@code sector_identifier_uri} client metadata field. If set the URI 351 * will be checked for having an {@code https} scheme and a host 352 * component unless the URI is an URN. 353 * 354 * @param sectorIDURI The sector identifier URI, {@code null} if not 355 * specified. 356 * 357 * @throws IllegalArgumentException If the URI was found to be illegal. 358 */ 359 public void setSectorIDURI(final URI sectorIDURI) { 360 361 if (sectorIDURI != null && ! "urn".equalsIgnoreCase(sectorIDURI.getScheme())) { 362 SectorID.ensureHTTPScheme(sectorIDURI); 363 SectorID.ensureHostComponent(sectorIDURI); 364 } 365 366 this.sectorIDURI = sectorIDURI; 367 } 368 369 370 /** 371 * Resolves the sector identifier from the client metadata. 372 * 373 * @return The sector identifier, {@code null} if the subject type is 374 * set to public. 375 * 376 * @throws IllegalStateException If resolution failed due to incomplete 377 * or inconsistent metadata. 378 */ 379 public SectorID resolveSectorID() { 380 381 if (! SubjectType.PAIRWISE.equals(getSubjectType())) { 382 // subject type is not pairwise or null 383 return null; 384 } 385 386 // Check sector identifier URI first 387 if (getSectorIDURI() != null) { 388 return new SectorID(getSectorIDURI()); 389 } 390 391 // Check redirect URIs second 392 if (CollectionUtils.isEmpty(getRedirectionURIs())) { 393 throw new IllegalStateException("Couldn't resolve sector ID: Missing redirect_uris"); 394 } 395 396 if (getRedirectionURIs().size() > 1) { 397 throw new IllegalStateException("Couldn't resolve sector ID: More than one redirect_uri, sector_identifier_uri not specified"); 398 } 399 400 return new SectorID(getRedirectionURIs().iterator().next()); 401 } 402 403 404 /** 405 * Gets the JSON Web Signature (JWS) algorithm required for the ID 406 * Tokens issued to this client. Corresponds to the 407 * {@code id_token_signed_response_alg} client metadata field. 408 * 409 * @return The JWS algorithm, {@code null} if not specified. 410 */ 411 public JWSAlgorithm getIDTokenJWSAlg() { 412 413 return idTokenJWSAlg; 414 } 415 416 417 /** 418 * Sets the JSON Web Signature (JWS) algorithm required for the ID 419 * Tokens issued to this client. Corresponds to the 420 * {@code id_token_signed_response_alg} client metadata field. 421 * 422 * @param idTokenJWSAlg The JWS algorithm, {@code null} if not 423 * specified. 424 */ 425 public void setIDTokenJWSAlg(final JWSAlgorithm idTokenJWSAlg) { 426 427 this.idTokenJWSAlg = idTokenJWSAlg; 428 } 429 430 431 /** 432 * Gets the JSON Web Encryption (JWE) algorithm required for the ID 433 * Tokens issued to this client. Corresponds to the 434 * {@code id_token_encrypted_response_alg} client metadata field. 435 * 436 * @return The JWE algorithm, {@code null} if not specified. 437 */ 438 public JWEAlgorithm getIDTokenJWEAlg() { 439 440 return idTokenJWEAlg; 441 } 442 443 444 /** 445 * Sets the JSON Web Encryption (JWE) algorithm required for the ID 446 * Tokens issued to this client. Corresponds to the 447 * {@code id_token_encrypted_response_alg} client metadata field. 448 * 449 * @param idTokenJWEAlg The JWE algorithm, {@code null} if not 450 * specified. 451 */ 452 public void setIDTokenJWEAlg(final JWEAlgorithm idTokenJWEAlg) { 453 454 this.idTokenJWEAlg = idTokenJWEAlg; 455 } 456 457 458 /** 459 * Gets the JSON Web Encryption (JWE) method required for the ID Tokens 460 * issued to this client. Corresponds to the 461 * {@code id_token_encrypted_response_enc} client metadata field. 462 * 463 * @return The JWE method, {@code null} if not specified. 464 */ 465 public EncryptionMethod getIDTokenJWEEnc() { 466 467 return idTokenJWEEnc; 468 } 469 470 471 /** 472 * Sets the JSON Web Encryption (JWE) method required for the ID Tokens 473 * issued to this client. Corresponds to the 474 * {@code id_token_encrypted_response_enc} client metadata field. 475 * 476 * @param idTokenJWEEnc The JWE method, {@code null} if not specified. 477 */ 478 public void setIDTokenJWEEnc(final EncryptionMethod idTokenJWEEnc) { 479 480 this.idTokenJWEEnc = idTokenJWEEnc; 481 } 482 483 484 /** 485 * Gets the JSON Web Signature (JWS) algorithm required for the 486 * UserInfo responses to this client. Corresponds to the 487 * {@code userinfo_signed_response_alg} client metadata field. 488 * 489 * @return The JWS algorithm, {@code null} if not specified. 490 */ 491 public JWSAlgorithm getUserInfoJWSAlg() { 492 493 return userInfoJWSAlg; 494 } 495 496 497 /** 498 * Sets the JSON Web Signature (JWS) algorithm required for the 499 * UserInfo responses to this client. Corresponds to the 500 * {@code userinfo_signed_response_alg} client metadata field. 501 * 502 * @param userInfoJWSAlg The JWS algorithm, {@code null} if not 503 * specified. 504 */ 505 public void setUserInfoJWSAlg(final JWSAlgorithm userInfoJWSAlg) { 506 507 this.userInfoJWSAlg = userInfoJWSAlg; 508 } 509 510 511 /** 512 * Gets the JSON Web Encryption (JWE) algorithm required for the 513 * UserInfo responses to this client. Corresponds to the 514 * {@code userinfo_encrypted_response_alg} client metadata field. 515 * 516 * @return The JWE algorithm, {@code null} if not specified. 517 */ 518 public JWEAlgorithm getUserInfoJWEAlg() { 519 520 return userInfoJWEAlg; 521 } 522 523 524 /** 525 * Sets the JSON Web Encryption (JWE) algorithm required for the 526 * UserInfo responses to this client. Corresponds to the 527 * {@code userinfo_encrypted_response_alg} client metadata field. 528 * 529 * @param userInfoJWEAlg The JWE algorithm, {@code null} if not 530 * specified. 531 */ 532 public void setUserInfoJWEAlg(final JWEAlgorithm userInfoJWEAlg) { 533 534 this.userInfoJWEAlg = userInfoJWEAlg; 535 } 536 537 538 /** 539 * Gets the JSON Web Encryption (JWE) method required for the UserInfo 540 * responses to this client. Corresponds to the 541 * {@code userinfo_encrypted_response_enc} client metadata field. 542 * 543 * @return The JWE method, {@code null} if not specified. 544 */ 545 public EncryptionMethod getUserInfoJWEEnc() { 546 547 return userInfoJWEEnc; 548 } 549 550 551 /** 552 * Sets the JSON Web Encryption (JWE) method required for the UserInfo 553 * responses to this client. Corresponds to the 554 * {@code userinfo_encrypted_response_enc} client metadata field. 555 * 556 * @param userInfoJWEEnc The JWE method, {@code null} if not specified. 557 */ 558 public void setUserInfoJWEEnc(final EncryptionMethod userInfoJWEEnc) { 559 560 this.userInfoJWEEnc = userInfoJWEEnc; 561 } 562 563 564 /** 565 * Gets the default maximum authentication age. Corresponds to the 566 * {@code default_max_age} client metadata field. 567 * 568 * @return The default max authentication age, in seconds. If not 569 * specified -1. 570 */ 571 public int getDefaultMaxAge() { 572 573 return defaultMaxAge; 574 } 575 576 577 /** 578 * Sets the default maximum authentication age. Corresponds to the 579 * {@code default_max_age} client metadata field. 580 * 581 * @param defaultMaxAge The default max authentication age, in seconds. 582 * If not specified -1. 583 */ 584 public void setDefaultMaxAge(final int defaultMaxAge) { 585 586 this.defaultMaxAge = defaultMaxAge; 587 } 588 589 590 /** 591 * Gets the default requirement for the {@code auth_time} claim in the 592 * ID Token. Corresponds to the {@code require_auth_time} client 593 * metadata field. 594 * 595 * @return If {@code true} the {@code auth_Time} claim in the ID Token 596 * is required by default. 597 */ 598 public boolean requiresAuthTime() { 599 600 return requiresAuthTime; 601 } 602 603 604 /** 605 * Sets the default requirement for the {@code auth_time} claim in the 606 * ID Token. Corresponds to the {@code require_auth_time} client 607 * metadata field. 608 * 609 * @param requiresAuthTime If {@code true} the {@code auth_Time} claim 610 * in the ID Token is required by default. 611 */ 612 public void requiresAuthTime(final boolean requiresAuthTime) { 613 614 this.requiresAuthTime = requiresAuthTime; 615 } 616 617 618 /** 619 * Gets the default Authentication Context Class Reference (ACR) 620 * values. Corresponds to the {@code default_acr_values} client 621 * metadata field. 622 * 623 * @return The default ACR values, by order of preference, 624 * {@code null} if not specified. 625 */ 626 public List<ACR> getDefaultACRs() { 627 628 return defaultACRs; 629 } 630 631 632 /** 633 * Sets the default Authentication Context Class Reference (ACR) 634 * values. Corresponds to the {@code default_acr_values} client 635 * metadata field. 636 * 637 * @param defaultACRs The default ACRs, by order of preference, 638 * {@code null} if not specified. 639 */ 640 public void setDefaultACRs(final List<ACR> defaultACRs) { 641 642 this.defaultACRs = defaultACRs; 643 } 644 645 646 /** 647 * Gets the HTTPS URI that the authorisation server can call to 648 * initiate a login at the client. Corresponds to the 649 * {@code initiate_login_uri} client metadata field. 650 * 651 * @return The login URI, {@code null} if not specified. 652 */ 653 public URI getInitiateLoginURI() { 654 655 return initiateLoginURI; 656 } 657 658 659 /** 660 * Sets the HTTPS URI that the authorisation server can call to 661 * initiate a login at the client. Corresponds to the 662 * {@code initiate_login_uri} client metadata field. 663 * 664 * @param loginURI The login URI, {@code null} if not specified. The 665 * URI scheme must be https. 666 */ 667 public void setInitiateLoginURI(final URI loginURI) { 668 669 URIUtils.ensureSchemeIsHTTPS(loginURI); 670 this.initiateLoginURI = loginURI; 671 } 672 673 674 /** 675 * Gets the post logout redirection URIs. Corresponds to the 676 * {@code post_logout_redirect_uris} client metadata field. 677 * 678 * @return The logout redirection URIs, {@code null} if not specified. 679 */ 680 public Set<URI> getPostLogoutRedirectionURIs() { 681 682 return postLogoutRedirectURIs; 683 } 684 685 686 /** 687 * Sets the post logout redirection URIs. Corresponds to the 688 * {@code post_logout_redirect_uris} client metadata field. 689 * 690 * @param logoutURIs The post logout redirection URIs, {@code null} if 691 * not specified. 692 */ 693 public void setPostLogoutRedirectionURIs(final Set<URI> logoutURIs) { 694 695 if (logoutURIs != null) { 696 for (URI uri: logoutURIs) { 697 URIUtils.ensureSchemeIsNotProhibited(uri, PROHIBITED_REDIRECT_URI_SCHEMES); 698 } 699 } 700 postLogoutRedirectURIs = logoutURIs; 701 } 702 703 704 /** 705 * Gets the front-channel logout URI. Corresponds to the 706 * {@code frontchannel_logout_uri} client metadata field. 707 * 708 * @return The front-channel logout URI, {@code null} if not specified. 709 */ 710 public URI getFrontChannelLogoutURI() { 711 712 return frontChannelLogoutURI; 713 } 714 715 716 /** 717 * Sets the front-channel logout URI. Corresponds to the 718 * {@code frontchannel_logout_uri} client metadata field. 719 * 720 * @param frontChannelLogoutURI The front-channel logout URI, 721 * {@code null} if not specified. The URI 722 * scheme must be https or http. 723 */ 724 public void setFrontChannelLogoutURI(final URI frontChannelLogoutURI) { 725 726 URIUtils.ensureSchemeIsHTTPSorHTTP(frontChannelLogoutURI); 727 this.frontChannelLogoutURI = frontChannelLogoutURI; 728 } 729 730 731 /** 732 * Gets the requirement for a session identifier on front-channel 733 * logout. Corresponds to 734 * the {@code frontchannel_logout_session_required} client metadata 735 * field. 736 * 737 * @return {@code true} if a session identifier is required, else 738 * {@code false}. 739 */ 740 public boolean requiresFrontChannelLogoutSession() { 741 742 return frontChannelLogoutSessionRequired; 743 } 744 745 746 /** 747 * Sets the requirement for a session identifier on front-channel 748 * logout. Corresponds to 749 * the {@code frontchannel_logout_session_required} client metadata 750 * field. 751 * 752 * @param requiresSession {@code true} if a session identifier is 753 * required, else {@code false}. 754 */ 755 public void requiresFrontChannelLogoutSession(boolean requiresSession) { 756 757 frontChannelLogoutSessionRequired = requiresSession; 758 } 759 760 761 /** 762 * Gets the back-channel logout URI. Corresponds to the 763 * {@code backchannel_logout_uri} client metadata field. 764 * 765 * @return The back-channel logout URI, {@code null} if not specified. 766 */ 767 public URI getBackChannelLogoutURI() { 768 769 return backChannelLogoutURI; 770 } 771 772 773 /** 774 * Sets the back-channel logout URI. Corresponds to the 775 * {@code backchannel_logout_uri} client metadata field. 776 * 777 * @param backChannelLogoutURI The back-channel logout URI, 778 * {@code null} if not specified. The URI 779 * scheme must be https or http. 780 */ 781 public void setBackChannelLogoutURI(final URI backChannelLogoutURI) { 782 783 URIUtils.ensureSchemeIsHTTPSorHTTP(backChannelLogoutURI); 784 this.backChannelLogoutURI = backChannelLogoutURI; 785 } 786 787 788 /** 789 * Gets the requirement for a session identifier on back-channel 790 * logout. Corresponds to 791 * the {@code backchannel_logout_session_required} client metadata 792 * field. 793 * 794 * @return {@code true} if a session identifier is required, else 795 * {@code false}. 796 */ 797 public boolean requiresBackChannelLogoutSession() { 798 799 return backChannelLogoutSessionRequired; 800 } 801 802 803 /** 804 * Sets the requirement for a session identifier on back-channel 805 * logout. Corresponds to 806 * the {@code backchannel_logout_session_required} client metadata 807 * field. 808 * 809 * @param requiresSession {@code true} if a session identifier is 810 * required, else {@code false}. 811 */ 812 public void requiresBackChannelLogoutSession(final boolean requiresSession) { 813 814 backChannelLogoutSessionRequired = requiresSession; 815 } 816 817 818 /** 819 * Applies the client metadata defaults where no values have been 820 * specified. 821 * 822 * <ul> 823 * <li>The response types default to {@code ["code"]}. 824 * <li>The grant types default to {@code "authorization_code".} 825 * <li>The client authentication method defaults to 826 * "client_secret_basic". 827 * <li>The application type defaults to 828 * {@link ApplicationType#WEB}. 829 * <li>The ID token JWS algorithm defaults to "RS256". 830 * </ul> 831 */ 832 @Override 833 public void applyDefaults() { 834 835 super.applyDefaults(); 836 837 if (applicationType == null) { 838 applicationType = ApplicationType.WEB; 839 } 840 841 if (idTokenJWSAlg == null) { 842 idTokenJWSAlg = JWSAlgorithm.RS256; 843 } 844 } 845 846 847 @Override 848 public JSONObject toJSONObject(boolean includeCustomFields) { 849 850 JSONObject o = super.toJSONObject(includeCustomFields); 851 852 o.putAll(getCustomFields()); 853 854 if (applicationType != null) 855 o.put("application_type", applicationType.toString()); 856 857 if (subjectType != null) 858 o.put("subject_type", subjectType.toString()); 859 860 861 if (sectorIDURI != null) 862 o.put("sector_identifier_uri", sectorIDURI.toString()); 863 864 865 if (idTokenJWSAlg != null) 866 o.put("id_token_signed_response_alg", idTokenJWSAlg.getName()); 867 868 869 if (idTokenJWEAlg != null) 870 o.put("id_token_encrypted_response_alg", idTokenJWEAlg.getName()); 871 872 873 if (idTokenJWEEnc != null) 874 o.put("id_token_encrypted_response_enc", idTokenJWEEnc.getName()); 875 876 877 if (userInfoJWSAlg != null) 878 o.put("userinfo_signed_response_alg", userInfoJWSAlg.getName()); 879 880 881 if (userInfoJWEAlg != null) 882 o.put("userinfo_encrypted_response_alg", userInfoJWEAlg.getName()); 883 884 885 if (userInfoJWEEnc != null) 886 o.put("userinfo_encrypted_response_enc", userInfoJWEEnc.getName()); 887 888 889 if (defaultMaxAge > 0) 890 o.put("default_max_age", defaultMaxAge); 891 892 893 if (requiresAuthTime()) 894 o.put("require_auth_time", requiresAuthTime); 895 896 897 if (defaultACRs != null) { 898 899 JSONArray acrList = new JSONArray(); 900 901 for (ACR acr: defaultACRs) { 902 acrList.add(acr.getValue()); 903 } 904 o.put("default_acr_values", acrList); 905 } 906 907 908 if (initiateLoginURI != null) 909 o.put("initiate_login_uri", initiateLoginURI.toString()); 910 911 912 if (postLogoutRedirectURIs != null) { 913 914 JSONArray uriList = new JSONArray(); 915 916 for (URI uri: postLogoutRedirectURIs) 917 uriList.add(uri.toString()); 918 919 o.put("post_logout_redirect_uris", uriList); 920 } 921 922 if (frontChannelLogoutURI != null) { 923 o.put("frontchannel_logout_uri", frontChannelLogoutURI.toString()); 924 o.put("frontchannel_logout_session_required", frontChannelLogoutSessionRequired); 925 } 926 927 if (backChannelLogoutURI != null) { 928 o.put("backchannel_logout_uri", backChannelLogoutURI.toString()); 929 o.put("backchannel_logout_session_required", backChannelLogoutSessionRequired); 930 } 931 932 return o; 933 } 934 935 936 /** 937 * Parses an OpenID Connect client metadata instance from the specified 938 * JSON object. 939 * 940 * @param jsonObject The JSON object to parse. Must not be 941 * {@code null}. 942 * 943 * @return The OpenID Connect client metadata. 944 * 945 * @throws ParseException If the JSON object couldn't be parsed to an 946 * OpenID Connect client metadata instance. 947 */ 948 public static OIDCClientMetadata parse(final JSONObject jsonObject) 949 throws ParseException { 950 951 ClientMetadata baseMetadata = ClientMetadata.parse(jsonObject); 952 953 OIDCClientMetadata metadata = new OIDCClientMetadata(baseMetadata); 954 955 // Parse the OIDC-specific fields from the custom OAuth 2.0 dyn 956 // reg fields 957 958 JSONObject oidcFields = baseMetadata.getCustomFields(); 959 960 try { 961 if (jsonObject.get("application_type") != null) { 962 metadata.setApplicationType(JSONObjectUtils.getEnum(jsonObject, "application_type", ApplicationType.class)); 963 oidcFields.remove("application_type"); 964 } 965 966 if (jsonObject.get("subject_type") != null) { 967 metadata.setSubjectType(JSONObjectUtils.getEnum(jsonObject, "subject_type", SubjectType.class)); 968 oidcFields.remove("subject_type"); 969 } 970 971 if (jsonObject.get("sector_identifier_uri") != null) { 972 try { 973 metadata.setSectorIDURI(JSONObjectUtils.getURI(jsonObject, "sector_identifier_uri")); 974 } catch (IllegalArgumentException e) { 975 throw new ParseException("Invalid sector_identifier_uri parameter: " + e.getMessage()); 976 } 977 oidcFields.remove("sector_identifier_uri"); 978 } 979 980 if (jsonObject.get("id_token_signed_response_alg") != null) { 981 metadata.setIDTokenJWSAlg(JWSAlgorithm.parse( 982 JSONObjectUtils.getString(jsonObject, "id_token_signed_response_alg"))); 983 984 oidcFields.remove("id_token_signed_response_alg"); 985 } 986 987 if (jsonObject.get("id_token_encrypted_response_alg") != null) { 988 metadata.setIDTokenJWEAlg(JWEAlgorithm.parse( 989 JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_alg"))); 990 991 oidcFields.remove("id_token_encrypted_response_alg"); 992 } 993 994 if (jsonObject.get("id_token_encrypted_response_enc") != null) { 995 metadata.setIDTokenJWEEnc(EncryptionMethod.parse( 996 JSONObjectUtils.getString(jsonObject, "id_token_encrypted_response_enc"))); 997 998 oidcFields.remove("id_token_encrypted_response_enc"); 999 } 1000 1001 if (jsonObject.get("userinfo_signed_response_alg") != null) { 1002 metadata.setUserInfoJWSAlg(JWSAlgorithm.parse( 1003 JSONObjectUtils.getString(jsonObject, "userinfo_signed_response_alg"))); 1004 1005 oidcFields.remove("userinfo_signed_response_alg"); 1006 } 1007 1008 if (jsonObject.get("userinfo_encrypted_response_alg") != null) { 1009 metadata.setUserInfoJWEAlg(JWEAlgorithm.parse( 1010 JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_alg"))); 1011 1012 oidcFields.remove("userinfo_encrypted_response_alg"); 1013 } 1014 1015 if (jsonObject.get("userinfo_encrypted_response_enc") != null) { 1016 metadata.setUserInfoJWEEnc(EncryptionMethod.parse( 1017 JSONObjectUtils.getString(jsonObject, "userinfo_encrypted_response_enc"))); 1018 1019 oidcFields.remove("userinfo_encrypted_response_enc"); 1020 } 1021 1022 if (jsonObject.get("default_max_age") != null) { 1023 metadata.setDefaultMaxAge(JSONObjectUtils.getInt(jsonObject, "default_max_age")); 1024 oidcFields.remove("default_max_age"); 1025 } 1026 1027 if (jsonObject.get("require_auth_time") != null) { 1028 metadata.requiresAuthTime(JSONObjectUtils.getBoolean(jsonObject, "require_auth_time")); 1029 oidcFields.remove("require_auth_time"); 1030 } 1031 1032 if (jsonObject.get("default_acr_values") != null) { 1033 1034 List<ACR> acrValues = new LinkedList<>(); 1035 1036 for (String acrString : JSONObjectUtils.getStringArray(jsonObject, "default_acr_values")) 1037 acrValues.add(new ACR(acrString)); 1038 1039 metadata.setDefaultACRs(acrValues); 1040 1041 oidcFields.remove("default_acr_values"); 1042 } 1043 1044 if (jsonObject.get("initiate_login_uri") != null) { 1045 try { 1046 metadata.setInitiateLoginURI(JSONObjectUtils.getURI(jsonObject, "initiate_login_uri")); 1047 } catch (IllegalArgumentException e) { 1048 throw new ParseException("Invalid initiate_login_uri parameter: " + e.getMessage()); 1049 } 1050 oidcFields.remove("initiate_login_uri"); 1051 } 1052 1053 if (jsonObject.get("post_logout_redirect_uris") != null) { 1054 1055 Set<URI> logoutURIs = new LinkedHashSet<>(); 1056 1057 for (String uriString : JSONObjectUtils.getStringArray(jsonObject, "post_logout_redirect_uris")) { 1058 1059 try { 1060 logoutURIs.add(new URI(uriString)); 1061 } catch (URISyntaxException e) { 1062 throw new ParseException("Invalid post_logout_redirect_uris parameter"); 1063 } 1064 } 1065 1066 try { 1067 metadata.setPostLogoutRedirectionURIs(logoutURIs); 1068 } catch (IllegalArgumentException e) { 1069 throw new ParseException("Invalid post_logout_redirect_uris parameter: " + e.getMessage()); 1070 } 1071 oidcFields.remove("post_logout_redirect_uris"); 1072 } 1073 1074 if (jsonObject.get("frontchannel_logout_uri") != null) { 1075 1076 try { 1077 metadata.setFrontChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "frontchannel_logout_uri")); 1078 } catch (IllegalArgumentException e) { 1079 throw new ParseException("Invalid frontchannel_logout_uri parameter: " + e.getMessage()); 1080 } 1081 oidcFields.remove("frontchannel_logout_uri"); 1082 1083 if (jsonObject.get("frontchannel_logout_session_required") != null) { 1084 metadata.requiresFrontChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_required")); 1085 oidcFields.remove("frontchannel_logout_session_required"); 1086 } 1087 } 1088 1089 1090 if (jsonObject.get("backchannel_logout_uri") != null) { 1091 1092 try { 1093 metadata.setBackChannelLogoutURI(JSONObjectUtils.getURI(jsonObject, "backchannel_logout_uri")); 1094 } catch (IllegalArgumentException e) { 1095 throw new ParseException("Invalid backchannel_logout_uri parameter: " + e.getMessage()); 1096 } 1097 oidcFields.remove("backchannel_logout_uri"); 1098 1099 if (jsonObject.get("backchannel_logout_session_required") != null) { 1100 metadata.requiresBackChannelLogoutSession(JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_required")); 1101 oidcFields.remove("backchannel_logout_session_required"); 1102 } 1103 } 1104 1105 } catch (ParseException e) { 1106 // Insert client_client_metadata error code so that it 1107 // can be reported back to the client if we have a 1108 // registration event 1109 throw new ParseException(e.getMessage(), RegistrationError.INVALID_CLIENT_METADATA.appendDescription(": " + e.getMessage()), e.getCause()); 1110 } 1111 1112 // The remaining fields are custom 1113 metadata.setCustomFields(oidcFields); 1114 1115 return metadata; 1116 } 1117}