001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2021, 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.api;
019
020
021import com.nimbusds.jwt.JWTClaimsSet;
022import com.nimbusds.oauth2.sdk.ParseException;
023import com.nimbusds.oauth2.sdk.id.Issuer;
024import com.nimbusds.oauth2.sdk.id.Subject;
025import com.nimbusds.oauth2.sdk.util.CollectionUtils;
026import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
027import com.nimbusds.oauth2.sdk.util.MapUtils;
028import com.nimbusds.openid.connect.sdk.federation.entities.CommonFederationClaimsSet;
029import com.nimbusds.openid.connect.sdk.federation.entities.EntityID;
030import com.nimbusds.openid.connect.sdk.federation.trust.TrustChain;
031import net.minidev.json.JSONObject;
032
033import java.util.*;
034
035
036/**
037 * Resolve response claims set.
038 *
039 * <p>Related specifications:
040 *
041 * <ul>
042 *     <li>OpenID Connect Federation 1.0, section 7.2.2.
043 * </ul>
044 */
045public class ResolveClaimsSet extends CommonFederationClaimsSet {
046        
047        
048        /**
049         * The trust chain claim name.
050         */
051        public static final String TRUST_CHAIN_CLAIM_NAME = "trust_chain";
052        
053        
054        /**
055         * The names of the standard top-level claims.
056         */
057        private static final Set<String> STD_CLAIM_NAMES;
058        
059        static {
060                Set<String> claimNames = new HashSet<>();
061                claimNames.add(ISS_CLAIM_NAME);
062                claimNames.add(SUB_CLAIM_NAME);
063                claimNames.add(IAT_CLAIM_NAME);
064                claimNames.add(EXP_CLAIM_NAME);
065                claimNames.add(METADATA_CLAIM_NAME);
066                claimNames.add(TRUST_MARKS_CLAIM_NAME);
067                claimNames.add(TRUST_CHAIN_CLAIM_NAME);
068                STD_CLAIM_NAMES = Collections.unmodifiableSet(claimNames);
069        }
070        
071        
072        /**
073         * Gets the names of the standard top-level claims.
074         *
075         * @return The names of the standard top-level claims (read-only set).
076         */
077        public static Set<String> getStandardClaimNames() {
078                
079                return STD_CLAIM_NAMES;
080        }
081        
082        
083        /**
084         * Creates a new resolve response claims set with the minimum required
085         * claims.
086         *
087         * @param iss      The issuer. Must not be {@code null}.
088         * @param sub      The subject. Must not be {@code null}.
089         * @param iat      The issue time. Must not be {@code null}.
090         * @param exp      The expiration time. Must not be {@code null}.
091         * @param metadata The metadata JSON object. Must not be {@code null}.
092         */
093        public ResolveClaimsSet(final Issuer iss,
094                                final Subject sub,
095                                final Date iat,
096                                final Date exp,
097                                final JSONObject metadata) {
098                
099                this(new EntityID(iss.getValue()), new EntityID(sub.getValue()), iat, exp, metadata);
100        }
101        
102        
103        /**
104         * Creates a new resolve response claims set with the minimum required
105         * claims.
106         *
107         * @param iss      The issuer. Must not be {@code null}.
108         * @param sub      The subject. Must not be {@code null}.
109         * @param iat      The issue time. Must not be {@code null}.
110         * @param exp      The expiration time. Must not be {@code null}.
111         * @param metadata The metadata JSON object. Must not be {@code null}.
112         */
113        public ResolveClaimsSet(final EntityID iss,
114                                final EntityID sub,
115                                final Date iat,
116                                final Date exp,
117                                final JSONObject metadata) {
118                
119                setClaim(ISS_CLAIM_NAME, iss.getValue());
120                setClaim(SUB_CLAIM_NAME, sub.getValue());
121                
122                if (iat == null) {
123                        throw new IllegalArgumentException("The iat (issued-at) claim must not be null");
124                }
125                setDateClaim(IAT_CLAIM_NAME, iat);
126                
127                if (exp == null) {
128                        throw new IllegalArgumentException("The exp (expiration) claim must not be null");
129                }
130                setDateClaim(EXP_CLAIM_NAME, exp);
131                
132                if (metadata == null || metadata.isEmpty()) {
133                        throw new IllegalArgumentException("The metadata claim must not be null");
134                }
135                setClaim(METADATA_CLAIM_NAME, metadata);
136        }
137        
138        
139        /**
140         * Creates a new resolve response claims set from the specified JWT
141         * claims set.
142         *
143         * @param jwtClaimsSet The JWT claims set. Must not be {@code null}.
144         *
145         * @throws ParseException If the JWT claims set doesn't represent a
146         *                        valid resolve response claims set.
147         */
148        public ResolveClaimsSet(final JWTClaimsSet jwtClaimsSet)
149                throws ParseException {
150                
151                super(JSONObjectUtils.toJSONObject(jwtClaimsSet));
152                
153                validateRequiredClaimsPresence();
154        }
155        
156        
157        /**
158         * Validates this claims set for having all minimum required claims for
159         * a resolve response.
160         *
161         * @throws ParseException If the validation failed and a required claim
162         *                        is missing.
163         */
164        public void validateRequiredClaimsPresence()
165                throws ParseException {
166                
167                super.validateRequiredClaimsPresence();
168                
169                if (MapUtils.isEmpty(getJSONObjectClaim(METADATA_CLAIM_NAME))) {
170                        throw new ParseException("Missing metadata claim");
171                }
172        }
173        
174        
175        /**
176         * Gets the trust chain. Corresponds to the {@code trust_chain} claim.
177         *
178         * @return The trust chain, {@code null} if not specified or parsing
179         *         failed.
180         */
181        public TrustChain getTrustChain() {
182                
183                List<String> chainJWTs = getStringListClaim(TRUST_CHAIN_CLAIM_NAME);
184                
185                if (CollectionUtils.isEmpty(chainJWTs)) {
186                        return null;
187                }
188                
189                try {
190                        return TrustChain.parseSerialized(chainJWTs);
191                } catch (ParseException e) {
192                        return null;
193                }
194        }
195        
196        
197        /**
198         * Sets the trust chain. Corresponds to the {@code trust_chain} claim.
199         *
200         * @param trustChain The trust chain, {@code null} if not specified.
201         */
202        public void setTrustChain(final TrustChain trustChain) {
203                
204                if (trustChain != null) {
205                        setClaim(TRUST_CHAIN_CLAIM_NAME, trustChain.toSerializedJWTs());
206                } else {
207                        setClaim(TRUST_CHAIN_CLAIM_NAME, null);
208                }
209        }
210}