From commits-return-2927-apmail-knox-commits-archive=knox.apache.org@knox.apache.org Fri Mar 30 15:27:26 2018 Return-Path: X-Original-To: apmail-knox-commits-archive@minotaur.apache.org Delivered-To: apmail-knox-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D18E117D4E for ; Fri, 30 Mar 2018 15:27:26 +0000 (UTC) Received: (qmail 30639 invoked by uid 500); 30 Mar 2018 15:27:26 -0000 Delivered-To: apmail-knox-commits-archive@knox.apache.org Received: (qmail 30604 invoked by uid 500); 30 Mar 2018 15:27:26 -0000 Mailing-List: contact commits-help@knox.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@knox.apache.org Delivered-To: mailing list commits@knox.apache.org Received: (qmail 30589 invoked by uid 99); 30 Mar 2018 15:27:26 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 30 Mar 2018 15:27:26 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 3B0DEEB4FF; Fri, 30 Mar 2018 15:27:26 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: lmccay@apache.org To: commits@knox.apache.org Message-Id: <82f5ad88423d46459b781b91390c66aa@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: knox git commit: KNOX-1230 - Many Concurrent Requests to Knox causes URL Mangling Date: Fri, 30 Mar 2018 15:27:26 +0000 (UTC) Repository: knox Updated Branches: refs/heads/master c7f28551f -> fe84b0456 KNOX-1230 - Many Concurrent Requests to Knox causes URL Mangling Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/fe84b045 Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/fe84b045 Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/fe84b045 Branch: refs/heads/master Commit: fe84b04561f6131ddc0593fb811cd1bfba21316d Parents: c7f2855 Author: Larry McCay Authored: Fri Mar 30 11:26:57 2018 -0400 Committer: Larry McCay Committed: Fri Mar 30 11:26:57 2018 -0400 ---------------------------------------------------------------------- .../SecureQueryDecryptProcessor.java | 30 +- .../SecureQueryEncryptProcessor.java | 21 +- .../securequery/SecureQueryMessages.java | 5 + .../security/impl/DefaultCryptoService.java | 20 +- .../security/impl/DefaultKeystoreService.java | 399 +++++++++++++------ .../dispatch/AbstractGatewayDispatch.java | 4 +- .../knox/gateway/dispatch/DefaultDispatch.java | 2 +- .../gateway/dispatch/GatewayDispatchFilter.java | 56 +-- .../security/impl/CMFMasterService.java | 4 +- .../security/impl/ConfigurableEncryptor.java | 91 +---- 10 files changed, 376 insertions(+), 256 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryDecryptProcessor.java ---------------------------------------------------------------------- diff --git a/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryDecryptProcessor.java b/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryDecryptProcessor.java index 3cccc4d..77e990e 100644 --- a/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryDecryptProcessor.java +++ b/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryDecryptProcessor.java @@ -18,13 +18,14 @@ package org.apache.knox.gateway.securequery; import org.apache.commons.codec.binary.Base64; +import org.apache.knox.gateway.config.GatewayConfig; import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment; import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext; import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStepProcessor; import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStepStatus; -import org.apache.knox.gateway.services.GatewayServices; -import org.apache.knox.gateway.services.security.CryptoService; +import org.apache.knox.gateway.i18n.messages.MessagesFactory; import org.apache.knox.gateway.services.security.EncryptionResult; +import org.apache.knox.gateway.services.security.impl.ConfigurableEncryptor; import org.apache.knox.gateway.util.urltemplate.Builder; import org.apache.knox.gateway.util.urltemplate.Query; import org.apache.knox.gateway.util.urltemplate.Template; @@ -36,10 +37,10 @@ import java.util.StringTokenizer; public class SecureQueryDecryptProcessor implements UrlRewriteStepProcessor { + private static SecureQueryMessages log = MessagesFactory.get( SecureQueryMessages.class ); private static final String ENCRYPTED_PARAMETER_NAME = "_"; - private String clusterName; - private CryptoService cryptoService; + private ConfigurableEncryptor encryptor = null; @Override public String getType() { @@ -48,9 +49,8 @@ public class SecureQueryDecryptProcessor implements @Override public void initialize( UrlRewriteEnvironment environment, SecureQueryDecryptDescriptor descriptor ) throws Exception { - clusterName = environment.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE ); - GatewayServices services = environment.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); - cryptoService = (CryptoService) services.getService(GatewayServices.CRYPTO_SERVICE); + encryptor = new ConfigurableEncryptor("encryptQueryString"); + encryptor.init((GatewayConfig)environment.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)); } @Override @@ -107,13 +107,17 @@ public class SecureQueryDecryptProcessor implements String decode( String string ) throws UnsupportedEncodingException { byte[] bytes = Base64.decodeBase64( string ); EncryptionResult result = EncryptionResult.fromByteArray(bytes); - byte[] clear = cryptoService.decryptForCluster(clusterName, - "encryptQueryString", - result.cipher, - result.iv, - result.salt); + byte[] clear = null; + try { + clear = encryptor.decrypt( + result.salt, + result.iv, + result.cipher); + } catch (Exception e) { + log.unableToDecryptValue(e); + } if (clear != null) { - return new String(clear); + return new String(clear, "UTF-8"); } return null; } http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryEncryptProcessor.java ---------------------------------------------------------------------- diff --git a/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryEncryptProcessor.java b/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryEncryptProcessor.java index 5e44d20..f24b539 100644 --- a/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryEncryptProcessor.java +++ b/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryEncryptProcessor.java @@ -18,13 +18,14 @@ package org.apache.knox.gateway.securequery; import org.apache.commons.codec.binary.Base64; +import org.apache.knox.gateway.config.GatewayConfig; import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment; import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext; import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStepProcessor; import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStepStatus; -import org.apache.knox.gateway.services.GatewayServices; -import org.apache.knox.gateway.services.security.CryptoService; +import org.apache.knox.gateway.i18n.messages.MessagesFactory; import org.apache.knox.gateway.services.security.EncryptionResult; +import org.apache.knox.gateway.services.security.impl.ConfigurableEncryptor; import org.apache.knox.gateway.util.urltemplate.Parser; import org.apache.knox.gateway.util.urltemplate.Template; @@ -33,10 +34,10 @@ import java.io.UnsupportedEncodingException; public class SecureQueryEncryptProcessor implements UrlRewriteStepProcessor { + private static SecureQueryMessages log = MessagesFactory.get( SecureQueryMessages.class ); private static final String ENCRYPTED_PARAMETER_NAME = "_"; - private String clusterName; - private CryptoService cryptoService = null; + private ConfigurableEncryptor encryptor; @Override public String getType() { @@ -45,9 +46,8 @@ public class SecureQueryEncryptProcessor @Override public void initialize( UrlRewriteEnvironment environment, SecureQueryEncryptDescriptor descriptor ) throws Exception { - clusterName = environment.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE ); - GatewayServices services = environment.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); - cryptoService = (CryptoService) services.getService(GatewayServices.CRYPTO_SERVICE); + encryptor = new ConfigurableEncryptor("encryptQueryString"); + encryptor.init((GatewayConfig)environment.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)); } @Override @@ -77,7 +77,12 @@ public class SecureQueryEncryptProcessor } private String encode( String string ) throws UnsupportedEncodingException { - EncryptionResult result = cryptoService.encryptForCluster(clusterName, "encryptQueryString", string.getBytes("UTF-8")); + EncryptionResult result = null; + try { + result = encryptor.encrypt(string); + } catch (Exception e) { + log.unableToEncryptValue(e); + } string = Base64.encodeBase64URLSafeString(result.toByteAray()); return string; } http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryMessages.java ---------------------------------------------------------------------- diff --git a/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryMessages.java b/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryMessages.java index 2375011..c7990f2 100644 --- a/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryMessages.java +++ b/gateway-provider-rewrite-step-secure-query/src/main/java/org/apache/knox/gateway/securequery/SecureQueryMessages.java @@ -28,4 +28,9 @@ public interface SecureQueryMessages { @Message( level = MessageLevel.ERROR, text = "Failed to create or verify the presence of a password for query string encryption: {0}" ) void unableCreatePasswordForEncryption(@StackTrace( level = MessageLevel.DEBUG ) Exception e); + @Message( level = MessageLevel.ERROR, text = "Failed to encrypt a sensitive value due to an exception: {0}" ) + void unableToEncryptValue(@StackTrace( level = MessageLevel.ERROR ) Exception e); + + @Message( level = MessageLevel.ERROR, text = "Failed to decrypt a sensitive value due to an exception: {0}" ) + void unableToDecryptValue(@StackTrace( level = MessageLevel.ERROR ) Exception e); } http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java index f47a17b..584255e 100644 --- a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java +++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java @@ -122,13 +122,16 @@ public class DefaultCryptoService implements CryptoService { @Override public byte[] decryptForCluster(String clusterName, String alias, byte[] cipherText, byte[] iv, byte[] salt) { try { - final char[] password = as.getPasswordFromAliasForCluster(clusterName, alias); - if (password != null) { - try { - return getEncryptor(clusterName,password ).decrypt( salt, iv, cipherText); - } catch (Exception e) { - LOG.failedToDecryptPasswordForCluster( clusterName, e ); - } + char[] password = null; + ConfigurableEncryptor encryptor = null; + password = as.getPasswordFromAliasForCluster(clusterName, alias); + if (password != null) { + encryptor = getEncryptor(clusterName,password ); + try { + return encryptor.decrypt( salt, iv, cipherText); + } catch (Exception e) { + LOG.failedToDecryptPasswordForCluster( clusterName, e ); + } } else { LOG.failedToDecryptCipherForClusterNullPassword( clusterName ); @@ -167,7 +170,8 @@ public class DefaultCryptoService implements CryptoService { @Override public byte[] sign(String algorithm, String alias, String payloadToSign) { try { - char[] passphrase = as.getGatewayIdentityPassphrase(); + char[] passphrase = null; + passphrase = as.getGatewayIdentityPassphrase(); PrivateKey privateKey = (PrivateKey) ks.getKeyForGateway(alias, passphrase); Signature signature = Signature.getInstance(algorithm); signature.initSign(privateKey); http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java index 5d4bd27..f4cf523 100644 --- a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java +++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java @@ -29,6 +29,7 @@ import org.apache.knox.gateway.services.security.KeystoreServiceException; import java.io.File; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.security.GeneralSecurityException; import java.security.Key; @@ -41,7 +42,12 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.text.MessageFormat; +import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; public class DefaultKeystoreService extends BaseKeystoreService implements KeystoreService, Service { @@ -57,10 +63,17 @@ public class DefaultKeystoreService extends BaseKeystoreService implements private String signingKeystoreName = null; private String signingKeyAlias = null; + private Map> cache = new ConcurrentHashMap>(); + private Lock readLock = null; + private Lock writeLock = null; @Override public void init(GatewayConfig config, Map options) throws ServiceLifecycleException { + ReadWriteLock lock = new ReentrantReadWriteLock(true); + readLock = lock.readLock(); + writeLock = lock.writeLock(); + this.keyStoreDir = config.getGatewaySecurityDir() + File.separator + "keystores" + File.separator; File ksd = new File(this.keyStoreDir); if (!ksd.exists()) { @@ -106,20 +119,31 @@ public class DefaultKeystoreService extends BaseKeystoreService implements @Override public void createKeystoreForGateway() throws KeystoreServiceException { - String filename = getKeystorePath(); - createKeystore(filename, "JKS"); + writeLock.lock(); + try { + String filename = getKeystorePath(); + createKeystore(filename, "JKS"); + } + finally { + writeLock.unlock(); + } } @Override public KeyStore getKeystoreForGateway() throws KeystoreServiceException { final File keyStoreFile = new File( keyStoreDir + GATEWAY_KEYSTORE ); - return getKeystore(keyStoreFile, "JKS"); + readLock.lock(); + try { + return getKeystore(keyStoreFile, "JKS"); + } + finally { + readLock.unlock(); + } } @Override public KeyStore getSigningKeystore() throws KeystoreServiceException { File keyStoreFile = null; - if (signingKeystoreName == null) { keyStoreFile = new File(keyStoreDir + GATEWAY_KEYSTORE); } @@ -130,53 +154,70 @@ public class DefaultKeystoreService extends BaseKeystoreService implements throw new KeystoreServiceException("Configured signing keystore does not exist."); } } - return getKeystore(keyStoreFile, "JKS"); + readLock.lock(); + try { + return getKeystore(keyStoreFile, "JKS"); + } + finally { + readLock.unlock(); + } } @Override public void addSelfSignedCertForGateway(String alias, char[] passphrase) throws KeystoreServiceException { - addSelfSignedCertForGateway(alias, passphrase, null); + writeLock.lock(); + try { + addSelfSignedCertForGateway(alias, passphrase, null); + } + finally { + writeLock.unlock(); + } } @Override public void addSelfSignedCertForGateway(String alias, char[] passphrase, String hostname) throws KeystoreServiceException { - - KeyPairGenerator keyPairGenerator; + writeLock.lock(); try { - keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(1024); - KeyPair KPair = keyPairGenerator.generateKeyPair(); - if (hostname == null) { - hostname = System.getProperty(CERT_GEN_MODE, CERT_GEN_MODE_LOCALHOST); - } - X509Certificate cert = null; - if(hostname.equals(CERT_GEN_MODE_HOSTNAME)) { - String dn = buildDistinguishedName(InetAddress.getLocalHost().getHostName()); - cert = X509CertificateUtil.generateCertificate(dn, KPair, 365, "SHA1withRSA"); - } - else { - String dn = buildDistinguishedName(hostname); - cert = X509CertificateUtil.generateCertificate(dn, KPair, 365, "SHA1withRSA"); + KeyPairGenerator keyPairGenerator; + try { + keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(1024); + KeyPair KPair = keyPairGenerator.generateKeyPair(); + if (hostname == null) { + hostname = System.getProperty(CERT_GEN_MODE, CERT_GEN_MODE_LOCALHOST); + } + X509Certificate cert = null; + if(hostname.equals(CERT_GEN_MODE_HOSTNAME)) { + String dn = buildDistinguishedName(InetAddress.getLocalHost().getHostName()); + cert = X509CertificateUtil.generateCertificate(dn, KPair, 365, "SHA1withRSA"); + } + else { + String dn = buildDistinguishedName(hostname); + cert = X509CertificateUtil.generateCertificate(dn, KPair, 365, "SHA1withRSA"); + } + + KeyStore privateKS = getKeystoreForGateway(); + privateKS.setKeyEntry(alias, KPair.getPrivate(), + passphrase, + new java.security.cert.Certificate[]{cert}); + + writeKeystoreToFile(privateKS, new File( keyStoreDir + GATEWAY_KEYSTORE )); + //writeCertificateToFile( cert, new File( keyStoreDir + alias + ".pem" ) ); + } catch (NoSuchAlgorithmException e) { + LOG.failedToAddSeflSignedCertForGateway( alias, e ); + throw new KeystoreServiceException(e); + } catch (GeneralSecurityException e) { + LOG.failedToAddSeflSignedCertForGateway( alias, e ); + throw new KeystoreServiceException(e); + } catch (IOException e) { + LOG.failedToAddSeflSignedCertForGateway( alias, e ); + throw new KeystoreServiceException(e); } - - KeyStore privateKS = getKeystoreForGateway(); - privateKS.setKeyEntry(alias, KPair.getPrivate(), - passphrase, - new java.security.cert.Certificate[]{cert}); - - writeKeystoreToFile(privateKS, new File( keyStoreDir + GATEWAY_KEYSTORE )); - //writeCertificateToFile( cert, new File( keyStoreDir + alias + ".pem" ) ); - } catch (NoSuchAlgorithmException e) { - LOG.failedToAddSeflSignedCertForGateway( alias, e ); - throw new KeystoreServiceException(e); - } catch (GeneralSecurityException e) { - LOG.failedToAddSeflSignedCertForGateway( alias, e ); - throw new KeystoreServiceException(e); - } catch (IOException e) { - LOG.failedToAddSeflSignedCertForGateway( alias, e ); - throw new KeystoreServiceException(e); - } + } + finally { + writeLock.unlock(); + } } private String buildDistinguishedName(String hostname) { @@ -190,147 +231,255 @@ public class DefaultKeystoreService extends BaseKeystoreService implements @Override public void createCredentialStoreForCluster(String clusterName) throws KeystoreServiceException { String filename = keyStoreDir + clusterName + CREDENTIALS_SUFFIX; - createKeystore(filename, "JCEKS"); + writeLock.lock(); + try { + createKeystore(filename, "JCEKS"); + } + finally { + writeLock.unlock(); + } } @Override public boolean isCredentialStoreForClusterAvailable(String clusterName) throws KeystoreServiceException { boolean rc = false; final File keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX ); + readLock.lock(); try { - rc = isKeystoreAvailable(keyStoreFile, "JCEKS"); - } catch (KeyStoreException e) { - throw new KeystoreServiceException(e); - } catch (IOException e) { - throw new KeystoreServiceException(e); + try { + rc = isKeystoreAvailable(keyStoreFile, "JCEKS"); + } catch (KeyStoreException e) { + throw new KeystoreServiceException(e); + } catch (IOException e) { + throw new KeystoreServiceException(e); + } + return rc; + } + finally { + readLock.unlock(); } - return rc; } @Override public boolean isKeystoreForGatewayAvailable() throws KeystoreServiceException { boolean rc = false; final File keyStoreFile = new File( keyStoreDir + GATEWAY_KEYSTORE ); + readLock.lock(); try { - rc = isKeystoreAvailable(keyStoreFile, "JKS"); - } catch (KeyStoreException e) { - throw new KeystoreServiceException(e); - } catch (IOException e) { - throw new KeystoreServiceException(e); + try { + rc = isKeystoreAvailable(keyStoreFile, "JKS"); + } catch (KeyStoreException e) { + throw new KeystoreServiceException(e); + } catch (IOException e) { + throw new KeystoreServiceException(e); + } + return rc; + } + finally { + readLock.unlock(); } - return rc; } @Override public Key getKeyForGateway(String alias, char[] passphrase) throws KeystoreServiceException { Key key = null; - KeyStore ks = getKeystoreForGateway(); - if (passphrase == null) { - passphrase = masterService.getMasterSecret(); - LOG.assumingKeyPassphraseIsMaster(); - } - if (ks != null) { - try { - key = ks.getKey(alias, passphrase); - } catch (UnrecoverableKeyException e) { - LOG.failedToGetKeyForGateway( alias, e ); - } catch (KeyStoreException e) { - LOG.failedToGetKeyForGateway( alias, e ); - } catch (NoSuchAlgorithmException e) { - LOG.failedToGetKeyForGateway( alias, e ); + readLock.lock(); + try { + KeyStore ks = getKeystoreForGateway(); + if (passphrase == null) { + passphrase = masterService.getMasterSecret(); + LOG.assumingKeyPassphraseIsMaster(); + } + if (ks != null) { + try { + key = ks.getKey(alias, passphrase); + } catch (UnrecoverableKeyException e) { + LOG.failedToGetKeyForGateway( alias, e ); + } catch (KeyStoreException e) { + LOG.failedToGetKeyForGateway( alias, e ); + } catch (NoSuchAlgorithmException e) { + LOG.failedToGetKeyForGateway( alias, e ); + } } + return key; + } + finally { + readLock.unlock(); } - return key; } @Override public Key getSigningKey(String alias, char[] passphrase) throws KeystoreServiceException { Key key = null; - KeyStore ks = getSigningKeystore(); - if (passphrase == null) { - passphrase = masterService.getMasterSecret(); - LOG.assumingKeyPassphraseIsMaster(); - } - if (ks != null) { - try { - key = ks.getKey(alias, passphrase); - } catch (UnrecoverableKeyException e) { - LOG.failedToGetKeyForGateway( alias, e ); - } catch (KeyStoreException e) { - LOG.failedToGetKeyForGateway( alias, e ); - } catch (NoSuchAlgorithmException e) { - LOG.failedToGetKeyForGateway( alias, e ); + readLock.lock(); + try { + KeyStore ks = getSigningKeystore(); + if (passphrase == null) { + passphrase = masterService.getMasterSecret(); + LOG.assumingKeyPassphraseIsMaster(); } + if (ks != null) { + try { + key = ks.getKey(alias, passphrase); + } catch (UnrecoverableKeyException e) { + LOG.failedToGetKeyForGateway( alias, e ); + } catch (KeyStoreException e) { + LOG.failedToGetKeyForGateway( alias, e ); + } catch (NoSuchAlgorithmException e) { + LOG.failedToGetKeyForGateway( alias, e ); + } + } + return key; + } + finally { + readLock.unlock(); } - return key; } public KeyStore getCredentialStoreForCluster(String clusterName) throws KeystoreServiceException { final File keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX ); - return getKeystore(keyStoreFile, "JCEKS"); + readLock.lock(); + try { + return getKeystore(keyStoreFile, "JCEKS"); + } + finally { + readLock.unlock(); + } } public void addCredentialForCluster(String clusterName, String alias, String value) throws KeystoreServiceException { - KeyStore ks = getCredentialStoreForCluster(clusterName); - addCredential(alias, value, ks); - final File keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX ); + writeLock.lock(); try { - writeKeystoreToFile(ks, keyStoreFile); - } catch (KeyStoreException e) { - LOG.failedToAddCredentialForCluster( clusterName, e ); - } catch (NoSuchAlgorithmException e) { - LOG.failedToAddCredentialForCluster( clusterName, e ); - } catch (CertificateException e) { - LOG.failedToAddCredentialForCluster( clusterName, e ); - } catch (IOException e) { - LOG.failedToAddCredentialForCluster( clusterName, e ); + removeFromCache(clusterName, alias); + KeyStore ks = getCredentialStoreForCluster(clusterName); + addCredential(alias, value, ks); + final File keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX ); + try { + writeKeystoreToFile(ks, keyStoreFile); + } catch (KeyStoreException e) { + LOG.failedToAddCredentialForCluster( clusterName, e ); + } catch (NoSuchAlgorithmException e) { + LOG.failedToAddCredentialForCluster( clusterName, e ); + } catch (CertificateException e) { + LOG.failedToAddCredentialForCluster( clusterName, e ); + } catch (IOException e) { + LOG.failedToAddCredentialForCluster( clusterName, e ); + } + } finally { + writeLock.unlock(); } } - + @Override public char[] getCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException { char[] credential = null; - KeyStore ks = getCredentialStoreForCluster(clusterName); - if (ks != null) { - try { - char[] masterSecret = masterService.getMasterSecret(); - Key credentialKey = ks.getKey( alias, masterSecret ); - if (credentialKey != null) { - byte[] credentialBytes = credentialKey.getEncoded(); - String credentialString = new String( credentialBytes ); - credential = credentialString.toCharArray(); + readLock.lock(); + try { + credential = checkCache(clusterName, alias); + if (credential == null) { + KeyStore ks = getCredentialStoreForCluster(clusterName); + if (ks != null) { + try { + char[] masterSecret = masterService.getMasterSecret(); + Key credentialKey = ks.getKey( alias, masterSecret ); + if (credentialKey != null) { + byte[] credentialBytes = credentialKey.getEncoded(); + String credentialString = new String( credentialBytes, "UTF-8" ); + credential = credentialString.toCharArray(); + addToCache(clusterName, alias, credentialString); + } + } catch (UnrecoverableKeyException e) { + LOG.failedToGetCredentialForCluster( clusterName, e ); + } catch (KeyStoreException e) { + LOG.failedToGetCredentialForCluster( clusterName, e ); + } catch (NoSuchAlgorithmException e) { + LOG.failedToGetCredentialForCluster( clusterName, e ); + } catch (UnsupportedEncodingException e) { + LOG.failedToGetCredentialForCluster( clusterName, e ); + } + } - } catch (UnrecoverableKeyException e) { - LOG.failedToGetCredentialForCluster( clusterName, e ); - } catch (KeyStoreException e) { - LOG.failedToGetCredentialForCluster( clusterName, e ); - } catch (NoSuchAlgorithmException e) { - LOG.failedToGetCredentialForCluster( clusterName, e ); } + return credential; + } + finally { + readLock.unlock(); } - return credential; } - @Override public void removeCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException { - KeyStore ks = getCredentialStoreForCluster(clusterName); - removeCredential(alias, ks); final File keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX ); + writeLock.lock(); try { - writeKeystoreToFile(ks, keyStoreFile); - } catch (KeyStoreException e) { - LOG.failedToRemoveCredentialForCluster(clusterName, e); - } catch (NoSuchAlgorithmException e) { - LOG.failedToRemoveCredentialForCluster(clusterName, e); - } catch (CertificateException e) { - LOG.failedToRemoveCredentialForCluster(clusterName, e); - } catch (IOException e) { - LOG.failedToRemoveCredentialForCluster(clusterName, e); + removeFromCache(clusterName, alias); + KeyStore ks = getCredentialStoreForCluster(clusterName); + removeCredential(alias, ks); + try { + writeKeystoreToFile(ks, keyStoreFile); + } catch (KeyStoreException e) { + LOG.failedToRemoveCredentialForCluster(clusterName, e); + } catch (NoSuchAlgorithmException e) { + LOG.failedToRemoveCredentialForCluster(clusterName, e); + } catch (CertificateException e) { + LOG.failedToRemoveCredentialForCluster(clusterName, e); + } catch (IOException e) { + LOG.failedToRemoveCredentialForCluster(clusterName, e); + } } + finally { + writeLock.unlock(); + } + } + + /** + * Called only from within critical sections of other methods above. + * @param clusterName + * @param alias + * @return + */ + private char[] checkCache(String clusterName, String alias) { + char[] c = null; + String cred = null; + HashMap clusterCache = (HashMap) cache.get(clusterName); + if (clusterCache == null) { + return null; + } + cred = clusterCache.get(alias); + if (cred != null) { + c = cred.toCharArray(); + } + return c; + } + + /** + * Called only from within critical sections of other methods above. + * @param clusterName + * @param alias + * @param credentialString + */ + private void addToCache(String clusterName, String alias, String credentialString) { + HashMap clusterCache = (HashMap) cache.get(clusterName); + if (clusterCache == null) { + clusterCache = new HashMap(); + } + clusterCache.put(alias, credentialString); + } + + /** + * Called only from within critical sections of other methods above. + * @param clusterName + * @param alias + */ + private void removeFromCache(String clusterName, String alias) { + HashMap clusterCache = (HashMap) cache.get(clusterName); + if (clusterCache == null) { + return; + } + clusterCache.remove(alias); } @Override http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java index 0377142..d89a1dd 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java @@ -70,12 +70,12 @@ public abstract class AbstractGatewayDispatch implements Dispatch { } @Override - public HttpClient getHttpClient() { + synchronized public HttpClient getHttpClient() { return client; } @Override - public void setHttpClient(HttpClient client) { + synchronized public void setHttpClient(HttpClient client) { this.client = client; } http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java index c2c1b53..4f8c82f 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java @@ -127,7 +127,7 @@ public class DefaultDispatch extends AbstractGatewayDispatch { // Hadoop cluster not Kerberos enabled addCredentialsToRequest( outboundRequest ); } - inboundResponse = client.execute( outboundRequest ); + inboundResponse = getHttpClient().execute( outboundRequest ); int statusCode = inboundResponse.getStatusLine().getStatusCode(); if( statusCode != 201 ) { http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java index 8bef80d..8f3399a 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java @@ -41,6 +41,8 @@ public class GatewayDispatchFilter extends AbstractGatewayFilter { protected static final SpiGatewayMessages LOG = MessagesFactory.get(SpiGatewayMessages.class); + private final Object lock = new Object(); + private Dispatch dispatch; private HttpClient httpClient; @@ -59,41 +61,49 @@ public class GatewayDispatchFilter extends AbstractGatewayFilter { @Override public void init(FilterConfig filterConfig) throws ServletException { super.init(filterConfig); - if (dispatch == null) { - String dispatchImpl = filterConfig.getInitParameter("dispatch-impl"); - dispatch = newInstanceFromName(dispatchImpl); - } - ConfigurationInjectorBuilder.configuration().target(dispatch).source(filterConfig).inject(); - HttpClientFactory httpClientFactory; - String httpClientFactoryClass = filterConfig.getInitParameter("httpClientFactory"); - if (httpClientFactoryClass != null) { - httpClientFactory = newInstanceFromName(httpClientFactoryClass); - } else { - httpClientFactory = new DefaultHttpClientFactory(); + synchronized(lock) { + if (dispatch == null) { + String dispatchImpl = filterConfig.getInitParameter("dispatch-impl"); + dispatch = newInstanceFromName(dispatchImpl); + } + ConfigurationInjectorBuilder.configuration().target(dispatch).source(filterConfig).inject(); + HttpClientFactory httpClientFactory; + String httpClientFactoryClass = filterConfig.getInitParameter("httpClientFactory"); + if (httpClientFactoryClass != null) { + httpClientFactory = newInstanceFromName(httpClientFactoryClass); + } else { + httpClientFactory = new DefaultHttpClientFactory(); + } + httpClient = httpClientFactory.createHttpClient(filterConfig); + dispatch.setHttpClient(httpClient); + dispatch.init(); } - httpClient = httpClientFactory.createHttpClient(filterConfig); - dispatch.setHttpClient(httpClient); - dispatch.init(); } @Override public void destroy() { - dispatch.destroy(); - try { - if (httpClient instanceof CloseableHttpClient) { - ((CloseableHttpClient) httpClient).close(); + synchronized(lock) { + dispatch.destroy(); + try { + if (httpClient instanceof CloseableHttpClient) { + ((CloseableHttpClient) httpClient).close(); + } + } catch ( IOException e ) { + LOG.errorClosingHttpClient(e); } - } catch ( IOException e ) { - LOG.errorClosingHttpClient(e); } } public Dispatch getDispatch() { - return dispatch; + synchronized(lock) { + return dispatch; + } } public void setDispatch(Dispatch dispatch) { - this.dispatch = dispatch; + synchronized(lock) { + this.dispatch = dispatch; + } } @Override @@ -102,7 +112,7 @@ public class GatewayDispatchFilter extends AbstractGatewayFilter { Adapter adapter = METHOD_ADAPTERS.get(method); if ( adapter != null ) { try { - adapter.doMethod(dispatch, request, response); + adapter.doMethod(getDispatch(), request, response); } catch ( URISyntaxException e ) { throw new ServletException(e); } http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFMasterService.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFMasterService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFMasterService.java index 15919f8..b39e6ab 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFMasterService.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFMasterService.java @@ -167,7 +167,9 @@ public class CMFMasterService { LOG.loadingFromPersistentMaster( tag ); String line = new String(Base64.decodeBase64(lines.get(1))); String[] parts = line.split("::"); - this.master = new String(encryptor.decrypt(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2])), "UTF8").toCharArray(); + this.master = new String(encryptor.decrypt(Base64.decodeBase64(parts[0]), + Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2])), + "UTF8").toCharArray(); } catch (IOException e) { LOG.failedToInitializeFromPersistentMaster(masterFile.getName(), e); throw e; http://git-wip-us.apache.org/repos/asf/knox/blob/fe84b045/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/ConfigurableEncryptor.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/ConfigurableEncryptor.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/ConfigurableEncryptor.java index b576f29..ed7feac 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/ConfigurableEncryptor.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/ConfigurableEncryptor.java @@ -17,16 +17,12 @@ */ package org.apache.knox.gateway.services.security.impl; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; -import java.security.spec.InvalidParameterSpecException; import java.security.spec.KeySpec; import javax.crypto.Cipher; -import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; @@ -44,10 +40,6 @@ public class ConfigurableEncryptor { private static final int ITERATION_COUNT = 65536; private static final int KEY_LENGTH = 128; - private Cipher ecipher; - private Cipher dcipher; - private SecretKey secret; - private byte[] salt = null; private char[] passPhrase = null; private String alg = "AES"; private String pbeAlg = "PBKDF2WithHmacSHA1"; @@ -57,60 +49,12 @@ public class ConfigurableEncryptor { private int keyLength = KEY_LENGTH; public ConfigurableEncryptor(String passPhrase) { - try { - this.passPhrase = passPhrase.toCharArray(); - salt = new byte[saltSize]; - SecureRandom rnd = new SecureRandom(); - rnd.nextBytes(salt); - - SecretKey tmp = getKeyFromPassword(passPhrase); - secret = new SecretKeySpec (tmp.getEncoded(), alg); - - ecipher = Cipher.getInstance(transformation); - ecipher.init(Cipher.ENCRYPT_MODE, secret); - - dcipher = Cipher.getInstance(transformation); - byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); - dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); - } catch (NoSuchAlgorithmException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (NoSuchPaddingException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (InvalidKeyException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (InvalidParameterSpecException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (InvalidAlgorithmParameterException e) { - LOG.failedToEncryptPassphrase( e ); - } - } - - ConfigurableEncryptor(SecretKey secret) { - try { - this.secret = new SecretKeySpec (secret.getEncoded(), alg); - - ecipher = Cipher.getInstance(transformation); - ecipher.init(Cipher.ENCRYPT_MODE, secret); - - dcipher = Cipher.getInstance(transformation); - byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); - dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); - } catch (NoSuchAlgorithmException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (NoSuchPaddingException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (InvalidKeyException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (InvalidParameterSpecException e) { - LOG.failedToEncryptPassphrase( e ); - } catch (InvalidAlgorithmParameterException e) { - LOG.failedToEncryptPassphrase( e ); - } + this.passPhrase = passPhrase.toCharArray(); } public void init(GatewayConfig config) { if (config != null) { - String alg = config.getAlgorithm(); + String alg = config.getAlgorithm(); if (alg != null) { this.alg = alg; } @@ -137,10 +81,6 @@ public class ConfigurableEncryptor { } } - public SecretKey getKeyFromPassword(String passPhrase) { - return getKeyFromPassword(passPhrase, salt); - } - public SecretKey getKeyFromPassword(String passPhrase, byte[] salt) { SecretKeyFactory factory; SecretKey key = null; @@ -158,31 +98,32 @@ public class ConfigurableEncryptor { } public EncryptionResult encrypt(String encrypt) throws Exception { - byte[] bytes = encrypt.getBytes("UTF8"); + byte[] bytes = encrypt.getBytes("UTF-8"); EncryptionResult atom = encrypt(bytes); return atom; } public EncryptionResult encrypt(byte[] plain) throws Exception { - EncryptionResult atom = new EncryptionResult(salt, ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(), ecipher.doFinal(plain)); - return atom; - } + byte[] salt = new byte[saltSize]; + SecureRandom rnd = new SecureRandom(); + rnd.nextBytes(salt); - public String decrypt(String salt, String iv, String cipher) throws Exception { - byte[] decrypted = decrypt(salt.getBytes("UTF8"), iv.getBytes("UTF8"), cipher.getBytes("UTF8")); - return new String(decrypted, "UTF8"); + SecretKey tmp = getKeyFromPassword(new String(passPhrase), salt); + SecretKey secret = new SecretKeySpec(tmp.getEncoded(), alg); + Cipher ecipher = Cipher.getInstance(transformation); + ecipher.init(Cipher.ENCRYPT_MODE, secret); + EncryptionResult atom = new EncryptionResult(salt, + ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(), + ecipher.doFinal(plain)); + return atom; } public byte[] decrypt(byte[] salt, byte[] iv, byte[] encrypt) throws Exception { SecretKey tmp = getKeyFromPassword(new String(passPhrase), salt); - secret = new SecretKeySpec(tmp.getEncoded(), alg); + SecretKey secret = new SecretKeySpec(tmp.getEncoded(), alg); + Cipher dcipher = Cipher.getInstance(transformation); dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); return dcipher.doFinal(encrypt); } - - public byte[] decrypt(byte[] encrypt) throws Exception { - dcipher.init(Cipher.DECRYPT_MODE, secret); - return dcipher.doFinal(encrypt); - } }