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.federation.entities; 019 020 021import com.nimbusds.jose.jwk.JWKSet; 022import com.nimbusds.jwt.JWTClaimsSet; 023import com.nimbusds.oauth2.sdk.ParseException; 024import com.nimbusds.oauth2.sdk.id.Identifier; 025import com.nimbusds.oauth2.sdk.id.Issuer; 026import com.nimbusds.oauth2.sdk.id.Subject; 027import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 028import com.nimbusds.oauth2.sdk.util.MapUtils; 029import com.nimbusds.openid.connect.sdk.federation.policy.MetadataPolicy; 030import com.nimbusds.openid.connect.sdk.federation.policy.language.PolicyViolationException; 031import com.nimbusds.openid.connect.sdk.federation.trust.constraints.TrustChainConstraints; 032import com.nimbusds.openid.connect.sdk.federation.trust.marks.TrustMarkEntry; 033import com.nimbusds.openid.connect.sdk.federation.trust.marks.TrustMarkIssuerMetadata; 034import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation; 035import net.minidev.json.JSONArray; 036import net.minidev.json.JSONObject; 037 038import java.util.*; 039 040 041/** 042 * Federation entity statement claims set, serialisable to a JSON object. 043 * 044 * <p>Example claims set: 045 * 046 * <pre> 047 * { 048 * "iss": "https://feide.no", 049 * "sub": "https://ntnu.no", 050 * "iat": 1516239022, 051 * "exp": 1516298022, 052 * "crit": ["jti"], 053 * "jti": "7l2lncFdY6SlhNia", 054 * "policy_language_crit": ["regexp"], 055 * "metadata": { 056 * "openid_provider": { 057 * "issuer": "https://ntnu.no", 058 * "organization_name": "NTNU", 059 * }, 060 * "oauth_client": { 061 * "organization_name": "NTNU" 062 * } 063 * }, 064 * "metadata_policy": { 065 * "openid_provider": { 066 * "id_token_signing_alg_values_supported": { 067 * "subset_of": ["RS256", "RS384", "RS512"] 068 * }, 069 * "op_policy_uri": { 070 * "regexp": "^https:\/\/[\\w-]+\\.example\\.com\/[\\w-]+\\.html"} 071 * }, 072 * "oauth_client": { 073 * "grant_types": { 074 * "subset_of": ["authorization_code", "client_credentials"]}, 075 * "scope": { 076 * "subset_of": ["openid", "profile", "email", "phone"]} 077 * } 078 * }, 079 * "constraints": { 080 * "max_path_length": 2 081 * }, 082 * "jwks": { 083 * "keys": [ 084 * { 085 * "alg": "RS256", 086 * "e": "AQAB", 087 * "key_ops": ["verify"], 088 * "kid": "key1", 089 * "kty": "RSA", 090 * "n": "pnXBOusEANuug6ewezb9J_...", 091 * "use": "sig" 092 * } 093 * ] 094 * } 095 * } 096 * </pre> 097 * 098 * <p>Related specifications: 099 * 100 * <ul> 101 * <li>OpenID Connect Federation 1.0, section 3.1. 102 * </ul> 103 */ 104public class EntityStatementClaimsSet extends CommonFederationClaimsSet { 105 106 107 /** 108 * The JWK set claim name. 109 */ 110 public static final String JWKS_CLAIM_NAME = "jwks"; 111 112 113 /** 114 * The authority hints claim name. 115 */ 116 public static final String AUTHORITY_HINTS_CLAIM_NAME = "authority_hints"; 117 118 119 /** 120 * The metadata policy claim name. 121 */ 122 public static final String METADATA_POLICY_CLAIM_NAME = "metadata_policy"; 123 124 125 /** 126 * The assumed trust anchor in a explicit client registration. Intended 127 * for entity statements issued by an OP for RP performing explicit 128 * client registration only. 129 */ 130 public static final String TRUST_ANCHOR_ID_CLAIM_NAME = "trust_anchor_id"; 131 132 133 /** 134 * The constraints claim name. 135 */ 136 public static final String CONSTRAINTS_CLAIM_NAME = "constraints"; 137 138 139 /** 140 * The trust marks issuers claim name. 141 */ 142 public static final String TRUST_MARKS_ISSUERS_CLAIM_NAME = "trust_marks_issuers"; 143 144 145 /** 146 * The critical claim name. 147 */ 148 public static final String CRITICAL_CLAIM_NAME = "crit"; 149 150 151 /** 152 * The policy critical claim name. 153 */ 154 public static final String POLICY_LANGUAGE_CRITICAL_CLAIM_NAME = "policy_language_crit"; 155 156 157 /** 158 * The names of the standard top-level claims. 159 */ 160 private static final Set<String> STD_CLAIM_NAMES; 161 162 static { 163 Set<String> claimNames = new HashSet<>(); 164 claimNames.add(ISS_CLAIM_NAME); 165 claimNames.add(SUB_CLAIM_NAME); 166 claimNames.add(IAT_CLAIM_NAME); 167 claimNames.add(EXP_CLAIM_NAME); 168 claimNames.add(JWKS_CLAIM_NAME); 169 claimNames.add(AUD_CLAIM_NAME); 170 claimNames.add(AUTHORITY_HINTS_CLAIM_NAME); 171 claimNames.add(METADATA_CLAIM_NAME); 172 claimNames.add(METADATA_POLICY_CLAIM_NAME); 173 claimNames.add(CONSTRAINTS_CLAIM_NAME); 174 claimNames.add(CRITICAL_CLAIM_NAME); 175 claimNames.add(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME); 176 claimNames.add(TRUST_MARKS_CLAIM_NAME); 177 claimNames.add(TRUST_MARKS_ISSUERS_CLAIM_NAME); 178 claimNames.add(TRUST_ANCHOR_ID_CLAIM_NAME); 179 STD_CLAIM_NAMES = Collections.unmodifiableSet(claimNames); 180 } 181 182 183 /** 184 * Gets the names of the standard top-level claims. 185 * 186 * @return The names of the standard top-level claims (read-only set). 187 */ 188 public static Set<String> getStandardClaimNames() { 189 190 return STD_CLAIM_NAMES; 191 } 192 193 194 /** 195 * Creates a new federation entity statement claims set with the 196 * minimum required claims. 197 * 198 * @param iss The issuer. Must not be {@code null}. 199 * @param sub The subject. Must not be {@code null}. 200 * @param iat The issue time. Must not be {@code null}. 201 * @param exp The expiration time. Must not be {@code null}. 202 * @param jwks The entity public JWK set, {@code null} if not required. 203 */ 204 public EntityStatementClaimsSet(final Issuer iss, 205 final Subject sub, 206 final Date iat, 207 final Date exp, 208 final JWKSet jwks) { 209 210 this(new EntityID(iss.getValue()), new EntityID(sub.getValue()), iat, exp, jwks); 211 } 212 213 214 /** 215 * Creates a new federation entity statement claims set with the 216 * minimum required claims. 217 * 218 * @param iss The issuer. Must not be {@code null}. 219 * @param sub The subject. Must not be {@code null}. 220 * @param iat The issue time. Must not be {@code null}. 221 * @param exp The expiration time. Must not be {@code null}. 222 * @param jwks The entity public JWK set, {@code null} if not required. 223 */ 224 public EntityStatementClaimsSet(final EntityID iss, 225 final EntityID sub, 226 final Date iat, 227 final Date exp, 228 final JWKSet jwks) { 229 230 setClaim(ISS_CLAIM_NAME, iss.getValue()); 231 setClaim(SUB_CLAIM_NAME, sub.getValue()); 232 233 if (iat == null) { 234 throw new IllegalArgumentException("The iat (issued-at) claim must not be null"); 235 } 236 setDateClaim(IAT_CLAIM_NAME, iat); 237 238 if (exp == null) { 239 throw new IllegalArgumentException("The exp (expiration) claim must not be null"); 240 } 241 setDateClaim(EXP_CLAIM_NAME, exp); 242 243 if (jwks != null) { 244 setClaim(JWKS_CLAIM_NAME, new JSONObject(jwks.toJSONObject(true))); // public JWKs only 245 } 246 } 247 248 249 /** 250 * Creates a new federation entity statement claims set from the 251 * specified JWT claims set. 252 * 253 * @param jwtClaimsSet The JWT claims set. Must not be {@code null}. 254 * 255 * @throws ParseException If the JWT claims set doesn't represent a 256 * valid federation entity statement claims set. 257 */ 258 public EntityStatementClaimsSet(final JWTClaimsSet jwtClaimsSet) 259 throws ParseException { 260 261 super(JSONObjectUtils.toJSONObject(jwtClaimsSet)); 262 263 validateRequiredClaimsPresence(); 264 } 265 266 267 /** 268 * Validates this claims set for having all minimum required claims for 269 * an entity statement. If a {@link #isSelfStatement() selt-statement} 270 * check for the {@link #hasMetadata() presence of metadata}. If 271 * {@link #getCriticalExtensionClaims() critical extension claims} are 272 * listed their presence is also checked. 273 * 274 * @throws ParseException If the validation failed and a required claim 275 * is missing. 276 */ 277 public void validateRequiredClaimsPresence() 278 throws ParseException { 279 280 super.validateRequiredClaimsPresence(); 281 282 // jwks always required for self-statements 283 if (isSelfStatement() && getJWKSet() == null) { 284 throw new ParseException("Missing jwks (JWK set) claim"); 285 } 286 287 if (isSelfStatement() && ! hasMetadata()) { 288 throw new ParseException("Missing required metadata claim for self-statement"); 289 } 290 291 List<String> crit = getCriticalExtensionClaims(); 292 293 if (crit != null) { 294 for (String claimName: crit) { 295 if (getClaim(claimName) == null) { 296 throw new ParseException("Missing critical " + claimName + " claim"); 297 } 298 } 299 } 300 } 301 302 303 /** 304 * Returns {@code true} if this is a self-statement (issuer and subject 305 * match). 306 * 307 * @return {@code true} for a self-statement, {@code false} if not. 308 */ 309 public boolean isSelfStatement() { 310 311 Issuer issuer = getIssuer(); 312 Subject subject = getSubject(); 313 314 return issuer != null && subject != null && issuer.getValue().equals(subject.getValue()); 315 } 316 317 318 /** 319 * Gets the entity JWK set. Corresponds to the {@code jwks} claim. 320 * 321 * @return The entity JWK set, {@code null} if not specified or parsing 322 * failed. 323 */ 324 public JWKSet getJWKSet() { 325 326 JSONObject jwkSetJSONObject = getJSONObjectClaim(JWKS_CLAIM_NAME); 327 if (jwkSetJSONObject == null) { 328 return null; 329 } 330 try { 331 return JWKSet.parse(jwkSetJSONObject); 332 } catch (java.text.ParseException e) { 333 return null; 334 } 335 } 336 337 338 /** 339 * Gets the entity IDs of the intermediate entities or trust anchors. 340 * Corresponds to the {@code authority_hints} claim. 341 * 342 * @return The entity IDs, {@code null} or empty list for a trust 343 * anchor, or if parsing failed. 344 */ 345 public List<EntityID> getAuthorityHints() { 346 347 List<String> strings = getStringListClaim(AUTHORITY_HINTS_CLAIM_NAME); 348 349 if (strings == null) { 350 return null; 351 } 352 353 List<EntityID> trustChain = new LinkedList<>(); 354 for (String s: strings) { 355 trustChain.add(new EntityID(s)); 356 } 357 return trustChain; 358 } 359 360 361 /** 362 * Sets the entity IDs of the intermediate entities or trust anchors. 363 * Corresponds to the {@code authority_hints} claim. 364 * 365 * @param trustChain The entity IDs, {@code null} or empty list for a 366 * trust anchor. 367 */ 368 public void setAuthorityHints(final List<EntityID> trustChain) { 369 370 if (trustChain != null) { 371 setClaim(AUTHORITY_HINTS_CLAIM_NAME, Identifier.toStringList(trustChain)); 372 } else { 373 setClaim(AUTHORITY_HINTS_CLAIM_NAME, null); 374 } 375 } 376 377 378 /** 379 * Returns {@code true} if a metadata field is present. Corresponds to 380 * the {@code metadata} claim. 381 * 382 * @return {@code true} if a metadata field for an OpenID relying 383 * party, an OpenID provider, an OAuth authorisation server, an 384 * OAuth client, an OAuth protected resource, a federation 385 * entity, or a trust mark issuer is present. 386 */ 387 public boolean hasMetadata() { 388 389 JSONObject metadataObject = getJSONObjectClaim(METADATA_CLAIM_NAME); 390 391 if (MapUtils.isEmpty(metadataObject)) { 392 return false; 393 } 394 395 if (metadataObject.get(EntityType.OPENID_RELYING_PARTY.getValue()) != null) return true; 396 if (metadataObject.get(EntityType.OPENID_PROVIDER.getValue()) != null) return true; 397 if (metadataObject.get(EntityType.OAUTH_AUTHORIZATION_SERVER.getValue()) != null) return true; 398 if (metadataObject.get(EntityType.OAUTH_CLIENT.getValue()) != null) return true; 399 if (metadataObject.get(EntityType.OAUTH_RESOURCE.getValue()) != null) return true; 400 if (metadataObject.get(EntityType.FEDERATION_ENTITY.getValue()) != null) return true; 401 if (metadataObject.get(EntityType.TRUST_MARK_ISSUER.getValue()) != null) return true; 402 403 return false; 404 } 405 406 407 /** 408 * Gets the OpenID relying party information (metadata plus {@code 409 * client_id} and potentially other client information fields) if 410 * present for this entity. Corresponds to the 411 * {@code metadata.openid_relying_party} claim. 412 * 413 * @return The RP information, {@code null} if not specified or if 414 * parsing failed. 415 */ 416 public OIDCClientInformation getRPInformation() { 417 418 JSONObject o = getMetadata(EntityType.OPENID_RELYING_PARTY); 419 420 if (o == null) { 421 return null; 422 } 423 424 try { 425 return OIDCClientInformation.parse(o); 426 } catch (ParseException e) { 427 return null; 428 } 429 } 430 431 432 /** 433 * Sets the OpenID relying party information (metadata plus {@code 434 * client_id} and potentially other client information fields) if 435 * present for this entity. Corresponds to the 436 * {@code metadata.openid_relying_party} claim. 437 * 438 * @param rpInfo The RP information, {@code null} if not specified or 439 * if parsing failed. 440 */ 441 public void setRPInformation(final OIDCClientInformation rpInfo) { 442 443 JSONObject o = rpInfo != null ? rpInfo.toJSONObject() : null; 444 setMetadata(EntityType.OPENID_RELYING_PARTY, o); 445 } 446 447 448 /** 449 * Sets the trust mark issuer metadata for this entity. 450 * Corresponds to the {@code metadata.trust_mark_issuer} claim. 451 * 452 * @param trustMarkIssuerMetadata The trust mark issuer metadata, 453 * {@code null} if not specified. 454 */ 455 @Deprecated 456 public void setTrustMarkIssuerMetadata(final TrustMarkIssuerMetadata trustMarkIssuerMetadata) { 457 458 JSONObject o = trustMarkIssuerMetadata != null ? trustMarkIssuerMetadata.toJSONObject() : null; 459 setMetadata(EntityType.TRUST_MARK_ISSUER, o); 460 } 461 462 463 /** 464 * Gets the complete metadata policy JSON object. Corresponds to the 465 * {@code metadata_policy} claim. 466 * 467 * @return The metadata policy JSON object, {@code null} if not 468 * specified or if parsing failed. 469 */ 470 public JSONObject getMetadataPolicyJSONObject() { 471 472 return getJSONObjectClaim(METADATA_POLICY_CLAIM_NAME); 473 } 474 475 476 /** 477 * Sets the complete metadata policy JSON object. Corresponds to the 478 * {@code metadata_policy} claim. 479 * 480 * @param metadataPolicy The metadata policy JSON object, {@code null} 481 * if not specified. 482 */ 483 public void setMetadataPolicyJSONObject(final JSONObject metadataPolicy) { 484 485 setClaim(METADATA_POLICY_CLAIM_NAME, metadataPolicy); 486 } 487 488 489 /** 490 * Gets the metadata policy for the specified type. Corresponds to the 491 * {@code metadata_policy} claim. 492 * 493 * @param type The entity type. Must not be {@code null}. 494 * 495 * @return The metadata policy, {@code null} or if JSON parsing failed. 496 * 497 * @throws PolicyViolationException On a policy violation. 498 */ 499 public MetadataPolicy getMetadataPolicy(final EntityType type) 500 throws PolicyViolationException { 501 502 JSONObject o = getMetadataPolicyJSONObject(); 503 504 if (o == null) { 505 return null; 506 } 507 508 try { 509 JSONObject policyJSONObject = JSONObjectUtils.getJSONObject(o, type.getValue(), null); 510 if (policyJSONObject == null) { 511 return null; 512 } 513 return MetadataPolicy.parse(policyJSONObject); 514 } catch (ParseException e) { 515 return null; 516 } 517 } 518 519 520 /** 521 * Sets the metadata policy for the specified type. Corresponds to the 522 * {@code metadata_policy} claim. 523 * 524 * @param type The entity type. Must not be {@code null}. 525 * @param metadataPolicy The metadata policy, {@code null} if not 526 * specified. 527 */ 528 public void setMetadataPolicy(final EntityType type, final MetadataPolicy metadataPolicy) { 529 530 JSONObject o = getMetadataPolicyJSONObject(); 531 532 if (o == null) { 533 if (metadataPolicy == null) { 534 return; // nothing to clear 535 } 536 o = new JSONObject(); 537 } 538 539 if (metadataPolicy != null) { 540 o.put(type.getValue(), metadataPolicy.toJSONObject()); 541 } else { 542 o.remove(type.getValue()); 543 } 544 545 if (o.isEmpty()) { 546 o = null; 547 } 548 setMetadataPolicyJSONObject(o); 549 } 550 551 552 /** 553 * Gets the used trust anchor in a explicit client registration in 554 * OpenID Connect Federation 1.0. Intended for entity statements issued 555 * by an OpenID provider for a Relying party performing explicit client 556 * registration only. Corresponds to the {@code trust_anchor_id} claim. 557 * 558 * @return The trust anchor ID, {@code null} if not specified. 559 */ 560 public EntityID getTrustAnchorID() { 561 562 String value = getStringClaim(TRUST_ANCHOR_ID_CLAIM_NAME); 563 564 try { 565 return EntityID.parse(value); 566 } catch (ParseException e) { 567 return null; 568 } 569 } 570 571 572 /** 573 * Sets the used trust anchor in a explicit client registration in 574 * OpenID Connect Federation 1.0. Intended for entity statements issued 575 * by an OpenID provider for a Relying party performing explicit client 576 * registration only. Corresponds to the {@code trust_anchor_id} claim. 577 * 578 * @param trustAnchorID The trust anchor ID, {@code null} if not 579 * specified. 580 */ 581 public void setTrustAnchorID(final EntityID trustAnchorID) { 582 583 if (trustAnchorID != null) { 584 setClaim(TRUST_ANCHOR_ID_CLAIM_NAME, trustAnchorID.getValue()); 585 } else { 586 setClaim(TRUST_ANCHOR_ID_CLAIM_NAME, null); 587 } 588 } 589 590 591 /** 592 * Gets the trust chain constraints for subordinate entities. 593 * Corresponds to the {@code constraints} claim. 594 * 595 * @return The trust chain constraints, {@code null} if not specified 596 * or if parsing failed. 597 */ 598 public TrustChainConstraints getConstraints() { 599 600 JSONObject o = getJSONObjectClaim(CONSTRAINTS_CLAIM_NAME); 601 602 if (o == null) { 603 return null; 604 } 605 606 try { 607 return TrustChainConstraints.parse(o); 608 } catch (ParseException e) { 609 return null; 610 } 611 } 612 613 614 /** 615 * Sets the trust chain constraint for subordinate entities. 616 * Corresponds to the {@code constraints} claim. 617 * 618 * @param constraints The trust chain constraints, {@code null} if not 619 * specified. 620 */ 621 public void setConstraints(final TrustChainConstraints constraints) { 622 623 if (constraints != null) { 624 setClaim(CONSTRAINTS_CLAIM_NAME, constraints.toJSONObject()); 625 } else { 626 setClaim(CONSTRAINTS_CLAIM_NAME, null); 627 } 628 } 629 630 631 /** 632 * Sets the trust marks. Corresponds to the {@code trust_marks} claim. 633 * 634 * @param marks The trust marks, {@code null} if not specified. 635 */ 636 public void setTrustMarks(final List<TrustMarkEntry> marks) { 637 638 if (marks != null) { 639 JSONArray array = new JSONArray(); 640 for (TrustMarkEntry en: marks) { 641 array.add(en.toJSONObject()); 642 } 643 setClaim(TRUST_MARKS_CLAIM_NAME, array); 644 } else { 645 setClaim(TRUST_MARKS_CLAIM_NAME, null); 646 } 647 } 648 649 650 /** 651 * Gets the trust marks issuers. Corresponds to the 652 * {@code trust_marks_issuers} claim. 653 * 654 * @return The trust marks issuers, {@code null} if not specified or 655 * parsing failed. 656 */ 657 public Map<Identifier, List<Issuer>> getTrustMarksIssuers() { 658 659 JSONObject o = getJSONObjectClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME); 660 661 if (o == null) { 662 return null; 663 } 664 665 Map<Identifier, List<Issuer>> issuers = new HashMap<>(); 666 667 for (String id: o.keySet()) { 668 try { 669 List<Issuer> issuerList = new LinkedList<>(); 670 for (String issuerString: JSONObjectUtils.getStringList(o, id)) { 671 issuerList.add(new Issuer(issuerString)); 672 } 673 issuers.put(new Identifier(id), issuerList); 674 } catch (ParseException e) { 675 return null; 676 } 677 } 678 679 return issuers; 680 } 681 682 683 /** 684 * Sets the trust marks issuers. Corresponds to the 685 * {@code trust_marks_issuers} claim. 686 * 687 * @param issuers The trust marks issuers, {@code null} if not 688 * specified. 689 */ 690 public void setTrustMarksIssuers(final Map<Identifier, List<Issuer>> issuers) { 691 692 if (issuers != null) { 693 JSONObject issuersObject = new JSONObject(); 694 for (Map.Entry<Identifier, List<Issuer>> en: issuers.entrySet()) { 695 issuersObject.put(en.getKey().getValue(), Issuer.toStringList(en.getValue())); 696 setClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME, issuersObject); 697 } 698 } else { 699 setClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME, null); 700 } 701 } 702 703 704 /** 705 * Gets the names of the critical extension claims. Corresponds to the 706 * {@code crit} claim. 707 * 708 * @return The names of the critical extension claims, {@code null} if 709 * not specified or if parsing failed. 710 */ 711 public List<String> getCriticalExtensionClaims() { 712 713 return getStringListClaim(CRITICAL_CLAIM_NAME); 714 } 715 716 717 /** 718 * Sets the names of the critical extension claims. Corresponds to the 719 * {@code crit} claim. 720 * 721 * @param claimNames The names of the critical extension claims, 722 * {@code null} if not specified. Must not be an 723 * empty list. 724 */ 725 public void setCriticalExtensionClaims(final List<String> claimNames) { 726 727 if (claimNames != null && claimNames.isEmpty()) { 728 throw new IllegalArgumentException("The critical extension claim names must not be empty"); 729 } 730 731 setClaim(CRITICAL_CLAIM_NAME, claimNames); 732 } 733 734 735 /** 736 * Gets the names of the critical policy extensions. Corresponds to the 737 * {@code policy_language_crit} claim. 738 * 739 * @return The names of the critical policy extensions or if parsing 740 * failed. 741 */ 742 public List<String> getCriticalPolicyExtensions() { 743 744 return getStringListClaim(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME); 745 } 746 747 748 /** 749 * Sets the names of the critical policy extensions. Corresponds to the 750 * {@code policy_language_crit} claim. 751 * 752 * @param extNames The names of the critical policy extensions, 753 * {@code null} if not specified. Must not be an empty 754 * list. 755 */ 756 public void setCriticalPolicyExtensions(final List<String> extNames) { 757 758 if (extNames != null && extNames.isEmpty()) { 759 throw new IllegalArgumentException("The critical policy extension names must not be empty"); 760 } 761 762 setClaim(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME, extNames); 763 } 764}