azkaban-aplcache
Changes
az-crypto/build.gradle 39(+39 -0)
az-crypto/scripts/encrypt.sh 15(+15 -0)
az-crypto/src/azkaban/crypto/Crypto.java 78(+78 -0)
az-crypto/src/azkaban/crypto/CryptoV1.java 65(+65 -0)
az-crypto/src/azkaban/crypto/CryptoV1_1.java 71(+71 -0)
az-crypto/src/azkaban/crypto/ICrypto.java 39(+39 -0)
az-crypto/src/azkaban/crypto/Version.java 68(+68 -0)
build.gradle 5(+5 -0)
settings.gradle 4(+3 -1)
Details
az-crypto/build.gradle 39(+39 -0)
diff --git a/az-crypto/build.gradle b/az-crypto/build.gradle
new file mode 100644
index 0000000..d8b01b7
--- /dev/null
+++ b/az-crypto/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 LinkedIn Corp.
+ *
+ * Licensed 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.
+ */
+
+apply plugin: 'distribution'
+
+dependencies {
+ compile deps.bcprov
+ compile deps.commonsCli
+ compile deps.commonsLang
+ compile deps.guava
+ compile deps.jacksonAnnotation
+ compile deps.jacksonCore
+ compile deps.jacksonDatabind
+ compile deps.jasypt
+ compile deps.hadoopCommon
+}
+
+distributions {
+ main {
+ contents {
+ from(jar) {
+ into 'lib'
+ }
+ }
+ }
+}
az-crypto/scripts/encrypt.sh 15(+15 -0)
diff --git a/az-crypto/scripts/encrypt.sh b/az-crypto/scripts/encrypt.sh
new file mode 100755
index 0000000..cf43a87
--- /dev/null
+++ b/az-crypto/scripts/encrypt.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+if [[ $# -ne 2 ]]; then
+ echo "Usage: encrypt.sh [pass phrase] [plain text]"
+ exit 128
+fi
+
+#Use version fit for your service.
+version=1.1
+class_path=../../jars/*:../lib/*
+
+command="-cp $class_path azkaban.crypto.EncryptionCLI -k $1 -p $2 -v $version"
+#echo "Executing: java $command"
+
+java $command
\ No newline at end of file
az-crypto/src/azkaban/crypto/Crypto.java 78(+78 -0)
diff --git a/az-crypto/src/azkaban/crypto/Crypto.java b/az-crypto/src/azkaban/crypto/Crypto.java
new file mode 100644
index 0000000..2ed5317
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/Crypto.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.Base64;
+import java.util.Map;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * Crypto class that actually delegates to version specific implementation of ICrypto interface. In
+ * other words, it's a factory method class that implements ICrypto interface
+ */
+public class Crypto implements ICrypto {
+
+ private static final Logger logger = Logger.getLogger(Crypto.class);
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+ private final Map<Version, ICrypto> cryptos;
+
+ public Crypto() {
+ this.cryptos = ImmutableMap.<Version, ICrypto>builder()
+ .put(Version.V1_0, new CryptoV1())
+ .put(Version.V1_1, new CryptoV1_1())
+ .build();
+ }
+
+ public static String encode(final String s) {
+ return Base64.getEncoder().encodeToString(s.getBytes());
+ }
+
+ public static String decode(final String s) {
+ return new String(Base64.getDecoder().decode(s));
+ }
+
+ @Override
+ public String encrypt(final String plaintext, final String passphrase,
+ final Version cryptoVersion) {
+ Preconditions.checkNotNull(cryptoVersion, "Crypto version is required.");
+ Preconditions.checkArgument(!StringUtils.isEmpty(plaintext), "plaintext should not be empty");
+ Preconditions.checkArgument(!StringUtils.isEmpty(passphrase), "passphrase should not be empty");
+
+ final ICrypto crypto = this.cryptos.get(cryptoVersion);
+ Preconditions.checkNotNull(crypto, cryptoVersion + " is not supported.");
+ return crypto.encrypt(plaintext, passphrase, cryptoVersion);
+ }
+
+ @Override
+ public String decrypt(final String cipheredText, final String passphrase) {
+ Preconditions
+ .checkArgument(!StringUtils.isEmpty(cipheredText), "cipheredText should not be empty");
+ Preconditions.checkArgument(!StringUtils.isEmpty(passphrase), "passphrase should not be empty");
+
+ try {
+ final String jsonStr = decode(cipheredText);
+ final JsonNode json = MAPPER.readTree(jsonStr);
+ final String ver = json.get(VERSION_IDENTIFIER).asText();
+
+ final ICrypto crypto = this.cryptos.get(Version.fromVerString(ver));
+ Preconditions.checkNotNull(crypto);
+ return crypto.decrypt(cipheredText, passphrase);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
az-crypto/src/azkaban/crypto/CryptoV1.java 65(+65 -0)
diff --git a/az-crypto/src/azkaban/crypto/CryptoV1.java b/az-crypto/src/azkaban/crypto/CryptoV1.java
new file mode 100644
index 0000000..af10d93
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/CryptoV1.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Preconditions;
+import org.apache.log4j.Logger;
+import org.jasypt.encryption.pbe.PBEStringEncryptor;
+import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
+
+/**
+ * Encrypts and decrypts using DES algorithm.
+ * DES is not recommended by NIST, but this is particularly useful for the JRE environment
+ * that haven't installed (or cannot install) JCE unlimited strength.
+ */
+public class CryptoV1 implements ICrypto {
+
+ private static final Logger logger = Logger.getLogger(CryptoV1.class);
+
+ private static final String CIPHERED_TEXT_KEY = "val";
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ @Override
+ public String encrypt(final String plaintext, final String passphrase,
+ final Version cryptoVersion) {
+ Preconditions.checkArgument(Version.V1_0.equals(cryptoVersion));
+
+ final String cipheredText = newEncryptor(passphrase).encrypt(plaintext);
+ final ObjectNode node = MAPPER.createObjectNode();
+ node.put(CIPHERED_TEXT_KEY, cipheredText);
+ node.put(VERSION_IDENTIFIER, Version.V1_0.versionStr());
+
+ return Crypto.encode(node.toString());
+ }
+
+ @Override
+ public String decrypt(final String cipheredText, final String passphrase) {
+ try {
+ final JsonNode json = MAPPER.readTree(Crypto.decode(cipheredText));
+ return newEncryptor(passphrase).decrypt(json.get(CIPHERED_TEXT_KEY).asText());
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * DES algorithm
+ */
+ private PBEStringEncryptor newEncryptor(final String passphrase) {
+ final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
+ encryptor.setPassword(passphrase);
+ return encryptor;
+ }
+}
az-crypto/src/azkaban/crypto/CryptoV1_1.java 71(+71 -0)
diff --git a/az-crypto/src/azkaban/crypto/CryptoV1_1.java b/az-crypto/src/azkaban/crypto/CryptoV1_1.java
new file mode 100644
index 0000000..c01f359
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/CryptoV1_1.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Preconditions;
+import java.security.Provider;
+import org.apache.log4j.Logger;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.jasypt.encryption.pbe.PBEStringEncryptor;
+import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
+
+/**
+ * Uses AES algorithm to encrypt and decrypt.
+ */
+public class CryptoV1_1 implements ICrypto {
+
+ private static final Logger logger = Logger.getLogger(CryptoV1_1.class);
+
+ private static final String CIPHERED_TEXT_KEY = "val";
+ private static final String CRYPTO_ALGO = "PBEWITHSHA256AND128BITAES-CBC-BC";
+ private static final Provider PROVIDER = new BouncyCastleProvider();
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ @Override
+ public String encrypt(final String plaintext, final String passphrase,
+ final Version cryptoVersion) {
+ Preconditions.checkArgument(Version.V1_1.equals(cryptoVersion));
+
+ final String cipheredText = newEncryptor(passphrase).encrypt(plaintext);
+ final ObjectNode node = MAPPER.createObjectNode();
+ node.put(CIPHERED_TEXT_KEY, cipheredText);
+ node.put(VERSION_IDENTIFIER, Version.V1_1.versionStr());
+
+ return Crypto.encode(node.toString());
+ }
+
+ @Override
+ public String decrypt(final String cipheredText, final String passphrase) {
+ try {
+ final String jsonStr = Crypto.decode(cipheredText);
+ final JsonNode json = MAPPER.readTree(jsonStr);
+ return newEncryptor(passphrase).decrypt(json.get(CIPHERED_TEXT_KEY).asText());
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * AES algorithm
+ */
+ private PBEStringEncryptor newEncryptor(final String passphrase) {
+ final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
+ encryptor.setPassword(passphrase);
+ encryptor.setProvider(PROVIDER);
+ encryptor.setAlgorithm(CRYPTO_ALGO);
+ return encryptor;
+ }
+}
diff --git a/az-crypto/src/azkaban/crypto/Decryptions.java b/az-crypto/src/azkaban/crypto/Decryptions.java
new file mode 100644
index 0000000..8ea44df
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/Decryptions.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+import com.google.common.base.Preconditions;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.FsAction;
+import org.apache.hadoop.fs.permission.FsPermission;
+
+public class Decryptions {
+
+ private static final FsPermission USER_READ_PERMISSION_ONLY = new FsPermission(FsAction.READ,
+ FsAction.NONE,
+ FsAction.NONE);
+
+ public String decrypt(final String cipheredText, final String passphrasePath, final FileSystem fs)
+ throws IOException {
+ Preconditions.checkNotNull(cipheredText);
+ Preconditions.checkNotNull(passphrasePath);
+
+ final Path path = new Path(passphrasePath);
+ Preconditions.checkArgument(fs.exists(path), "File does not exist at " + passphrasePath);
+ Preconditions
+ .checkArgument(fs.isFile(path), "Passphrase path is not a file. " + passphrasePath);
+
+ final FileStatus fileStatus = fs.getFileStatus(path);
+ Preconditions.checkArgument(USER_READ_PERMISSION_ONLY.equals(fileStatus.getPermission()),
+ "Passphrase file should only have read only permission on only user. " + passphrasePath);
+
+ final Crypto crypto = new Crypto();
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(fs.open(path)))) {
+ final String passphrase = br.readLine();
+ final String decrypted = crypto.decrypt(cipheredText, passphrase);
+ Preconditions.checkNotNull(decrypted, "Was not able to decrypt");
+ return decrypted;
+ }
+ }
+}
\ No newline at end of file
diff --git a/az-crypto/src/azkaban/crypto/EncryptionCLI.java b/az-crypto/src/azkaban/crypto/EncryptionCLI.java
new file mode 100644
index 0000000..045ba4d
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/EncryptionCLI.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/**
+ * Command line interface for user to encrypt plain text with passphrase.
+ */
+public class EncryptionCLI {
+
+ private static final String PASSPHRASE_KEY = "k";
+ private static final String PLAINTEXT_KEY = "p";
+ private static final String VERSION_KEY = "v";
+ private static final String HELP_KEY = "h";
+
+ /**
+ * Outputs ciphered text to STDOUT.
+ *
+ * usage: EncryptionCLI [-h] -k <pass phrase> -p <plainText> -v <crypto version>
+ * -h,--help print this message
+ * -k,--key <pass phrase> Passphrase used for encrypting plain text
+ * -p,--plaintext <plainText> Plaintext that needs to be encrypted
+ * -v,--version <crypto version> Version it will use to encrypt Version: [1.0, 1.1]
+ */
+ public static void main(final String[] args) throws ParseException {
+ final CommandLineParser parser = new DefaultParser();
+
+ if (parser.parse(createHelpOptions(), args, true).hasOption(HELP_KEY)) {
+ new HelpFormatter().printHelp(EncryptionCLI.class.getSimpleName(), createOptions(), true);
+ return;
+ }
+
+ final CommandLine line = parser.parse(createOptions(), args);
+
+ final String passphraseKey = line.getOptionValue(PASSPHRASE_KEY);
+ final String plainText = line.getOptionValue(PLAINTEXT_KEY);
+ final String version = line.getOptionValue(VERSION_KEY);
+
+ final ICrypto crypto = new Crypto();
+ final String cipheredText = crypto
+ .encrypt(plainText, passphraseKey, Version.fromVerString(version));
+ System.out.println(cipheredText);
+ }
+
+ private static Options createHelpOptions() {
+ final Options options = new Options();
+ options.addOption(Option.builder(HELP_KEY).longOpt("help")
+ .desc("print this message").build());
+ return options;
+ }
+
+ private static Options createOptions() {
+ final Options options = createHelpOptions();
+
+ options.addOption(Option.builder(PLAINTEXT_KEY).longOpt("plaintext").hasArg().required()
+ .desc("Plaintext that needs to be encrypted")
+ .argName("plainText").build());
+
+ options.addOption(Option.builder(PASSPHRASE_KEY).longOpt("key").hasArg().required()
+ .desc("Passphrase used for encrypting plain text")
+ .argName("pass phrase").build());
+
+ options.addOption(Option.builder(VERSION_KEY).longOpt("version").hasArg().required()
+ .desc("Version it will use to encrypt Version: " + Version.versionStrings())
+ .argName("crypto version").build());
+
+ return options;
+ }
+}
\ No newline at end of file
az-crypto/src/azkaban/crypto/ICrypto.java 39(+39 -0)
diff --git a/az-crypto/src/azkaban/crypto/ICrypto.java b/az-crypto/src/azkaban/crypto/ICrypto.java
new file mode 100644
index 0000000..65f46a9
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/ICrypto.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+/**
+ * Encrypts plain text and decrypts ciphered text.
+ */
+public interface ICrypto {
+
+ static final String VERSION_IDENTIFIER = "ver";
+
+ /**
+ * Encrypts plain text using pass phrase and crypto version.
+ *
+ * @param plaintext The plain text (secret) need to be encrypted.
+ * @param passphrase Passphrase that will be used as a key to encrypt
+ * @param cryptoVersion Version of this encryption.
+ * @return A ciphered text, Base64 encoded.
+ */
+ public String encrypt(String plaintext, String passphrase, Version cryptoVersion);
+
+ /**
+ * Decrypts ciphered text.
+ *
+ * @param cipheredText Base64 encoded ciphered text
+ * @param passphrase Passphrase that was used as a key to encrypt the ciphered text
+ * @return plain text String
+ */
+ public String decrypt(String cipheredText, String passphrase);
+}
\ No newline at end of file
az-crypto/src/azkaban/crypto/Version.java 68(+68 -0)
diff --git a/az-crypto/src/azkaban/crypto/Version.java b/az-crypto/src/azkaban/crypto/Version.java
new file mode 100644
index 0000000..d076b52
--- /dev/null
+++ b/az-crypto/src/azkaban/crypto/Version.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package azkaban.crypto;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Lists;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public enum Version {
+ V1_0("1.0"),
+ V1_1("1.1");
+
+ private static final Map<String, Version> REVERSE_ENTRIES;
+
+ static {
+ final Builder<String, Version> builder = ImmutableMap.builder();
+ for (final Version version : Version.values()) {
+ builder.put(version._ver, version);
+ }
+ REVERSE_ENTRIES = builder.build();
+ }
+
+ private final String _ver;
+
+ private Version(final String ver) {
+ this._ver = ver;
+ }
+
+ /**
+ * Provides Version enum based on version String
+ *
+ * @param ver Version String
+ */
+ public static Version fromVerString(final String ver) {
+ final Version result = REVERSE_ENTRIES.get(ver);
+ Preconditions.checkNotNull(ver, "Invalid version " + ver);
+ return result;
+ }
+
+ /**
+ * @return Naturally ordered list of version String.
+ */
+ public static List<String> versionStrings() {
+ final List<String> versions = Lists.newArrayList(REVERSE_ENTRIES.keySet());
+ Collections.sort(versions);
+ return versions;
+ }
+
+ /**
+ * @return Version string
+ */
+ public String versionStr() {
+ return this._ver;
+ }
+}
diff --git a/az-crypto/test/azkaban/crypto/DecryptionTest.java b/az-crypto/test/azkaban/crypto/DecryptionTest.java
new file mode 100644
index 0000000..83005b4
--- /dev/null
+++ b/az-crypto/test/azkaban/crypto/DecryptionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package crypto;
+
+import azkaban.crypto.Crypto;
+import azkaban.crypto.CryptoV1;
+import azkaban.crypto.CryptoV1_1;
+import java.io.IOException;
+import junit.framework.Assert;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.junit.Test;
+
+public class DecryptionTest {
+
+ @Test
+ public void testV1_1() throws IOException {
+ BasicConfigurator.configure();
+ Logger.getRootLogger().setLevel(Level.DEBUG);
+
+ final String expected = "test";
+
+ final String ciphered = "eyJ2ZXIiOiIxLjEiLCJ2YWwiOiJpaE9CM2VzTzBad2F4cHZBV2Z5YUVicHZLQzJBWDJZZnVzS3hVWFN2R3A0PSJ9";
+ final String passphrase = "test1234";
+
+ final Crypto crypto = new Crypto();
+ final String actual = crypto.decrypt(ciphered, passphrase);
+ Assert.assertEquals(expected, actual);
+
+ try {
+ new CryptoV1().decrypt(ciphered, passphrase);
+ Assert.fail("Should have failed when decrypt v1.1 ciphered text with v1 decryption.");
+ } catch (final Exception e) {
+ Assert.assertTrue(e instanceof RuntimeException);
+ }
+ }
+
+ @Test
+ public void testV1() throws IOException {
+ BasicConfigurator.configure();
+ Logger.getRootLogger().setLevel(Level.DEBUG);
+
+ final String expected = "test";
+
+ final String ciphered = "eyJ2ZXIiOiIxLjAiLCJ2YWwiOiJOd1hRejdOMjBXUU05SXEzaE94RVZnPT0ifQ==";
+ final String passphrase = "test1234";
+
+ final Crypto crypto = new Crypto();
+ final String actual = crypto.decrypt(ciphered, passphrase);
+ Assert.assertEquals(expected, actual);
+
+ try {
+ new CryptoV1_1().decrypt(ciphered, passphrase);
+ Assert.fail("Should have failed when decrypt v1 ciphered text with v1.1 decryption.");
+ } catch (final Exception e) {
+ Assert.assertTrue(e instanceof RuntimeException);
+ }
+ }
+
+ @Test
+ public void testInvalidParams() throws IOException {
+ BasicConfigurator.configure();
+ Logger.getRootLogger().setLevel(Level.DEBUG);
+
+ final String expected = "test";
+ final String[] cipheredtexts = {
+ "eyJ2ZXIiOiIxLjAiLCJ2YWwiOiJOd1hRejdOMjBXUU05SXEzaE94RVZnPT0ifQ==", null, ""};
+ final String[] passphrases = {"test1234", null, ""};
+
+ for (final String cipheredtext : cipheredtexts) {
+ for (final String passphrase : passphrases) {
+ final Crypto crypto = new Crypto();
+ if (!StringUtils.isEmpty(cipheredtext) && !StringUtils.isEmpty(passphrase)) {
+ final String actual = crypto.decrypt(cipheredtext, passphrase);
+ Assert.assertEquals(expected, actual);
+ } else {
+ try {
+ crypto.decrypt(cipheredtext, passphrase);
+ Assert.fail("Encyption should have failed with invalid parameters. cipheredtext: "
+ + cipheredtext + " , passphrase: " + passphrase);
+ } catch (final Exception e) {
+ Assert.assertTrue(e instanceof IllegalArgumentException);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/az-crypto/test/azkaban/crypto/EncryptionTest.java b/az-crypto/test/azkaban/crypto/EncryptionTest.java
new file mode 100644
index 0000000..d01d84e
--- /dev/null
+++ b/az-crypto/test/azkaban/crypto/EncryptionTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 LinkedIn Corp. All rights reserved.
+ *
+ * Licensed 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.
+ */
+package crypto;
+
+import azkaban.crypto.Crypto;
+import azkaban.crypto.ICrypto;
+import azkaban.crypto.Version;
+import junit.framework.Assert;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Test;
+
+public class EncryptionTest {
+
+ @Test
+ public void testEncryption() {
+ final String plainText = "test";
+ final String passphrase = "test1234";
+
+ final ICrypto crypto = new Crypto();
+
+ for (final Version ver : Version.values()) {
+ final String cipheredText = crypto.encrypt(plainText, passphrase, ver);
+ Assert.assertEquals(plainText, crypto.decrypt(cipheredText, passphrase));
+ }
+ }
+
+ @Test
+ public void testInvalidParams() {
+ final ICrypto crypto = new Crypto();
+ final String[] args = {"", null, "test"};
+ for (final Version ver : Version.values()) {
+ for (final String plaintext : args) {
+ for (final String passphrase : args) {
+ try {
+ if (!StringUtils.isEmpty(plaintext) && !StringUtils.isEmpty(passphrase)) {
+ final String cipheredText = crypto.encrypt(plaintext, passphrase, ver);
+ Assert.assertEquals(plaintext, crypto.decrypt(cipheredText, passphrase));
+ } else {
+ crypto.encrypt(plaintext, passphrase, ver);
+ Assert.fail("Encyption should have failed with invalid parameters. plaintext: "
+ + plaintext + " , passphrase: " + passphrase);
+ }
+ } catch (final Exception e) {
+ Assert.assertTrue(e instanceof IllegalArgumentException);
+ }
+
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
build.gradle 5(+5 -0)
diff --git a/build.gradle b/build.gradle
index 962e8c1..e825fdc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -120,6 +120,11 @@ ext.deps = [
snakeyaml : 'org.yaml:snakeyaml:1.18',
velocity : 'org.apache.velocity:velocity:1.7',
velocityTools : 'org.apache.velocity:velocity-tools:2.0',
+ bcprov : 'org.bouncycastle:bcprov-jdk15on:1.54',
+ jacksonAnnotation : 'com.fasterxml.jackson.core:jackson-annotations:2.7.4',
+ jacksonDatabind : 'com.fasterxml.jackson.core:jackson-databind:2.7.4',
+ jasypt : 'org.jasypt:jasypt:1.9.2',
+ jacksonCore : 'com.fasterxml.jackson.core:jackson-core:2.9.2'
]
subprojects {
settings.gradle 4(+3 -1)
diff --git a/settings.gradle b/settings.gradle
index 4b4c9b4..4f9edec 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,4 +33,6 @@ include 'az-jobsummary'
include 'az-hdfs-viewer'
include 'az-flow-trigger-dependency-type'
include 'az-flow-trigger-dependency-type:kafka-event-trigger'
-include 'tools'
\ No newline at end of file
+include 'tools'
+include 'az-crypto'
+