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.assurance.request;
019
020
021import java.util.List;
022import java.util.Objects;
023
024import net.jcip.annotations.Immutable;
025import net.minidev.json.JSONArray;
026import net.minidev.json.JSONObject;
027
028import com.nimbusds.oauth2.sdk.ParseException;
029import com.nimbusds.oauth2.sdk.util.CollectionUtils;
030import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
031import com.nimbusds.openid.connect.sdk.assurance.IdentityTrustFramework;
032
033
034/**
035 * Minimal verification spec. Allows setting of a preferred trust framework for
036 * the identity verification. Can be extended with additional setters.
037 *
038 * <p>Default verification example:
039 *
040 * <pre>
041 * {
042 *   "trust_framework": null
043 * }
044 * </pre>
045 *
046 * <p>Verification example with preferred trust framework:
047 *
048 * <pre>
049 * {
050 *   "trust_framework": {
051 *      "value" : "eidas"
052 *   }
053 * }
054 * </pre>
055 *
056 * <p>Verification example with list of two preferred trust frameworks:
057 *
058 * <pre>
059 * {
060 *   "trust_framework": {
061 *      "values" : [ "eidas", "de_aml" ]
062 *   }
063 * }
064 * </pre>
065 *
066 * <p>Related specifications:
067 *
068 * <ul>
069 *     <li>OpenID Connect for Identity Assurance 1.0, section 6.
070 * </ul>
071 */
072@Immutable
073public class MinimalVerificationSpec implements VerificationSpec {
074        
075        
076        /**
077         * The underlying JSON object.
078         */
079        protected final JSONObject jsonObject;
080        
081        
082        /**
083         * Creates a new minimal verification spec with the specified JSON
084         * object.
085         *
086         * @param jsonObject The JSON object. Must not be {@code null}.
087         */
088        protected MinimalVerificationSpec(final JSONObject jsonObject) {
089                Objects.requireNonNull(jsonObject);
090                this.jsonObject = jsonObject;
091        }
092        
093        
094        /**
095         * Creates a new minimal verification spec.
096         */
097        public MinimalVerificationSpec() {
098                this(new JSONObject());
099                jsonObject.put("trust_framework", null);
100        }
101        
102        
103        /**
104         * Creates a new minimal verification spec with a preferred trust
105         * framework.
106         *
107         * @param trustFramework The trust framework, {@code null} if not
108         *                       specified.
109         */
110        public MinimalVerificationSpec(final IdentityTrustFramework trustFramework) {
111                this();
112                if (trustFramework != null) {
113                        JSONObject tfSpec = new JSONObject();
114                        tfSpec.put("value", trustFramework.getValue());
115                        jsonObject.put("trust_framework", tfSpec);
116                }
117        }
118        
119        
120        /**
121         * Creates a new minimal verification spec with a list of preferred
122         * trust frameworks.
123         *
124         * @param trustFrameworks The trust frameworks, {@code null} if not
125         *                        specified.
126         */
127        public MinimalVerificationSpec(final List<IdentityTrustFramework> trustFrameworks) {
128                this();
129                if (CollectionUtils.isNotEmpty(trustFrameworks)) {
130                        JSONObject tfSpec = new JSONObject();
131                        JSONArray tfValues = new JSONArray();
132                        for (IdentityTrustFramework tf: trustFrameworks) {
133                                if (tf != null) {
134                                        tfValues.add(tf.getValue());
135                                }
136                        }
137                        tfSpec.put("values", tfValues);
138                        jsonObject.put("trust_framework", tfSpec);
139                }
140        }
141        
142        
143        @Override
144        public JSONObject toJSONObject() {
145                
146                JSONObject o = new JSONObject();
147                o.putAll(jsonObject);
148                return o;
149        }
150        
151        
152        /**
153         * Parses a verification spec from the specified JSON object
154         * representation.
155         *
156         * @param jsonObject The JSON object. Must not be {@code null}.
157         *
158         * @return The verification spec.
159         *
160         * @throws ParseException If parsing failed.
161         */
162        public static MinimalVerificationSpec parse(final JSONObject jsonObject)
163                throws ParseException {
164                
165                // Verify the trust_framework element
166                if (! jsonObject.containsKey("trust_framework")) {
167                        throw new ParseException("Missing required trust_framework key");
168                }
169                
170                if (jsonObject.get("trust_framework") != null) {
171                        
172                        JSONObject tfSpec = JSONObjectUtils.getJSONObject(jsonObject, "trust_framework");
173                        
174                        try {
175                                validateTrustFrameworkSpec(tfSpec);
176                        } catch (ParseException e) {
177                                throw new ParseException("Invalid trust_framework spec: " + e.getMessage(), e);
178                        }
179                }
180                
181                return new MinimalVerificationSpec(jsonObject);
182        }
183        
184        
185        /**
186         * Validates the {@code trust_framework} JSON object.
187         *
188         * @param tfSpec The JSON object. Must be {@code null}.
189         *
190         * @throws ParseException If the JSON object is illegal.
191         */
192        private static void validateTrustFrameworkSpec(final JSONObject tfSpec)
193                throws ParseException {
194                
195                String value = null;
196                if (tfSpec.containsKey("value")) {
197                        value = JSONObjectUtils.getString(tfSpec, "value");
198                }
199                
200                List<String> values = null;
201                if (tfSpec.containsKey("values")) {
202                        values = JSONObjectUtils.getStringList(tfSpec, "values");
203                        if (values.isEmpty()) {
204                                // If set values must not be empty
205                                throw new ParseException("The values JSON array must not be empty");
206                        }
207                }
208                
209                if (value != null && values != null) {
210                        // Value or values must not be set together
211                        throw new ParseException("Value and values must not be set together");
212                }
213        }
214}