1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.common.util.property;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.Properties;
22 import java.util.Random;
23
24 import org.apache.commons.lang3.StringUtils;
25 import org.jasypt.util.text.TextEncryptor;
26 import org.kuali.common.util.EncUtils;
27 import org.kuali.common.util.EncryptionMode;
28 import org.kuali.common.util.EncryptionStrength;
29 import org.kuali.common.util.PropertyUtils;
30 import org.kuali.common.util.Str;
31 import org.kuali.common.util.property.processor.AddPrefixProcessor;
32 import org.kuali.common.util.property.processor.EndsWithDecryptProcessor;
33 import org.kuali.common.util.property.processor.EndsWithEncryptProcessor;
34 import org.kuali.common.util.property.processor.GlobalOverrideProcessor;
35 import org.kuali.common.util.property.processor.PropertyProcessor;
36 import org.kuali.common.util.property.processor.ReformatKeysAsEnvVarsProcessor;
37 import org.kuali.common.util.property.processor.ResolvePlaceholdersProcessor;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.springframework.util.Assert;
41 import org.springframework.util.PropertyPlaceholderHelper;
42
43 public class DefaultPropertyContext implements PropertyContext {
44
45 private static final Logger logger = LoggerFactory.getLogger(DefaultPropertyContext.class);
46 private static final Random RANDOM = new Random(System.currentTimeMillis());
47
48 PropertyPlaceholderHelper helper = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER;
49 String globalPropertiesMode = Constants.DEFAULT_GLOBAL_PROPERTIES_MODE.name();
50 String resolvePlaceholders = Boolean.toString(Constants.DEFAULT_RESOLVE_PLACEHOLDERS);
51 String style = PropertyStyle.NORMAL.name();
52 String encryptionMode = EncryptionMode.NONE.name();
53 String encryptionStrength = EncryptionStrength.BASIC.name();
54 String encryptionPassword;
55 String prefix;
56 List<PropertyProcessor> processors;
57 Properties properties;
58
59 protected List<PropertyProcessor> getDefaultProcessors() {
60 List<PropertyProcessor> processors = new ArrayList<PropertyProcessor>();
61
62
63 if (encryptionMode != null) {
64 EncryptionMode mode = EncryptionMode.valueOf(encryptionMode);
65 EncryptionStrength strength = EncryptionStrength.valueOf(encryptionStrength);
66 processors.add(getEncProcessor(mode, strength, encryptionPassword));
67 }
68
69
70
71
72
73
74
75 this.encryptionPassword = null;
76
77 GlobalPropertiesMode gpm = GlobalPropertiesMode.valueOf(globalPropertiesMode);
78
79
80 processors.add(new GlobalOverrideProcessor(gpm));
81
82
83 if (Boolean.parseBoolean(resolvePlaceholders)) {
84 processors.add(new ResolvePlaceholdersProcessor(helper, gpm));
85 }
86
87
88 if (!StringUtils.isBlank(prefix)) {
89 processors.add(new AddPrefixProcessor(prefix));
90 }
91
92
93 if (style != null) {
94 processors.add(getStyleProcessor(style));
95 }
96
97
98 return processors;
99 }
100
101 protected PropertyProcessor getStyleProcessor(String style) {
102 switch (PropertyStyle.valueOf(style)) {
103 case NORMAL:
104 return Constants.NO_OP_PROCESSOR;
105 case ENVIRONMENT_VARIABLE:
106 return new ReformatKeysAsEnvVarsProcessor();
107 default:
108 throw new IllegalArgumentException("Property style " + style + " is unknown");
109 }
110 }
111
112 protected PropertyProcessor getEncProcessor(EncryptionMode mode, EncryptionStrength strength, String password) {
113 switch (mode) {
114 case NONE:
115 return Constants.NO_OP_PROCESSOR;
116 case ENCRYPT:
117 TextEncryptor encryptor = EncUtils.getTextEncryptor(strength, password);
118 return new EndsWithEncryptProcessor(encryptor);
119 case DECRYPT:
120 TextEncryptor decryptor = EncUtils.getTextEncryptor(strength, password);
121 return new EndsWithDecryptProcessor(decryptor);
122 default:
123 throw new IllegalArgumentException("Encryption mode '" + mode + "' is unknown");
124 }
125 }
126
127 protected void log() {
128 if (!StringUtils.equals(EncryptionMode.NONE.name(), encryptionMode)) {
129 logger.info("Encryption mode - " + StringUtils.trimToEmpty(encryptionMode));
130 logger.info("Encryption strength - " + StringUtils.trimToEmpty(encryptionStrength));
131 String displayPassword = null;
132 if (!StringUtils.isBlank(encryptionPassword)) {
133 int len = encryptionPassword.length();
134 displayPassword = StringUtils.repeat("*", Math.max(RANDOM.nextInt(len * 2), len / 2));
135 }
136 logger.info("Encryption password - " + StringUtils.trimToEmpty(displayPassword));
137 }
138 if (!StringUtils.equals(PropertyStyle.NORMAL.name(), style)) {
139 logger.info("Property style - " + StringUtils.trimToEmpty(style));
140 }
141 if (!StringUtils.isEmpty(prefix)) {
142 logger.info("Property prefix - " + StringUtils.trimToEmpty(prefix));
143 }
144 if (!StringUtils.equals(Boolean.toString(Constants.DEFAULT_RESOLVE_PLACEHOLDERS), resolvePlaceholders)) {
145 logger.info("Resolve placeholders - " + resolvePlaceholders);
146 }
147 }
148
149 @Override
150 public void initialize(Properties properties) {
151 GlobalPropertiesMode gpm = GlobalPropertiesMode.valueOf(globalPropertiesMode);
152 Properties global = PropertyUtils.getProperties(properties, gpm);
153 this.encryptionMode = resolve(encryptionMode, global);
154 this.encryptionPassword = resolveAndRemove(encryptionPassword, global, properties);
155 this.encryptionStrength = resolve(encryptionStrength, global);
156 this.style = resolve(style, global);
157 this.prefix = resolve(prefix, global);
158 this.resolvePlaceholders = resolve(resolvePlaceholders, global);
159 log();
160 validate();
161 addProcessors();
162 logger.info("Proceeding with " + processors.size() + " processors.");
163 }
164
165 protected void addProcessors() {
166 List<PropertyProcessor> defaultProcessors = getDefaultProcessors();
167 if (processors == null) {
168 processors = defaultProcessors;
169 } else {
170 processors.addAll(0, defaultProcessors);
171 }
172 }
173
174 protected void validate() {
175 EncryptionMode.valueOf(encryptionMode);
176 EncryptionStrength.valueOf(encryptionStrength);
177 PropertyStyle.valueOf(style);
178 Boolean.parseBoolean(resolvePlaceholders);
179 }
180
181 protected String getPlaceholderKey(String string) {
182 String prefix = Constants.DEFAULT_PLACEHOLDER_PREFIX;
183 String suffix = Constants.DEFAULT_PLACEHOLDER_SUFFIX;
184 String separator = Constants.DEFAULT_VALUE_SEPARATOR;
185 String key = StringUtils.substringBetween(string, prefix, separator);
186 if (key == null) {
187 return StringUtils.substringBetween(string, prefix, suffix);
188 } else {
189 return key;
190 }
191 }
192
193 protected void remove(String string, String resolvedString, Properties properties) {
194 boolean placeholder = PropertyUtils.isSingleUnresolvedPlaceholder(string);
195 boolean resolved = !StringUtils.equals(string, resolvedString);
196 boolean irrelevant = Str.contains(Arrays.asList(Constants.NONE, Constants.NULL), resolvedString, false);
197 boolean remove = placeholder && resolved && !irrelevant;
198 if (remove) {
199 String key = getPlaceholderKey(string);
200 Assert.notNull(key, "key is null");
201 if (properties.getProperty(key) != null) {
202 logger.info("Removing property '" + key + "'");
203 properties.remove(key);
204 }
205 }
206 }
207
208 protected String resolveAndRemove(String string, Properties global, Properties properties) {
209 String resolvedString = resolve(string, global);
210 remove(string, resolvedString, properties);
211 return resolvedString;
212 }
213
214 protected String resolve(String string, Properties properties) {
215 if (string == null) {
216 return null;
217 } else {
218 String resolvedValue = helper.replacePlaceholders(string, properties);
219 if (!StringUtils.equals(string, resolvedValue)) {
220 logger.debug("Resolved {} -> {}", string, resolvedValue);
221 }
222 return resolvedValue;
223 }
224 }
225
226 public String getPrefix() {
227 return prefix;
228 }
229
230 public void setPrefix(String prefix) {
231 this.prefix = prefix;
232 }
233
234 public String getStyle() {
235 return style;
236 }
237
238 public void setStyle(String style) {
239 this.style = style;
240 }
241
242 public PropertyPlaceholderHelper getHelper() {
243 return helper;
244 }
245
246 public void setHelper(PropertyPlaceholderHelper helper) {
247 this.helper = helper;
248 }
249
250 public String getEncryptionMode() {
251 return encryptionMode;
252 }
253
254 public void setEncryptionMode(String encryptionMode) {
255 this.encryptionMode = encryptionMode;
256 }
257
258 public String getEncryptionStrength() {
259 return encryptionStrength;
260 }
261
262 public void setEncryptionStrength(String encryptionStrength) {
263 this.encryptionStrength = encryptionStrength;
264 }
265
266 public String getEncryptionPassword() {
267 return encryptionPassword;
268 }
269
270 public void setEncryptionPassword(String encryptionPassword) {
271 this.encryptionPassword = encryptionPassword;
272 }
273
274 @Override
275 public List<PropertyProcessor> getProcessors() {
276 return processors;
277 }
278
279 public void setProcessors(List<PropertyProcessor> processors) {
280 this.processors = processors;
281 }
282
283 public Properties getProperties() {
284 return properties;
285 }
286
287 public void setProperties(Properties properties) {
288 this.properties = properties;
289 }
290
291 public String getGlobalPropertiesMode() {
292 return globalPropertiesMode;
293 }
294
295 public void setGlobalPropertiesMode(String globalPropertiesMode) {
296 this.globalPropertiesMode = globalPropertiesMode;
297 }
298
299 public String getResolvePlaceholders() {
300 return resolvePlaceholders;
301 }
302
303 public void setResolvePlaceholders(String resolvePlaceholders) {
304 this.resolvePlaceholders = resolvePlaceholders;
305 }
306 }