Author: shawkins
Date: 2011-05-26 11:47:40 -0400 (Thu, 26 May 2011)
New Revision: 3201
Modified:
branches/7.4.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
branches/7.4.x/build/kits/jboss-container/teiid-releasenotes.html
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/odbc.xml
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/ssl.xml
branches/7.4.x/engine/src/main/java/org/teiid/security/Credentials.java
branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java
branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
branches/7.4.x/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java
branches/7.4.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
branches/7.4.x/runtime/src/main/resources/org/teiid/runtime/i18n.properties
branches/7.4.x/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
Log:
TEIID-1460 adding ssl support to odbc
Modified: branches/7.4.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
===================================================================
---
branches/7.4.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-05-26
15:47:40 UTC (rev 3201)
@@ -229,7 +229,7 @@
<bean name="OdbcSslConfiguration"
class="org.teiid.transport.SSLConfiguration">
<!-- can be one of disabled or enabled
disabled = no transport or message level security will be used
- enabled = traffic will be secured using this configuration
+ enabled = traffic will be secured using this configuration if the client
supports SSL
-->
<property name="mode">disabled</property>
<property name="keystoreFilename">cert.keystore</property>
Modified: branches/7.4.x/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- branches/7.4.x/build/kits/jboss-container/teiid-releasenotes.html 2011-05-26 14:59:56
UTC (rev 3200)
+++ branches/7.4.x/build/kits/jboss-container/teiid-releasenotes.html 2011-05-26 15:47:40
UTC (rev 3201)
@@ -56,6 +56,7 @@
<LI><B>Cache Invalidation</B> - Prepared plan and result set caches
have will invalidate entries based upon metadata and data changes respectively. See the
cache configuration maxStaleness setting and the Admin and Developer Guides for more.
<LI><B>Runtime Updates of Metadata</B> - ALTER statements have been
added to change view/procedure/INSTEAD OF trigger (update procedure) definitions. A
CREATE TRIGGER statement is also available to add an INSTEAD OF trigger (update
procedures) to views.
System procedures were added to set extension metadata and stat values. By default all
effects of metadata updates happen only on running vdbs across the cluster. To make the
changes persistent see the Developers Guide Runtime Updates section.
+ <LI><B>ODBC SSL</B> - added support for SSL encrypted ODBC
connections.
</UL>
<h2><a name="Compatibility">Compatibility
Issues</a></h2>
Modified:
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/odbc.xml
===================================================================
---
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/odbc.xml 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/odbc.xml 2011-05-26
15:47:40 UTC (rev 3201)
@@ -23,6 +23,11 @@
<para>Before an application can use ODBC, you must first install the ODBC
driver on same machine that
the application is running on and then create Data Source Name (DSN) that represents
a connection profile for your Teiid VDB.
</para>
+
+ <warning><para>Teiid currently only supports plain text passward
authentication for ODBC.
+ If the client/server are not configured to use SSL, the password will be sent in
plain text over the network.
+ If you need secure passwords in transit and are not using SSL, then consider
installing a security domain
+ that will accept safe password values from the client (for example encrypted or
hashed).</para></warning>
<section id="install">
<title>Installing the ODBC Driver Client</title>
@@ -145,7 +150,6 @@
listenes for ODBC requests on port 35432</para>
<para>In the <emphasis>User Name</emphasis> and
<emphasis>Password</emphasis> edit boxes, supply the user name and password
for the Teiid runtime access.</para>
- <para>Leave <emphasis>SSL Mode</emphasis> to
disabled. SSL connections are currently not supported.</para>
<para>Provide any description about the data source in the
<emphasis>Description</emphasis> field.</para>
</listitem>
Modified:
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/ssl.xml
===================================================================
---
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/ssl.xml 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/documentation/client-developers-guide/src/main/docbook/en-US/content/ssl.xml 2011-05-26
15:47:40 UTC (rev 3201)
@@ -13,13 +13,13 @@
<section id="default_security">
<title>Default Security</title>
- <para>If you are using a socket connection, then you may need to secure the
channel more completely.</para>
-
- <para>By default all sensitive (non-data) messages between client and
server
+ <para>By default all JDBC/Admin sensitive (non-data) messages between
client and server
are encrypted using a <ulink
url="http://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange"&...
key that is negotiated per connection. This
encryption is controlled by <code>clientEncryptionEnabled</code>
property in <code>JdbcSslConfiguration</code> and
<code>AdminSslConfiguration</code> sections in the &jboss-beans;
file.</para>
+
+ <para>If you are using a socket connection, then you may need to secure the
channel more completely - especially if using ODBC, which currently only supports plain
text authentication.</para>
</section>
<section id="ssl_modes">
Modified: branches/7.4.x/engine/src/main/java/org/teiid/security/Credentials.java
===================================================================
--- branches/7.4.x/engine/src/main/java/org/teiid/security/Credentials.java 2011-05-26
14:59:56 UTC (rev 3200)
+++ branches/7.4.x/engine/src/main/java/org/teiid/security/Credentials.java 2011-05-26
15:47:40 UTC (rev 3201)
@@ -26,7 +26,9 @@
public class Credentials implements Serializable {
- private char[] credentials = null;
+ private static final long serialVersionUID = 7453114713211221240L;
+
+ private char[] credentials = null;
/**
* Construct a new PasswordCredentials
Modified: branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java
===================================================================
--- branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java 2011-05-26
14:59:56 UTC (rev 3200)
+++ branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java 2011-05-26
15:47:40 UTC (rev 3201)
@@ -85,7 +85,7 @@
void functionCallResponse(byte[] data);
void functionCallResponse(int data);
- void sslDenied();
+ void sendSslResponse();
// unimplemented backend messages
Modified: branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
===================================================================
---
branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java 2011-05-26
15:47:40 UTC (rev 3201)
@@ -637,7 +637,7 @@
@Override
public void sslRequest() {
- this.client.sslDenied();
+ this.client.sendSslResponse();
}
private void setEncoding() {
Modified:
branches/7.4.x/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java
===================================================================
---
branches/7.4.x/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java 2011-05-26
15:47:40 UTC (rev 3201)
@@ -23,11 +23,8 @@
import java.util.Properties;
-import javax.net.ssl.SSLEngine;
-
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.DefaultChannelPipeline;
-import org.jboss.netty.handler.ssl.SslHandler;
import org.teiid.common.buffer.StorageManager;
import org.teiid.core.TeiidException;
import org.teiid.jdbc.EmbeddedProfile;
@@ -66,12 +63,8 @@
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = new DefaultChannelPipeline();
- SSLEngine engine = config.getServerSSLEngine();
- if (engine != null) {
- pipeline.addLast("ssl", new SslHandler(engine)); //$NON-NLS-1$
- }
pipeline.addLast("odbcFrontendProtocol", new PgFrontendProtocol(1
<< 20)); //$NON-NLS-1$
- pipeline.addLast("odbcBackendProtocol", new
PgBackendProtocol(maxLobSize)); //$NON-NLS-1$
+ pipeline.addLast("odbcBackendProtocol", new
PgBackendProtocol(maxLobSize, config)); //$NON-NLS-1$
pipeline.addLast("handler", this); //$NON-NLS-1$
return pipeline;
}
Modified: branches/7.4.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
===================================================================
---
branches/7.4.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java 2011-05-26
15:47:40 UTC (rev 3201)
@@ -28,6 +28,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
+import java.security.GeneralSecurityException;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ParameterMetaData;
@@ -41,13 +42,18 @@
import java.util.List;
import java.util.Properties;
+import javax.net.ssl.SSLEngine;
+
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelDownstreamHandler;
import org.jboss.netty.channel.ChannelEvent;
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.handler.ssl.SslHandler;
import org.teiid.client.util.ResultsFuture;
import org.teiid.core.util.ObjectConverterUtil;
import org.teiid.core.util.ReaderInputStream;
@@ -59,6 +65,7 @@
import org.teiid.logging.LogManager;
import org.teiid.net.socket.ServiceInvocationStruct;
import org.teiid.odbc.ODBCClientRemote;
+import org.teiid.runtime.RuntimePlugin;
import org.teiid.transport.pg.PGbytea;
/**
@@ -68,7 +75,25 @@
@SuppressWarnings("nls")
public class PgBackendProtocol implements ChannelDownstreamHandler, ODBCClientRemote {
- private final class ResultsWorkItem implements Runnable {
+ private final class SSLEnabler implements ChannelFutureListener {
+
+ private SSLEngine engine;
+
+ public SSLEnabler(SSLEngine engine) {
+ this.engine = engine;
+ }
+
+ @Override
+ public void operationComplete(ChannelFuture future) throws Exception {
+ if (future.isSuccess()) {
+ SslHandler handler = new SslHandler(engine);
+ future.getChannel().getPipeline().addFirst("sslHandler", handler);
+ handler.handshake();
+ }
+ }
+ }
+
+ private final class ResultsWorkItem implements Runnable {
private final List<PgColInfo> cols;
private final String sql;
private final ResultSetImpl rs;
@@ -164,8 +189,11 @@
private volatile ResultsFuture<Boolean> nextFuture;
- public PgBackendProtocol(int maxLobSize) {
+ private SSLConfiguration config;
+
+ public PgBackendProtocol(int maxLobSize, SSLConfiguration config) {
this.maxLobSize = maxLobSize;
+ this.config = config;
}
@Override
@@ -550,10 +578,23 @@
}
@Override
- public void sslDenied() {
+ public void sendSslResponse() {
+ SSLEngine engine = null;
+ try {
+ engine = config.getServerSSLEngine();
+ } catch (IOException e) {
+ LogManager.logError(LogConstants.CTX_ODBC, e,
RuntimePlugin.Util.getString("PgBackendProtocol.ssl_error"));
+ } catch (GeneralSecurityException e) {
+ LogManager.logError(LogConstants.CTX_ODBC, e,
RuntimePlugin.Util.getString("PgBackendProtocol.ssl_error"));
+ }
ChannelBuffer buffer = ChannelBuffers.directBuffer(1);
- buffer.writeByte('N');
- Channels.write(this.ctx, this.message.getFuture(), buffer,
this.message.getRemoteAddress());
+ if (engine == null) {
+ buffer.writeByte('N');
+ } else {
+ this.message.getFuture().addListener(new SSLEnabler(engine));
+ buffer.writeByte('S');
+ }
+ Channels.write(this.ctx, this.message.getFuture(), buffer,
this.message.getRemoteAddress());
}
private void sendErrorResponse(Throwable t) throws IOException {
Modified: branches/7.4.x/runtime/src/main/resources/org/teiid/runtime/i18n.properties
===================================================================
--- branches/7.4.x/runtime/src/main/resources/org/teiid/runtime/i18n.properties 2011-05-26
14:59:56 UTC (rev 3200)
+++ branches/7.4.x/runtime/src/main/resources/org/teiid/runtime/i18n.properties 2011-05-26
15:47:40 UTC (rev 3201)
@@ -91,4 +91,6 @@
metadata_loaded=VDB {0}.{1} model {2} metadata is currently being loaded.
ambigious_name=Ambiguous VDB name specified. Only single occurrence of the "."
is allowed in the VDB name. Also, when version based vdb name is specified, then a
separate "version" connection option is not allowed:{0}.{1}
lo_not_supported=LO functions are not supported
-SSLConfiguration.no_anonymous=The anonymous cipher suite TLS_DH_anon_WITH_AES_128_CBC_SHA
is not available. Please change the transport to be non-SSL or use non-anonymous SSL.
\ No newline at end of file
+SSLConfiguration.no_anonymous=The anonymous cipher suite TLS_DH_anon_WITH_AES_128_CBC_SHA
is not available. Please change the transport to be non-SSL or use non-anonymous SSL.
+
+PgBackendProtocol.ssl_error=Could not initialize ODBC SSL. non-SSL connections will
still be allowed.
\ No newline at end of file
Modified:
branches/7.4.x/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
===================================================================
---
branches/7.4.x/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java 2011-05-26
14:59:56 UTC (rev 3200)
+++
branches/7.4.x/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java 2011-05-26
15:47:40 UTC (rev 3201)
@@ -24,8 +24,13 @@
import static org.junit.Assert.*;
+import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
import java.nio.charset.Charset;
+import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -33,6 +38,10 @@
import java.sql.Statement;
import java.util.Properties;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -44,37 +53,107 @@
import org.teiid.jdbc.FakeServer;
import org.teiid.jdbc.TeiidDriver;
import org.teiid.jdbc.TestMMDatabaseMetaData;
+import org.teiid.net.socket.SocketUtil;
@SuppressWarnings("nls")
public class TestODBCSocketTransport {
-
- static InetSocketAddress addr;
- static ODBCSocketListener odbcTransport;
- @BeforeClass public static void oneTimeSetup() throws Exception {
- SocketConfiguration config = new SocketConfiguration();
- config.setSSLConfiguration(new SSLConfiguration());
- addr = new InetSocketAddress(0);
- config.setBindAddress(addr.getHostName());
- config.setPortNumber(0);
- odbcTransport = new ODBCSocketListener(config,
BufferManagerFactory.getStandaloneBufferManager(), 0, 100000);
+public static class AnonSSLSocketFactory extends SSLSocketFactory {
- FakeServer server = new FakeServer();
- server.setUseCallingThread(false);
- server.deployVDB("parts", UnitTestUtil.getTestDataPath() +
"/PartsSupplier.vdb");
+ private SSLSocketFactory sslSocketFactory;
- TeiidDriver driver = new TeiidDriver();
- driver.setEmbeddedProfile(server);
- odbcTransport.setDriver(driver);
+ public AnonSSLSocketFactory() {
+ try {
+ sslSocketFactory = SSLContext.getDefault().getSocketFactory();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ public Socket createSocket() throws IOException {
+ return sslSocketFactory.createSocket();
+ }
+
+ public Socket createSocket(InetAddress address, int port,
+ InetAddress localAddress, int localPort) throws IOException {
+ return sslSocketFactory.createSocket(address, port, localAddress,
+ localPort);
+ }
+
+ public Socket createSocket(InetAddress host, int port)
+ throws IOException {
+ return sslSocketFactory.createSocket(host, port);
+ }
+
+ public Socket createSocket(Socket s, String host, int port,
+ boolean autoClose) throws IOException {
+ SSLSocket socket = (SSLSocket)sslSocketFactory.createSocket(s, host, port,
autoClose);
+ SocketUtil.addCipherSuite(socket, SocketUtil.ANON_CIPHER_SUITE);
+ return socket;
+ }
+
+ public Socket createSocket(String host, int port,
+ InetAddress localHost, int localPort) throws IOException,
+ UnknownHostException {
+ return sslSocketFactory.createSocket(host, port, localHost,
+ localPort);
+ }
+
+ public Socket createSocket(String host, int port) throws IOException,
+ UnknownHostException {
+ return sslSocketFactory.createSocket(host, port);
+ }
+
+ public String[] getDefaultCipherSuites() {
+ return sslSocketFactory.getDefaultCipherSuites();
+ }
+
+ public String[] getSupportedCipherSuites() {
+ return sslSocketFactory.getSupportedCipherSuites();
+ }
}
- @AfterClass public static void oneTimeTearDown() throws Exception {
- if (odbcTransport != null) {
+ static class FakeOdbcServer {
+ InetSocketAddress addr;
+ ODBCSocketListener odbcTransport;
+
+ public void start() throws Exception {
+ SocketConfiguration config = new SocketConfiguration();
+ SSLConfiguration sslConfig = new SSLConfiguration();
+ sslConfig.setMode(SSLConfiguration.ENABLED);
+ sslConfig.setAuthenticationMode(SSLConfiguration.ANONYMOUS);
+ config.setSSLConfiguration(sslConfig);
+ addr = new InetSocketAddress(0);
+ config.setBindAddress(addr.getHostName());
+ config.setPortNumber(0);
+ odbcTransport = new ODBCSocketListener(config,
BufferManagerFactory.getStandaloneBufferManager(), 0, 100000);
+
+ FakeServer server = new FakeServer();
+ server.setUseCallingThread(false);
+ server.deployVDB("parts", UnitTestUtil.getTestDataPath() +
"/PartsSupplier.vdb");
+
+ TeiidDriver driver = new TeiidDriver();
+ driver.setEmbeddedProfile(server);
+ odbcTransport.setDriver(driver);
+ }
+
+ public void stop() {
odbcTransport.stop();
}
+
}
+ private static FakeOdbcServer odbcServer = new FakeOdbcServer();
+
+ @BeforeClass public static void oneTimeSetup() throws Exception {
+ odbcServer.start();
+ }
+
+ @AfterClass public static void oneTimeTearDown() throws Exception {
+ odbcServer.stop();
+ }
+
Connection conn;
@Before public void setUp() throws Exception {
@@ -82,7 +161,7 @@
Properties p = new Properties();
p.setProperty("user", "testuser");
p.setProperty("password", "testpassword");
- conn = d.connect("jdbc:postgresql://"+addr.getHostName()+":"
+odbcTransport.getPort()+"/parts", p);
+ conn =
d.connect("jdbc:postgresql://"+odbcServer.addr.getHostName()+":"
+odbcServer.odbcTransport.getPort()+"/parts", p);
}
@After public void tearDown() throws Exception {
@@ -181,4 +260,18 @@
ResultSet rs = stmt.executeQuery("select has_function_privilege(100,
'foo')");
rs.next();
}
+
+ @Test public void testSelectSsl() throws Exception {
+ conn.close();
+ Driver d = new Driver();
+ Properties p = new Properties();
+ p.setProperty("user", "testuser");
+ p.setProperty("password", "testpassword");
+ p.setProperty("ssl", "true");
+ p.setProperty("sslfactory", AnonSSLSocketFactory.class.getName());
+ conn =
d.connect("jdbc:postgresql://"+odbcServer.addr.getHostName()+":"
+odbcServer.odbcTransport.getPort()+"/parts", p);
+ Statement s = conn.createStatement();
+ assertTrue(s.execute("select * from tables order by name"));
+ TestMMDatabaseMetaData.compareResultSet("TestODBCSocketTransport/testSelect",
s.getResultSet());
+ }
}