package me.prettyprint.cassandra.connection.factory; import javax.security.auth.Subject; import javax.security.auth.login.LoginException; import me.prettyprint.cassandra.connection.client.HClient; import me.prettyprint.cassandra.connection.client.HKerberosThriftClient; import me.prettyprint.cassandra.connection.security.KerberosHelper; import me.prettyprint.cassandra.connection.security.SSLHelper; import me.prettyprint.cassandra.service.CassandraHost; import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Client Factory that provides Secure sockets using Kerberos as authentication * mechanism. * * It expects few system properties to be set up: * <ul> * <li><code>java.security.auth.login.config</code>: location of the "jaas.conf" * file. Default is <code>jaas.conf</code> at the root of the classpath. * <li><code>java.security.krb5.conf</code>: location of the "krb5.conf" * file. Default is <code>krb5.conf</code> at the root of the classpath. * <li><code>sun.security.krb5.debug</code>. Set to <code>TRUE</code> for debug. Default is <code>FALSE</code>. * <li><code>kerberos.client.reference.name</code> Kerberos client reference name specified in <code>jaas.conf</code>. * Default: "Client". * <li><code>kerberos.service.principal.name</code> Kerberos Service principal name without the domain. Default: "cassandra". * <li><code>kerberos.client.principal.name</code> Username for when .keytab file is not specified. * <li><code>kerberos.client.password</code> Password for then .keytab file is not specified. * * <li><code>ssl.truststore</code> File path for trust store * <li><code>ssl.truststore.password</code> Password for trust store * <li><code>ssl.protocol</code> SSL protocol, default SSL * <li><code>ssl.store.type</code> Store type, default JKS * <li><code>ssl.cipher.suites</code> Cipher suites * </ul> * <p> * * If a <code>.keytab</code> is going to be used, please avoid setting <code>kerberos.client.username</code> and * <code>kerberos.client.password</code>. * * {@link HKerberosThriftClient} completes the authentication that this factory started against Kerberos. * * Sample <code>jaas.conf</code> file: * <p> * * <pre> * Client { * com.sun.security.auth.module.Krb5LoginModule required * useKeyTab=true * keyTab="./hector-kerberos.keytab" * useTicketCache=true * renewTGT=true * storeKey=true * principal="<user_name>@your_realm"; * }; * * Server { * com.sun.security.auth.module.Krb5LoginModule required * useKeyTab=false * storeKey=true * useTicketCache=false * principal="service_principal@your_realm"; * }; * </pre> * * <code>useKeyTab</code> and <code>keytab</code> can be omitted if <code>kerberos.client.principal.name</code> * and <code>kerberos.client.password</code> are specified. * * @see HKerberosThriftClient * * @author patricioe (Patricio Echague - patricioe@gmail.com) * */ public class HKerberosSecuredThriftClientFactoryImpl implements HClientFactory { private static final Logger log = LoggerFactory.getLogger(HKerberosSecuredThriftClientFactoryImpl.class); public static final String JAAS_CONFIG = "jaas.conf"; public static final String KRB5_CONFIG = "krb5.conf"; private final Subject kerberosTicket; private String krbServicePrincipalName; private TSSLTransportParameters params; public HKerberosSecuredThriftClientFactoryImpl() { params = SSLHelper.getTSSLTransportParameters(); log.info("SSL enabled for client<->server communications."); log.info("Properties:"); log.info(" ssl.truststore = {}", System.getProperty("ssl.truststore")); log.info(" ssl.protocol = {}", System.getProperty("ssl.protocol")); log.info(" ssl.store.type = {}", System.getProperty("ssl.store.type")); log.info(" ssl.cipher.suites = {}", System.getProperty("ssl.cipher.suites")); String jaasConf = System.getProperty("java.security.auth.login.config"); String krb5Conf = System.getProperty("java.security.krb5.conf"); String krbDebug = System.getProperty("sun.security.krb5.debug"); String krbClientReferenceName = System.getProperty("kerberos.client.reference.name"); String krbClientUsername = System.getProperty("kerberos.client.principal.name"); String krbClientPassword = System.getProperty("kerberos.client.password"); krbServicePrincipalName = System.getProperty("kerberos.service.principal.name"); if (krbDebug == null) System.setProperty("sun.security.krb5.debug", "false"); if (jaasConf == null) System.setProperty("java.security.auth.login.config", JAAS_CONFIG); if (krb5Conf == null) System.setProperty("java.security.krb5.conf", KRB5_CONFIG); if (krbClientReferenceName == null) krbClientReferenceName = "Client"; if (krbServicePrincipalName == null) krbServicePrincipalName = "cassandra"; System.setProperty("javax.security.auth.useSubjectCredsOnly", "true"); log.info("Kerberos V5 was enabled for client<->server communications."); log.info("Properties:"); log.info(" sun.security.krb5.debug = {}", System.getProperty("sun.security.krb5.debug")); log.info(" java.security.auth.login.config = {}", System.getProperty("java.security.auth.login.config")); log.info(" java.security.krb5.conf = {}", System.getProperty("java.security.krb5.conf")); log.info(" kerberos.client.reference.name = {}", System.getProperty("kerberos.client.reference.name", krbClientReferenceName)); log.info(" kerberos.service.principal.name = {}", System.getProperty("kerberos.service.principal.name", krbServicePrincipalName)); log.info(" kerberos.client.principal.name = {}", System.getProperty("kerberos.client.principal.name")); log.info(" kerberos.client.password = {}", System.getProperty("kerberos.client.password")); log.info(" javax.security.auth.useSubjectCredsOnly = true"); log.info("Trying to login to the KDC..."); try { // Ticket Granting Ticket (TGT) from the Authentication Server (AS) if (krbClientUsername != null && krbClientPassword != null) kerberosTicket = KerberosHelper.loginService(krbClientReferenceName, krbClientUsername, krbClientPassword); else kerberosTicket = KerberosHelper.loginService(krbClientReferenceName); } catch (LoginException e) { throw new RuntimeException(e); } log.info("Kerberos authenticated successfully against KDC"); } /** * {@inheritDoc} */ public HClient createClient(CassandraHost ch) { if (log.isDebugEnabled()) { log.debug("Creation of new client"); } return params == null ? new HKerberosThriftClient(kerberosTicket, ch, krbServicePrincipalName) : new HKerberosThriftClient(kerberosTicket, ch, krbServicePrincipalName, params); } }