mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
encrypt credentials.json with AES
This commit is contained in:
parent
84e9bd96d2
commit
c3e0ead0a4
10 changed files with 149 additions and 7 deletions
|
|
@ -132,6 +132,12 @@
|
|||
<version>${aether.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.52</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-aether-provider</artifactId>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,21 @@ public class Credentials {
|
|||
private Boolean credentialsPersist = true;
|
||||
File credentialsFile;
|
||||
|
||||
public Credentials(Boolean credentialsPersist, String credentialsPath) {
|
||||
private Encryptor encryptor;
|
||||
|
||||
/**
|
||||
* Wrapper fro user credentials. It can load credentials from a file if credentialsPath is
|
||||
* supplied, and will encrypt the file if an encryptKey is supplied.
|
||||
*
|
||||
* @param credentialsPersist
|
||||
* @param credentialsPath
|
||||
* @param encryptKey
|
||||
*/
|
||||
public Credentials(Boolean credentialsPersist, String credentialsPath, String encryptKey) {
|
||||
if (encryptKey != null) {
|
||||
this.encryptor = new Encryptor(encryptKey);
|
||||
}
|
||||
|
||||
this.credentialsPersist = credentialsPersist;
|
||||
if (credentialsPath != null) {
|
||||
credentialsFile = new File(credentialsPath);
|
||||
|
|
@ -119,6 +133,11 @@ public class Credentials {
|
|||
fis.close();
|
||||
|
||||
String json = sb.toString();
|
||||
|
||||
if (encryptor != null) {
|
||||
json = encryptor.decrypt(json);
|
||||
}
|
||||
|
||||
CredentialsInfoSaving info = CredentialsInfoSaving.fromJson(json);
|
||||
this.credentialsMap = info.credentialsMap;
|
||||
} catch (IOException e) {
|
||||
|
|
@ -146,6 +165,11 @@ public class Credentials {
|
|||
|
||||
FileOutputStream fos = new FileOutputStream(credentialsFile, false);
|
||||
OutputStreamWriter out = new OutputStreamWriter(fos);
|
||||
|
||||
if (encryptor != null) {
|
||||
jsonString = encryptor.encrypt(jsonString);
|
||||
}
|
||||
|
||||
out.append(jsonString);
|
||||
out.close();
|
||||
fos.close();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
package org.apache.zeppelin.user;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||
import org.bouncycastle.crypto.engines.AESEngine;
|
||||
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
|
||||
import org.bouncycastle.crypto.paddings.ZeroBytePadding;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt arrays of bytes!
|
||||
*/
|
||||
public class Encryptor {
|
||||
private final BufferedBlockCipher encryptCipher;
|
||||
private final BufferedBlockCipher decryptCipher;
|
||||
|
||||
public Encryptor(String encryptKey) {
|
||||
encryptCipher = new PaddedBufferedBlockCipher(new AESEngine(), new ZeroBytePadding());
|
||||
encryptCipher.init(true, new KeyParameter(encryptKey.getBytes()));
|
||||
|
||||
decryptCipher = new PaddedBufferedBlockCipher(new AESEngine(), new ZeroBytePadding());
|
||||
decryptCipher.init(false, new KeyParameter(encryptKey.getBytes()));
|
||||
}
|
||||
|
||||
|
||||
public String encrypt(String inputString) throws IOException {
|
||||
byte[] input = inputString.getBytes();
|
||||
byte[] result = new byte[encryptCipher.getOutputSize(input.length)];
|
||||
int size = encryptCipher.processBytes(input, 0, input.length, result, 0);
|
||||
|
||||
try {
|
||||
size += encryptCipher.doFinal(result, size);
|
||||
|
||||
byte[] out = new byte[size];
|
||||
System.arraycopy(result, 0, out, 0, size);
|
||||
return new String(Base64.encode(out));
|
||||
} catch (InvalidCipherTextException e) {
|
||||
throw new IOException("Cannot encrypt: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String decrypt(String base64Input) throws IOException {
|
||||
byte[] input = Base64.decode(base64Input);
|
||||
byte[] result = new byte[decryptCipher.getOutputSize(input.length)];
|
||||
int size = decryptCipher.processBytes(input, 0, input.length, result, 0);
|
||||
|
||||
try {
|
||||
size += decryptCipher.doFinal(result, size);
|
||||
|
||||
byte[] out = new byte[size];
|
||||
System.arraycopy(result, 0, out, 0, size);
|
||||
return new String(out);
|
||||
} catch (InvalidCipherTextException e) {
|
||||
throw new IOException("Cannot decrypt: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ public class CredentialsTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultProperty() throws IOException {
|
||||
Credentials credentials = new Credentials(false, null);
|
||||
Credentials credentials = new Credentials(false, null, null);
|
||||
UserCredentials userCredentials = new UserCredentials();
|
||||
UsernamePassword up1 = new UsernamePassword("user2", "password");
|
||||
userCredentials.putUsernamePassword("hive(vertica)", up1);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.zeppelin.user;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
public class EncryptorTest {
|
||||
|
||||
@Test
|
||||
public void testEncryption() throws IOException {
|
||||
Encryptor encryptor = new Encryptor("foobar1234567890");
|
||||
|
||||
String input = "test";
|
||||
|
||||
String encrypted = encryptor.encrypt(input);
|
||||
assertNotEquals(input, encrypted);
|
||||
|
||||
String decrypted = encryptor.decrypt(encrypted);
|
||||
assertEquals(input, decrypted);
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +132,10 @@ public class ZeppelinServer extends Application {
|
|||
this.notebookRepo = new NotebookRepoSync(conf);
|
||||
this.noteSearchService = new LuceneSearch();
|
||||
this.notebookAuthorization = NotebookAuthorization.init(conf);
|
||||
this.credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
|
||||
this.credentials = new Credentials(
|
||||
conf.credentialsPersist(),
|
||||
conf.getCredentialsPath(),
|
||||
conf.getCredentialsEncryptKey());
|
||||
notebook = new Notebook(conf,
|
||||
notebookRepo, schedulerFactory, replFactory, interpreterSettingManager, notebookWsServer,
|
||||
noteSearchService, notebookAuthorization, credentials);
|
||||
|
|
@ -152,7 +155,7 @@ public class ZeppelinServer extends Application {
|
|||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
|
||||
// to update notebook from application event from remote process.
|
||||
heliumApplicationFactory.setNotebook(notebook);
|
||||
// to update fire websocket event on application event.
|
||||
|
|
|
|||
|
|
@ -443,6 +443,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
return getBoolean(ConfVars.ZEPPELIN_CREDENTIALS_PERSIST);
|
||||
}
|
||||
|
||||
public String getCredentialsEncryptKey() {
|
||||
return getString(ConfVars.ZEPPELIN_CREDENTIALS_ENCRYPT_KEY);
|
||||
}
|
||||
|
||||
public String getCredentialsPath() {
|
||||
return getRelativeDir(String.format("%s/credentials.json", getConfDir()));
|
||||
}
|
||||
|
|
@ -680,6 +684,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
ZEPPELIN_ALLOWED_ORIGINS("zeppelin.server.allowed.origins", "*"),
|
||||
ZEPPELIN_ANONYMOUS_ALLOWED("zeppelin.anonymous.allowed", true),
|
||||
ZEPPELIN_CREDENTIALS_PERSIST("zeppelin.credentials.persist", true),
|
||||
ZEPPELIN_CREDENTIALS_ENCRYPT_KEY("zeppelin.credentials.encryptKey", null),
|
||||
ZEPPELIN_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE("zeppelin.websocket.max.text.message.size", "1024000"),
|
||||
ZEPPELIN_SERVER_DEFAULT_DIR_ALLOWED("zeppelin.server.default.dir.allowed", false),
|
||||
ZEPPELIN_SERVER_XFRAME_OPTIONS("zeppelin.server.xframe.options", "SAMEORIGIN"),
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public class HeliumApplicationFactoryTest extends AbstractInterpreterTest implem
|
|||
this,
|
||||
search,
|
||||
notebookAuthorization,
|
||||
new Credentials(false, null));
|
||||
new Credentials(false, null, null));
|
||||
|
||||
heliumAppFactory.setNotebook(notebook);
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ public class NotebookTest extends AbstractInterpreterTest implements JobListener
|
|||
SearchService search = mock(SearchService.class);
|
||||
notebookRepo = new VFSNotebookRepo(conf);
|
||||
notebookAuthorization = NotebookAuthorization.init(conf);
|
||||
credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
|
||||
credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath(), null);
|
||||
|
||||
notebook = new Notebook(conf, notebookRepo, schedulerFactory, interpreterFactory, interpreterSettingManager, this, search,
|
||||
notebookAuthorization, credentials);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class NotebookRepoSyncTest implements JobListenerFactory {
|
|||
search = mock(SearchService.class);
|
||||
notebookRepoSync = new NotebookRepoSync(conf);
|
||||
notebookAuthorization = NotebookAuthorization.init(conf);
|
||||
credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
|
||||
credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath(), null);
|
||||
notebookSync = new Notebook(conf, notebookRepoSync, schedulerFactory, factory, interpreterSettingManager, this, search,
|
||||
notebookAuthorization, credentials);
|
||||
anonymous = new AuthenticationInfo("anonymous");
|
||||
|
|
|
|||
Loading…
Reference in a new issue