Search in sources :

Example 1 with TSaslClientTransport

use of org.apache.thrift.transport.TSaslClientTransport in project accumulo by apache.

the class KerberosProxyIT method startMac.

@Before
public void startMac() throws Exception {
    MiniClusterHarness harness = new MiniClusterHarness();
    mac = harness.create(getClass().getName(), testName.getMethodName(), new PasswordToken("unused"), new MiniClusterConfigurationCallback() {

        @Override
        public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration coreSite) {
            cfg.setNumTservers(1);
            Map<String, String> siteCfg = cfg.getSiteConfig();
            // Allow the proxy to impersonate the "root" Accumulo user and our one special user.
            siteCfg.put(Property.INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION.getKey(), proxyPrincipal + ":" + kdc.getRootUser().getPrincipal() + "," + kdc.qualifyUser(PROXIED_USER1) + "," + kdc.qualifyUser(PROXIED_USER2));
            siteCfg.put(Property.INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION.getKey(), "*");
            cfg.setSiteConfig(siteCfg);
        }
    }, kdc);
    mac.start();
    MiniAccumuloConfigImpl cfg = mac.getConfig();
    // Generate Proxy configuration and start the proxy
    proxyProcess = startProxy(cfg);
    // Enabled kerberos auth
    Configuration conf = new Configuration(false);
    conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
    UserGroupInformation.setConfiguration(conf);
    boolean success = false;
    ClusterUser rootUser = kdc.getRootUser();
    // Rely on the junit timeout rule
    while (!success) {
        UserGroupInformation ugi;
        try {
            ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(rootUser.getPrincipal(), rootUser.getKeytab().getAbsolutePath());
        } catch (IOException ex) {
            log.info("Login as root is failing", ex);
            Thread.sleep(3000);
            continue;
        }
        TSocket socket = new TSocket(hostname, proxyPort);
        log.info("Connecting to proxy with server primary '{}' running on {}", proxyPrimary, hostname);
        TSaslClientTransport transport = new TSaslClientTransport("GSSAPI", null, proxyPrimary, hostname, Collections.singletonMap("javax.security.sasl.qop", "auth"), null, socket);
        final UGIAssumingTransport ugiTransport = new UGIAssumingTransport(transport, ugi);
        try {
            // UGI transport will perform the doAs for us
            ugiTransport.open();
            success = true;
        } catch (TTransportException e) {
            Throwable cause = e.getCause();
            if (null != cause && cause instanceof ConnectException) {
                log.info("Proxy not yet up, waiting");
                Thread.sleep(3000);
                proxyProcess = checkProxyAndRestart(proxyProcess, cfg);
                continue;
            }
        } finally {
            if (null != ugiTransport) {
                ugiTransport.close();
            }
        }
    }
    assertTrue("Failed to connect to the proxy repeatedly", success);
}
Also used : Configuration(org.apache.hadoop.conf.Configuration) TTransportException(org.apache.thrift.transport.TTransportException) TSaslClientTransport(org.apache.thrift.transport.TSaslClientTransport) MiniClusterHarness(org.apache.accumulo.harness.MiniClusterHarness) IOException(java.io.IOException) MiniAccumuloConfigImpl(org.apache.accumulo.minicluster.impl.MiniAccumuloConfigImpl) UGIAssumingTransport(org.apache.accumulo.core.rpc.UGIAssumingTransport) PasswordToken(org.apache.accumulo.core.client.security.tokens.PasswordToken) MiniClusterConfigurationCallback(org.apache.accumulo.harness.MiniClusterConfigurationCallback) ClusterUser(org.apache.accumulo.cluster.ClusterUser) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation) TSocket(org.apache.thrift.transport.TSocket) ConnectException(java.net.ConnectException) Before(org.junit.Before)

Example 2 with TSaslClientTransport

use of org.apache.thrift.transport.TSaslClientTransport in project accumulo by apache.

the class KerberosProxyIT method testProxyClient.

@Test
public void testProxyClient() throws Exception {
    ClusterUser rootUser = kdc.getRootUser();
    UserGroupInformation ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(rootUser.getPrincipal(), rootUser.getKeytab().getAbsolutePath());
    TSocket socket = new TSocket(hostname, proxyPort);
    log.info("Connecting to proxy with server primary '{}' running on {}", proxyPrimary, hostname);
    TSaslClientTransport transport = new TSaslClientTransport("GSSAPI", null, proxyPrimary, hostname, Collections.singletonMap("javax.security.sasl.qop", "auth"), null, socket);
    final UGIAssumingTransport ugiTransport = new UGIAssumingTransport(transport, ugi);
    // UGI transport will perform the doAs for us
    ugiTransport.open();
    AccumuloProxy.Client.Factory factory = new AccumuloProxy.Client.Factory();
    Client client = factory.getClient(new TCompactProtocol(ugiTransport), new TCompactProtocol(ugiTransport));
    // Will fail if the proxy can impersonate the client
    ByteBuffer login = client.login(rootUser.getPrincipal(), Collections.<String, String>emptyMap());
    // For all of the below actions, the proxy user doesn't have permission to do any of them, but the client user does.
    // The fact that any of them actually run tells us that impersonation is working.
    // Create a table
    String table = "table";
    if (!client.tableExists(login, table)) {
        client.createTable(login, table, true, TimeType.MILLIS);
    }
    // Write two records to the table
    String writer = client.createWriter(login, table, new WriterOptions());
    Map<ByteBuffer, List<ColumnUpdate>> updates = new HashMap<>();
    ColumnUpdate update = new ColumnUpdate(ByteBuffer.wrap("cf1".getBytes(UTF_8)), ByteBuffer.wrap("cq1".getBytes(UTF_8)));
    update.setValue(ByteBuffer.wrap("value1".getBytes(UTF_8)));
    updates.put(ByteBuffer.wrap("row1".getBytes(UTF_8)), Collections.singletonList(update));
    update = new ColumnUpdate(ByteBuffer.wrap("cf2".getBytes(UTF_8)), ByteBuffer.wrap("cq2".getBytes(UTF_8)));
    update.setValue(ByteBuffer.wrap("value2".getBytes(UTF_8)));
    updates.put(ByteBuffer.wrap("row2".getBytes(UTF_8)), Collections.singletonList(update));
    client.update(writer, updates);
    // Flush and close the writer
    client.flush(writer);
    client.closeWriter(writer);
    // Open a scanner to the table
    String scanner = client.createScanner(login, table, new ScanOptions());
    ScanResult results = client.nextK(scanner, 10);
    assertEquals(2, results.getResults().size());
    // Check the first key-value
    KeyValue kv = results.getResults().get(0);
    Key k = kv.key;
    ByteBuffer v = kv.value;
    assertEquals(ByteBuffer.wrap("row1".getBytes(UTF_8)), k.row);
    assertEquals(ByteBuffer.wrap("cf1".getBytes(UTF_8)), k.colFamily);
    assertEquals(ByteBuffer.wrap("cq1".getBytes(UTF_8)), k.colQualifier);
    assertEquals(ByteBuffer.wrap(new byte[0]), k.colVisibility);
    assertEquals(ByteBuffer.wrap("value1".getBytes(UTF_8)), v);
    // And then the second
    kv = results.getResults().get(1);
    k = kv.key;
    v = kv.value;
    assertEquals(ByteBuffer.wrap("row2".getBytes(UTF_8)), k.row);
    assertEquals(ByteBuffer.wrap("cf2".getBytes(UTF_8)), k.colFamily);
    assertEquals(ByteBuffer.wrap("cq2".getBytes(UTF_8)), k.colQualifier);
    assertEquals(ByteBuffer.wrap(new byte[0]), k.colVisibility);
    assertEquals(ByteBuffer.wrap("value2".getBytes(UTF_8)), v);
    // Close the scanner
    client.closeScanner(scanner);
    ugiTransport.close();
}
Also used : AccumuloProxy(org.apache.accumulo.proxy.thrift.AccumuloProxy) ScanResult(org.apache.accumulo.proxy.thrift.ScanResult) ColumnUpdate(org.apache.accumulo.proxy.thrift.ColumnUpdate) KeyValue(org.apache.accumulo.proxy.thrift.KeyValue) HashMap(java.util.HashMap) LoggerFactory(org.slf4j.LoggerFactory) TSaslClientTransport(org.apache.thrift.transport.TSaslClientTransport) TCompactProtocol(org.apache.thrift.protocol.TCompactProtocol) ByteBuffer(java.nio.ByteBuffer) UGIAssumingTransport(org.apache.accumulo.core.rpc.UGIAssumingTransport) WriterOptions(org.apache.accumulo.proxy.thrift.WriterOptions) ClusterUser(org.apache.accumulo.cluster.ClusterUser) List(java.util.List) ScanOptions(org.apache.accumulo.proxy.thrift.ScanOptions) Client(org.apache.accumulo.proxy.thrift.AccumuloProxy.Client) Key(org.apache.accumulo.proxy.thrift.Key) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation) TSocket(org.apache.thrift.transport.TSocket) Test(org.junit.Test)

Example 3 with TSaslClientTransport

use of org.apache.thrift.transport.TSaslClientTransport in project accumulo by apache.

the class KerberosProxyIT method testDisallowedClientForImpersonation.

@Test
public void testDisallowedClientForImpersonation() throws Exception {
    String user = testName.getMethodName();
    File keytab = new File(kdc.getKeytabDir(), user + ".keytab");
    kdc.createPrincipal(keytab, user);
    // Login as the new user
    UserGroupInformation ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(user, keytab.getAbsolutePath());
    log.info("Logged in as {}", ugi);
    // Expect an AccumuloSecurityException
    thrown.expect(AccumuloSecurityException.class);
    // Error msg would look like:
    // 
    // org.apache.accumulo.core.client.AccumuloSecurityException: Error BAD_CREDENTIALS for user Principal in credentials object should match kerberos
    // principal.
    // Expected 'proxy/hw10447.local@EXAMPLE.COM' but was 'testDisallowedClientForImpersonation@EXAMPLE.COM' - Username or Password is Invalid)
    thrown.expect(new ThriftExceptionMatchesPattern(".*Error BAD_CREDENTIALS.*"));
    thrown.expect(new ThriftExceptionMatchesPattern(".*Expected '" + proxyPrincipal + "' but was '" + kdc.qualifyUser(user) + "'.*"));
    TSocket socket = new TSocket(hostname, proxyPort);
    log.info("Connecting to proxy with server primary '{}' running on {}", proxyPrimary, hostname);
    // Should fail to open the tran
    TSaslClientTransport transport = new TSaslClientTransport("GSSAPI", null, proxyPrimary, hostname, Collections.singletonMap("javax.security.sasl.qop", "auth"), null, socket);
    final UGIAssumingTransport ugiTransport = new UGIAssumingTransport(transport, ugi);
    // UGI transport will perform the doAs for us
    ugiTransport.open();
    AccumuloProxy.Client.Factory factory = new AccumuloProxy.Client.Factory();
    Client client = factory.getClient(new TCompactProtocol(ugiTransport), new TCompactProtocol(ugiTransport));
    // Will fail because the proxy can't impersonate this user (per the site configuration)
    try {
        client.login(kdc.qualifyUser(user), Collections.<String, String>emptyMap());
    } finally {
        if (null != ugiTransport) {
            ugiTransport.close();
        }
    }
}
Also used : UGIAssumingTransport(org.apache.accumulo.core.rpc.UGIAssumingTransport) AccumuloProxy(org.apache.accumulo.proxy.thrift.AccumuloProxy) LoggerFactory(org.slf4j.LoggerFactory) TSaslClientTransport(org.apache.thrift.transport.TSaslClientTransport) Client(org.apache.accumulo.proxy.thrift.AccumuloProxy.Client) TCompactProtocol(org.apache.thrift.protocol.TCompactProtocol) File(java.io.File) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation) TSocket(org.apache.thrift.transport.TSocket) Test(org.junit.Test)

Example 4 with TSaslClientTransport

use of org.apache.thrift.transport.TSaslClientTransport in project accumulo by apache.

the class KerberosProxyIT method testMismatchPrincipals.

@Test
public void testMismatchPrincipals() throws Exception {
    ClusterUser rootUser = kdc.getRootUser();
    // Should get an AccumuloSecurityException and the given message
    thrown.expect(AccumuloSecurityException.class);
    thrown.expect(new ThriftExceptionMatchesPattern(ProxyServer.RPC_ACCUMULO_PRINCIPAL_MISMATCH_MSG));
    // Make a new user
    String user = testName.getMethodName();
    File keytab = new File(kdc.getKeytabDir(), user + ".keytab");
    kdc.createPrincipal(keytab, user);
    // Login as the new user
    UserGroupInformation ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(user, keytab.getAbsolutePath());
    log.info("Logged in as {}", ugi);
    TSocket socket = new TSocket(hostname, proxyPort);
    log.info("Connecting to proxy with server primary '{}' running on {}", proxyPrimary, hostname);
    // Should fail to open the tran
    TSaslClientTransport transport = new TSaslClientTransport("GSSAPI", null, proxyPrimary, hostname, Collections.singletonMap("javax.security.sasl.qop", "auth"), null, socket);
    final UGIAssumingTransport ugiTransport = new UGIAssumingTransport(transport, ugi);
    // UGI transport will perform the doAs for us
    ugiTransport.open();
    AccumuloProxy.Client.Factory factory = new AccumuloProxy.Client.Factory();
    Client client = factory.getClient(new TCompactProtocol(ugiTransport), new TCompactProtocol(ugiTransport));
    // Accumulo should let this through -- we need to rely on the proxy to dump me before talking to accumulo
    try {
        client.login(rootUser.getPrincipal(), Collections.<String, String>emptyMap());
    } finally {
        if (null != ugiTransport) {
            ugiTransport.close();
        }
    }
}
Also used : AccumuloProxy(org.apache.accumulo.proxy.thrift.AccumuloProxy) LoggerFactory(org.slf4j.LoggerFactory) TSaslClientTransport(org.apache.thrift.transport.TSaslClientTransport) TCompactProtocol(org.apache.thrift.protocol.TCompactProtocol) UGIAssumingTransport(org.apache.accumulo.core.rpc.UGIAssumingTransport) ClusterUser(org.apache.accumulo.cluster.ClusterUser) Client(org.apache.accumulo.proxy.thrift.AccumuloProxy.Client) File(java.io.File) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation) TSocket(org.apache.thrift.transport.TSocket) Test(org.junit.Test)

Example 5 with TSaslClientTransport

use of org.apache.thrift.transport.TSaslClientTransport in project accumulo by apache.

the class ThriftUtil method createClientTransport.

/**
 * Create a TTransport for clients to the given address with the provided socket timeout and session-layer configuration
 *
 * @param address
 *          Server address to connect to
 * @param timeout
 *          Client socket timeout
 * @param sslParams
 *          RPC options for SSL servers
 * @param saslParams
 *          RPC options for SASL servers
 * @return An open TTransport which must be closed when finished
 */
public static TTransport createClientTransport(HostAndPort address, int timeout, SslConnectionParams sslParams, SaslConnectionParams saslParams) throws TTransportException {
    boolean success = false;
    TTransport transport = null;
    try {
        if (sslParams != null) {
            // The check in AccumuloServerContext ensures that servers are brought up with sane configurations, but we also want to validate clients
            if (null != saslParams) {
                throw new IllegalStateException("Cannot use both SSL and SASL");
            }
            log.trace("Creating SSL client transport");
            // TSSLTransportFactory handles timeout 0 -> forever natively
            if (sslParams.useJsse()) {
                transport = TSSLTransportFactory.getClientSocket(address.getHost(), address.getPort(), timeout);
            } else {
                // JDK6's factory doesn't appear to pass the protocol onto the Socket properly so we have
                // to do some magic to make sure that happens. Not an issue in JDK7
                // Taken from thrift-0.9.1 to make the SSLContext
                SSLContext sslContext = createSSLContext(sslParams);
                // Create the factory from it
                SSLSocketFactory sslSockFactory = sslContext.getSocketFactory();
                // Wrap the real factory with our own that will set the protocol on the Socket before returning it
                ProtocolOverridingSSLSocketFactory wrappingSslSockFactory = new ProtocolOverridingSSLSocketFactory(sslSockFactory, new String[] { sslParams.getClientProtocol() });
                // Create the TSocket from that
                transport = createClient(wrappingSslSockFactory, address.getHost(), address.getPort(), timeout);
            // TSSLTransportFactory leaves transports open, so no need to open here
            }
            transport = ThriftUtil.transportFactory().getTransport(transport);
        } else if (null != saslParams) {
            if (!UserGroupInformation.isSecurityEnabled()) {
                throw new IllegalStateException("Expected Kerberos security to be enabled if SASL is in use");
            }
            log.trace("Creating SASL connection to {}:{}", address.getHost(), address.getPort());
            // Make sure a timeout is set
            try {
                transport = TTimeoutTransport.create(address, timeout);
            } catch (IOException e) {
                log.warn("Failed to open transport to {}", address);
                throw new TTransportException(e);
            }
            try {
                // Log in via UGI, ensures we have logged in with our KRB credentials
                final UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();
                final UserGroupInformation userForRpc;
                if (AuthenticationMethod.PROXY == currentUser.getAuthenticationMethod()) {
                    // that the current user is the user that has some credentials.
                    if (currentUser.getRealUser() != null) {
                        userForRpc = currentUser.getRealUser();
                        log.trace("{} is a proxy user, using real user instead {}", currentUser, userForRpc);
                    } else {
                        // The current user has no credentials, let it fail naturally at the RPC layer (no ticket)
                        // We know this won't work, but we can't do anything else
                        log.warn("The current user is a proxy user but there is no underlying real user (likely that RPCs will fail): {}", currentUser);
                        userForRpc = currentUser;
                    }
                } else {
                    // The normal case: the current user has its own ticket
                    userForRpc = currentUser;
                }
                // Is this pricey enough that we want to cache it?
                final String hostname = InetAddress.getByName(address.getHost()).getCanonicalHostName();
                final SaslMechanism mechanism = saslParams.getMechanism();
                log.trace("Opening transport to server as {} to {}/{} using {}", userForRpc, saslParams.getKerberosServerPrimary(), hostname, mechanism);
                // Create the client SASL transport using the information for the server
                // Despite the 'protocol' argument seeming to be useless, it *must* be the primary of the server being connected to
                transport = new TSaslClientTransport(mechanism.getMechanismName(), null, saslParams.getKerberosServerPrimary(), hostname, saslParams.getSaslProperties(), saslParams.getCallbackHandler(), transport);
                // Wrap it all in a processor which will run with a doAs the current user
                transport = new UGIAssumingTransport(transport, userForRpc);
                // Open the transport
                transport.open();
            } catch (TTransportException e) {
                log.warn("Failed to open SASL transport", e);
                // We might have had a valid ticket, but it expired. We'll let the caller retry, but we will attempt to re-login to make the next attempt work.
                // Sadly, we have no way to determine the actual reason we got this TTransportException other than inspecting the exception msg.
                log.debug("Caught TTransportException opening SASL transport, checking if re-login is necessary before propagating the exception.");
                attemptClientReLogin();
                throw e;
            } catch (IOException e) {
                log.warn("Failed to open SASL transport", e);
                throw new TTransportException(e);
            }
        } else {
            log.trace("Opening normal transport");
            if (timeout == 0) {
                transport = new TSocket(address.getHost(), address.getPort());
                transport.open();
            } else {
                try {
                    transport = TTimeoutTransport.create(address, timeout);
                } catch (IOException ex) {
                    log.warn("Failed to open transport to {}", address);
                    throw new TTransportException(ex);
                }
                // Open the transport
                transport.open();
            }
            transport = ThriftUtil.transportFactory().getTransport(transport);
        }
        success = true;
    } finally {
        if (!success && transport != null) {
            transport.close();
        }
    }
    return transport;
}
Also used : SaslMechanism(org.apache.accumulo.core.rpc.SaslConnectionParams.SaslMechanism) TTransportException(org.apache.thrift.transport.TTransportException) TSaslClientTransport(org.apache.thrift.transport.TSaslClientTransport) SSLContext(javax.net.ssl.SSLContext) IOException(java.io.IOException) TTransport(org.apache.thrift.transport.TTransport) SSLSocketFactory(javax.net.ssl.SSLSocketFactory) UserGroupInformation(org.apache.hadoop.security.UserGroupInformation) TSocket(org.apache.thrift.transport.TSocket)

Aggregations

TSaslClientTransport (org.apache.thrift.transport.TSaslClientTransport)13 TTransport (org.apache.thrift.transport.TTransport)8 IOException (java.io.IOException)7 TSocket (org.apache.thrift.transport.TSocket)7 UserGroupInformation (org.apache.hadoop.security.UserGroupInformation)5 UGIAssumingTransport (org.apache.accumulo.core.rpc.UGIAssumingTransport)4 TTransportException (org.apache.thrift.transport.TTransportException)4 ByteBuffer (java.nio.ByteBuffer)3 HashMap (java.util.HashMap)3 ClusterUser (org.apache.accumulo.cluster.ClusterUser)3 AccumuloProxy (org.apache.accumulo.proxy.thrift.AccumuloProxy)3 Client (org.apache.accumulo.proxy.thrift.AccumuloProxy.Client)3 TUGIAssumingTransport (org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport)3 TCompactProtocol (org.apache.thrift.protocol.TCompactProtocol)3 Test (org.junit.Test)3 LoggerFactory (org.slf4j.LoggerFactory)3 File (java.io.File)2 UncheckedIOException (java.io.UncheckedIOException)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2