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.op; 019 020 021import java.io.IOException; 022import java.net.MalformedURLException; 023import java.net.URI; 024import java.net.URL; 025import java.util.*; 026 027import com.nimbusds.jose.EncryptionMethod; 028import com.nimbusds.jose.JWEAlgorithm; 029import com.nimbusds.jose.JWSAlgorithm; 030import com.nimbusds.langtag.LangTag; 031import com.nimbusds.langtag.LangTagException; 032import com.nimbusds.oauth2.sdk.GeneralException; 033import com.nimbusds.oauth2.sdk.ParseException; 034import com.nimbusds.oauth2.sdk.as.AuthorizationServerEndpointMetadata; 035import com.nimbusds.oauth2.sdk.as.AuthorizationServerMetadata; 036import com.nimbusds.oauth2.sdk.http.HTTPRequest; 037import com.nimbusds.oauth2.sdk.http.HTTPResponse; 038import com.nimbusds.oauth2.sdk.id.Issuer; 039import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 040import com.nimbusds.openid.connect.sdk.Display; 041import com.nimbusds.openid.connect.sdk.SubjectType; 042import com.nimbusds.openid.connect.sdk.claims.ACR; 043import com.nimbusds.openid.connect.sdk.claims.ClaimType; 044import net.minidev.json.JSONObject; 045 046 047/** 048 * OpenID Provider (OP) metadata. 049 * 050 * <p>Related specifications: 051 * 052 * <ul> 053 * <li>OpenID Connect Discovery 1.0, section 3. 054 * <li>OpenID Connect Session Management 1.0, section 2.1 (draft 28). 055 * <li>OpenID Connect Front-Channel Logout 1.0, section 3 (draft 02). 056 * <li>OpenID Connect Back-Channel Logout 1.0, section 2.1 (draft 04). 057 * <li>OAuth 2.0 Authorization Server Metadata (RFC 8414) 058 * <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound 059 * Access Tokens (draft-ietf-oauth-mtls-15) 060 * <li>Financial-grade API: JWT Secured Authorization Response Mode for 061 * OAuth 2.0 (JARM) 062 * </ul> 063 */ 064public class OIDCProviderMetadata extends AuthorizationServerMetadata { 065 066 067 /** 068 * The registered parameter names. 069 */ 070 private static final Set<String> REGISTERED_PARAMETER_NAMES; 071 072 073 static { 074 Set<String> p = new HashSet<>(AuthorizationServerMetadata.getRegisteredParameterNames()); 075 p.addAll(OIDCProviderEndpointMetadata.getRegisteredParameterNames()); 076 p.add("check_session_iframe"); 077 p.add("end_session_endpoint"); 078 p.add("acr_values_supported"); 079 p.add("subject_types_supported"); 080 p.add("id_token_signing_alg_values_supported"); 081 p.add("id_token_encryption_alg_values_supported"); 082 p.add("id_token_encryption_enc_values_supported"); 083 p.add("userinfo_signing_alg_values_supported"); 084 p.add("userinfo_encryption_alg_values_supported"); 085 p.add("userinfo_encryption_enc_values_supported"); 086 p.add("display_values_supported"); 087 p.add("claim_types_supported"); 088 p.add("claims_supported"); 089 p.add("claims_locales_supported"); 090 p.add("claims_parameter_supported"); 091 p.add("backchannel_logout_supported"); 092 p.add("backchannel_logout_session_supported"); 093 p.add("frontchannel_logout_supported"); 094 p.add("frontchannel_logout_session_supported"); 095 REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p); 096 } 097 098 099 /** 100 * The UserInfo endpoint. 101 */ 102 private URI userInfoEndpoint; 103 104 105 /** 106 * The cross-origin check session iframe. 107 */ 108 private URI checkSessionIframe; 109 110 111 /** 112 * The logout endpoint. 113 */ 114 private URI endSessionEndpoint; 115 116 117 /** 118 * The supported ACRs. 119 */ 120 private List<ACR> acrValues; 121 122 123 /** 124 * The supported subject types. 125 */ 126 private final List<SubjectType> subjectTypes; 127 128 129 /** 130 * The supported ID token JWS algorithms. 131 */ 132 private List<JWSAlgorithm> idTokenJWSAlgs; 133 134 135 /** 136 * The supported ID token JWE algorithms. 137 */ 138 private List<JWEAlgorithm> idTokenJWEAlgs; 139 140 141 /** 142 * The supported ID token encryption methods. 143 */ 144 private List<EncryptionMethod> idTokenJWEEncs; 145 146 147 /** 148 * The supported UserInfo JWS algorithms. 149 */ 150 private List<JWSAlgorithm> userInfoJWSAlgs; 151 152 153 /** 154 * The supported UserInfo JWE algorithms. 155 */ 156 private List<JWEAlgorithm> userInfoJWEAlgs; 157 158 159 /** 160 * The supported UserInfo encryption methods. 161 */ 162 private List<EncryptionMethod> userInfoJWEEncs; 163 164 165 /** 166 * The supported displays. 167 */ 168 private List<Display> displays; 169 170 171 /** 172 * The supported claim types. 173 */ 174 private List<ClaimType> claimTypes; 175 176 177 /** 178 * The supported claims names. 179 */ 180 private List<String> claims; 181 182 183 /** 184 * The supported claims locales. 185 */ 186 private List<LangTag> claimsLocales; 187 188 189 /** 190 * If {@code true} the {@code claims} parameter is supported, else not. 191 */ 192 private boolean claimsParamSupported = false; 193 194 195 /** 196 * If {@code true} the {@code frontchannel_logout_supported} parameter 197 * is set, else not. 198 */ 199 private boolean frontChannelLogoutSupported = false; 200 201 202 /** 203 * If {@code true} the {@code frontchannel_logout_session_supported} 204 * parameter is set, else not. 205 */ 206 private boolean frontChannelLogoutSessionSupported = false; 207 208 209 /** 210 * If {@code true} the {@code backchannel_logout_supported} parameter 211 * is set, else not. 212 */ 213 private boolean backChannelLogoutSupported = false; 214 215 216 /** 217 * If {@code true} the {@code backchannel_logout_session_supported} 218 * parameter is set, else not. 219 */ 220 private boolean backChannelLogoutSessionSupported = false; 221 222 223 /** 224 * Creates a new OpenID Connect provider metadata instance. 225 * 226 * @param issuer The issuer identifier. Must be an URI using the 227 * https scheme with no query or fragment 228 * component. Must not be {@code null}. 229 * @param subjectTypes The supported subject types. At least one must 230 * be specified. Must not be {@code null}. 231 * @param jwkSetURI The JWK set URI. Must not be {@code null}. 232 */ 233 public OIDCProviderMetadata(final Issuer issuer, 234 final List<SubjectType> subjectTypes, 235 final URI jwkSetURI) { 236 237 super(issuer); 238 239 if (subjectTypes.size() < 1) 240 throw new IllegalArgumentException("At least one supported subject type must be specified"); 241 242 this.subjectTypes = subjectTypes; 243 244 if (jwkSetURI == null) 245 throw new IllegalArgumentException("The public JWK set URI must not be null"); 246 247 setJWKSetURI(jwkSetURI); 248 249 // Default OpenID Connect setting is supported 250 setSupportsRequestParam(true); 251 } 252 253 254 @Override 255 public void setMtlsEndpointAliases(AuthorizationServerEndpointMetadata mtlsEndpointAliases) { 256 257 if (mtlsEndpointAliases != null && !(mtlsEndpointAliases instanceof OIDCProviderEndpointMetadata)) { 258 // convert the provided endpoints to OIDC 259 super.setMtlsEndpointAliases(new OIDCProviderEndpointMetadata(mtlsEndpointAliases)); 260 } else { 261 super.setMtlsEndpointAliases(mtlsEndpointAliases); 262 } 263 } 264 265 @Override 266 public OIDCProviderEndpointMetadata getMtlsEndpointAliases() { 267 268 return (OIDCProviderEndpointMetadata) super.getMtlsEndpointAliases(); 269 } 270 271 272 /** 273 * Gets the registered OpenID Connect provider metadata parameter 274 * names. 275 * 276 * @return The registered OpenID Connect provider metadata parameter 277 * names, as an unmodifiable set. 278 */ 279 public static Set<String> getRegisteredParameterNames() { 280 281 return REGISTERED_PARAMETER_NAMES; 282 } 283 284 285 /** 286 * Gets the UserInfo endpoint URI. Corresponds the 287 * {@code userinfo_endpoint} metadata field. 288 * 289 * @return The UserInfo endpoint URI, {@code null} if not specified. 290 */ 291 public URI getUserInfoEndpointURI() { 292 293 return userInfoEndpoint; 294 } 295 296 297 /** 298 * Sets the UserInfo endpoint URI. Corresponds the 299 * {@code userinfo_endpoint} metadata field. 300 * 301 * @param userInfoEndpoint The UserInfo endpoint URI, {@code null} if 302 * not specified. 303 */ 304 public void setUserInfoEndpointURI(final URI userInfoEndpoint) { 305 306 this.userInfoEndpoint = userInfoEndpoint; 307 } 308 309 310 /** 311 * Gets the cross-origin check session iframe URI. Corresponds to the 312 * {@code check_session_iframe} metadata field. 313 * 314 * @return The check session iframe URI, {@code null} if not specified. 315 */ 316 public URI getCheckSessionIframeURI() { 317 318 return checkSessionIframe; 319 } 320 321 322 /** 323 * Sets the cross-origin check session iframe URI. Corresponds to the 324 * {@code check_session_iframe} metadata field. 325 * 326 * @param checkSessionIframe The check session iframe URI, {@code null} 327 * if not specified. 328 */ 329 public void setCheckSessionIframeURI(final URI checkSessionIframe) { 330 331 this.checkSessionIframe = checkSessionIframe; 332 } 333 334 335 /** 336 * Gets the logout endpoint URI. Corresponds to the 337 * {@code end_session_endpoint} metadata field. 338 * 339 * @return The logoout endpoint URI, {@code null} if not specified. 340 */ 341 public URI getEndSessionEndpointURI() { 342 343 return endSessionEndpoint; 344 } 345 346 347 /** 348 * Sets the logout endpoint URI. Corresponds to the 349 * {@code end_session_endpoint} metadata field. 350 * 351 * @param endSessionEndpoint The logoout endpoint URI, {@code null} if 352 * not specified. 353 */ 354 public void setEndSessionEndpointURI(final URI endSessionEndpoint) { 355 356 this.endSessionEndpoint = endSessionEndpoint; 357 } 358 359 /** 360 * Gets the supported Authentication Context Class References (ACRs). 361 * Corresponds to the {@code acr_values_supported} metadata field. 362 * 363 * @return The supported ACRs, {@code null} if not specified. 364 */ 365 public List<ACR> getACRs() { 366 367 return acrValues; 368 } 369 370 371 /** 372 * Sets the supported Authentication Context Class References (ACRs). 373 * Corresponds to the {@code acr_values_supported} metadata field. 374 * 375 * @param acrValues The supported ACRs, {@code null} if not specified. 376 */ 377 public void setACRs(final List<ACR> acrValues) { 378 379 this.acrValues = acrValues; 380 } 381 382 383 /** 384 * Gets the supported subject types. Corresponds to the 385 * {@code subject_types_supported} metadata field. 386 * 387 * @return The supported subject types. 388 */ 389 public List<SubjectType> getSubjectTypes() { 390 391 return subjectTypes; 392 } 393 394 395 /** 396 * Gets the supported JWS algorithms for ID tokens. Corresponds to the 397 * {@code id_token_signing_alg_values_supported} metadata field. 398 * 399 * @return The supported JWS algorithms, {@code null} if not specified. 400 */ 401 public List<JWSAlgorithm> getIDTokenJWSAlgs() { 402 403 return idTokenJWSAlgs; 404 } 405 406 407 /** 408 * Sets the supported JWS algorithms for ID tokens. Corresponds to the 409 * {@code id_token_signing_alg_values_supported} metadata field. 410 * 411 * @param idTokenJWSAlgs The supported JWS algorithms, {@code null} if 412 * not specified. 413 */ 414 public void setIDTokenJWSAlgs(final List<JWSAlgorithm> idTokenJWSAlgs) { 415 416 this.idTokenJWSAlgs = idTokenJWSAlgs; 417 } 418 419 420 /** 421 * Gets the supported JWE algorithms for ID tokens. Corresponds to the 422 * {@code id_token_encryption_alg_values_supported} metadata field. 423 * 424 * @return The supported JWE algorithms, {@code null} if not specified. 425 */ 426 public List<JWEAlgorithm> getIDTokenJWEAlgs() { 427 428 return idTokenJWEAlgs; 429 } 430 431 432 /** 433 * Sets the supported JWE algorithms for ID tokens. Corresponds to the 434 * {@code id_token_encryption_alg_values_supported} metadata field. 435 * 436 * @param idTokenJWEAlgs The supported JWE algorithms, {@code null} if 437 * not specified. 438 */ 439 public void setIDTokenJWEAlgs(final List<JWEAlgorithm> idTokenJWEAlgs) { 440 441 this.idTokenJWEAlgs = idTokenJWEAlgs; 442 } 443 444 445 /** 446 * Gets the supported encryption methods for ID tokens. Corresponds to 447 * the {@code id_token_encryption_enc_values_supported} metadata field. 448 * 449 * @return The supported encryption methods, {@code null} if not 450 * specified. 451 */ 452 public List<EncryptionMethod> getIDTokenJWEEncs() { 453 454 return idTokenJWEEncs; 455 } 456 457 458 /** 459 * Sets the supported encryption methods for ID tokens. Corresponds to 460 * the {@code id_token_encryption_enc_values_supported} metadata field. 461 * 462 * @param idTokenJWEEncs The supported encryption methods, {@code null} 463 * if not specified. 464 */ 465 public void setIDTokenJWEEncs(final List<EncryptionMethod> idTokenJWEEncs) { 466 467 this.idTokenJWEEncs = idTokenJWEEncs; 468 } 469 470 471 /** 472 * Gets the supported JWS algorithms for UserInfo JWTs. Corresponds to 473 * the {@code userinfo_signing_alg_values_supported} metadata field. 474 * 475 * @return The supported JWS algorithms, {@code null} if not specified. 476 */ 477 public List<JWSAlgorithm> getUserInfoJWSAlgs() { 478 479 return userInfoJWSAlgs; 480 } 481 482 483 /** 484 * Sets the supported JWS algorithms for UserInfo JWTs. Corresponds to 485 * the {@code userinfo_signing_alg_values_supported} metadata field. 486 * 487 * @param userInfoJWSAlgs The supported JWS algorithms, {@code null} if 488 * not specified. 489 */ 490 public void setUserInfoJWSAlgs(final List<JWSAlgorithm> userInfoJWSAlgs) { 491 492 this.userInfoJWSAlgs = userInfoJWSAlgs; 493 } 494 495 496 /** 497 * Gets the supported JWE algorithms for UserInfo JWTs. Corresponds to 498 * the {@code userinfo_encryption_alg_values_supported} metadata field. 499 * 500 * @return The supported JWE algorithms, {@code null} if not specified. 501 */ 502 public List<JWEAlgorithm> getUserInfoJWEAlgs() { 503 504 return userInfoJWEAlgs; 505 } 506 507 508 /** 509 * Sets the supported JWE algorithms for UserInfo JWTs. Corresponds to 510 * the {@code userinfo_encryption_alg_values_supported} metadata field. 511 * 512 * @param userInfoJWEAlgs The supported JWE algorithms, {@code null} if 513 * not specified. 514 */ 515 public void setUserInfoJWEAlgs(final List<JWEAlgorithm> userInfoJWEAlgs) { 516 517 this.userInfoJWEAlgs = userInfoJWEAlgs; 518 } 519 520 521 /** 522 * Gets the supported encryption methods for UserInfo JWTs. Corresponds 523 * to the {@code userinfo_encryption_enc_values_supported} metadata 524 * field. 525 * 526 * @return The supported encryption methods, {@code null} if not 527 * specified. 528 */ 529 public List<EncryptionMethod> getUserInfoJWEEncs() { 530 531 return userInfoJWEEncs; 532 } 533 534 535 /** 536 * Sets the supported encryption methods for UserInfo JWTs. Corresponds 537 * to the {@code userinfo_encryption_enc_values_supported} metadata 538 * field. 539 * 540 * @param userInfoJWEEncs The supported encryption methods, 541 * {@code null} if not specified. 542 */ 543 public void setUserInfoJWEEncs(final List<EncryptionMethod> userInfoJWEEncs) { 544 545 this.userInfoJWEEncs = userInfoJWEEncs; 546 } 547 548 549 /** 550 * Gets the supported displays. Corresponds to the 551 * {@code display_values_supported} metadata field. 552 * 553 * @return The supported displays, {@code null} if not specified. 554 */ 555 public List<Display> getDisplays() { 556 557 return displays; 558 } 559 560 561 /** 562 * Sets the supported displays. Corresponds to the 563 * {@code display_values_supported} metadata field. 564 * 565 * @param displays The supported displays, {@code null} if not 566 * specified. 567 */ 568 public void setDisplays(final List<Display> displays) { 569 570 this.displays = displays; 571 } 572 573 574 /** 575 * Gets the supported claim types. Corresponds to the 576 * {@code claim_types_supported} metadata field. 577 * 578 * @return The supported claim types, {@code null} if not specified. 579 */ 580 public List<ClaimType> getClaimTypes() { 581 582 return claimTypes; 583 } 584 585 586 /** 587 * Sets the supported claim types. Corresponds to the 588 * {@code claim_types_supported} metadata field. 589 * 590 * @param claimTypes The supported claim types, {@code null} if not 591 * specified. 592 */ 593 public void setClaimTypes(final List<ClaimType> claimTypes) { 594 595 this.claimTypes = claimTypes; 596 } 597 598 599 /** 600 * Gets the supported claims names. Corresponds to the 601 * {@code claims_supported} metadata field. 602 * 603 * @return The supported claims names, {@code null} if not specified. 604 */ 605 public List<String> getClaims() { 606 607 return claims; 608 } 609 610 611 /** 612 * Sets the supported claims names. Corresponds to the 613 * {@code claims_supported} metadata field. 614 * 615 * @param claims The supported claims names, {@code null} if not 616 * specified. 617 */ 618 public void setClaims(final List<String> claims) { 619 620 this.claims = claims; 621 } 622 623 624 /** 625 * Gets the supported claims locales. Corresponds to the 626 * {@code claims_locales_supported} metadata field. 627 * 628 * @return The supported claims locales, {@code null} if not specified. 629 */ 630 public List<LangTag> getClaimsLocales() { 631 632 return claimsLocales; 633 } 634 635 636 /** 637 * Sets the supported claims locales. Corresponds to the 638 * {@code claims_locales_supported} metadata field. 639 * 640 * @param claimsLocales The supported claims locales, {@code null} if 641 * not specified. 642 */ 643 public void setClaimLocales(final List<LangTag> claimsLocales) { 644 645 this.claimsLocales = claimsLocales; 646 } 647 648 649 /** 650 * Gets the support for the {@code claims} authorisation request 651 * parameter. Corresponds to the {@code claims_parameter_supported} 652 * metadata field. 653 * 654 * @return {@code true} if the {@code claim} parameter is supported, 655 * else {@code false}. 656 */ 657 public boolean supportsClaimsParam() { 658 659 return claimsParamSupported; 660 } 661 662 663 /** 664 * Sets the support for the {@code claims} authorisation request 665 * parameter. Corresponds to the {@code claims_parameter_supported} 666 * metadata field. 667 * 668 * @param claimsParamSupported {@code true} if the {@code claim} 669 * parameter is supported, else 670 * {@code false}. 671 */ 672 public void setSupportsClaimsParams(final boolean claimsParamSupported) { 673 674 this.claimsParamSupported = claimsParamSupported; 675 } 676 677 678 /** 679 * Gets the support for front-channel logout. Corresponds to the 680 * {@code frontchannel_logout_supported} metadata field. 681 * 682 * @return {@code true} if front-channel logout is supported, else 683 * {@code false}. 684 */ 685 public boolean supportsFrontChannelLogout() { 686 687 return frontChannelLogoutSupported; 688 } 689 690 691 /** 692 * Sets the support for front-channel logout. Corresponds to the 693 * {@code frontchannel_logout_supported} metadata field. 694 * 695 * @param frontChannelLogoutSupported {@code true} if front-channel 696 * logout is supported, else 697 * {@code false}. 698 */ 699 public void setSupportsFrontChannelLogout(final boolean frontChannelLogoutSupported) { 700 701 this.frontChannelLogoutSupported = frontChannelLogoutSupported; 702 } 703 704 705 /** 706 * Gets the support for front-channel logout with a session ID. 707 * Corresponds to the {@code frontchannel_logout_session_supported} 708 * metadata field. 709 * 710 * @return {@code true} if front-channel logout with a session ID is 711 * supported, else {@code false}. 712 */ 713 public boolean supportsFrontChannelLogoutSession() { 714 715 return frontChannelLogoutSessionSupported; 716 } 717 718 719 /** 720 * Sets the support for front-channel logout with a session ID. 721 * Corresponds to the {@code frontchannel_logout_session_supported} 722 * metadata field. 723 * 724 * @param frontChannelLogoutSessionSupported {@code true} if 725 * front-channel logout with 726 * a session ID is supported, 727 * else {@code false}. 728 */ 729 public void setSupportsFrontChannelLogoutSession(final boolean frontChannelLogoutSessionSupported) { 730 731 this.frontChannelLogoutSessionSupported = frontChannelLogoutSessionSupported; 732 } 733 734 735 /** 736 * Gets the support for back-channel logout. Corresponds to the 737 * {@code backchannel_logout_supported} metadata field. 738 * 739 * @return {@code true} if back-channel logout is supported, else 740 * {@code false}. 741 */ 742 public boolean supportsBackChannelLogout() { 743 744 return backChannelLogoutSupported; 745 } 746 747 748 /** 749 * Sets the support for back-channel logout. Corresponds to the 750 * {@code backchannel_logout_supported} metadata field. 751 * 752 * @param backChannelLogoutSupported {@code true} if back-channel 753 * logout is supported, else 754 * {@code false}. 755 */ 756 public void setSupportsBackChannelLogout(final boolean backChannelLogoutSupported) { 757 758 this.backChannelLogoutSupported = backChannelLogoutSupported; 759 } 760 761 762 /** 763 * Gets the support for back-channel logout with a session ID. 764 * Corresponds to the {@code backchannel_logout_session_supported} 765 * metadata field. 766 * 767 * @return {@code true} if back-channel logout with a session ID is 768 * supported, else {@code false}. 769 */ 770 public boolean supportsBackChannelLogoutSession() { 771 772 return backChannelLogoutSessionSupported; 773 } 774 775 776 /** 777 * Sets the support for back-channel logout with a session ID. 778 * Corresponds to the {@code backchannel_logout_session_supported} 779 * metadata field. 780 * 781 * @param backChannelLogoutSessionSupported {@code true} if 782 * back-channel logout with a 783 * session ID is supported, 784 * else {@code false}. 785 */ 786 public void setSupportsBackChannelLogoutSession(final boolean backChannelLogoutSessionSupported) { 787 788 this.backChannelLogoutSessionSupported = backChannelLogoutSessionSupported; 789 } 790 791 792 /** 793 * Applies the OpenID Provider metadata defaults where no values have 794 * been specified. 795 * 796 * <ul> 797 * <li>The response modes default to {@code ["query", "fragment"]}. 798 * <li>The grant types default to {@code ["authorization_code", 799 * "implicit"]}. 800 * <li>The token endpoint authentication methods default to 801 * {@code ["client_secret_basic"]}. 802 * <li>The claim types default to {@code ["normal]}. 803 * </ul> 804 */ 805 public void applyDefaults() { 806 807 super.applyDefaults(); 808 809 if (claimTypes == null) { 810 claimTypes = new ArrayList<>(1); 811 claimTypes.add(ClaimType.NORMAL); 812 } 813 } 814 815 816 /** 817 * Returns the JSON object representation of this OpenID Connect 818 * provider metadata. 819 * 820 * @return The JSON object representation. 821 */ 822 public JSONObject toJSONObject() { 823 824 JSONObject o = super.toJSONObject(); 825 826 // Mandatory fields 827 828 List<String> stringList = new ArrayList<>(subjectTypes.size()); 829 830 for (SubjectType st: subjectTypes) 831 stringList.add(st.toString()); 832 833 o.put("subject_types_supported", stringList); 834 835 // Optional fields 836 837 if (userInfoEndpoint != null) 838 o.put("userinfo_endpoint", userInfoEndpoint.toString()); 839 840 if (checkSessionIframe != null) 841 o.put("check_session_iframe", checkSessionIframe.toString()); 842 843 if (endSessionEndpoint != null) 844 o.put("end_session_endpoint", endSessionEndpoint.toString()); 845 846 if (acrValues != null) { 847 848 stringList = new ArrayList<>(acrValues.size()); 849 850 for (ACR acr: acrValues) 851 stringList.add(acr.getValue()); 852 853 o.put("acr_values_supported", stringList); 854 } 855 856 if (idTokenJWSAlgs != null) { 857 858 stringList = new ArrayList<>(idTokenJWSAlgs.size()); 859 860 for (JWSAlgorithm alg: idTokenJWSAlgs) 861 stringList.add(alg.getName()); 862 863 o.put("id_token_signing_alg_values_supported", stringList); 864 } 865 866 if (idTokenJWEAlgs != null) { 867 868 stringList = new ArrayList<>(idTokenJWEAlgs.size()); 869 870 for (JWEAlgorithm alg: idTokenJWEAlgs) 871 stringList.add(alg.getName()); 872 873 o.put("id_token_encryption_alg_values_supported", stringList); 874 } 875 876 if (idTokenJWEEncs != null) { 877 878 stringList = new ArrayList<>(idTokenJWEEncs.size()); 879 880 for (EncryptionMethod m: idTokenJWEEncs) 881 stringList.add(m.getName()); 882 883 o.put("id_token_encryption_enc_values_supported", stringList); 884 } 885 886 if (userInfoJWSAlgs != null) { 887 888 stringList = new ArrayList<>(userInfoJWSAlgs.size()); 889 890 for (JWSAlgorithm alg: userInfoJWSAlgs) 891 stringList.add(alg.getName()); 892 893 o.put("userinfo_signing_alg_values_supported", stringList); 894 } 895 896 if (userInfoJWEAlgs != null) { 897 898 stringList = new ArrayList<>(userInfoJWEAlgs.size()); 899 900 for (JWEAlgorithm alg: userInfoJWEAlgs) 901 stringList.add(alg.getName()); 902 903 o.put("userinfo_encryption_alg_values_supported", stringList); 904 } 905 906 if (userInfoJWEEncs != null) { 907 908 stringList = new ArrayList<>(userInfoJWEEncs.size()); 909 910 for (EncryptionMethod m: userInfoJWEEncs) 911 stringList.add(m.getName()); 912 913 o.put("userinfo_encryption_enc_values_supported", stringList); 914 } 915 916 if (displays != null) { 917 918 stringList = new ArrayList<>(displays.size()); 919 920 for (Display d: displays) 921 stringList.add(d.toString()); 922 923 o.put("display_values_supported", stringList); 924 } 925 926 if (claimTypes != null) { 927 928 stringList = new ArrayList<>(claimTypes.size()); 929 930 for (ClaimType ct: claimTypes) 931 stringList.add(ct.toString()); 932 933 o.put("claim_types_supported", stringList); 934 } 935 936 if (claims != null) 937 o.put("claims_supported", claims); 938 939 if (claimsLocales != null) { 940 941 stringList = new ArrayList<>(claimsLocales.size()); 942 943 for (LangTag l: claimsLocales) 944 stringList.add(l.toString()); 945 946 o.put("claims_locales_supported", stringList); 947 } 948 949 o.put("claims_parameter_supported", claimsParamSupported); 950 951 // optional front and back-channel logout 952 o.put("frontchannel_logout_supported", frontChannelLogoutSupported); 953 954 if (frontChannelLogoutSupported) { 955 o.put("frontchannel_logout_session_supported", frontChannelLogoutSessionSupported); 956 } 957 958 o.put("backchannel_logout_supported", backChannelLogoutSupported); 959 960 if (backChannelLogoutSupported) { 961 o.put("backchannel_logout_session_supported", backChannelLogoutSessionSupported); 962 } 963 964 return o; 965 } 966 967 968 /** 969 * Parses an OpenID Provider metadata from the specified JSON object. 970 * 971 * @param jsonObject The JSON object to parse. Must not be 972 * {@code null}. 973 * 974 * @return The OpenID Provider metadata. 975 * 976 * @throws ParseException If the JSON object couldn't be parsed to an 977 * OpenID Provider metadata. 978 */ 979 public static OIDCProviderMetadata parse(final JSONObject jsonObject) 980 throws ParseException { 981 982 AuthorizationServerMetadata as = AuthorizationServerMetadata.parse(jsonObject); 983 984 List<SubjectType> subjectTypes = new ArrayList<>(); 985 for (String v: JSONObjectUtils.getStringArray(jsonObject, "subject_types_supported")) { 986 subjectTypes.add(SubjectType.parse(v)); 987 } 988 989 OIDCProviderMetadata op = new OIDCProviderMetadata( 990 as.getIssuer(), 991 Collections.unmodifiableList(subjectTypes), 992 as.getJWKSetURI()); 993 994 // Endpoints 995 op.setAuthorizationEndpointURI(as.getAuthorizationEndpointURI()); 996 op.setTokenEndpointURI(as.getTokenEndpointURI()); 997 op.setRegistrationEndpointURI(as.getRegistrationEndpointURI()); 998 op.setIntrospectionEndpointURI(as.getIntrospectionEndpointURI()); 999 op.setRevocationEndpointURI(as.getRevocationEndpointURI()); 1000 op.setRequestObjectEndpoint(as.getRequestObjectEndpoint()); 1001 op.userInfoEndpoint = JSONObjectUtils.getURI(jsonObject, "userinfo_endpoint", null); 1002 op.checkSessionIframe = JSONObjectUtils.getURI(jsonObject, "check_session_iframe", null); 1003 op.endSessionEndpoint = JSONObjectUtils.getURI(jsonObject, "end_session_endpoint", null); 1004 1005 // Capabilities 1006 op.setScopes(as.getScopes()); 1007 op.setResponseTypes(as.getResponseTypes()); 1008 op.setResponseModes(as.getResponseModes()); 1009 op.setGrantTypes(as.getGrantTypes()); 1010 1011 op.setTokenEndpointAuthMethods(as.getTokenEndpointAuthMethods()); 1012 op.setTokenEndpointJWSAlgs(as.getTokenEndpointJWSAlgs()); 1013 1014 op.setIntrospectionEndpointAuthMethods(as.getIntrospectionEndpointAuthMethods()); 1015 op.setIntrospectionEndpointJWSAlgs(as.getIntrospectionEndpointJWSAlgs()); 1016 1017 op.setRevocationEndpointAuthMethods(as.getRevocationEndpointAuthMethods()); 1018 op.setRevocationEndpointJWSAlgs(as.getRevocationEndpointJWSAlgs()); 1019 1020 op.setRequestObjectJWSAlgs(as.getRequestObjectJWSAlgs()); 1021 op.setRequestObjectJWEAlgs(as.getRequestObjectJWEAlgs()); 1022 op.setRequestObjectJWEEncs(as.getRequestObjectJWEEncs()); 1023 1024 op.setSupportsRequestParam(as.supportsRequestParam()); 1025 op.setSupportsRequestURIParam(as.supportsRequestURIParam()); 1026 op.setRequiresRequestURIRegistration(as.requiresRequestURIRegistration()); 1027 1028 op.setCodeChallengeMethods(as.getCodeChallengeMethods()); 1029 1030 if (jsonObject.get("acr_values_supported") != null) { 1031 1032 op.acrValues = new ArrayList<>(); 1033 1034 for (String v: JSONObjectUtils.getStringArray(jsonObject, "acr_values_supported")) { 1035 1036 if (v != null) 1037 op.acrValues.add(new ACR(v)); 1038 } 1039 } 1040 1041 // ID token 1042 1043 if (jsonObject.get("id_token_signing_alg_values_supported") != null) { 1044 1045 op.idTokenJWSAlgs = new ArrayList<>(); 1046 1047 for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_signing_alg_values_supported")) { 1048 1049 if (v != null) 1050 op.idTokenJWSAlgs.add(JWSAlgorithm.parse(v)); 1051 } 1052 } 1053 1054 1055 if (jsonObject.get("id_token_encryption_alg_values_supported") != null) { 1056 1057 op.idTokenJWEAlgs = new ArrayList<>(); 1058 1059 for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_encryption_alg_values_supported")) { 1060 1061 if (v != null) 1062 op.idTokenJWEAlgs.add(JWEAlgorithm.parse(v)); 1063 } 1064 } 1065 1066 1067 if (jsonObject.get("id_token_encryption_enc_values_supported") != null) { 1068 1069 op.idTokenJWEEncs = new ArrayList<>(); 1070 1071 for (String v: JSONObjectUtils.getStringArray(jsonObject, "id_token_encryption_enc_values_supported")) { 1072 1073 if (v != null) 1074 op.idTokenJWEEncs.add(EncryptionMethod.parse(v)); 1075 } 1076 } 1077 1078 // UserInfo 1079 1080 if (jsonObject.get("userinfo_signing_alg_values_supported") != null) { 1081 1082 op.userInfoJWSAlgs = new ArrayList<>(); 1083 1084 for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_signing_alg_values_supported")) { 1085 1086 if (v != null) 1087 op.userInfoJWSAlgs.add(JWSAlgorithm.parse(v)); 1088 } 1089 } 1090 1091 1092 if (jsonObject.get("userinfo_encryption_alg_values_supported") != null) { 1093 1094 op.userInfoJWEAlgs = new ArrayList<>(); 1095 1096 for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_encryption_alg_values_supported")) { 1097 1098 if (v != null) 1099 op.userInfoJWEAlgs.add(JWEAlgorithm.parse(v)); 1100 } 1101 } 1102 1103 1104 if (jsonObject.get("userinfo_encryption_enc_values_supported") != null) { 1105 1106 op.userInfoJWEEncs = new ArrayList<>(); 1107 1108 for (String v: JSONObjectUtils.getStringArray(jsonObject, "userinfo_encryption_enc_values_supported")) { 1109 1110 if (v != null) 1111 op.userInfoJWEEncs.add(EncryptionMethod.parse(v)); 1112 } 1113 } 1114 1115 1116 // Misc 1117 1118 if (jsonObject.get("display_values_supported") != null) { 1119 1120 op.displays = new ArrayList<>(); 1121 1122 for (String v: JSONObjectUtils.getStringArray(jsonObject, "display_values_supported")) { 1123 1124 if (v != null) 1125 op.displays.add(Display.parse(v)); 1126 } 1127 } 1128 1129 if (jsonObject.get("claim_types_supported") != null) { 1130 1131 op.claimTypes = new ArrayList<>(); 1132 1133 for (String v: JSONObjectUtils.getStringArray(jsonObject, "claim_types_supported")) { 1134 1135 if (v != null) 1136 op.claimTypes.add(ClaimType.parse(v)); 1137 } 1138 } 1139 1140 1141 if (jsonObject.get("claims_supported") != null) { 1142 1143 op.claims = new ArrayList<>(); 1144 1145 for (String v: JSONObjectUtils.getStringArray(jsonObject, "claims_supported")) { 1146 1147 if (v != null) 1148 op.claims.add(v); 1149 } 1150 } 1151 1152 if (jsonObject.get("claims_locales_supported") != null) { 1153 1154 op.claimsLocales = new ArrayList<>(); 1155 1156 for (String v : JSONObjectUtils.getStringArray(jsonObject, "claims_locales_supported")) { 1157 1158 if (v != null) { 1159 1160 try { 1161 op.claimsLocales.add(LangTag.parse(v)); 1162 1163 } catch (LangTagException e) { 1164 1165 throw new ParseException("Invalid claims_locales_supported field: " + e.getMessage(), e); 1166 } 1167 } 1168 } 1169 } 1170 1171 op.setUILocales(as.getUILocales()); 1172 op.setServiceDocsURI(as.getServiceDocsURI()); 1173 op.setPolicyURI(as.getPolicyURI()); 1174 op.setTermsOfServiceURI(as.getTermsOfServiceURI()); 1175 1176 if (jsonObject.get("claims_parameter_supported") != null) 1177 op.claimsParamSupported = JSONObjectUtils.getBoolean(jsonObject, "claims_parameter_supported"); 1178 1179 // Optional front and back-channel logout 1180 if (jsonObject.get("frontchannel_logout_supported") != null) 1181 op.frontChannelLogoutSupported = JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_supported"); 1182 1183 if (op.frontChannelLogoutSupported && jsonObject.get("frontchannel_logout_session_supported") != null) 1184 op.frontChannelLogoutSessionSupported = JSONObjectUtils.getBoolean(jsonObject, "frontchannel_logout_session_supported"); 1185 1186 if (jsonObject.get("backchannel_logout_supported") != null) 1187 op.backChannelLogoutSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_supported"); 1188 1189 if (op.frontChannelLogoutSupported && jsonObject.get("backchannel_logout_session_supported") != null) 1190 op.backChannelLogoutSessionSupported = JSONObjectUtils.getBoolean(jsonObject, "backchannel_logout_session_supported"); 1191 1192 if (jsonObject.get("mtls_endpoint_aliases") != null) 1193 op.setMtlsEndpointAliases(OIDCProviderEndpointMetadata.parse(JSONObjectUtils.getJSONObject(jsonObject, "mtls_endpoint_aliases"))); 1194 1195 op.setSupportsTLSClientCertificateBoundAccessTokens(as.supportsTLSClientCertificateBoundAccessTokens()); 1196 1197 // JARM 1198 op.setAuthorizationJWSAlgs(as.getAuthorizationJWSAlgs()); 1199 op.setAuthorizationJWEAlgs(as.getAuthorizationJWEAlgs()); 1200 op.setAuthorizationJWEEncs(as.getAuthorizationJWEEncs()); 1201 1202 // Parse custom (not registered) parameters 1203 for (Map.Entry<String,?> entry: as.getCustomParameters().entrySet()) { 1204 if (REGISTERED_PARAMETER_NAMES.contains(entry.getKey())) 1205 continue; // skip 1206 op.setCustomParameter(entry.getKey(), entry.getValue()); 1207 } 1208 1209 return op; 1210 } 1211 1212 1213 /** 1214 * Parses an OpenID Provider metadata from the specified JSON object 1215 * string. 1216 * 1217 * @param s The JSON object sting to parse. Must not be {@code null}. 1218 * 1219 * @return The OpenID Provider metadata. 1220 * 1221 * @throws ParseException If the JSON object string couldn't be parsed 1222 * to an OpenID Provider metadata. 1223 */ 1224 public static OIDCProviderMetadata parse(final String s) 1225 throws ParseException { 1226 1227 return parse(JSONObjectUtils.parse(s)); 1228 } 1229 1230 1231 /** 1232 * Resolves OpenID Provider metadata from the specified issuer 1233 * identifier. The metadata is downloaded by HTTP GET from 1234 * {@code [issuer-url]/.well-known/openid-configuration}. 1235 * 1236 * @param issuer The OpenID Provider issuer identifier. Must represent 1237 * a valid HTTPS or HTTP URL. Must not be {@code null}. 1238 * 1239 * @return The OpenID Provider metadata. 1240 * 1241 * @throws GeneralException If the issuer identifier or the downloaded 1242 * metadata are invalid. 1243 * @throws IOException On a HTTP exception. 1244 */ 1245 public static OIDCProviderMetadata resolve(final Issuer issuer) 1246 throws GeneralException, IOException { 1247 1248 return resolve(issuer, 0, 0); 1249 } 1250 1251 1252 /** 1253 * Resolves OpenID Provider metadata from the specified issuer 1254 * identifier. The metadata is downloaded by HTTP GET from 1255 * {@code [issuer-url]/.well-known/openid-configuration}, using the 1256 * specified HTTP timeouts. 1257 * 1258 * @param issuer The issuer identifier. Must represent a valid 1259 * HTTPS or HTTP URL. Must not be {@code null}. 1260 * @param connectTimeout The HTTP connect timeout, in milliseconds. 1261 * Zero implies no timeout. Must not be negative. 1262 * @param readTimeout The HTTP response read timeout, in 1263 * milliseconds. Zero implies no timeout. Must 1264 * not be negative. 1265 * 1266 * @return The OpenID Provider metadata. 1267 * 1268 * @throws GeneralException If the issuer identifier or the downloaded 1269 * metadata are invalid. 1270 * @throws IOException On a HTTP exception. 1271 */ 1272 public static OIDCProviderMetadata resolve(final Issuer issuer, 1273 final int connectTimeout, 1274 final int readTimeout) 1275 throws GeneralException, IOException { 1276 1277 URL configURL; 1278 1279 try { 1280 URL issuerURL = new URL(issuer.getValue()); 1281 1282 // Validate but don't insist on HTTPS, see 1283 // http://openid.net/specs/openid-connect-core-1_0.html#Terminology 1284 if (issuerURL.getQuery() != null && ! issuerURL.getQuery().trim().isEmpty()) { 1285 throw new GeneralException("The issuer identifier must not contain a query component"); 1286 } 1287 1288 if (issuerURL.getPath() != null && issuerURL.getPath().endsWith("/")) { 1289 configURL = new URL(issuerURL + ".well-known/openid-configuration"); 1290 } else { 1291 configURL = new URL(issuerURL + "/.well-known/openid-configuration"); 1292 } 1293 1294 } catch (MalformedURLException e) { 1295 throw new GeneralException("The issuer identifier doesn't represent a valid URL: " + e.getMessage(), e); 1296 } 1297 1298 HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, configURL); 1299 httpRequest.setConnectTimeout(connectTimeout); 1300 httpRequest.setReadTimeout(readTimeout); 1301 1302 HTTPResponse httpResponse = httpRequest.send(); 1303 1304 if (httpResponse.getStatusCode() != 200) { 1305 throw new IOException("Couldn't download OpenID Provider metadata from " + configURL + 1306 ": Status code " + httpResponse.getStatusCode()); 1307 } 1308 1309 JSONObject jsonObject = httpResponse.getContentAsJSONObject(); 1310 1311 OIDCProviderMetadata op = OIDCProviderMetadata.parse(jsonObject); 1312 1313 if (! issuer.equals(op.getIssuer())) { 1314 throw new GeneralException("The returned issuer doesn't match the expected: " + op.getIssuer()); 1315 } 1316 1317 return op; 1318 } 1319}