You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by pa...@apache.org on 2016/09/18 22:36:48 UTC
zest-java git commit: ZEST-176 Add authentication support to Riak
EntityStore
Repository: zest-java
Updated Branches:
refs/heads/develop 57412977d -> 39b0b6344
ZEST-176 Add authentication support to Riak EntityStore
Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/39b0b634
Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/39b0b634
Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/39b0b634
Branch: refs/heads/develop
Commit: 39b0b6344f18be1463cf824138b5b0a703780962
Parents: 5741297
Author: Paul Merlin <pa...@apache.org>
Authored: Sun Sep 18 15:36:29 2016 -0700
Committer: Paul Merlin <pa...@apache.org>
Committed: Sun Sep 18 15:36:29 2016 -0700
----------------------------------------------------------------------
extensions/entitystore-riak/build.gradle | 1 +
.../entitystore-riak/src/docs/es-riak.txt | 6 +
.../riak/RiakEntityStoreConfiguration.java | 75 ++++++++++++
.../riak/RiakMapEntityStoreMixin.java | 119 ++++++++++++++++---
4 files changed, 182 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/zest-java/blob/39b0b634/extensions/entitystore-riak/build.gradle
----------------------------------------------------------------------
diff --git a/extensions/entitystore-riak/build.gradle b/extensions/entitystore-riak/build.gradle
index 7a4c14c..54304f0 100644
--- a/extensions/entitystore-riak/build.gradle
+++ b/extensions/entitystore-riak/build.gradle
@@ -26,6 +26,7 @@ dependencies {
compile( project( ":org.apache.zest.core:org.apache.zest.core.bootstrap" ) )
compile( project( ":org.apache.zest.libraries:org.apache.zest.library.locking" ) )
+ compile( project( ":org.apache.zest.libraries:org.apache.zest.library.constraints" ) )
compile libraries.slf4j_api
compile( libraries.riak )
http://git-wip-us.apache.org/repos/asf/zest-java/blob/39b0b634/extensions/entitystore-riak/src/docs/es-riak.txt
----------------------------------------------------------------------
diff --git a/extensions/entitystore-riak/src/docs/es-riak.txt b/extensions/entitystore-riak/src/docs/es-riak.txt
index cc067b5..b2a2c69 100644
--- a/extensions/entitystore-riak/src/docs/es-riak.txt
+++ b/extensions/entitystore-riak/src/docs/es-riak.txt
@@ -52,3 +52,9 @@ Here are the available configuration properties:
source=extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakEntityStoreConfiguration.java
tag=config
----
+
+All authentication related properties are optional.
+By default no authentication is used.
+As soon as you provide a `username`, authentication is set up.
+Please note that you should then at least provide `truststoreType`, `truststorePath` and `truststorePassword`.
+To use client certificate authentication, set `keystoreType`, `keystorePath`, `keystorePassword` and `keyPassword`.
http://git-wip-us.apache.org/repos/asf/zest-java/blob/39b0b634/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakEntityStoreConfiguration.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakEntityStoreConfiguration.java b/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakEntityStoreConfiguration.java
index febd329..ee797f7 100644
--- a/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakEntityStoreConfiguration.java
+++ b/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakEntityStoreConfiguration.java
@@ -21,6 +21,7 @@ import org.apache.zest.api.common.Optional;
import org.apache.zest.api.common.UseDefaults;
import org.apache.zest.api.configuration.ConfigurationComposite;
import org.apache.zest.api.property.Property;
+import org.apache.zest.library.constraints.annotation.OneOf;
import java.util.List;
@@ -44,6 +45,80 @@ public interface RiakEntityStoreConfiguration extends ConfigurationComposite
Property<List<String>> hosts();
/**
+ * User name to use for authentication.
+ *
+ * @return Authentication user name
+ */
+ @Optional
+ Property<String> username();
+
+ /**
+ * Password to use for authentication.
+ *
+ * @return Authentication password
+ */
+ @Optional
+ Property<String> password();
+
+ /**
+ * Type of the keystore used for server certificate authentication.
+ *
+ * @return Type of the keystore used for server certificate authentication
+ */
+ @Optional
+ @OneOf( { "PKCS12", "JCEKS", "JKS" } )
+ Property<String> truststoreType();
+
+ /**
+ * Path of the keystore used for server certificate authentication.
+ *
+ * @return Path of the keystore used for server certificate authentication
+ */
+ @Optional
+ Property<String> truststorePath();
+
+ /**
+ * Password of the keystore used for server certificate authentication.
+ *
+ * @return Password of the keystore used for server certificate authentication
+ */
+ @Optional
+ Property<String> truststorePassword();
+
+ /**
+ * Type of the keystore used for client certificate authentication.
+ *
+ * @return Type of the keystore used for client certificate authentication
+ */
+ @Optional
+ @OneOf( { "PKCS12", "JCEKS", "JKS" } )
+ Property<String> keystoreType();
+
+ /**
+ * Path of the keystore used for client certificate authentication.
+ *
+ * @return Path of the keystore used for client certificate authentication
+ */
+ @Optional
+ Property<String> keystorePath();
+
+ /**
+ * Password of the keystore used for client certificate authentication.
+ *
+ * @return Password of the keystore used for client certificate authentication
+ */
+ @Optional
+ Property<String> keystorePassword();
+
+ /**
+ * Password of the key used for client certificate authentication.
+ *
+ * @return Password of the key used for client certificate authentication
+ */
+ @Optional
+ Property<String> keyPassword();
+
+ /**
* Riak Bucket where Entities state will be stored.
*
* Defaulted to "zest:entities".
http://git-wip-us.apache.org/repos/asf/zest-java/blob/39b0b634/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakMapEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakMapEntityStoreMixin.java b/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakMapEntityStoreMixin.java
index 5b14890..4402c0e 100644
--- a/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakMapEntityStoreMixin.java
+++ b/extensions/entitystore-riak/src/main/java/org/apache/zest/entitystore/riak/RiakMapEntityStoreMixin.java
@@ -28,6 +28,7 @@ import com.basho.riak.client.core.RiakNode;
import com.basho.riak.client.core.query.Location;
import com.basho.riak.client.core.query.Namespace;
import com.basho.riak.client.core.util.HostAndPort;
+import org.apache.zest.api.common.InvalidApplicationException;
import org.apache.zest.api.configuration.Configuration;
import org.apache.zest.api.entity.EntityDescriptor;
import org.apache.zest.api.entity.EntityReference;
@@ -41,7 +42,18 @@ import org.apache.zest.spi.entitystore.EntityNotFoundException;
import org.apache.zest.spi.entitystore.EntityStoreException;
import org.apache.zest.spi.entitystore.helpers.MapEntityStore;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.Provider;
+import java.security.Security;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -67,16 +79,37 @@ public class RiakMapEntityStoreMixin implements ServiceActivation, MapEntityStor
RiakEntityStoreConfiguration config = configuration.get();
String bucketName = config.bucket().get();
List<String> hosts = config.hosts().get();
- Integer clusterExecutionAttempts = config.clusterExecutionAttempts().get();
+
+ // Setup Riak Cluster Client
+ List<HostAndPort> hostsAndPorts = parseHosts( hosts );
+ RiakNode.Builder nodeBuilder = new RiakNode.Builder();
+ nodeBuilder = configureNodes( config, nodeBuilder );
+ nodeBuilder = configureAuthentication( config, nodeBuilder );
+ List<RiakNode> nodes = new ArrayList<>();
+ for( HostAndPort host : hostsAndPorts )
+ {
+ nodes.add( nodeBuilder.withRemoteAddress( host ).build() );
+ }
+ RiakCluster.Builder clusterBuilder = RiakCluster.builder( nodes );
+ clusterBuilder = configureCluster(config, clusterBuilder);
+
+ // Start Riak Cluster
+ RiakCluster cluster = clusterBuilder.build();
+ cluster.start();
+ namespace = new Namespace( bucketName );
+ riakClient = new RiakClient( cluster );
+
+ // Initialize Bucket
+ riakClient.execute( new StoreBucketProperties.Builder( namespace ).build() );
+ }
+
+ private RiakNode.Builder configureNodes( RiakEntityStoreConfiguration config, RiakNode.Builder nodeBuilder )
+ {
Integer minConnections = config.minConnections().get();
Integer maxConnections = config.maxConnections().get();
Boolean blockOnMaxConnections = config.blockOnMaxConnections().get();
Integer connectionTimeout = config.connectionTimeout().get();
Integer idleTimeout = config.idleTimeout().get();
-
- // Setup Riak Cluster Client
- List<HostAndPort> hostsAndPorts = parseHosts( hosts );
- RiakNode.Builder nodeBuilder = new RiakNode.Builder();
if( minConnections != null )
{
nodeBuilder = nodeBuilder.withMinConnections( minConnections );
@@ -94,25 +127,73 @@ public class RiakMapEntityStoreMixin implements ServiceActivation, MapEntityStor
{
nodeBuilder = nodeBuilder.withIdleTimeout( idleTimeout );
}
- List<RiakNode> nodes = new ArrayList<>();
- for( HostAndPort host : hostsAndPorts )
+ return nodeBuilder;
+ }
+
+ private RiakNode.Builder configureAuthentication( RiakEntityStoreConfiguration config, RiakNode.Builder nodeBuilder )
+ throws IOException, GeneralSecurityException
+ {
+ String username = config.username().get();
+ String password = config.password().get();
+ String truststoreType = config.truststoreType().get();
+ String truststorePath = config.truststorePath().get();
+ String truststorePassword = config.truststorePassword().get();
+ String keystoreType = config.keystoreType().get();
+ String keystorePath = config.keystorePath().get();
+ String keystorePassword = config.keystorePassword().get();
+ String keyPassword = config.keyPassword().get();
+ if( username != null )
{
- nodes.add( nodeBuilder.withRemoteAddress( host ).build() );
+ // Eventually load BouncyCastle to support PKCS12
+ if( "PKCS12".equals( keystoreType ) || "PKCS12".equals( truststoreType ) )
+ {
+ Provider bc = Security.getProvider( "BC" );
+ if( bc == null )
+ {
+ try
+ {
+ Class<?> bcType = Class.forName( "org.bouncycastle.jce.provider.BouncyCastleProvider" );
+ Security.addProvider( (Provider) bcType.newInstance() );
+ }
+ catch( Exception ex )
+ {
+ throw new InvalidApplicationException( "Need to open a PKCS#12 but was unable to register BouncyCastle, check your classpath", ex );
+ }
+ }
+ }
+ KeyStore truststore = loadStore( truststoreType, truststorePath, truststorePassword );
+ if( keystorePath != null )
+ {
+ KeyStore keyStore = loadStore( keystoreType, keystorePath, keystorePassword );
+ nodeBuilder = nodeBuilder.withAuth( username, password, truststore, keyStore, keyPassword );
+ }
+ else
+ {
+ nodeBuilder = nodeBuilder.withAuth( username, password, truststore );
+ }
}
- RiakCluster.Builder clusterBuilder = RiakCluster.builder( nodes );
+ return nodeBuilder;
+ }
+
+ private KeyStore loadStore( String type, String path, String password )
+ throws IOException, GeneralSecurityException
+ {
+ try( InputStream keystoreInput = new FileInputStream( new File( path ) ) )
+ {
+ KeyStore keyStore = KeyStore.getInstance( type );
+ keyStore.load( keystoreInput, password.toCharArray() );
+ return keyStore;
+ }
+ }
+
+ private RiakCluster.Builder configureCluster( RiakEntityStoreConfiguration config, RiakCluster.Builder clusterBuilder )
+ {
+ Integer clusterExecutionAttempts = config.clusterExecutionAttempts().get();
if( clusterExecutionAttempts != null )
{
clusterBuilder = clusterBuilder.withExecutionAttempts( clusterExecutionAttempts );
}
-
- // Start Riak Cluster
- RiakCluster cluster = clusterBuilder.build();
- cluster.start();
- namespace = new Namespace( bucketName );
- riakClient = new RiakClient( cluster );
-
- // Initialize Bucket
- riakClient.execute( new StoreBucketProperties.Builder( namespace ).build() );
+ return clusterBuilder;
}
@Override