Skip to content

Commit 55a5d6a

Browse files
committed
conga-aem-crypto-cli: Add command line options to encrypt and decrypt values using AEM crypto support.
1 parent 80d0925 commit 55a5d6a

6 files changed

Lines changed: 213 additions & 12 deletions

File tree

changes.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/plugins/maven-changes-plugin/xsd/changes-1.0.0.xsd">
2424
<body>
2525

26-
<release version="1.9.4" date="not released">
26+
<release version="1.10.0" date="not released">
27+
<action type="add" dev="sseifert">
28+
conga-aem-crypto-cli: Add command line options to encrypt and decrypt values using AEM crypto support.
29+
</action>
2730
<action type="fix" dev="sseifert">
2831
conga-aem-crypto-cli: Allow to generate AEM crypto keys without specifying and Ansible vault password.
2932
</action>

src/site/markdown/crypto-cli.md.vm

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
## CONGA AEM Crypto CLI tool
1+
#set( $symbol_pound = '#' )
2+
#set( $symbol_dollar = '$' )
3+
#set( $symbol_escape = '\' )
4+
${symbol_pound}${symbol_pound} CONGA AEM Crypto CLI tool
25

36
The CONGA AEM plugin also provides a command-line interface tool for generating new AEM crypto keys.
47

@@ -7,15 +10,15 @@ The generated keys are supported by AEM 6.3 and upwards.
710
_**Please note:** You need to install the [Java Cryptography Extension (JCE) Unlimited Strength policy files][jce-policy] from Oracle, because Ansible uses 256 bit keys to handle encryption and decryption of the vault files. If you are using Java 8u162 or higher they are already active by default._
811

912

10-
### Download
13+
${symbol_pound}${symbol_pound}${symbol_pound} Download
1114

1215
Download it from Maven Central:
1316

1417
|---|---|---|
1518
| [CONGA AEM Crypto CLI tool](https://repo1.maven.org/maven2/io/wcm/devops/conga/plugins/conga-aem-crypto-cli/${project.properties['releasedVersion.version']}/conga-aem-crypto-cli-${project.properties['releasedVersion.version']}-dist.zip) | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.wcm.devops.conga.plugins/conga-aem-crypto-cli/badge.svg)](https://repo1.maven.org/maven2/io/wcm/devops/conga/plugins/conga-aem-crypto-cli/${project.properties['releasedVersion.version']}/conga-aem-crypto-cli-${project.properties['releasedVersion.version']}-dist.zip) |
1619

1720

18-
### Generate AEM crypto keys
21+
${symbol_pound}${symbol_pound}${symbol_pound} Generate AEM crypto keys
1922

2023
Generate a set of crypto keys:
2124

@@ -49,4 +52,24 @@ java -Dansible.vault.password=mypassword -jar conga-aem-crypto-cli-${project.pro
4952
```
5053

5154

55+
${symbol_pound}${symbol_pound}${symbol_pound} Encrypt and decrypt values using AEM crypto support
56+
57+
Encrypt string using AEM crypto support and a given key:
58+
59+
60+
```
61+
java -jar conga-aem-crypto-cli-${project.properties['releasedVersion.version']}.jar \
62+
-cryptoAesKey <path to master file> -aemCryptoEncrypt <value>
63+
```
64+
65+
Decrypt string using AEM crypto support and a given key:
66+
67+
68+
```
69+
java -jar conga-aem-crypto-cli-${project.properties['releasedVersion.version']}.jar \
70+
-cryptoAesKey <path to master file> -aemCryptoDecrypt <encrypted value>
71+
```
72+
73+
74+
5275
[jce-policy]: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* #%L
3+
* wcm.io
4+
* %%
5+
* Copyright (C) 2019 wcm.io
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 io.wcm.devops.conga.plugins.aem.tooling.crypto.cli;
21+
22+
import java.io.BufferedInputStream;
23+
import java.io.File;
24+
import java.io.FileInputStream;
25+
import java.io.IOException;
26+
import java.io.InputStream;
27+
import java.security.GeneralSecurityException;
28+
import java.security.Key;
29+
30+
import org.apache.commons.io.IOUtils;
31+
import org.apache.commons.lang3.StringUtils;
32+
33+
import io.wcm.devops.conga.plugins.aem.crypto.CryptoSupport;
34+
import io.wcm.devops.conga.plugins.aem.crypto.impl.AesCryptoSupport;
35+
36+
/**
37+
* Encrypts and decrypts values using AEM crypto support.
38+
*/
39+
public final class AemCrypto {
40+
41+
private AemCrypto() {
42+
// static methods only
43+
}
44+
45+
/**
46+
* Encrypts a string value using AEM crypto support.
47+
* @param value Value to encrypt
48+
* @param cryptoAesKey Path to 'master' key file
49+
* @return Encrypted value
50+
* @throws IOException I/O Exception
51+
* @throws GeneralSecurityException Security exception
52+
*/
53+
public static String encryptString(String value, String cryptoAesKey)
54+
throws IOException, GeneralSecurityException {
55+
CryptoSupport crypto = new AesCryptoSupport();
56+
Key key = getCryptoKey(cryptoAesKey, crypto);
57+
return crypto.encrypt(value, key);
58+
}
59+
60+
/**
61+
* Decrypts a string value using AEM crypto support.
62+
* @param value Value to decrypt
63+
* @param cryptoAesKey Path to 'master' key file
64+
* @return Decrypted value
65+
* @throws IOException I/O Exception
66+
* @throws GeneralSecurityException Security exception
67+
*/
68+
public static String decryptString(String value, String cryptoAesKey)
69+
throws IOException, GeneralSecurityException {
70+
CryptoSupport crypto = new AesCryptoSupport();
71+
Key key = getCryptoKey(cryptoAesKey, crypto);
72+
return crypto.decrypt(value, key);
73+
}
74+
75+
private static Key getCryptoKey(String cryptoAesKey, CryptoSupport crypto)
76+
throws IOException, GeneralSecurityException {
77+
if (StringUtils.isBlank(cryptoAesKey)) {
78+
throw new IllegalArgumentException("Please specify AEM crypto 'master' key via parameter '" + AemCryptoCli.CRYPTO_AES_KEY + "'.");
79+
}
80+
File file = new File(cryptoAesKey);
81+
if (!(file.exists() && file.isFile())) {
82+
throw new IllegalArgumentException("Unable to find AEM crypto 'master' key: " + file.getAbsolutePath());
83+
}
84+
try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
85+
byte[] data = IOUtils.toByteArray(is);
86+
return crypto.readKey(data);
87+
}
88+
}
89+
90+
}

tooling/conga-aem-crypto-cli/src/main/java/io/wcm/devops/conga/plugins/aem/tooling/crypto/cli/AemCryptoCli.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@
3232
*/
3333
public final class AemCryptoCli {
3434

35-
private static final String CRYPTO_KEYS_GENERATE = "cryptoKeysGenerate";
36-
private static final String CRYPTO_KEYS_ANSIBLE_VAULT_ENCRYPT = "cryptoKeysAnsibleVaultEncrypt";
37-
private static final String TARGET = "target";
38-
private static final String ANSIBLE_VAULT_ENCRYPT = "ansibleVaultEncrypt";
39-
private static final String ANSIBLE_VAULT_DECRYPT = "ansibleVaultDecrypt";
35+
static final String CRYPTO_KEYS_GENERATE = "cryptoKeysGenerate";
36+
static final String CRYPTO_KEYS_ANSIBLE_VAULT_ENCRYPT = "cryptoKeysAnsibleVaultEncrypt";
37+
static final String TARGET = "target";
38+
static final String ANSIBLE_VAULT_ENCRYPT = "ansibleVaultEncrypt";
39+
static final String ANSIBLE_VAULT_DECRYPT = "ansibleVaultDecrypt";
40+
static final String AEM_CRYPTO_ENCRYPT = "aemCryptoEncrypt";
41+
static final String AEM_CRYPTO_DECRYPT = "aemCryptoDecrypt";
42+
static final String CRYPTO_AES_KEY = "cryptoAesKey";
4043

4144
/**
4245
* Command line options
@@ -48,6 +51,10 @@ public final class AemCryptoCli {
4851
CLI_OPTIONS.addOption(TARGET, true, "Target path for the generated keys.");
4952
CLI_OPTIONS.addOption(ANSIBLE_VAULT_ENCRYPT, true, "Encrypts the given file with Ansible Vault.");
5053
CLI_OPTIONS.addOption(ANSIBLE_VAULT_DECRYPT, true, "Decrypts the given file with Ansible Vault.");
54+
CLI_OPTIONS.addOption(AEM_CRYPTO_ENCRYPT, true, "Encrypts the given value with AEM crypto support.");
55+
CLI_OPTIONS.addOption(AEM_CRYPTO_DECRYPT, true, "Decrypts the given value with AEM crypto support.");
56+
CLI_OPTIONS.addOption(CRYPTO_AES_KEY, true, "Path to 'master' file from AEM crypto keys for "
57+
+ "'" + AEM_CRYPTO_ENCRYPT + "' and '" + AEM_CRYPTO_DECRYPT + "'.");
5158
CLI_OPTIONS.addOption("?", false, "Print usage help.");
5259
}
5360

@@ -70,6 +77,9 @@ public static void main(String[] args) throws Exception {
7077
File targetDir = new File(commandLine.getOptionValue(TARGET, "target"));
7178
String ansibleVaultEncryptPath = commandLine.getOptionValue(ANSIBLE_VAULT_ENCRYPT);
7279
String ansibleVaultDecryptPath = commandLine.getOptionValue(ANSIBLE_VAULT_DECRYPT);
80+
String aemCryptoEncrypt = commandLine.getOptionValue(AEM_CRYPTO_ENCRYPT);
81+
String aemCryptoDecrypt = commandLine.getOptionValue(AEM_CRYPTO_DECRYPT);
82+
String cryptoAesKey = commandLine.getOptionValue(CRYPTO_AES_KEY);
7383

7484
if (generateCryptoKeys) {
7585
CryptoKeys.generate(targetDir, ansibleVaultEncrypt)
@@ -84,6 +94,16 @@ else if (StringUtils.isNotBlank(ansibleVaultDecryptPath)) {
8494
AnsibleVault.decrypt(new File(ansibleVaultDecryptPath));
8595
return;
8696
}
97+
else if (StringUtils.isNotBlank(aemCryptoEncrypt)) {
98+
String result = AemCrypto.encryptString(aemCryptoEncrypt, cryptoAesKey);
99+
System.out.println(result);
100+
return;
101+
}
102+
else if (StringUtils.isNotBlank(aemCryptoDecrypt)) {
103+
String result = AemCrypto.decryptString(aemCryptoDecrypt, cryptoAesKey);
104+
System.out.println(result);
105+
return;
106+
}
87107

88108
// print usage help
89109
HelpFormatter formatter = new HelpFormatter();
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* #%L
3+
* wcm.io
4+
* %%
5+
* Copyright (C) 2019 wcm.io
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 io.wcm.devops.conga.plugins.aem.tooling.crypto.cli;
21+
22+
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
import static org.junit.jupiter.api.Assertions.assertFalse;
24+
25+
import java.io.File;
26+
27+
import org.apache.commons.io.FileUtils;
28+
import org.apache.commons.lang3.StringUtils;
29+
import org.junit.jupiter.api.AfterEach;
30+
import org.junit.jupiter.api.BeforeEach;
31+
import org.junit.jupiter.api.Test;
32+
33+
public class AemCryptoTest {
34+
35+
private File targetFolder;
36+
private String cryptoAesKey;
37+
38+
@BeforeEach
39+
public void setUp() throws Exception {
40+
// create temp directory path
41+
targetFolder = File.createTempFile(getClass().getName(), null);
42+
targetFolder.delete();
43+
44+
// generate crypto keys
45+
CryptoKeys.generate(targetFolder, false).forEach(item -> { /* generate */ });
46+
cryptoAesKey = targetFolder.getPath() + "/master";
47+
}
48+
49+
@AfterEach
50+
public void tearDown() throws Exception {
51+
FileUtils.deleteDirectory(targetFolder);
52+
}
53+
54+
@Test
55+
public void testEncryptDecryptString() throws Exception {
56+
String value = "myTestValue-äöü߀";
57+
58+
String encryptedValue = AemCrypto.encryptString(value, cryptoAesKey);
59+
assertFalse(StringUtils.equals(value, encryptedValue));
60+
61+
String decryptedValue = AemCrypto.decryptString(encryptedValue, cryptoAesKey);
62+
assertEquals(value, decryptedValue);
63+
}
64+
65+
}

tooling/conga-aem-crypto-cli/src/test/java/io/wcm/devops/conga/plugins/aem/tooling/crypto/cli/CryptoKeysTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,16 @@ public void tearDown() throws Exception {
5555
@Test
5656
public void testGenerate() throws Exception {
5757
Stream<File> files = CryptoKeys.generate(targetFolder, false);
58-
assetFiles(files);
58+
assertFiles(files);
5959
}
6060

6161
@Test
6262
public void testGenerateAnsibleVaultEncrypt() throws Exception {
6363
Stream<File> files = CryptoKeys.generate(targetFolder, true);
64-
assetFiles(files);
64+
assertFiles(files);
6565
}
6666

67-
private void assetFiles(Stream<File> filesStream) {
67+
private void assertFiles(Stream<File> filesStream) {
6868
List<File> files = filesStream.collect(Collectors.toList());
6969
assertEquals(2, files.size());
7070
assertTrue(files.get(0).exists());

0 commit comments

Comments
 (0)