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}