Skip to content

Commit 747884d

Browse files
committed
Add Jasypt module for encrypted properties
- Added Environment.setConfig(Config) too Fixes jooby-project#2127
1 parent 70f2f01 commit 747884d

8 files changed

Lines changed: 490 additions & 15 deletions

File tree

docs/asciidoc/modules/jasypt.adoc

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
== Jasypt
2+
3+
Decrypt configuration properties using http://www.jasypt.org
4+
5+
=== Usage
6+
7+
1) Add the dependency:
8+
9+
[dependency, artifactId="jooby-jasypt"]
10+
.
11+
12+
2) Setup properties:
13+
14+
.application.conf
15+
[source, properties]
16+
----
17+
jasypt.password = password <1>
18+
19+
enc.property = "uTSqb9grs1+vUv3iN8lItC0kl65lMG+8" <2>
20+
----
21+
22+
3) Install
23+
24+
.Java
25+
[source, java, role="primary"]
26+
----
27+
import io.jooby.jasypt.JasyptModule;
28+
29+
{
30+
install(new JasyptModule()); <3>
31+
32+
String property = getConfig().getString("property"); <4>
33+
34+
System.out.println(property);
35+
}
36+
----
37+
38+
.Kotlin
39+
[source, kotlin, role="secondary"]
40+
----
41+
import io.jooby.jasypt.JasyptModule
42+
43+
{
44+
install(JasyptModule()) <3>
45+
46+
val property = config.getString("property") <4>
47+
48+
println(property)
49+
}
50+
----
51+
52+
<1> Configure jasypt password. Jasypt use this to encrypt/decrypt values
53+
<2> Prefix encrypted properties with `enc`
54+
<3> Install Jasypt
55+
<4> Get a decrypted property
56+
57+
Due Jasypt overrides configuration properties, must be installed at very beginning of the
58+
application. Once installed, you can access to decrypted properties.
59+
60+
By default, encrypted properties must be prefixed with `enc`, you can change this by setting
61+
your own/preferred prefix:
62+
63+
install(new JasyptModule().setPrefix("secret"));
64+
65+
Module also export an instance of `PBEStringEncryptor`:
66+
67+
.Java
68+
[source, java, role="primary"]
69+
----
70+
import io.jooby.jasypt.JasyptModule;
71+
72+
{
73+
install(new JasyptModule());
74+
75+
PBEStringEncryptor encryptor = require(PBEStringEncryptor.class);
76+
}
77+
----
78+
79+
.Kotlin
80+
[source, kotlin, role="secondary"]
81+
----
82+
import io.jooby.jasypt.JasyptModule
83+
84+
{
85+
install(JasyptModule())
86+
87+
val encryptor = require(PBEStringEncryptor::class)
88+
}
89+
----
90+
91+
==== Securing password
92+
93+
Password can be configured as application property. It is accessed using the `jasypt.password`
94+
property name. It is important to keep your password safe and private.
95+
96+
One simple way is to use a default password for development and override it with an environment variable. For example:
97+
98+
.application.conf
99+
[source, properties]
100+
----
101+
jasypt.password = mypassword
102+
jasypt.password = ${?JASYPT_PASSWORD}
103+
----
104+
105+
Here Jasypt will use a default value of `mypassword`, unless an environment variable `JASYPT_PASSWORD` is set.
106+
107+
Another option is to keep the password in the file system. For that you need to provide your own
108+
password provider:
109+
110+
.File password provider
111+
[source, java]
112+
----
113+
{
114+
install(new JasyptModule(config -> {
115+
return new String(Files.path(Paths.get("mypassword"), UTF-8));
116+
}));
117+
}
118+
----
119+
120+
The password provider let you read password from multiple sources.
121+
122+
==== Options
123+
124+
Advanced configuration options are available from configuration file:
125+
126+
.application.conf
127+
[source, properties]
128+
----
129+
jasypt.password = mypassword
130+
131+
jasypt.algorithm = PBEWithMD5AndDES
132+
jasypt.keyObtentionIterations = 1000
133+
jasypt.poolSize = 2
134+
jasypt.ivGeneratorClassName = classname
135+
jasypt.saltGeneratorClassName = org.jasypt.salt.RandomSaltGenerator
136+
jasypt.providerName = SunJCE
137+
----
138+
139+
A `PooledPBEStringEncryptor` encryptor is configured when `poolSize` is set.

docs/asciidoc/modules/modules.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Available modules are listed next.
4747
* link:/modules/thymeleaf[Thymeleaf]: Thymeleaf template engine.
4848

4949
=== Security
50+
* link:/modules/jasypt[Jasypt]: Encripted configuration files.
5051
* link:/modules/pac4j[Pac4j]: Security engine module.
5152

5253
=== Session Store

jooby/src/main/java/io/jooby/Environment.java

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,37 +42,37 @@ public class Environment {
4242

4343
private final List<String> actives;
4444

45-
private final Config conf;
45+
private Config config;
4646

4747
private final ClassLoader classLoader;
4848

4949
/**
5050
* Creates a new environment.
5151
*
5252
* @param classLoader Class loader.
53-
* @param conf Application configuration.
53+
* @param config Application configuration.
5454
* @param actives Active environment names.
5555
*/
56-
public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config conf,
56+
public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config config,
5757
@Nonnull String... actives) {
58-
this(classLoader, conf, Arrays.asList(actives));
58+
this(classLoader, config, Arrays.asList(actives));
5959
}
6060

6161
/**
6262
* Creates a new environment.
6363
*
6464
* @param classLoader Class loader.
65-
* @param conf Application configuration.
65+
* @param config Application configuration.
6666
* @param actives Active environment names.
6767
*/
68-
public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config conf,
68+
public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config config,
6969
@Nonnull List<String> actives) {
7070
this.classLoader = classLoader;
7171
this.actives = actives.stream()
7272
.map(String::trim)
7373
.map(String::toLowerCase)
7474
.collect(Collectors.toList());
75-
this.conf = conf;
75+
this.config = config;
7676
}
7777

7878
/**
@@ -83,8 +83,8 @@ public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config conf,
8383
* @return Property or default value.
8484
*/
8585
public @Nonnull String getProperty(@Nonnull String key, @Nonnull String defaults) {
86-
if (hasPath(conf, key)) {
87-
return conf.getString(key);
86+
if (hasPath(config, key)) {
87+
return config.getString(key);
8888
}
8989
return defaults;
9090
}
@@ -96,8 +96,8 @@ public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config conf,
9696
* @return Property value or <code>null</code> when missing.
9797
*/
9898
public @Nullable String getProperty(@Nonnull String key) {
99-
if (hasPath(conf, key)) {
100-
return conf.getString(key);
99+
if (hasPath(config, key)) {
100+
return config.getString(key);
101101
}
102102
return null;
103103
}
@@ -136,10 +136,10 @@ public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config conf,
136136
* @return Properties under that key or empty map.
137137
*/
138138
public @Nonnull Map<String, String> getProperties(@Nonnull String key, @Nullable String prefix) {
139-
if (hasPath(conf, key)) {
139+
if (hasPath(config, key)) {
140140
Map<String, String> settings = new HashMap<>();
141141
String p = prefix == null || prefix.length() == 0 ? "" : prefix + ".";
142-
conf.getConfig(key).entrySet().stream()
142+
config.getConfig(key).entrySet().stream()
143143
.forEach(e -> {
144144
Object value = e.getValue().unwrapped();
145145
if (value instanceof List) {
@@ -159,7 +159,19 @@ public Environment(@Nonnull ClassLoader classLoader, @Nonnull Config conf,
159159
* @return Application configuration.
160160
*/
161161
public @Nonnull Config getConfig() {
162-
return conf;
162+
return config;
163+
}
164+
165+
/**
166+
* Set configuration properties. Please note setting a configuration object must be done at very
167+
* early application stage.
168+
*
169+
* @param config Configuration properties.
170+
* @return This environment.
171+
*/
172+
public Environment setConfig(@Nonnull Config config) {
173+
this.config = config;
174+
return this;
163175
}
164176

165177
/**
@@ -207,7 +219,7 @@ public boolean isActive(@Nonnull String name, String... names) {
207219
}
208220

209221
@Override public String toString() {
210-
return actives + "\n" + toString(conf).trim();
222+
return actives + "\n" + toString(config).trim();
211223
}
212224

213225
private String toString(final Config conf) {

modules/jooby-jasypt/pom.xml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<parent>
7+
<groupId>io.jooby</groupId>
8+
<artifactId>modules</artifactId>
9+
<version>2.9.4-SNAPSHOT</version>
10+
</parent>
11+
12+
<modelVersion>4.0.0</modelVersion>
13+
<artifactId>jooby-jasypt</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.google.code.findbugs</groupId>
18+
<artifactId>jsr305</artifactId>
19+
<scope>provided</scope>
20+
</dependency>
21+
22+
<dependency>
23+
<groupId>io.jooby</groupId>
24+
<artifactId>jooby</artifactId>
25+
<version>${jooby.version}</version>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>org.jasypt</groupId>
30+
<artifactId>jasypt</artifactId>
31+
</dependency>
32+
33+
<!-- Test dependencies -->
34+
<dependency>
35+
<groupId>org.junit.jupiter</groupId>
36+
<artifactId>junit-jupiter-engine</artifactId>
37+
<scope>test</scope>
38+
</dependency>
39+
40+
<dependency>
41+
<groupId>org.jacoco</groupId>
42+
<artifactId>org.jacoco.agent</artifactId>
43+
<classifier>runtime</classifier>
44+
<scope>test</scope>
45+
</dependency>
46+
47+
<dependency>
48+
<groupId>org.mockito</groupId>
49+
<artifactId>mockito-core</artifactId>
50+
<scope>test</scope>
51+
</dependency>
52+
</dependencies>
53+
</project>

0 commit comments

Comments
 (0)