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