diff --git a/README.adoc b/README.adoc
index c11631b..9dbdb7a 100644
--- a/README.adoc
+++ b/README.adoc
@@ -24,8 +24,8 @@ There are four implementation modules:
* cassandra-2.2 - builds against version 2.2.19
* cassandra-3.0 - builds against version 3.0.23
-* cassandra-3.11 - builds against version 3.11.9
-* cassandra-4.0 - builds against version 4.0-beta3
+* cassandra-3.11 - builds against version 3.11.10
+* cassandra-4.0 - builds against version 4.0-beta4
Project is built as:
@@ -89,6 +89,21 @@ The content of the configuration file is as follows:
|load_ldap_service
|defaults to false, if it is true, SPI mechanism will look on class path to load custom implementation of `LDAPUserRetriever`.
+
+|eligibility_class_name
+|defaults to `NoOpLoginEligibilityCheck`
+
+|eligibility_cassandra_keyspace
+|defaults to `login_eligibility`
+
+|eligibility_cassandra_table
+|defaults to `login_eligibility`
+
+|eligibility_cassandra_user_column
+|defaults to `user`
+
+|eligibility_cassandra_access_column
+|defaults to `has_access`
|===
@@ -158,6 +173,70 @@ may have a different search filter based on your need, a lot of people use e.g.
If you try to log in with `cqlsh -u cn=myuserinldap`, there will be no replacement done and this will be
used as a search filter instead.
+## Login eligibility checks
+
+There is an additional mechanims implemented for login eligibility resoultion after user is authenticated
+in LDAP. If user is authenticated against LDAP and he is not able to log in (e.g. submitted password is wrong),
+this check is bypassed. However, even if a user in LDAP is able to log in, Cassandra database administrators
+can use additional checks to decide if a user who passed LDAP authentication procedure is indeed able to log in or not.
+
+The login eligibility check implementation is driven by the configuration property `eligibility_class_name` which
+defaults to the no-op implementation which means that login to LDAP will make such user eligible to log in to Cassandra
+without any further restrictions / checks.
+
+There is a default Cassandra implementation provided which might be used by setting `eligibility_class_name` to
+`com.instaclustr.cassandra.ldap.auth.Cassandra311LoginEligibilityCheck` for C* 3.11. If you are running Cassandra 4.0, please
+set this property to `com.instaclustr.cassandra.ldap.auth.Cassandra40LoginEligibilityCheck`.
+IF you use 3.0 or 2.2, use `CassandraLoginEligibilityCheck`.
+
+Before using this feature (when you are using Cassandra check), respective keyspace
+and table need to be created which will capture eligibility data. The default script
+is located in `conf/eligibility_check.cql`. Please keep in mind that you might
+alter this keyspace to e.g. reflect your replication strategy requirements - this duty is
+left to Cassandra operator.
+
+Operator is responsible for the population of this table, plugin just reads from this table
+and it expects that such record is found. For example, let's say that operator inserted this record:
+
+----
+cqlsh> INSERT INTO login_eligibility.login_eligibility (user , has_access ) VALUES ( 'cn=stefan,dc=example,dc=org', true) USING TTL 60;
+cqlsh> select user, has_access, ttl(has_access) from login_eligibility.login_eligibility where user = 'stefan';
+
+ user | has_access | ttl(has_access)
+-----------------------------+------------+-----------------
+ cn=stefan,dc=example,dc=org | True | 55
+
+(1 rows)
+----
+
+The default Cassandra check implementation will do this check upon login:
+
+----
+clqsh> select user, has_access from login_eligibility.login_eligibility where user = 'cn=stefan,dc=example,dc=org';
+----
+
+Then the plugin looks into `has_access` and it has to be `true`.
+
+TTL is optional, here it is used with advantage that a user is eligible to be logged in
+just for 1 minute. There might be e.g. some company policy to enable a user to log in
+during 2 days, for example, which would mimic this policy. After 2 days, such record
+is not present in database anymore which renders a user to be unable to log in.
+
+If you want to use custom eligibility check implementation, you need to firstly implement the interface
+`com.instaclustr.cassandra.ldap.auth.LoginEligibilityCheck`, then you need to
+create a JAR with this class and put it on Cassandra's class path. In your JAR,
+you need to specify your implemenatation in `src/main/resources/META-INF/services` where you need
+to put a file with name of FQCN of interface and its content will be FQCN of your implementation which
+implements this interface.
+
+If you do not want to use SPI mechanism mentioned above, you still have to put your
+implementation on the class path but you have to specify your implementation
+in `eligibility_class_name` configuration property.
+
+If you want to use different configuration properties for your custom implementation, you have them
+available in interfaces' method `init` where they are passed from plugin internals upon
+its setup.
+
## How it Works
LDAPAuthenticator currently supports plain text authorization requests only in the form of a username and password.
diff --git a/base/pom.xml b/base/pom.xml
index bd9ee79..e98e53c 100644
--- a/base/pom.xml
+++ b/base/pom.xml
@@ -16,7 +16,7 @@
-->
cassandra-ldap-base
- 1.1.1
+ 1.2.0
Cassandra LDAP Authenticator common code
Common code for Apache Cassandra LDAP plugin
diff --git a/base/src/main/java/com/instaclustr/cassandra/ldap/auth/BaseCassandraLoginEligibilityCheck.java b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/BaseCassandraLoginEligibilityCheck.java
new file mode 100644
index 0000000..7ad5bf5
--- /dev/null
+++ b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/BaseCassandraLoginEligibilityCheck.java
@@ -0,0 +1,85 @@
+package com.instaclustr.cassandra.ldap.auth;
+
+import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN;
+import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE;
+import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_TABLE;
+import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN;
+
+import java.util.Properties;
+
+import com.instaclustr.cassandra.ldap.User;
+import com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration;
+import org.apache.cassandra.serializers.BooleanSerializer;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class BaseCassandraLoginEligibilityCheck implements LoginEligibilityCheck
+{
+ private static final Logger logger = LoggerFactory.getLogger(BaseCassandraLoginEligibilityCheck.class);
+
+ private static final String BASE_SELECT_USER_STATEMENT_TEMPLATE = "select %s from %s.%s where %s = ?";
+
+ protected ClientState clientState;
+ protected Properties configProperties;
+ protected String selectStatement;
+
+ @Override
+ public void init(final ClientState clientState, final Properties configProperties)
+ {
+ this.clientState = clientState;
+ this.configProperties = configProperties;
+
+ this.selectStatement = String.format(BASE_SELECT_USER_STATEMENT_TEMPLATE,
+ configProperties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN),
+ configProperties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE),
+ configProperties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_TABLE),
+ configProperties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN));
+
+ }
+
+ protected abstract ResultMessage.Rows getRows(final String loginName);
+
+ @Override
+ public boolean isEligibleToLogin(final User user, final String loginName)
+ {
+
+ // all non-ldap users are free to log in just fine
+ if (user.getLdapDN() == null)
+ {
+ return true;
+ }
+
+ assert clientState != null;
+
+ final ResultMessage.Rows rows = getRows(loginName);
+
+ final boolean noResults = rows.result.isEmpty();
+
+ if (noResults)
+ {
+ logger.debug(String.format("User with login name '%s' is not eligible to be logged in!", loginName));
+ return false;
+ }
+
+ if (rows.result.size() != 1)
+ {
+ throw new IllegalStateException("There was more than one record returned from eligibility check select query!");
+ }
+
+ if (rows.result.rows.get(0).size() != 1)
+ {
+ throw new IllegalStateException("There was more than one column returned from eligibility check select query!");
+ }
+
+ if (BooleanSerializer.instance.deserialize(rows.result.rows.get(0).get(0)))
+ {
+ logger.debug(String.format("User with login name '%s' is eligible to be logged in!", loginName));
+ return true;
+ }
+
+ logger.debug(String.format("User with login name '%s' is not eligible to be logged in!", loginName));
+ return false;
+ }
+}
diff --git a/base/src/main/java/com/instaclustr/cassandra/ldap/auth/CassandraLoginEligibilityCheck.java b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/CassandraLoginEligibilityCheck.java
new file mode 100644
index 0000000..f4b5bdf
--- /dev/null
+++ b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/CassandraLoginEligibilityCheck.java
@@ -0,0 +1,20 @@
+package com.instaclustr.cassandra.ldap.auth;
+
+import static java.util.Collections.singletonList;
+
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.SelectStatement;
+import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.messages.ResultMessage.Rows;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class CassandraLoginEligibilityCheck extends BaseCassandraLoginEligibilityCheck
+{
+ @Override
+ protected Rows getRows(final String loginName)
+ {
+ final SelectStatement selStmt = (SelectStatement) QueryProcessor.getStatement(selectStatement, clientState).statement;
+ return selStmt.execute(new QueryState(clientState), QueryOptions.forInternalCalls(singletonList(ByteBufferUtil.bytes(loginName))));
+ }
+}
diff --git a/base/src/main/java/com/instaclustr/cassandra/ldap/auth/LoginEligibilityCheck.java b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/LoginEligibilityCheck.java
new file mode 100644
index 0000000..4823357
--- /dev/null
+++ b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/LoginEligibilityCheck.java
@@ -0,0 +1,15 @@
+package com.instaclustr.cassandra.ldap.auth;
+
+import java.util.Properties;
+
+import com.instaclustr.cassandra.ldap.User;
+import org.apache.cassandra.service.ClientState;
+
+public interface LoginEligibilityCheck
+{
+
+ void init(final ClientState clientState, final Properties configProperties);
+
+ boolean isEligibleToLogin(final User user, final String loginName);
+
+}
diff --git a/base/src/main/java/com/instaclustr/cassandra/ldap/auth/NoOpLoginEligibilityCheck.java b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/NoOpLoginEligibilityCheck.java
new file mode 100644
index 0000000..04e218d
--- /dev/null
+++ b/base/src/main/java/com/instaclustr/cassandra/ldap/auth/NoOpLoginEligibilityCheck.java
@@ -0,0 +1,22 @@
+package com.instaclustr.cassandra.ldap.auth;
+
+import java.util.Properties;
+
+import com.instaclustr.cassandra.ldap.User;
+import org.apache.cassandra.service.ClientState;
+
+public final class NoOpLoginEligibilityCheck implements LoginEligibilityCheck
+{
+
+ @Override
+ public void init(final ClientState clientState, final Properties properties)
+ {
+
+ }
+
+ @Override
+ public boolean isEligibleToLogin(final User user, final String loginName)
+ {
+ return true;
+ }
+}
diff --git a/base/src/main/java/com/instaclustr/cassandra/ldap/conf/LdapAuthenticatorConfiguration.java b/base/src/main/java/com/instaclustr/cassandra/ldap/conf/LdapAuthenticatorConfiguration.java
index db591f1..34a9774 100644
--- a/base/src/main/java/com/instaclustr/cassandra/ldap/conf/LdapAuthenticatorConfiguration.java
+++ b/base/src/main/java/com/instaclustr/cassandra/ldap/conf/LdapAuthenticatorConfiguration.java
@@ -26,6 +26,7 @@
import java.io.IOException;
import java.util.Properties;
+import com.instaclustr.cassandra.ldap.auth.NoOpLoginEligibilityCheck;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,6 +61,19 @@ public final class LdapAuthenticatorConfiguration
public static final String CASSANDRA_LDAP_ADMIN_USER = "cassandra.ldap.admin.user";
+ public static final String ELIGIBILITY_CHECK_CLASS_NAME = "eligibility_class_name";
+ public static final String DEFAULT_ELIGIBILITY_CHECK_CLASS_NAME = NoOpLoginEligibilityCheck.class.getCanonicalName();
+
+ public static final String CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE = "eligibility_cassandra_keyspace";
+ public static final String CASSANDRA_ELIGIBILITY_CHECK_TABLE = "eligibility_cassandra_table";
+ public static final String CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN = "eligibility_cassandra_user_column";
+ public static final String CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN = "eligibility_cassandra_access_column";
+
+ public static final String DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE = "login_eligibility";
+ public static final String DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_TABLE = "login_eligibility";
+ public static final String DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN = "user";
+ public static final String DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN = "has_access";
+
public static final String CONSISTENCY_FOR_ROLE = "consistency_for_role";
public static final String DEFAULT_CONSISTENCY_FOR_ROLE = "LOCAL_ONE";
@@ -139,10 +153,22 @@ public Properties parseProperties() throws ConfigurationException
properties.setProperty(FILTER_TEMPLATE, filterTemplate);
+ properties.setProperty(LdapAuthenticatorConfiguration.CONTEXT_FACTORY_PROP, properties.getProperty(CONTEXT_FACTORY_PROP, DEFAULT_CONTEXT_FACTORY));
+ properties.setProperty(LdapAuthenticatorConfiguration.LDAP_URI_PROP, properties.getProperty(LDAP_URI_PROP));
+
+ properties.setProperty(LdapAuthenticatorConfiguration.ELIGIBILITY_CHECK_CLASS_NAME, properties.getProperty(ELIGIBILITY_CHECK_CLASS_NAME, DEFAULT_ELIGIBILITY_CHECK_CLASS_NAME));
+
+ properties.setProperty(LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE,
+ properties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE, DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_KEYSPACE));
+
+ properties.setProperty(LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_TABLE,
+ properties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_TABLE, DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_TABLE));
+ properties.setProperty(LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN,
+ properties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN, DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_USER_COLUMN));
- properties.put(LdapAuthenticatorConfiguration.CONTEXT_FACTORY_PROP, properties.getProperty(CONTEXT_FACTORY_PROP, DEFAULT_CONTEXT_FACTORY));
- properties.put(LdapAuthenticatorConfiguration.LDAP_URI_PROP, properties.getProperty(LDAP_URI_PROP));
+ properties.setProperty(LdapAuthenticatorConfiguration.CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN,
+ properties.getProperty(CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN, DEFAULT_CASSANDRA_ELIGIBILITY_CHECK_ACCESS_COLUMN));
return properties;
}
diff --git a/base/src/main/java/com/instaclustr/cassandra/ldap/utils/ServiceUtils.java b/base/src/main/java/com/instaclustr/cassandra/ldap/utils/ServiceUtils.java
index b2dbb37..eb07522 100644
--- a/base/src/main/java/com/instaclustr/cassandra/ldap/utils/ServiceUtils.java
+++ b/base/src/main/java/com/instaclustr/cassandra/ldap/utils/ServiceUtils.java
@@ -34,6 +34,20 @@ public class ServiceUtils
private static final Logger logger = LoggerFactory.getLogger(ServiceUtils.class);
+ public static T getServiceFromConfig(final Class clazz,
+ final String classNameFromConfig)
+ {
+ Class> defaultImplClazz;
+
+ try {
+ defaultImplClazz = Class.forName(classNameFromConfig);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalStateException(format("Could not find class %s", classNameFromConfig));
+ }
+
+ return getService(clazz, (Class) defaultImplClazz);
+ }
+
public static T getService(final Class clazz, final Class extends T> defaultImplClazz)
{
final ServiceLoader loader = ServiceLoader.load(clazz);
diff --git a/base/src/main/java/org/apache/cassandra/auth/LDAPAuthenticator.java b/base/src/main/java/org/apache/cassandra/auth/LDAPAuthenticator.java
index 56355c5..aa429a4 100644
--- a/base/src/main/java/org/apache/cassandra/auth/LDAPAuthenticator.java
+++ b/base/src/main/java/org/apache/cassandra/auth/LDAPAuthenticator.java
@@ -19,7 +19,9 @@
import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.CASSANDRA_AUTH_CACHE_ENABLED_PROP;
import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.CASSANDRA_LDAP_ADMIN_USER;
+import static com.instaclustr.cassandra.ldap.conf.LdapAuthenticatorConfiguration.ELIGIBILITY_CHECK_CLASS_NAME;
import static com.instaclustr.cassandra.ldap.utils.ServiceUtils.getService;
+import static com.instaclustr.cassandra.ldap.utils.ServiceUtils.getServiceFromConfig;
import static java.lang.Boolean.parseBoolean;
import static java.lang.String.format;
@@ -29,6 +31,7 @@
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.common.util.concurrent.Uninterruptibles;
import com.instaclustr.cassandra.ldap.AbstractLDAPAuthenticator;
+import com.instaclustr.cassandra.ldap.auth.LoginEligibilityCheck;
import com.instaclustr.cassandra.ldap.PlainTextSaslAuthenticator;
import com.instaclustr.cassandra.ldap.User;
import com.instaclustr.cassandra.ldap.auth.CassandraUserRetriever;
@@ -64,6 +67,7 @@ public class LDAPAuthenticator extends AbstractLDAPAuthenticator
private static final Logger logger = LoggerFactory.getLogger(AbstractLDAPAuthenticator.class);
protected CacheDelegate cacheDelegate;
+ protected LoginEligibilityCheck loginEligibilityCheck;
public void setup()
{
@@ -85,6 +89,9 @@ public void setup()
cacheDelegate = getService(CacheDelegate.class, null);
+ loginEligibilityCheck = getServiceFromConfig(LoginEligibilityCheck.class, properties.getProperty(ELIGIBILITY_CHECK_CLASS_NAME));
+ loginEligibilityCheck.init(clientState, properties);
+
final String adminRole = System.getProperty(CASSANDRA_LDAP_ADMIN_USER, "cassandra");
while (true)
@@ -166,9 +173,16 @@ public AuthenticatedUser authenticate(String username, String password) throws A
final String loginName = cachedUser.getLdapDN() == null ? cachedUser.getUsername() : cachedUser.getLdapDN();
- logger.debug("Going to log in with {}", loginName);
-
- return new AuthenticatedUser(loginName);
+ if (loginEligibilityCheck.isEligibleToLogin(cachedUser, loginName))
+ {
+ logger.debug("Going to log in with {}", loginName);
+ return new AuthenticatedUser(loginName);
+ }
+ else
+ {
+ throw new AuthenticationException(String.format("User %s is authenticated against LDAP fine but it is not able "
+ + "to log in based on an eligibility check.", loginName));
+ }
}
} catch (final UncheckedExecutionException ex)
{
diff --git a/cassandra-2.2/pom.xml b/cassandra-2.2/pom.xml
index 4070851..fe4ba36 100644
--- a/cassandra-2.2/pom.xml
+++ b/cassandra-2.2/pom.xml
@@ -11,7 +11,7 @@
cassandra-ldap-2.2
- 1.1.1
+ 1.2.0
Cassandra LDAP Authenticator for Cassandra 2.2
Pluggable LDAP authentication implementation for Apache Cassandra 2.2
@@ -50,7 +50,7 @@
com.instaclustr
cassandra-ldap-base
- 1.1.1
+ 1.2.0
org.apache.cassandra
@@ -93,7 +93,7 @@
cassandra-ldap-base
tests
test-jar
- 1.1.1
+ 1.2.0
test
diff --git a/cassandra-2.2/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra22LDAPIntegrationTest.java b/cassandra-2.2/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra22LDAPIntegrationTest.java
index 59736e0..3a40248 100644
--- a/cassandra-2.2/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra22LDAPIntegrationTest.java
+++ b/cassandra-2.2/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra22LDAPIntegrationTest.java
@@ -41,7 +41,7 @@ public List createPluginJars() throws IOException
{
File[] singleFile = Maven.resolver()
.loadPomFromFile("pom.xml")
- .resolve("com.instaclustr:cassandra-ldap-2.2:1.1.1")
+ .resolve("com.instaclustr:cassandra-ldap-2.2:1.2.0")
.withTransitivity()
.asFile();
diff --git a/cassandra-3.0/pom.xml b/cassandra-3.0/pom.xml
index 0df5675..87bc7b7 100644
--- a/cassandra-3.0/pom.xml
+++ b/cassandra-3.0/pom.xml
@@ -11,7 +11,7 @@
cassandra-ldap-3.0
- 1.1.1
+ 1.2.0
Cassandra LDAP Authenticator for Cassandra 3.0
Pluggable LDAP authentication implementation for Apache Cassandra 3.0
@@ -50,7 +50,7 @@
com.instaclustr
cassandra-ldap-base
- 1.1.1
+ 1.2.0
org.apache.cassandra
@@ -81,7 +81,7 @@
cassandra-ldap-base
tests
test-jar
- 1.1.1
+ 1.2.0
test
diff --git a/cassandra-3.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra30LDAPIntegrationTest.java b/cassandra-3.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra30LDAPIntegrationTest.java
index 9529344..c4ac7ac 100644
--- a/cassandra-3.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra30LDAPIntegrationTest.java
+++ b/cassandra-3.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra30LDAPIntegrationTest.java
@@ -38,7 +38,7 @@ public List createPluginJars() throws IOException
{
File[] singleFile = Maven.resolver()
.loadPomFromFile("pom.xml")
- .resolve("com.instaclustr:cassandra-ldap-3.0:1.1.1")
+ .resolve("com.instaclustr:cassandra-ldap-3.0:1.2.0")
.withTransitivity()
.asFile();
diff --git a/cassandra-3.11/pom.xml b/cassandra-3.11/pom.xml
index 715a63d..0c85982 100644
--- a/cassandra-3.11/pom.xml
+++ b/cassandra-3.11/pom.xml
@@ -11,7 +11,7 @@
cassandra-ldap-3.11
- 1.1.1
+ 1.2.0
Cassandra LDAP Authenticator for Cassandra 3.11
Pluggable LDAP authentication implementation for Apache Cassandra 3.11
@@ -51,7 +51,7 @@
com.instaclustr
cassandra-ldap-base
- 1.1.1
+ 1.2.0
org.apache.cassandra
@@ -116,7 +116,7 @@
cassandra-ldap-base
tests
test-jar
- 1.1.1
+ 1.2.0
test
diff --git a/cassandra-3.11/src/main/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LoginEligibilityCheck.java b/cassandra-3.11/src/main/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LoginEligibilityCheck.java
new file mode 100644
index 0000000..ca1d2dd
--- /dev/null
+++ b/cassandra-3.11/src/main/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LoginEligibilityCheck.java
@@ -0,0 +1,22 @@
+package com.instaclustr.cassandra.ldap.auth;
+
+import static java.util.Collections.singletonList;
+
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.SelectStatement;
+import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.messages.ResultMessage.Rows;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class Cassandra311LoginEligibilityCheck extends BaseCassandraLoginEligibilityCheck
+{
+ @Override
+ protected Rows getRows(final String loginName)
+ {
+ final SelectStatement selStmt = (SelectStatement) QueryProcessor.getStatement(selectStatement, clientState).statement;
+ return selStmt.execute(new QueryState(clientState),
+ QueryOptions.forInternalCalls(singletonList(ByteBufferUtil.bytes(loginName))),
+ System.nanoTime());
+ }
+}
diff --git a/cassandra-3.11/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LDAPIntegrationTest.java b/cassandra-3.11/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LDAPIntegrationTest.java
index 1762c83..d996e26 100644
--- a/cassandra-3.11/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LDAPIntegrationTest.java
+++ b/cassandra-3.11/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra311LDAPIntegrationTest.java
@@ -38,7 +38,7 @@ public List createPluginJars() throws IOException
{
File[] singleFile = Maven.resolver()
.loadPomFromFile("pom.xml")
- .resolve("com.instaclustr:cassandra-ldap-3.11:1.1.1")
+ .resolve("com.instaclustr:cassandra-ldap-3.11:1.2.0")
.withTransitivity()
.asFile();
diff --git a/cassandra-4.0/pom.xml b/cassandra-4.0/pom.xml
index e24c1a9..f4e9884 100644
--- a/cassandra-4.0/pom.xml
+++ b/cassandra-4.0/pom.xml
@@ -11,7 +11,7 @@
cassandra-ldap-4.0
- 1.1.1
+ 1.2.0
Cassandra LDAP Authenticator for Cassandra 4.0
Pluggable LDAP authentication implementation for Apache Cassandra 4.0
@@ -51,7 +51,7 @@
com.instaclustr
cassandra-ldap-base
- 1.1.1
+ 1.2.0
org.apache.cassandra
@@ -116,7 +116,7 @@
cassandra-ldap-base
tests
test-jar
- 1.1.1
+ 1.2.0
test
diff --git a/cassandra-4.0/src/main/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LoginEligibilityCheck.java b/cassandra-4.0/src/main/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LoginEligibilityCheck.java
new file mode 100644
index 0000000..cadec53
--- /dev/null
+++ b/cassandra-4.0/src/main/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LoginEligibilityCheck.java
@@ -0,0 +1,22 @@
+package com.instaclustr.cassandra.ldap.auth;
+
+import static java.util.Collections.singletonList;
+
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.QueryProcessor;
+import org.apache.cassandra.cql3.statements.SelectStatement;
+import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.messages.ResultMessage.Rows;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+public class Cassandra40LoginEligibilityCheck extends BaseCassandraLoginEligibilityCheck
+{
+ @Override
+ protected Rows getRows(final String loginName)
+ {
+ final SelectStatement selStmt = (SelectStatement) QueryProcessor.getStatement(selectStatement, clientState);
+ return selStmt.execute(new QueryState(clientState),
+ QueryOptions.forInternalCalls(singletonList(ByteBufferUtil.bytes(loginName))),
+ System.nanoTime());
+ }
+}
diff --git a/cassandra-4.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LDAPIntegrationTest.java b/cassandra-4.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LDAPIntegrationTest.java
index 10ec919..c98d099 100644
--- a/cassandra-4.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LDAPIntegrationTest.java
+++ b/cassandra-4.0/src/test/java/com/instaclustr/cassandra/ldap/auth/Cassandra40LDAPIntegrationTest.java
@@ -38,7 +38,7 @@ public List createPluginJars() throws IOException
{
File[] singleFile = Maven.resolver()
.loadPomFromFile("pom.xml")
- .resolve("com.instaclustr:cassandra-ldap-4.0:1.1.1")
+ .resolve("com.instaclustr:cassandra-ldap-4.0:1.2.0")
.withTransitivity()
.asFile();
diff --git a/conf/eligibility_check.cql b/conf/eligibility_check.cql
new file mode 100644
index 0000000..b96fd91
--- /dev/null
+++ b/conf/eligibility_check.cql
@@ -0,0 +1,4 @@
+-- change datacenter replication and strategy as you please to suite your needs
+
+CREATE KEYSPACE IF NOT EXISTS login_eligibility WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': 1};
+CREATE TABLE IF NOT EXISTS login_eligibility.login_eligibility (user text, has_access boolean, PRIMARY KEY (user));
\ No newline at end of file
diff --git a/conf/ldap.properties b/conf/ldap.properties
index 992845d..e9a0484 100644
--- a/conf/ldap.properties
+++ b/conf/ldap.properties
@@ -23,7 +23,16 @@ filter_template: (cn=%s)
# if you set this property, Cassandra will internally consider 'dba` to be same as 'cassandra'.
# so you might get rid of `cassandra` role (not recommended) or you might make it unable to log in at least.
# You need to create this admin role beforehand, it has to be super user.
-cassandra_ldap_admin_user=dba
+#cassandra_ldap_admin_user=dba
# consistency level to use for retrieval of a role to check if it can log in - defaults to LOCAL_ONE
-#consistency_for_role: LOCAL_ONE
\ No newline at end of file
+#consistency_for_role: LOCAL_ONE
+
+# Property telling what implementation of eligibility check you want, defaults to NoOp check when not specified
+#eligibility_class_name: com.instaclustr.cassandra.ldap.auth.NoOpLoginEligibilityCheck
+
+# Properties related to Cassandra's eligibility check implementation
+#eligibility_cassandra_keyspace: login_eligibility
+#eligibility_cassandra_table: login_eligibility
+#eligibility_cassandra_user_column: user
+#eligibility_cassandra_access_column: has_access
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 1bfdd50..6b14db8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.instaclustr
cassandra-ldap-parent
- 1.1.1
+ 1.2.0
pom