From 0ff4ce941d519aaa9851ca0f9b45246fb72fc5fd Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Thu, 23 Oct 2008 14:38:56 +0000 Subject: Qpid-1392: Add SSL support git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@707381 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/dotnet/client-010/client/client/Client.cs | 37 +++- .../client/transport/network/io/IIoTransport.cs | 57 ++++++ .../client/transport/network/io/IoSSLTransport.cs | 194 +++++++++++++++++++++ .../client/transport/network/io/IoSender.cs | 5 +- .../client/transport/network/io/IoTransport.cs | 6 +- 5 files changed, 292 insertions(+), 7 deletions(-) create mode 100644 qpid/dotnet/client-010/client/transport/network/io/IIoTransport.cs create mode 100644 qpid/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs diff --git a/qpid/dotnet/client-010/client/client/Client.cs b/qpid/dotnet/client-010/client/client/Client.cs index be279d5243..4871a1c3d9 100644 --- a/qpid/dotnet/client-010/client/client/Client.cs +++ b/qpid/dotnet/client-010/client/client/Client.cs @@ -52,7 +52,16 @@ namespace org.apache.qpid.client } #region Interface ClientInterface - + + /// + /// Establishes a connection with a broker using the provided user auths + /// + /// + /// Host name on which a broker is deployed + /// Broker port + /// virtual host name + /// User Name + /// Password public void connect(String host, int port, String virtualHost, String username, String password) { _log.debug(String.Format("Client Connecting to host {0}; port {1}; virtualHost {2}; username {3}", host, @@ -67,6 +76,32 @@ namespace org.apache.qpid.client negotiationComplete.WaitOne(); } + /// + /// Establishes a connection with a broker using SSL + /// + /// + /// Host name on which a broker is deployed + /// Broker port + /// virtual host name + /// User Name + /// Password + /// Name of the SSL server + /// Path to the X509 certificate to be used for client authentication + /// If true connection will not be established if the broker is not trusted + public void connectSSL(String host, int port, String virtualHost, String username, String password, string serverName, string certPath, bool rejectUntrusted) + { + _log.debug(String.Format("Client Connecting to host {0}; port {1}; virtualHost {2}; username {3}", host, + port, virtualHost, username)); + _log.debug(String.Format("SSL paramters: serverName: {0}; certPath: {1}; rejectUntrusted: {2}", serverName, certPath, rejectUntrusted)); + ConnectionDelegate connectionDelegate = new ClientConnectionDelegate(this, username, password); + ManualResetEvent negotiationComplete = new ManualResetEvent(false); + connectionDelegate.setCondition(negotiationComplete); + connectionDelegate.VirtualHost = virtualHost; + _conn = IoSSLTransport.connect(host, port, serverName, certPath, rejectUntrusted, connectionDelegate); + + _conn.send(new ProtocolHeader(1, 0, 10)); + negotiationComplete.WaitOne(); + } public void close() { diff --git a/qpid/dotnet/client-010/client/transport/network/io/IIoTransport.cs b/qpid/dotnet/client-010/client/transport/network/io/IIoTransport.cs new file mode 100644 index 0000000000..aab017dad1 --- /dev/null +++ b/qpid/dotnet/client-010/client/transport/network/io/IIoTransport.cs @@ -0,0 +1,57 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +using System.IO; +using System.Net.Sockets; + +namespace org.apache.qpid.transport.network.io +{ + public interface IIoTransport + { + Connection Connection + { + get; + set; + } + + Receiver> Receiver + { + get; + set; + } + + IoSender Sender + { + get; + set; + } + + + Stream Stream + { + get; + set; + } + + TcpClient Socket + { + get; + set; + } + } +} diff --git a/qpid/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs b/qpid/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs new file mode 100644 index 0000000000..8c5f161a35 --- /dev/null +++ b/qpid/dotnet/client-010/client/transport/network/io/IoSSLTransport.cs @@ -0,0 +1,194 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +using System; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using org.apache.qpid.transport.util; + +namespace org.apache.qpid.transport.network.io +{ + public sealed class IoSSLTransport : IIoTransport + { + // constants + private const int DEFAULT_READ_WRITE_BUFFER_SIZE = 64*1024; + private const int TIMEOUT = 60000; + private const int QUEUE_SIZE = 1000; + // props + private static readonly Logger log = Logger.get(typeof (IoSSLTransport)); + private Stream m_stream; + private IoSender m_sender; + private Receiver> m_receiver; + private TcpClient m_socket; + private Connection m_con; + private readonly bool _rejectUntrusted; + + public static Connection connect(String host, int port, string serverName, string certPath, bool rejectUntrusted, ConnectionDelegate conndel) + { + IIoTransport transport = new IoSSLTransport(host, port, serverName, certPath, rejectUntrusted, conndel); + return transport.Connection; + } + + public IoSSLTransport(String host, int port, string serverName, string certPath, bool rejectUntrusted, ConnectionDelegate conndel) + { + _rejectUntrusted = rejectUntrusted; + createSocket(host, port, serverName, certPath); + Sender = new IoSender(this, QUEUE_SIZE, TIMEOUT); + Receiver = new IoReceiver(Stream, Socket.ReceiveBufferSize*2, TIMEOUT); + Assembler assembler = new Assembler(); + InputHandler inputHandler = new InputHandler(InputHandler.State.PROTO_HDR); + Connection = new Connection(assembler, new Disassembler(Sender, 64*1024 - 1), conndel); + // Input handler listen to Receiver events + Receiver.Received += inputHandler.On_ReceivedBuffer; + // Assembler listen to inputhandler events + inputHandler.ReceivedEvent += assembler.On_ReceivedEvent; + // Connection listen to asembler protocol event + Receiver.Closed += Connection.On_ReceivedClosed; + Receiver.Exception += Connection.On_ReceivedException; + inputHandler.HandlerClosed += Connection.On_ReceivedClosed; + inputHandler.ExceptionProcessing += Connection.On_ReceivedException; + assembler.HandlerClosed += Connection.On_ReceivedClosed; + assembler.ExceptionProcessing += Connection.On_ReceivedException; + assembler.ReceivedEvent += Connection.On_ReceivedEvent; + } + + public Connection Connection + { + get { return m_con; } + set { m_con = value; } + } + + public Receiver> Receiver + { + get { return m_receiver; } + set { m_receiver = value; } + } + + public IoSender Sender + { + get { return m_sender; } + set { m_sender = value; } + } + + + public Stream Stream + { + get { return m_stream; } + set { m_stream = value; } + } + + public TcpClient Socket + { + get { return m_socket; } + set { m_socket = value; } + } + + #region Private Support Functions + + private void createSocket(String host, int port, string serverName, string certPath) + { + TcpClient socket; + try + { + socket = new TcpClient(); + String noDelay = Environment.GetEnvironmentVariable("qpid.tcpNoDelay"); + String writeBufferSize = Environment.GetEnvironmentVariable("qpid.writeBufferSize"); + String readBufferSize = Environment.GetEnvironmentVariable("qpid.readBufferSize"); + socket.NoDelay = noDelay != null && bool.Parse(noDelay); + socket.ReceiveBufferSize = readBufferSize == null + ? DEFAULT_READ_WRITE_BUFFER_SIZE + : int.Parse(readBufferSize); + socket.SendBufferSize = writeBufferSize == null + ? DEFAULT_READ_WRITE_BUFFER_SIZE + : int.Parse(writeBufferSize); + + log.debug("NoDelay : {0}", socket.NoDelay); + log.debug("ReceiveBufferSize : {0}", socket.ReceiveBufferSize); + log.debug("SendBufferSize : {0}", socket.SendBufferSize); + log.debug("Openning connection with host : {0}; port: {1}", host, port); + + socket.Connect(host, port); + Socket = socket; + } + catch (Exception e) + { + throw new TransportException("Error connecting to broker", e); + } + try + { + //Initializes a new instance of the SslStream class using the specified Stream, stream closure behavior, certificate validation delegate and certificate selection delegate + SslStream sslStream = new SslStream(socket.GetStream(), false, ValidateServerCertificate, LocalCertificateSelection); + if (certPath != null) + { + X509CertificateCollection col = new X509CertificateCollection(); + X509Certificate cert = X509Certificate.CreateFromCertFile(certPath); + col.Add(cert); + sslStream.AuthenticateAsClient(serverName, col, SslProtocols.Default, true); + } + else + { + sslStream.AuthenticateAsClient(serverName); + } + Stream = sslStream; + } + catch (AuthenticationException e) + { + log.warn("Exception: {0}", e.Message); + if (e.InnerException != null) + { + log.warn("Inner exception: {0}", e.InnerException.Message); + } + socket.Close(); + throw new TransportException("Authentication failed - closing the connection."); + } + } + + // The following method is invoked by the RemoteCertificateValidationDelegate. + public bool ValidateServerCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + bool result = true; + if (sslPolicyErrors != SslPolicyErrors.None && _rejectUntrusted ) + { + log.warn("Certificate error: {0}", sslPolicyErrors); + // Do not allow this client to communicate with unauthenticated servers. + result = false; + } + return result; + } + + public X509Certificate LocalCertificateSelection( + Object sender, + string targetHost, + X509CertificateCollection localCertificates, + X509Certificate remoteCertificate, + string[] acceptableIssuers + ) + { + return remoteCertificate; + } + + #endregion + } +} diff --git a/qpid/dotnet/client-010/client/transport/network/io/IoSender.cs b/qpid/dotnet/client-010/client/transport/network/io/IoSender.cs index 810e0b8cf4..924d871dd2 100644 --- a/qpid/dotnet/client-010/client/transport/network/io/IoSender.cs +++ b/qpid/dotnet/client-010/client/transport/network/io/IoSender.cs @@ -18,7 +18,6 @@ */ using System; using System.IO; -using System.Net.Sockets; using System.Threading; using common.org.apache.qpid.transport.util; using org.apache.qpid.transport.util; @@ -28,14 +27,14 @@ namespace org.apache.qpid.transport.network.io public sealed class IoSender : IIOSender { private static readonly Logger log = Logger.get(typeof (IoReceiver)); - private readonly NetworkStream bufStream; + private readonly Stream bufStream; private bool closed; private readonly Mutex mutClosed = new Mutex(); private readonly CircularBuffer queue; private readonly Thread thread; private readonly int timeout; private readonly MemoryStream _tobeSent = new MemoryStream(); - public IoSender(IoTransport transport, int queueSize, int timeout) + public IoSender(IIoTransport transport, int queueSize, int timeout) { this.timeout = timeout; bufStream = transport.Stream; diff --git a/qpid/dotnet/client-010/client/transport/network/io/IoTransport.cs b/qpid/dotnet/client-010/client/transport/network/io/IoTransport.cs index f2ebab67c9..3a2397870d 100644 --- a/qpid/dotnet/client-010/client/transport/network/io/IoTransport.cs +++ b/qpid/dotnet/client-010/client/transport/network/io/IoTransport.cs @@ -31,7 +31,7 @@ namespace org.apache.qpid.transport.network.io /// SO_RCVBUF - qpid.readBufferSize /// SO_SNDBUF - qpid.writeBufferSize /// - public sealed class IoTransport + public sealed class IoTransport : IIoTransport { // constants private const int DEFAULT_READ_WRITE_BUFFER_SIZE = 64*1024; @@ -39,7 +39,7 @@ namespace org.apache.qpid.transport.network.io private const int QUEUE_SIZE = 1000; // props private static readonly Logger log = Logger.get(typeof (IoTransport)); - private NetworkStream m_stream; + private Stream m_stream; private IoSender m_sender; private Receiver> m_receiver; private TcpClient m_socket; @@ -92,7 +92,7 @@ namespace org.apache.qpid.transport.network.io } - public NetworkStream Stream + public Stream Stream { get { return m_stream; } set { m_stream = value; } -- cgit v1.2.1