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