Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions components-starter/camel-jasypt-starter/src/main/doc/usage.adoc
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
Add encrypted values to your `application.properties` using the `ENC(...)` syntax:
Add encrypted values to your `application.properties` using the `ENC(...)` syntax, and point the starter at the master
password:

[source,properties]
----
my.secret = ENC(encrypted-value-here)
camel.component.jasypt.password = the-master-password
camel.component.jasypt.password = sysenv:JASYPT_PASSWORD
----

Use Camel's Jasypt tooling to encrypt values:
WARNING: The master password must never be stored in the same file, or the same repository, as the encrypted values it
protects. A file that carries both the ciphertext and the key that unlocks it is no better than a plaintext file. Supply
the master password from the environment or from an external secret store at deployment time.

`camel.component.jasypt.password` understands two prefixes that keep the password out of the configuration file:

* `sysenv:<name>` looks the password up in the OS environment variable `<name>`.
* `sys:<name>` looks the password up in the JVM system property `<name>`.

Any other value is used as the password verbatim, which is only appropriate when the property itself is injected by an
external secret store (for example a mounted secret or a config server) rather than checked in.

=== Encryption algorithm

The default algorithm is `PBEWITHHMACSHA256ANDAES_256`. It requires an initialization vector, which the starter
generates automatically (`org.jasypt.iv.RandomIvGenerator`) unless `camel.component.jasypt.iv-generator-class-name` is
set explicitly.

Use Jasypt tooling to encrypt values, passing the *same* algorithm and a random IV generator; a value encrypted under a
different algorithm, or without an IV generator, cannot be decrypted at runtime:

[source,bash]
----
camel jasypt encrypt --password=the-master-password --input=my-secret-value
jbang org.apache.camel:camel-jasypt:<camel-version> \
-c encrypt -p "$JASYPT_PASSWORD" -i my-secret-value \
-a PBEWITHHMACSHA256ANDAES_256 -riga SHA1PRNG
----

NOTE: The `camel-jasypt` CLI entrypoint is deprecated. The `encrypt.sh` script shipped in the
https://github.com/jasypt/jasypt/releases/tag/jasypt-1.9.3[Jasypt distribution] provides the same workflow, and takes
the algorithm and IV generator through its own `algorithm` and `ivGeneratorClassName` arguments.

To keep reading values that were encrypted with the previous default algorithm, pin it explicitly:

[source,properties]
----
camel.component.jasypt.algorithm = PBEWithMD5AndDES
----
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
{
"name": "camel.component.jasypt.algorithm",
"type": "java.lang.String",
"description": "The algorithm to be used for decryption. Default: PBEWithMD5AndDES",
"description": "The algorithm to be used for decryption. Default: PBEWITHHMACSHA256ANDAES_256. This algorithm requires an initialization vector, which is generated automatically unless ivGeneratorClassName is set explicitly. Values encrypted with a different algorithm can only be decrypted by setting this option to that algorithm, for example PBEWithMD5AndDES.",
"sourceType": "org.apache.camel.component.jasypt.springboot.JasyptEncryptedPropertiesConfiguration",
"defaultValue": "PBEWithMD5AndDES"
"defaultValue": "PBEWITHHMACSHA256ANDAES_256"
},
{
"name": "camel.component.jasypt.early-decryption-enabled",
Expand All @@ -37,7 +37,7 @@
{
"name": "camel.component.jasypt.password",
"type": "java.lang.String",
"description": "The master password used by Jasypt for decrypting the values. This option supports prefixes which influence the master password lookup behaviour: sysenv: means to lookup the OS system environment with the given key. sys: means to lookup a JVM system property.",
"description": "The master password used by Jasypt for decrypting the values. This option supports prefixes which influence the master password lookup behaviour: sysenv: means to lookup the OS system environment with the given key. sys: means to lookup a JVM system property. The master password should be supplied through one of those prefixes, or from an external secret store, and should not be stored alongside the encrypted values it protects.",
"sourceType": "org.apache.camel.component.jasypt.springboot.JasyptEncryptedPropertiesConfiguration"
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,18 @@ public class JasyptEncryptedPropertiesConfiguration {
private boolean earlyDecryptionEnabled;

/**
* The algorithm to be used for decryption. Default: PBEWithMD5AndDES
* The algorithm to be used for decryption. Default: PBEWITHHMACSHA256ANDAES_256. This algorithm requires an
* initialization vector, which is generated automatically unless ivGeneratorClassName is set explicitly. Values
* encrypted with a different algorithm can only be decrypted by setting this option to that algorithm, for example
* PBEWithMD5AndDES.
*/
private String algorithm = "PBEWithMD5AndDES";
private String algorithm = "PBEWITHHMACSHA256ANDAES_256";

/**
* The master password used by Jasypt for decrypting the values. This option supports prefixes which influence the
* master password lookup behaviour: sysenv: means to lookup the OS system environment with the given key. sys:
* means to lookup a JVM system property.
* means to lookup a JVM system property. The master password should be supplied through one of those prefixes, or
* from an external secret store, and should not be stored alongside the encrypted values it protects.
*/
private String password;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,18 @@ public class EncryptedPropertiesUtilsTest {

@Test
public void noIvGeneratorPropertyTest() {
// IVGenerator is null
// IVGenerator is not configured, the default algorithm requires one so it is auto detected
JasyptEncryptedPropertiesConfiguration configuration = new JasyptEncryptedPropertiesConfiguration();
IvGenerator ivGenerator = getIVGenerator(configuration);
assertThat(ivGenerator).isInstanceOf(RandomIvGenerator.class);
}

@Test
public void noIvGeneratorPropertyWithAlgorithmThatDoesNotNeedIvTest() {
// IVGenerator is not configured and the algorithm does not require one
JasyptEncryptedPropertiesConfiguration configuration = new JasyptEncryptedPropertiesConfiguration();
configuration.setAlgorithm("PBEWithMD5AndDES");
IvGenerator ivGenerator = getIVGenerator(configuration);
assertThat(ivGenerator).isInstanceOf(NoIvGenerator.class);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.jasypt.springboot;

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
import org.jasypt.iv.NoIvGenerator;
import org.jasypt.iv.RandomIvGenerator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

/**
* Verifies the default encryption algorithm of the starter, and that values encrypted with the previous default can
* still be read by pinning that algorithm explicitly.
*/
public class JasyptDefaultAlgorithmTest {

private static final String DEFAULT_ALGORITHM = "PBEWITHHMACSHA256ANDAES_256";

private static final String LEGACY_ALGORITHM = "PBEWithMD5AndDES";

private static final String PLAIN_TEXT = "mysecret";

private static final String MASTER_PASSWORD = "legacy-master-password";

/**
* {@value #PLAIN_TEXT} encrypted with {@value #LEGACY_ALGORITHM}, the master password {@value #MASTER_PASSWORD} and
* no initialization vector generator, which is how the starter encrypted values before the default changed.
*/
private static final String LEGACY_ENCRYPTED_VALUE = "+1thxaTtHh5z+yuyvFlCl5gafagmagQV";

private final ApplicationContextRunner runner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JasyptEncryptedPropertiesAutoconfiguration.class))
.withPropertyValues("camel.component.jasypt.password=" + MASTER_PASSWORD);

@Test
public void defaultAlgorithmRequiresAndGetsAnInitializationVector() {
runner.run(context -> {
assertThat(context.getBean(JasyptEncryptedPropertiesConfiguration.class).getAlgorithm())
.isEqualTo(DEFAULT_ALGORITHM);
EnvironmentStringPBEConfig config = context.getBean(EnvironmentStringPBEConfig.class);
assertThat(config.getAlgorithm()).isEqualTo(DEFAULT_ALGORITHM);
assertThat(config.getIvGenerator()).isInstanceOf(RandomIvGenerator.class);
});
}

@Test
public void defaultAlgorithmEncryptsAndDecrypts() {
runner.run(context -> {
StringEncryptor encryptor = context.getBean(StringEncryptor.class);
String encrypted = encryptor.encrypt(PLAIN_TEXT);
assertThat(encrypted).isNotEqualTo(PLAIN_TEXT);
assertThat(encryptor.decrypt(encrypted)).isEqualTo(PLAIN_TEXT);
});
}

@Test
public void legacyAlgorithmCanBePinnedExplicitly() {
runner.withPropertyValues("camel.component.jasypt.algorithm=" + LEGACY_ALGORITHM).run(context -> {
EnvironmentStringPBEConfig config = context.getBean(EnvironmentStringPBEConfig.class);
assertThat(config.getAlgorithm()).isEqualTo(LEGACY_ALGORITHM);
assertThat(config.getIvGenerator()).isInstanceOf(NoIvGenerator.class);
assertThat(context.getBean(StringEncryptor.class).decrypt(LEGACY_ENCRYPTED_VALUE)).isEqualTo(PLAIN_TEXT);
});
}

@Test
public void legacyValueIsNotReadableUnderTheDefaultAlgorithm() {
runner.run(context -> {
StringEncryptor encryptor = context.getBean(StringEncryptor.class);
assertThatExceptionOfType(EncryptionOperationNotPossibleException.class)
.isThrownBy(() -> encryptor.decrypt(LEGACY_ENCRYPTED_VALUE));
});
}
}
45 changes: 39 additions & 6 deletions docs/spring-boot/modules/ROOT/pages/starters/jasypt.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,52 @@ This starter integrates http://www.jasypt.org[Jasypt] with both Camel's property

== Usage

Add encrypted values to your `application.properties` using the `ENC(...)` syntax:
Add encrypted values to your `application.properties` using the `ENC(...)` syntax, and point the starter at the master
password:

[source,properties]
----
my.secret = ENC(encrypted-value-here)
camel.component.jasypt.password = the-master-password
camel.component.jasypt.password = sysenv:JASYPT_PASSWORD
----

Use Camel's Jasypt tooling to encrypt values:
WARNING: The master password must never be stored in the same file, or the same repository, as the encrypted values it
protects. A file that carries both the ciphertext and the key that unlocks it is no better than a plaintext file. Supply
the master password from the environment or from an external secret store at deployment time.

`camel.component.jasypt.password` understands two prefixes that keep the password out of the configuration file:

* `sysenv:<name>` looks the password up in the OS environment variable `<name>`.
* `sys:<name>` looks the password up in the JVM system property `<name>`.

Any other value is used as the password verbatim, which is only appropriate when the property itself is injected by an
external secret store (for example a mounted secret or a config server) rather than checked in.

=== Encryption algorithm

The default algorithm is `PBEWITHHMACSHA256ANDAES_256`. It requires an initialization vector, which the starter
generates automatically (`org.jasypt.iv.RandomIvGenerator`) unless `camel.component.jasypt.iv-generator-class-name` is
set explicitly.

Use Jasypt tooling to encrypt values, passing the *same* algorithm and a random IV generator; a value encrypted under a
different algorithm, or without an IV generator, cannot be decrypted at runtime:

[source,bash]
----
camel jasypt encrypt --password=the-master-password --input=my-secret-value
jbang org.apache.camel:camel-jasypt:<camel-version> \
-c encrypt -p "$JASYPT_PASSWORD" -i my-secret-value \
-a PBEWITHHMACSHA256ANDAES_256 -riga SHA1PRNG
----

NOTE: The `camel-jasypt` CLI entrypoint is deprecated. The `encrypt.sh` script shipped in the
https://github.com/jasypt/jasypt/releases/tag/jasypt-1.9.3[Jasypt distribution] provides the same workflow, and takes
the algorithm and IV generator through its own `algorithm` and `ivGeneratorClassName` arguments.

To keep reading values that were encrypted with the previous default algorithm, pin it explicitly:

[source,properties]
----
camel.component.jasypt.algorithm = PBEWithMD5AndDES
----

== Spring Boot Auto-Configuration
Expand All @@ -41,11 +74,11 @@ The starter supports 9 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| camel.component.jasypt.algorithm | The algorithm to be used for decryption. Default: PBEWithMD5AndDES | PBEWithMD5AndDES | String
| camel.component.jasypt.algorithm | The algorithm to be used for decryption. Default: PBEWITHHMACSHA256ANDAES_256. This algorithm requires an initialization vector, which is generated automatically unless ivGeneratorClassName is set explicitly. Values encrypted with a different algorithm can only be decrypted by setting this option to that algorithm, for example PBEWithMD5AndDES. | PBEWITHHMACSHA256ANDAES_256 | String
| camel.component.jasypt.early-decryption-enabled | Enable the early properties decryption during Spring Start Up. Enabling this feature, encrypted properties can be decrypted before the Spring Boot AutoConfiguration kicks in, for example, server.port=ENC(oBpQDDUvFY0c4WNAG0o4LIS5bWqmlxYlUUDTW2iXJIAZFYvM+3vOredaMcVfL4xW) will be decrypted to 8082, and the application will start using that port. | false | Boolean
| camel.component.jasypt.enabled | Enable the component | false | Boolean
| camel.component.jasypt.iv-generator-class-name | The initialization vector (IV) generator applied in decryption operations. Default: org.jasypt.iv. | | String
| camel.component.jasypt.password | The master password used by Jasypt for decrypting the values. This option supports prefixes which influence the master password lookup behaviour: sysenv: means to lookup the OS system environment with the given key. sys: means to lookup a JVM system property. | | String
| camel.component.jasypt.password | The master password used by Jasypt for decrypting the values. This option supports prefixes which influence the master password lookup behaviour: sysenv: means to lookup the OS system environment with the given key. sys: means to lookup a JVM system property. The master password should be supplied through one of those prefixes, or from an external secret store, and should not be stored alongside the encrypted values it protects. | | String
| camel.component.jasypt.provider-name | The class name of the security provider to be used for obtaining the encryption algorithm. | | String
| camel.component.jasypt.random-iv-generator-algorithm | The algorithm for the random iv generator | SHA1PRNG | String
| camel.component.jasypt.random-salt-generator-algorithm | The algorithm for the salt generator | SHA1PRNG | String
Expand Down
Loading