001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2020, 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.policy;
019
020
021import java.util.*;
022
023import net.minidev.json.JSONAware;
024import net.minidev.json.JSONObject;
025
026import com.nimbusds.oauth2.sdk.ParseException;
027import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
028import com.nimbusds.openid.connect.sdk.federation.policy.language.PolicyOperation;
029import com.nimbusds.openid.connect.sdk.federation.policy.language.PolicyViolationException;
030import com.nimbusds.openid.connect.sdk.federation.policy.operations.DefaultPolicyOperationCombinationValidator;
031import com.nimbusds.openid.connect.sdk.federation.policy.operations.DefaultPolicyOperationFactory;
032import com.nimbusds.openid.connect.sdk.federation.policy.operations.PolicyOperationCombinationValidator;
033import com.nimbusds.openid.connect.sdk.federation.policy.operations.PolicyOperationFactory;
034
035
036/**
037 * Policy for a federation entity metadata.
038 *
039 * <p>Example:
040 *
041 * <pre>
042 * {
043 *   "scopes" : {
044 *       "subset_of"   : [ "openid", "eduperson", "phone" ],
045 *       "superset_of" : [ "openid" ],
046 *       "default"     : [ "openid", "eduperson" ]
047 *   },
048 *   "id_token_signed_response_alg" : {
049 *       "one_of" : [ "ES256", "ES384", "ES512" ]
050 *   },
051 *   "contacts" : {
052 *       "add" : "helpdesk@federation.example.org"
053 *   },
054 *   "application_type" : { "value": "web"
055 *   }
056 * }
057 * </pre>
058 *
059 * <p>Related specifications:
060 *
061 * <ul>
062 *     <li>OpenID Connect Federation 1.0, section 4.1.
063 * </ul>
064 */
065public class MetadataPolicy implements JSONAware {
066        
067        
068        /**
069         * The policy entries, keyed by metadata parameter name.
070         */
071        private final Map<String,List<PolicyOperation>> entries = new LinkedHashMap<>();
072        
073        
074        /**
075         * Puts a policy entry for a metadata parameter.
076         *
077         * @param parameterName   The parameter name. Must not be {@code null}.
078         * @param policyOperation The policy operation for the parameter,
079         *                        {@code null} if none.
080         */
081        public void put(final String parameterName, final PolicyOperation policyOperation) {
082                put(new MetadataPolicyEntry(parameterName, Collections.singletonList(policyOperation)));
083        }
084        
085        
086        /**
087         * Puts a policy entry for a metadata parameter.
088         *
089         * @param parameterName    The parameter name. Must not be {@code null}.
090         * @param policyOperations The ordered policy operations for the
091         *                         parameter, {@code null} if none.
092         */
093        public void put(final String parameterName, final List<PolicyOperation> policyOperations) {
094                put(new MetadataPolicyEntry(parameterName, policyOperations));
095        }
096        
097        
098        /**
099         * Puts a policy entry for a metadata parameter.
100         *
101         * @param entry The policy entry. Must not be {@code null}.
102         */
103        public void put(final MetadataPolicyEntry entry) {
104                entries.put(entry.getKey(), entry.getValue());
105        }
106        
107        
108        /**
109         * Gets the policy operations for the specified metadata parameter
110         * name.
111         *
112         * @param parameterName The parameter name. Must not be {@code null}.
113         *
114         * @return The ordered policy operations for the parameter,
115         *         {@code null} if none.
116         */
117        public List<PolicyOperation> get(final String parameterName) {
118
119                return entries.get(parameterName);
120        }
121        
122        
123        /**
124         * Gets the policy entry for the specified metadata parameter name.
125         *
126         * @param parameterName The parameter name. Must not be {@code null}.
127         *
128         * @return The policy entry for the parameter, {@code null} if none.
129         */
130        public MetadataPolicyEntry getEntry(final String parameterName) {
131                
132                List<PolicyOperation> policyOperations = entries.get(parameterName);
133                
134                if (policyOperations == null) {
135                        return null;
136                }
137                
138                return new MetadataPolicyEntry(parameterName, policyOperations);
139        }
140        
141        
142        /**
143         * Gets the policy entries set.
144         *
145         * @return The policy entries set.
146         */
147        public Set<MetadataPolicyEntry> entrySet() {
148                
149                Set<MetadataPolicyEntry> set = new LinkedHashSet<>();
150                for (Map.Entry<String,List<PolicyOperation>> en: entries.entrySet()) {
151                        set.add(new MetadataPolicyEntry(en.getKey(), en.getValue()));
152                }
153                return set;
154        }
155        
156        
157        /**
158         * Removes a policy entry.
159         *
160         * @param parameterName The parameter name. Must not be {@code null}.
161         *
162         * @return The ordered policy operations for the removed parameter,
163         *         {@code null} if not found.
164         */
165        public List<PolicyOperation> remove(final String parameterName) {
166                
167                return entries.remove(parameterName);
168        }
169        
170        
171        /**
172         * Returns a JSON object representation of this metadata policy.
173         *
174         * @return The JSON object.
175         */
176        public Map<String,Object> toJSONObject() {
177                
178                Map<String,Object> jsonObject = new LinkedHashMap<>();
179                
180                for (MetadataPolicyEntry en: entrySet()) {
181                        jsonObject.put(en.getKey(), en.toJSONObject());
182                }
183                
184                return jsonObject;
185        }
186        
187        
188        @Override
189        public String toJSONString() {
190                return JSONObject.toJSONString(toJSONObject());
191        }
192        
193        
194        /**
195         * Parses a policy for a federation entity metadata. This method is
196         * intended for policies including non-standard
197         * {@link PolicyOperation}s.
198         *
199         * @param policySpec           The JSON object for the policy
200         *                             specification. Must not be {@code null}.
201         * @param factory              The policy operation factory. Must not
202         *                             be {@code null}.
203         * @param combinationValidator The policy operation combination
204         *                             validator. Must not be {@code null}.
205         *
206         * @return The metadata policy.
207         *
208         * @throws ParseException           On JSON parsing exception.
209         * @throws PolicyViolationException On a policy violation.
210         */
211        public static MetadataPolicy parse(final JSONObject policySpec,
212                                           final PolicyOperationFactory factory,
213                                           final PolicyOperationCombinationValidator combinationValidator)
214                throws ParseException, PolicyViolationException {
215                
216                MetadataPolicy metadataPolicy = new MetadataPolicy();
217                
218                for (String parameterName: policySpec.keySet()) {
219                        JSONObject entrySpec = JSONObjectUtils.getJSONObject(policySpec, parameterName);
220                        metadataPolicy.put(MetadataPolicyEntry.parse(parameterName, entrySpec, factory, combinationValidator));
221                }
222                
223                return metadataPolicy;
224        }
225        
226        
227        /**
228         * Parses a policy for a federation entity metadata. This method is
229         * intended for policies with standard {@link PolicyOperation}s only.
230         * Uses the default {@link DefaultPolicyOperationFactory policy
231         * operation} and {@link DefaultPolicyOperationCombinationValidator
232         * policy combination validator} factories.
233         *
234         * @param policySpec The JSON object string for the policy
235         *                   specification. Must not be {@code null}.
236         *
237         * @return The metadata policy.
238         *
239         * @throws ParseException           On JSON parsing exception.
240         * @throws PolicyViolationException On a policy violation.
241         */
242        public static MetadataPolicy parse(final JSONObject policySpec)
243                throws ParseException, PolicyViolationException {
244                
245                return parse(policySpec,
246                        MetadataPolicyEntry.DEFAULT_POLICY_OPERATION_FACTORY,
247                        MetadataPolicyEntry.DEFAULT_POLICY_COMBINATION_VALIDATOR);
248        }
249        
250        
251        /**
252         * Parses a policy for a federation entity metadata. This method is
253         * intended for policies including non-standard
254         * {@link PolicyOperation}s.
255         *
256         * @param policySpec           The JSON object for the policy
257         *                             specification. Must not be {@code null}.
258         * @param factory              The policy operation factory. Must not
259         *                             be {@code null}.
260         * @param combinationValidator The policy operation combination
261         *                             validator. Must not be {@code null}.
262         *
263         * @return The metadata policy.
264         *
265         * @throws ParseException           On JSON parsing exception.
266         * @throws PolicyViolationException On a policy violation.
267         */
268        public static MetadataPolicy parse(final String policySpec,
269                                           final PolicyOperationFactory factory,
270                                           final PolicyOperationCombinationValidator combinationValidator)
271                throws ParseException, PolicyViolationException {
272                
273                return parse(JSONObjectUtils.parse(policySpec), factory, combinationValidator);
274        }
275        
276        
277        /**
278         * Parses a policy for a federation entity metadata. This method is
279         * intended for policies with standard {@link PolicyOperation}s only.
280         * Uses the default {@link DefaultPolicyOperationFactory policy
281         * operation} and {@link DefaultPolicyOperationCombinationValidator
282         * policy combination validator} factories.
283         *
284         * @param policySpec The JSON object string for the policy
285         *                   specification. Must not be {@code null}.
286         *
287         * @return The metadata policy.
288         *
289         * @throws ParseException           On JSON parsing exception.
290         * @throws PolicyViolationException On a policy violation.
291         */
292        public static MetadataPolicy parse(final String policySpec)
293                throws ParseException, PolicyViolationException {
294                
295                return parse(policySpec,
296                        MetadataPolicyEntry.DEFAULT_POLICY_OPERATION_FACTORY,
297                        MetadataPolicyEntry.DEFAULT_POLICY_COMBINATION_VALIDATOR);
298        }
299}