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