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.policy.operations;
019
020
021import java.util.AbstractMap;
022import java.util.List;
023import java.util.Map;
024
025import net.minidev.json.JSONObject;
026
027import com.nimbusds.oauth2.sdk.ParseException;
028import com.nimbusds.oauth2.sdk.util.JSONUtils;
029import com.nimbusds.openid.connect.sdk.federation.policy.language.*;
030
031
032/**
033 * Values set (value) operation.
034 *
035 * <p>Example policy:
036 *
037 * <pre>
038 * "require_auth_time" : { "value": true }
039 * </pre>
040 *
041 * <p>Input:
042 *
043 * <pre>
044 * "require_auth_time" : false
045 * </pre>
046 *
047 * <p>Result:
048 *
049 * <pre>
050 * "require_auth_time" : true
051 * </pre>
052 *
053 * <p>Related specifications:
054 *
055 * <ul>
056 *     <li>OpenID Connect Federation 1.0, section 4.1.5.
057 * </ul>
058 */
059public class ValueOperation implements PolicyOperation,
060        BooleanConfiguration, NumberConfiguration, StringConfiguration, StringListConfiguration, JSONObjectConfiguration,
061        UntypedOperation {
062        
063        
064        public static final OperationName NAME = new OperationName("value");
065        
066        
067        private ConfigurationType configType;
068        
069        
070        private boolean booleanValue;
071        
072        
073        private Number numberValue = null;
074        
075        
076        private String stringValue;
077        
078        
079        private List<String> stringListValue;
080        
081        
082        private JSONObject jsonObjectValue;
083        
084        
085        @Override
086        public OperationName getOperationName() {
087                return NAME;
088        }
089        
090        
091        @Override
092        public void configure(final boolean parameter) {
093                configType = ConfigurationType.BOOLEAN;
094                this.booleanValue = parameter;
095        }
096        
097        
098        @Override
099        public void configure(final Number parameter) {
100                configType = ConfigurationType.NUMBER;
101                this.numberValue = parameter;
102        }
103        
104        
105        @Override
106        public void configure(final String parameter) {
107                configType = ConfigurationType.STRING;
108                this.stringValue = parameter;
109        }
110        
111        
112        @Override
113        public void configure(final List<String> parameter) {
114                configType = ConfigurationType.STRING_LIST;
115                this.stringListValue = parameter;
116        }
117        
118        
119        @Override
120        public void configure(final JSONObject parameter) {
121                configType = ConfigurationType.JSON_OBJECT;
122                this.jsonObjectValue = parameter;
123        }
124        
125        
126        @Override
127        public void parseConfiguration(final Object jsonEntity) throws ParseException {
128                if (jsonEntity instanceof Boolean) {
129                        configure(JSONUtils.toBoolean(jsonEntity));
130                } else if (jsonEntity instanceof Number) {
131                        configure(JSONUtils.toNumber(jsonEntity));
132                } else if (jsonEntity instanceof String) {
133                        configure(JSONUtils.toString(jsonEntity));
134                } else if (jsonEntity instanceof JSONObject) {
135                        configure(JSONUtils.to(jsonEntity, JSONObject.class));
136                } else {
137                        configure(JSONUtils.toStringList(jsonEntity));
138                }
139        }
140        
141        
142        @Override
143        public Map.Entry<String,Object> toJSONObjectEntry() {
144                if (configType == null) {
145                        throw new IllegalStateException("The policy is not initialized");
146                }
147                Object value;
148                if (configType.equals(ConfigurationType.BOOLEAN)) {
149                        value = getBooleanConfiguration();
150                } else if (configType.equals(ConfigurationType.NUMBER)) {
151                        value = getNumberConfiguration();
152                } else if (configType.equals(ConfigurationType.STRING)) {
153                        value = getStringConfiguration();
154                } else if (configType.equals(ConfigurationType.STRING_LIST)) {
155                        value = getStringListConfiguration();
156                } else if (configType.equals(ConfigurationType.JSON_OBJECT)) {
157                        value = getJSONObjectConfiguration();
158                } else {
159                        throw new IllegalStateException("Unsupported configuration type: " + configType);
160                }
161                return new AbstractMap.SimpleImmutableEntry<>(getOperationName().getValue(), value);
162        }
163        
164        
165        @Override
166        public boolean getBooleanConfiguration() {
167                return booleanValue;
168        }
169        
170        
171        @Override
172        public Number getNumberConfiguration() {
173                return numberValue;
174        }
175        
176        
177        @Override
178        public String getStringConfiguration() {
179                return stringValue;
180        }
181        
182        
183        @Override
184        public List<String> getStringListConfiguration() {
185                return stringListValue;
186        }
187        
188        
189        @Override
190        public JSONObject getJSONObjectConfiguration() {
191                return jsonObjectValue;
192        }
193        
194        
195        @Override
196        public PolicyOperation merge(final PolicyOperation other)
197                throws PolicyViolationException {
198                
199                ValueOperation otherTyped = Utils.castForMerge(other, ValueOperation.class);
200                
201                if (configType == null ||  otherTyped.configType == null) {
202                        throw new PolicyViolationException("The value operation is not initialized");
203                }
204                
205                if (configType.equals(ConfigurationType.STRING_LIST)) {
206                        
207                        if (getStringListConfiguration() != null && getStringListConfiguration().equals(otherTyped.getStringListConfiguration())) {
208                                ValueOperation copy = new ValueOperation();
209                                copy.configure(getStringListConfiguration());
210                                return copy;
211                        }
212                }
213                
214                if (configType.equals(ConfigurationType.STRING)) {
215                        
216                        if (getStringConfiguration() != null && getStringConfiguration().equals(otherTyped.getStringConfiguration())) {
217                                ValueOperation copy = new ValueOperation();
218                                copy.configure(getStringConfiguration());
219                                return copy;
220                        }
221                }
222                
223                if (configType.equals(ConfigurationType.BOOLEAN)) {
224                        
225                        if (getBooleanConfiguration() == otherTyped.getBooleanConfiguration()) {
226                                ValueOperation copy = new ValueOperation();
227                                copy.configure(getBooleanConfiguration());
228                                return copy;
229                        }
230                }
231                
232                if (configType.equals(ConfigurationType.NUMBER)) {
233                        
234                        if (getNumberConfiguration() != null && getNumberConfiguration().equals(otherTyped.getNumberConfiguration())) {
235                                ValueOperation copy = new ValueOperation();
236                                copy.configure(getNumberConfiguration());
237                                return copy;
238                        }
239                }
240                
241                if (configType.equals(ConfigurationType.JSON_OBJECT)) {
242                        
243                        if (getJSONObjectConfiguration() == otherTyped.getJSONObjectConfiguration()) {
244                                ValueOperation copy = new ValueOperation();
245                                copy.configure(getJSONObjectConfiguration());
246                                return copy;
247                        }
248                }
249                
250                throw new PolicyViolationException("Value mismatch");
251        }
252        
253        
254        @Override
255        public Object apply(final Object value) {
256                
257                if (configType == null) {
258                        throw new IllegalStateException("The policy is not initialized");
259                }
260                
261                if (configType.equals(ConfigurationType.BOOLEAN)) {
262                        return booleanValue;
263                }
264                if (configType.equals(ConfigurationType.NUMBER)) {
265                        return numberValue;
266                }
267                if (configType.equals(ConfigurationType.STRING)) {
268                        return stringValue;
269                }
270                if (configType.equals(ConfigurationType.JSON_OBJECT)) {
271                        return jsonObjectValue;
272                }
273                return stringListValue;
274        }
275}