001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.property;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.List;
021import java.util.Properties;
022
023import org.apache.commons.lang3.StringUtils;
024import org.jasypt.util.text.TextEncryptor;
025import org.kuali.common.util.PropertyUtils;
026import org.kuali.common.util.Str;
027import org.kuali.common.util.obscure.DefaultObscurer;
028import org.kuali.common.util.obscure.Obscurer;
029import org.kuali.common.util.property.processor.AddPrefixProcessor;
030import org.kuali.common.util.property.processor.GlobalOverrideProcessor;
031import org.kuali.common.util.property.processor.OverrideProcessor;
032import org.kuali.common.util.property.processor.PropertyProcessor;
033import org.kuali.common.util.property.processor.ReformatKeysAsEnvVarsProcessor;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036import org.springframework.util.Assert;
037import org.springframework.util.PropertyPlaceholderHelper;
038
039/**
040 * @deprecated
041 */
042@Deprecated
043public class DefaultPropertyContext implements PropertyContext {
044
045        private static final Logger logger = LoggerFactory.getLogger(DefaultPropertyContext.class);
046        PropertyPlaceholderHelper helper = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER;
047        String globalPropertiesMode = Constants.DEFAULT_GLOBAL_PROPERTIES_MODE.name();
048        String resolvePlaceholders = Boolean.toString(Constants.DEFAULT_RESOLVE_PLACEHOLDERS);
049        Obscurer obscurer = new DefaultObscurer();
050        String style = PropertyStyle.NORMAL.name();
051        String encryptionMode = org.kuali.common.util.EncryptionMode.NONE.name();
052        String encryptionStrength = org.kuali.common.util.EncryptionStrength.BASIC.name();
053        String encryptionPassword;
054        String prefix;
055        List<PropertyProcessor> processors;
056        Properties properties;
057        Properties buildProperties;
058        List<String> buildPropertyIncludes;
059        List<String> buildPropertyExcludes;
060
061        protected List<PropertyProcessor> getDefaultProcessors() {
062                List<PropertyProcessor> processors = new ArrayList<PropertyProcessor>();
063
064                // If this context is being loaded as part of a build process, build properties win over properties from .properties files
065                if (buildProperties != null) {
066                        OverrideProcessor overrideProcessor = new OverrideProcessor(Constants.DEFAULT_PROPERTY_OVERWRITE_MODE, buildProperties);
067                        if (buildPropertyIncludes != null) {
068                                overrideProcessor.setIncludes(buildPropertyIncludes);
069                        }
070                        if (buildPropertyExcludes != null) {
071                                overrideProcessor.setExcludes(buildPropertyExcludes);
072                        }
073                        processors.add(overrideProcessor);
074                }
075
076                // Decrypt/encrypt as appropriate
077                if (encryptionMode != null) {
078                        org.kuali.common.util.EncryptionMode mode = org.kuali.common.util.EncryptionMode.valueOf(encryptionMode);
079                        org.kuali.common.util.EncryptionStrength strength = org.kuali.common.util.EncryptionStrength.valueOf(encryptionStrength);
080                        processors.add(getEncProcessor(mode, strength, encryptionPassword));
081                }
082
083                /**
084                 * Remove the local reference to the encryption password now that the TextEncryptor has been created.<br>
085                 * Note that the encryption password is VERY likely to be hanging around in memory even after being set to null locally.<br>
086                 * Setting it to null here just makes it slightly tougher for someone to obtain the password.<br>
087                 * Having a reference to this bean no longer does them any good, they'll have to search around in memory to find it.<br>
088                 */
089                this.encryptionPassword = null;
090
091                GlobalPropertiesMode gpm = GlobalPropertiesMode.valueOf(globalPropertiesMode);
092
093                // By default, system/environment properties override loaded properties
094                processors.add(new GlobalOverrideProcessor(gpm));
095
096                // By default, all placeholders in the properties are resolved
097                if (Boolean.parseBoolean(resolvePlaceholders)) {
098                        processors.add(new org.kuali.common.util.property.processor.ResolvePlaceholdersProcessor(helper, gpm));
099                }
100
101                // Add a prefix to the property keys if appropriate
102                if (!StringUtils.isBlank(prefix)) {
103                        processors.add(new AddPrefixProcessor(prefix));
104                }
105
106                // Reformat the keys in environment variable format if appropriate
107                if (style != null) {
108                        processors.add(getStyleProcessor(style));
109                }
110
111                // Return the list of processors
112                return processors;
113        }
114
115        protected PropertyProcessor getStyleProcessor(String style) {
116                switch (PropertyStyle.valueOf(style)) {
117                case NORMAL:
118                        return Constants.NO_OP_PROCESSOR;
119                case ENVIRONMENT_VARIABLE:
120                        return new ReformatKeysAsEnvVarsProcessor();
121                default:
122                        throw new IllegalArgumentException("Property style " + style + " is unknown");
123                }
124        }
125
126        protected PropertyProcessor getEncProcessor(org.kuali.common.util.EncryptionMode mode, org.kuali.common.util.EncryptionStrength strength, String password) {
127                switch (mode) {
128                case NONE:
129                        return Constants.NO_OP_PROCESSOR;
130                case ENCRYPT:
131                        TextEncryptor encryptor = org.kuali.common.util.EncUtils.getTextEncryptor(strength, password);
132                        return new org.kuali.common.util.property.processor.EndsWithEncryptProcessor(encryptor);
133                case DECRYPT:
134                        TextEncryptor decryptor = org.kuali.common.util.EncUtils.getTextEncryptor(strength, password);
135                        return new org.kuali.common.util.property.processor.EndsWithDecryptProcessor(decryptor);
136                default:
137                        throw new IllegalArgumentException("Encryption mode '" + mode + "' is unknown");
138                }
139        }
140
141        protected void log() {
142                if (!StringUtils.equals(org.kuali.common.util.EncryptionMode.NONE.name(), encryptionMode)) {
143                        logger.info("Encryption mode - " + StringUtils.trimToEmpty(encryptionMode));
144                        logger.info("Encryption strength - " + StringUtils.trimToEmpty(encryptionStrength));
145                        String displayPassword = org.kuali.common.util.LoggerUtils.getNullAsNone(encryptionPassword);
146                        if (encryptionPassword != null) {
147                                displayPassword = obscurer.obscure(encryptionPassword);
148                        }
149                        logger.info("Encryption password - " + displayPassword);
150                }
151                if (!StringUtils.equals(PropertyStyle.NORMAL.name(), style)) {
152                        logger.info("Property style - " + StringUtils.trimToEmpty(style));
153                }
154                if (!StringUtils.isEmpty(prefix)) {
155                        logger.info("Property prefix - " + StringUtils.trimToEmpty(prefix));
156                }
157                if (!StringUtils.equals(Boolean.toString(Constants.DEFAULT_RESOLVE_PLACEHOLDERS), resolvePlaceholders)) {
158                        logger.info("Resolve placeholders - " + resolvePlaceholders);
159                }
160        }
161
162        @Override
163        public void initialize(Properties properties) {
164                GlobalPropertiesMode gpm = GlobalPropertiesMode.valueOf(globalPropertiesMode);
165                Properties global = PropertyUtils.getProperties(properties, gpm);
166                this.encryptionMode = resolve(encryptionMode, global);
167                this.encryptionPassword = resolveAndRemove(encryptionPassword, global, properties);
168                this.encryptionStrength = resolve(encryptionStrength, global);
169                this.style = resolve(style, global);
170                this.prefix = resolve(prefix, global);
171                this.resolvePlaceholders = resolve(resolvePlaceholders, global);
172                log();
173                validate();
174                addProcessors();
175                logger.info("Proceeding with " + processors.size() + " processors.");
176        }
177
178        protected void addProcessors() {
179                List<PropertyProcessor> defaultProcessors = getDefaultProcessors();
180                if (processors == null) {
181                        processors = defaultProcessors;
182                } else {
183                        processors.addAll(0, defaultProcessors);
184                }
185        }
186
187        protected void validate() {
188                org.kuali.common.util.EncryptionMode.valueOf(encryptionMode);
189                org.kuali.common.util.EncryptionStrength.valueOf(encryptionStrength);
190                PropertyStyle.valueOf(style);
191                Boolean.parseBoolean(resolvePlaceholders);
192        }
193
194        protected String getPlaceholderKey(String string) {
195                String prefix = Constants.DEFAULT_PLACEHOLDER_PREFIX;
196                String suffix = Constants.DEFAULT_PLACEHOLDER_SUFFIX;
197                String separator = Constants.DEFAULT_VALUE_SEPARATOR;
198                String key = StringUtils.substringBetween(string, prefix, separator);
199                if (key == null) {
200                        return StringUtils.substringBetween(string, prefix, suffix);
201                } else {
202                        return key;
203                }
204        }
205
206        protected void remove(String string, String resolvedString, Properties properties) {
207                boolean placeholder = PropertyUtils.isSingleUnresolvedPlaceholder(string);
208                boolean resolved = !StringUtils.equals(string, resolvedString);
209                boolean irrelevant = Str.contains(Arrays.asList(Constants.NONE, Constants.NULL), resolvedString, false);
210                boolean remove = placeholder && resolved && !irrelevant;
211                if (remove) {
212                        String key = getPlaceholderKey(string);
213                        Assert.notNull(key, "key is null");
214                        if (properties.getProperty(key) != null) {
215                                logger.info("Removing property '" + key + "'");
216                                properties.remove(key);
217                        }
218                }
219        }
220
221        protected String resolveAndRemove(String string, Properties global, Properties properties) {
222                String resolvedString = resolve(string, global);
223                remove(string, resolvedString, properties);
224                return resolvedString;
225        }
226
227        protected String resolve(String string, Properties properties) {
228                if (string == null) {
229                        return null;
230                } else {
231                        String resolvedValue = helper.replacePlaceholders(string, properties);
232                        if (!StringUtils.equals(string, resolvedValue)) {
233                                logger.debug("Resolved {} -> {}", string, resolvedValue);
234                        }
235                        return resolvedValue;
236                }
237        }
238
239        public String getPrefix() {
240                return prefix;
241        }
242
243        public void setPrefix(String prefix) {
244                this.prefix = prefix;
245        }
246
247        public String getStyle() {
248                return style;
249        }
250
251        public void setStyle(String style) {
252                this.style = style;
253        }
254
255        public PropertyPlaceholderHelper getHelper() {
256                return helper;
257        }
258
259        public void setHelper(PropertyPlaceholderHelper helper) {
260                this.helper = helper;
261        }
262
263        public String getEncryptionMode() {
264                return encryptionMode;
265        }
266
267        public void setEncryptionMode(String encryptionMode) {
268                this.encryptionMode = encryptionMode;
269        }
270
271        public String getEncryptionStrength() {
272                return encryptionStrength;
273        }
274
275        public void setEncryptionStrength(String encryptionStrength) {
276                this.encryptionStrength = encryptionStrength;
277        }
278
279        public String getEncryptionPassword() {
280                return encryptionPassword;
281        }
282
283        public void setEncryptionPassword(String encryptionPassword) {
284                this.encryptionPassword = encryptionPassword;
285        }
286
287        @Override
288        public List<PropertyProcessor> getProcessors() {
289                return processors;
290        }
291
292        public void setProcessors(List<PropertyProcessor> processors) {
293                this.processors = processors;
294        }
295
296        public Properties getProperties() {
297                return properties;
298        }
299
300        public void setProperties(Properties properties) {
301                this.properties = properties;
302        }
303
304        public String getGlobalPropertiesMode() {
305                return globalPropertiesMode;
306        }
307
308        public void setGlobalPropertiesMode(String globalPropertiesMode) {
309                this.globalPropertiesMode = globalPropertiesMode;
310        }
311
312        public String getResolvePlaceholders() {
313                return resolvePlaceholders;
314        }
315
316        public void setResolvePlaceholders(String resolvePlaceholders) {
317                this.resolvePlaceholders = resolvePlaceholders;
318        }
319
320        public Obscurer getObscurer() {
321                return obscurer;
322        }
323
324        public void setObscurer(Obscurer obscurer) {
325                this.obscurer = obscurer;
326        }
327
328        public Properties getBuildProperties() {
329                return buildProperties;
330        }
331
332        public void setBuildProperties(Properties buildProperties) {
333                this.buildProperties = buildProperties;
334        }
335
336        public List<String> getBuildPropertyIncludes() {
337                return buildPropertyIncludes;
338        }
339
340        public void setBuildPropertyIncludes(List<String> buildPropertyIncludes) {
341                this.buildPropertyIncludes = buildPropertyIncludes;
342        }
343
344        public List<String> getBuildPropertyExcludes() {
345                return buildPropertyExcludes;
346        }
347
348        public void setBuildPropertyExcludes(List<String> buildPropertyExcludes) {
349                this.buildPropertyExcludes = buildPropertyExcludes;
350        }
351}