View Javadoc
1   /*-
2    * #%L
3    * Secured Properties
4    * ===============================================================
5    * Copyright (C) 2016 Brabenetz Harald, Austria
6    * ===============================================================
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package net.brabenetz.lib.securedproperties;
21  
22  import net.brabenetz.lib.securedproperties.test.TestUtils;
23  import net.brabenetz.lib.securedproperties.utils.SecuredPropertiesUtils;
24  import org.apache.commons.io.FileUtils;
25  import org.apache.commons.lang3.StringUtils;
26  import org.junit.Assert;
27  import org.junit.Before;
28  import org.junit.Test;
29  
30  import java.io.File;
31  import java.io.IOException;
32  import java.nio.charset.StandardCharsets;
33  import java.util.Arrays;
34  import java.util.Map;
35  import java.util.Properties;
36  
37  import static org.hamcrest.CoreMatchers.containsString;
38  import static org.hamcrest.MatcherAssert.assertThat;
39  import static org.hamcrest.Matchers.is;
40  import static org.hamcrest.Matchers.not;
41  import static org.hamcrest.Matchers.nullValue;
42  
43  public class SecuredPropertiesTest {
44  
45      @Before
46      public void before() throws Exception {
47          System.clearProperty("mySecretPassword");
48          if (getTestPropertyFile().exists()) {
49              FileUtils.forceDelete(getTestPropertyFile());
50          }
51          if (getTestSecretFile().exists()) {
52              FileUtils.forceDelete(getTestSecretFile());
53          }
54  
55      }
56  
57      @Test
58      public void testUtilityPattern() {
59          // this test is more for test-coverage than logic :D
60          Assert.assertTrue(TestUtils.isDefaultConstructorHidden(SecuredProperties.class));
61      }
62  
63      @Test
64      public void testGetSecretValue_withMultipleFiles_shouldIgnoreNotExistingOnes() throws Exception {
65          // run test
66          final String secretValue = SecuredProperties.getSecretValue(
67                  new SecuredPropertiesConfig().withSecretFile(getSecretFileExample()),
68                  new File[] {
69                          new File("./conf-abc/application.properties"),
70                          new File("./src/test/data/TestProperties-Valid.properties"),
71                          new File("./conf-xyz/application.properties"),
72                  },
73                  "mySecretPassword");
74  
75          // validate result
76          assertThat(secretValue, is("test"));
77  
78      }
79  
80      @Test
81      public void testGetSecretValue_withSecretFileFromProperty() throws Exception {
82          // run test
83          final String secretValue = SecuredProperties.getSecretValue(
84                  new SecuredPropertiesConfig().withSecretFile(getSecretFileExample()),
85                  new File("./src/test/data/TestProperties-Valid.properties"), "mySecretPassword");
86  
87          // validate result
88          assertThat(secretValue, is("test"));
89  
90      }
91  
92      @Test
93      public void testGetSecretValue_fromEncryptedPropertyFile() throws Exception {
94          // prepare property File
95          writeProperties(getTestPropertyFile(), "mySecretPassword={buMkr+yZH9RclafjETtlSQ==}");
96  
97          // run test
98          final String secretValue = SecuredProperties.getSecretValue(
99                  new SecuredPropertiesConfig().withSecretFile(getSecretFileExample()),
100                 getTestPropertyFile(), "mySecretPassword");
101 
102         // validate result
103         assertThat(secretValue, is("test"));
104 
105         // validate that property file is unchanged
106         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
107         assertThat(props.get("mySecretPassword"), is("{buMkr+yZH9RclafjETtlSQ==}"));
108 
109     }
110 
111     @Test
112     public void testGetSecretValue_notDefinedProperty_shouldReturnNull() throws Exception {
113         // prepare SystemProperty
114         writeProperties(getTestPropertyFile(), "title=Some Test");
115 
116         // run test
117         final String secretValue = SecuredProperties.getSecretValue(
118                 new SecuredPropertiesConfig().withSecretFile(getSecretFileExample()),
119                 getTestPropertyFile(), "mySecretPassword");
120         // validate result
121         assertThat(secretValue, is(nullValue()));
122 
123     }
124 
125     @Test
126     public void testManualExampleEncryptAndDecrypt_fromEncryptedSystemProperty() throws Exception {
127         // prepare SystemProperty
128         System.setProperty("mySecretPassword", "{buMkr+yZH9RclafjETtlSQ==}");
129 
130         // run test
131         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getSecretFileExample());
132 
133         final String encryptedValue = checkSystemProperties(config, "mySecretPassword");
134 
135         // validate result
136         assertThat(encryptedValue, is("test"));
137 
138     }
139 
140     @Test
141     public void testManualExampleEncryptAndDecrypt_fromUnencryptedSystemProperty_shouldLogInfoMessage() throws Exception {
142         // prepare SystemProperty
143         System.setProperty("mySecretPassword", "test");
144 
145         // run test
146         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getSecretFileExample());
147         final String encryptedValue = checkSystemProperties(config, "mySecretPassword");
148 
149         // validate result
150         assertThat(encryptedValue, is("test"));
151 
152         // TODO brabenetz 28.10.2016 : validate Log Message
153     }
154 
155     @Test
156     public void testGetSecretValue_fromUnencryptedPropertyFile_shouldNotReplaceProperty() throws Exception {
157         // prepare property File
158         writeProperties(getTestPropertyFile(), "mySecretPassword=test");
159 
160         // run test
161         final String secretValue = SecuredProperties.getSecretValue(
162                 new SecuredPropertiesConfig().withSecretFile(getSecretFileExample()),
163                 getTestPropertyFile(), "mySecretPassword");
164         // validate result
165         assertThat(secretValue, is("test"));
166 
167         // validate that property file is unchanged
168         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
169         final String newPasswordValue = props.getProperty("mySecretPassword");
170         assertThat(newPasswordValue, is("test"));
171 
172     }
173 
174     @Test
175     public void testGetSecretValue_withoutSecretFile_shouldCreateSecretFile() throws Exception {
176         // prepare property File
177         writeProperties(getTestPropertyFile(), "mySecretPassword=test");
178 
179         // run test
180         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getTestSecretFile());
181         // validate result
182         final String secretValue = SecuredProperties.getSecretValue(config, getTestPropertyFile(), "mySecretPassword");
183         assertThat(secretValue, is("test"));
184 
185         // validate that property file is unchanged
186         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
187         final String newPasswordValue = props.getProperty("mySecretPassword");
188         assertThat(newPasswordValue, is("test"));
189         assertThat(SecuredProperties.isEncryptedValue(newPasswordValue), is(false));
190         assertThat(getTestSecretFile().exists(), is(true));
191 
192     }
193 
194     @Test
195     public void testEncryptNonEncryptedValues_withMultipleFiles_shouldIgnoreNotExistingOnes() throws Exception {
196         writeProperties(getTestPropertyFile(), "pwd1=test");
197         // run test
198         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getSecretFileExample());
199         SecuredProperties.encryptNonEncryptedValues(
200                 config,
201                 new File[] {
202                         new File("./conf-abc/application.properties"),
203                         getTestPropertyFile(),
204                         new File("./conf-xyz/application.properties"),
205                 },
206                 "pwd1", "pwd2", "pwd3");
207 
208         // validate result
209         final String secretValue = SecuredProperties.getSecretValue(
210                 config, getTestPropertyFile(), "pwd1");
211         assertThat(secretValue, is("test"));
212 
213         // validate that property file is changed
214         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
215         assertThat(props.getProperty("pwd1"), is(not("test")));
216         assertThat(SecuredProperties.isEncryptedValue(props.getProperty("pwd1")), is(true));
217 
218     }
219 
220     @Test
221     public void testEncryptNonEncryptedValues_multipleValues_shouldReplaceUnencryptedProperties() throws Exception {
222         // prepare property File
223         writeProperties(getTestPropertyFile(), "pwd1=test", "pwd2={buMkr+yZH9RclafjETtlSQ==}", "pwd3=test");
224 
225         // run test
226         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getSecretFileExample());
227         SecuredProperties.encryptNonEncryptedValues(
228                 config, getTestPropertyFile(), "pwd1", "pwd2", "pwd3", "pwd99");
229         final Map<String, String> secretValues = SecuredProperties.getSecretValues(
230                 config, getTestPropertyFile(), "pwd1", "pwd2", "pwd3", "pwd99");
231         // validate result
232         assertThat(secretValues.get("pwd1"), is("test"));
233         assertThat(secretValues.get("pwd2"), is("test"));
234         assertThat(secretValues.get("pwd3"), is("test"));
235         assertThat(secretValues.get("pwd99"), is(nullValue()));
236 
237         // validate that property file is unchanged
238         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
239         assertThat(props.getProperty("pwd1"), is(not("test")));
240         assertThat(props.getProperty("pwd2"), is("{buMkr+yZH9RclafjETtlSQ==}"));
241         assertThat(props.getProperty("pwd3"), is(not("test")));
242         assertThat(SecuredProperties.isEncryptedValue(props.getProperty("pwd1")), is(true));
243         assertThat(SecuredProperties.isEncryptedValue(props.getProperty("pwd2")), is(true));
244         assertThat(SecuredProperties.isEncryptedValue(props.getProperty("pwd3")), is(true));
245 
246     }
247 
248     @Test
249     public void testEncryptNonEncryptedValues_fromUnencryptedPropertyFileWithoutSalt_shouldReplacePropertyWithAlwaysSameValue()
250             throws Exception {
251         // prepare property File
252         writeProperties(getTestPropertyFile(), "mySecretPassword=test");
253 
254         // run test
255         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getSecretFileExample()).withSaltLength(0);
256         SecuredProperties.encryptNonEncryptedValues(config, getTestPropertyFile(), "mySecretPassword");
257 
258         // validate result
259         final String secretValue = SecuredProperties.getSecretValue(config, getTestPropertyFile(), "mySecretPassword");
260         assertThat(secretValue, is("test"));
261 
262         // validate that property file contains the encrypted value but without salt it will result always with the same value.
263         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
264         final String newPasswordValue = props.getProperty("mySecretPassword");
265         assertThat(newPasswordValue, is("{wNnuFmepE9cAN6GpaULDZw==}"));
266 
267     }
268 
269     @Test
270     public void testEncryptNonEncryptedValues_withoutSecretFile_shouldCreateSecretFile() throws Exception {
271         // prepare property File
272         writeProperties(getTestPropertyFile(), "mySecretPassword=test");
273 
274         // run test
275         final SecuredPropertiesConfig config = new SecuredPropertiesConfig().withSecretFile(getTestSecretFile());
276         SecuredProperties.encryptNonEncryptedValues(config, getTestPropertyFile(), "mySecretPassword");
277         assertThat(getTestSecretFile().exists(), is(true));
278 
279         // validate result
280         final String secretValue = SecuredProperties.getSecretValue(config, getTestPropertyFile(), "mySecretPassword");
281         assertThat(secretValue, is("test"));
282 
283         // validate that property file is unchanged
284         final Properties props = SecuredPropertiesUtils.readProperties(getTestPropertyFile());
285         final String newPasswordValue = props.getProperty("mySecretPassword");
286         assertThat(newPasswordValue, is(not("test")));
287         assertThat(SecuredProperties.isEncryptedValue(newPasswordValue), is(true));
288         assertThat(getTestSecretFile().exists(), is(true));
289 
290     }
291 
292     @Test
293     public void testEncryptNonEncryptedValues_withoutSecretFile_shouldNotCreateSecretFile() throws Exception {
294         // prepare property File
295         writeProperties(getTestPropertyFile(), "mySecretPassword=test");
296 
297         // run test
298         final SecuredPropertiesConfig config = new SecuredPropertiesConfig()
299                 .withSecretFile(getTestSecretFile())
300                 .withAutoCreateSecretKey(false);
301         final Exception expectException = TestUtils.expectException(
302                 () -> SecuredProperties.encryptNonEncryptedValues(config, getTestPropertyFile(), "mySecretPassword"));
303         // validate result
304         assertThat(expectException.getMessage(), containsString("test.key"));
305         assertThat(expectException.getMessage(), containsString("doesn't exist, and auto create is off"));
306 
307         // validate that property file is unchanged
308         assertThat(getTestSecretFile().exists(), is(false));
309 
310     }
311 
312     private String checkSystemProperties(final SecuredPropertiesConfig config, final String key) {
313 
314         final String systemPropPassword = System.getProperty(key);
315         if (SecuredProperties.isEncryptedValue(systemPropPassword)) {
316             return SecuredProperties.decrypt(config, systemPropPassword);
317         } else if (StringUtils.isNotEmpty(systemPropPassword)) {
318             System.out.println(String.format("you could now use the following encrypted password: -D%s=%s", key,
319                     SecuredProperties.encrypt(config, systemPropPassword)));
320             return systemPropPassword;
321         } else {
322             return null;
323         }
324     }
325 
326     private File getTestSecretFile() {
327         return new File("./target/tests/test.key");
328     }
329 
330     private void writeProperties(final File testPropertyFile, final String... line) throws IOException {
331         FileUtils.writeLines(testPropertyFile, StandardCharsets.ISO_8859_1.name(), Arrays.asList(line));
332     }
333 
334     private File getTestPropertyFile() {
335         return new File("./target/tests/test.properties");
336     }
337 
338     private File getSecretFileExample() {
339         return new File("./src/test/data/secretFileExample.key");
340     }
341 
342 }