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