[Nmailserver-commits] SF.net SVN: nmailserver: [29] NMail/trunk/NMail
Brought to you by:
dframpton-oss,
tmyroadctfig
|
From: <tmy...@us...> - 2006-05-09 00:53:23
|
Revision: 29 Author: tmyroadctfig Date: 2006-05-06 08:33:43 -0700 (Sat, 06 May 2006) ViewCVS: http://svn.sourceforge.net/nmailserver/?rev=29&view=rev Log Message: ----------- Work on TCP remoting channel. Changes to connection TLS. Work on authentication and ACLs. Modified Paths: -------------- NMail/trunk/NMail/Authentication/BasicAuthToken.cs NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs NMail/trunk/NMail/Authentication/IAuthenticationToken.cs NMail/trunk/NMail/Authentication/IHashAuthProvider.cs NMail/trunk/NMail/Authentication/NullAuthentication.cs NMail/trunk/NMail/ILocalStoreData.cs NMail/trunk/NMail/IO/TcpChannel.cs NMail/trunk/NMail/IO/TcpClientChannel.cs NMail/trunk/NMail/IO/TcpClientTransportSink.cs NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs NMail/trunk/NMail/IO/TcpServerChannel.cs NMail/trunk/NMail/IO/TcpServerTransportSink.cs NMail/trunk/NMail/IO/TcpTextConnection.cs NMail/trunk/NMail/NMail.csproj NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj NMail/trunk/NMail.ImapService/ImapServiceConnection.cs NMail/trunk/NMail.ImapService/State/ConnectedState.cs NMail/trunk/NMail.LocalStore/LocalStore.cs NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs NMail/trunk/NMail.Server/RemoteAdministration.cs Removed Paths: ------------- NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs Modified: NMail/trunk/NMail/Authentication/BasicAuthToken.cs =================================================================== --- NMail/trunk/NMail/Authentication/BasicAuthToken.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/BasicAuthToken.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -21,15 +21,32 @@ /// <summary> /// A simple authentication token. /// </summary> + [Serializable] public class BasicAuthToken : IAuthenticationToken { /// <summary> /// Creates a new basic authentication token with the given username. /// </summary> /// <param name="username">The username associated with then authentication token.</param> - public BasicAuthToken(string username) { + /// <param name="credentialsExpiry">The date and time that the user's credentials expire.</param> + public BasicAuthToken(string username, DateTime credentialsExpiry) { this.username = username; + this.credentialsExpiry = credentialsExpiry; } + private Guid tokenId; + + /// <summary> + /// The Id for this token. + /// </summary> + public Guid TokenId { + get { + return this.tokenId; + } + set { + this.tokenId = value; + } + } + #region IAuthenticationToken Members private string username; @@ -38,6 +55,14 @@ return this.username; } } + + private DateTime credentialsExpiry; + + public DateTime CredentialsExpiry { + get { + return this.credentialsExpiry; + } + } #endregion } } Modified: NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs =================================================================== --- NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IAuthenticationProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -19,18 +19,52 @@ namespace NMail.Authentication { /// <summary> - /// A top level interface for the password and hash authentication types. + /// The interface for an authentication provider that operates on username and + /// password pairs. /// </summary> + /// <remarks> + /// This interface is for a provider that will compute a hash based on the given + /// username and password and then compare it to a previously generated hash. + /// </remarks> public interface IAuthenticationProvider { /// <summary> - /// Gets the date and time that the user's credentials will expire. E.g. Their - /// password expires and needs changing. + /// Attempts to authenticate the user with the given password. /// </summary> - /// <param name="user">The details of the user to get the expiry time for.</param> + /// <param name="username">The username for the user to authenticate.</param> + /// <param name="password">The given password to attempt authentication with.</param> + /// <returns>The authentication token or null if authentication fails.</returns> + IAuthenticationToken Authenticate(string username, string password); + + /// <summary> + /// Creates an authentication token for a trusted party, e.g. a part of the + /// NMail system. + /// </summary> + /// <param name="username">The username to create the token for.</param> + /// <returns>The token or null if the user is invalid</returns> + IAuthenticationToken CreateAuthToken(string username); + + /// <summary> + /// Gets the date and time that the given token will expire. + /// </summary> + /// <param name="user">The token to check the expire time for.</param> /// <returns>The expiry time.</returns> - DateTime GetCredentialsExpiry(IAuthenticationToken user); + DateTime GetTokenExpiry(IAuthenticationToken user); /// <summary> + /// Checks if the given token has expired. + /// </summary> + /// <param name="user">The token to check the expire time for.</param> + /// <returns>True if the token has expired.</returns> + bool TokenExpired(IAuthenticationToken user); + + /// <summary> + /// Checks if the given authentication token is valid. + /// </summary> + /// <param name="user">The token to check.</param> + /// <returns>True if the token is valid.</returns> + bool ValidToken(IAuthenticationToken user); + + /// <summary> /// Checks if the user's account is currently locked out. /// </summary> /// <param name="user">The user to check.</param> Modified: NMail/trunk/NMail/Authentication/IAuthenticationToken.cs =================================================================== --- NMail/trunk/NMail/Authentication/IAuthenticationToken.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IAuthenticationToken.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -26,5 +26,11 @@ /// Returns the username for the authenticated user. /// </summary> string Username { get; } + + /// <summary> + /// Gets the date and time that the user's credentials will expire. E.g. Their + /// password expires and needs changing. + /// </summary> + DateTime CredentialsExpiry { get; } } } Modified: NMail/trunk/NMail/Authentication/IHashAuthProvider.cs =================================================================== --- NMail/trunk/NMail/Authentication/IHashAuthProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IHashAuthProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -31,7 +31,7 @@ /// A provider that is able to authenticate multiple hash types will typically store /// the passwords with reversible encryption. /// </remarks> - public interface IHashAuthProvider : IPasswordAuthProvider { + public interface IHashAuthProvider : IAuthenticationProvider { /// <summary> /// Attempts to authenticate the user with the given password. /// </summary> Deleted: NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs =================================================================== --- NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/IPasswordAuthProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -1,39 +0,0 @@ -/* - * Copyright 2004-2006 Luke Quinane and Daniel Frampton - * - * Licensed 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.Security; - -namespace NMail.Authentication { - /// <summary> - /// The interface for an authentication provider that operates on username and - /// password pairs. - /// </summary> - /// <remarks> - /// This interface is for a provider that will compute a hash based on the given - /// username and password and then compare it to a previously generated hash. - /// </remarks> - public interface IPasswordAuthProvider : IAuthenticationProvider { - /// <summary> - /// Attempts to authenticate the user with the given password. - /// </summary> - /// <param name="username">The username for the user to authenticate.</param> - /// <param name="password">The given password to attempt authentication with.</param> - /// <returns>The authentication token or null if authentication fails.</returns> - IAuthenticationToken Authenticate(string username, string password); - } -} Modified: NMail/trunk/NMail/Authentication/NullAuthentication.cs =================================================================== --- NMail/trunk/NMail/Authentication/NullAuthentication.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/Authentication/NullAuthentication.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -23,22 +23,33 @@ /// An authentication provider that performs no checks. <b>Should only be used for /// developement purposes.</b> /// </summary> - public class NullAuthentication : IPasswordAuthProvider { + public class NullAuthentication : IAuthenticationProvider { - #region IPasswordAuthProvider Members + #region IAuthenticationProvider Members public IAuthenticationToken Authenticate(string username, string password) { - return new BasicAuthToken(username); + return new BasicAuthToken(username, DateTime.MaxValue); } - public DateTime GetCredentialsExpiry(IAuthenticationToken user) { + public IAuthenticationToken CreateAuthToken(string username) { + return new BasicAuthToken(username, DateTime.MaxValue); + } + + public DateTime GetTokenExpiry(IAuthenticationToken user) { return DateTime.MaxValue; } + public bool TokenExpired(IAuthenticationToken user) { + return false; + } + + public bool ValidToken(IAuthenticationToken user) { + return true; + } + public bool IsLockedOut(IAuthenticationToken user) { return false; } - #endregion } } Modified: NMail/trunk/NMail/ILocalStoreData.cs =================================================================== --- NMail/trunk/NMail/ILocalStoreData.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/ILocalStoreData.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -362,7 +362,7 @@ LocalStoreGroupResult UpdateGroup(LocalStoreGroup group); #endregion - #region ACLs + #region Folder ACLs /// <summary> /// Sets the privileges on the folder. If no ACE exists for the associated /// identifier one is added. Modified: NMail/trunk/NMail/IO/TcpChannel.cs =================================================================== --- NMail/trunk/NMail/IO/TcpChannel.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpChannel.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -18,14 +18,14 @@ using System; using System.Collections; using System.IO; +using System.Net.Security; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Security.Cryptography.X509Certificates; using System.Text; -using Mono.Security.Authenticode; - +using NMail.Authentication; using NMail.DataTypes; namespace NMail.IO { @@ -39,20 +39,35 @@ private TcpServerChannel serverChannel; public TcpChannel(IDictionary properties, IClientChannelSinkProvider clientSinkProvider, IServerChannelSinkProvider serverSinkProvider) { + // Create the client sink provider if needed if (clientSinkProvider == null) { clientSinkProvider = new BinaryClientFormatterSinkProvider(); } - this.clientChannel = new TcpClientChannel(clientSinkProvider); + // Parse the client properties + RemoteCertificateValidationCallback certValidationCallback = (RemoteCertificateValidationCallback) properties["certificateValidation"]; + GetAuthDetailsDelegate getAuthDetailsCallback = (GetAuthDetailsDelegate) properties["authDetailCallback"]; + ChannelAuthComplete authCompleteCallback = (ChannelAuthComplete) properties["authCompleteCallback"]; + this.clientChannel = new TcpClientChannel(clientSinkProvider, + getAuthDetailsCallback, + certValidationCallback, + authCompleteCallback); + if (properties["isServer"] != null && ((string) properties["isServer"]) == "yes") { + // Create the server sink provider if needed if (serverSinkProvider == null) { serverSinkProvider = new BinaryServerFormatterSinkProvider(); } + // Parse the server properties int port = Int32.Parse((string) properties["port"]); + X509Certificate2 certificate = (X509Certificate2) properties["certificate"]; + IAuthenticationProvider authProvider = (IAuthenticationProvider) properties["authProvider"]; + this.serverChannel = new TcpServerChannel(port, - (X509Certificate2) properties["certificate"], + certificate, + authProvider, serverSinkProvider); } } @@ -215,8 +230,7 @@ /// <param name="objectURI">The object URI in the URL or null if the URL is invalid.</param> /// <returns>True if the URL is valid.</returns> public static bool ParseUrl(string url, out Host host, out int port, out string objectURI) { - url = url.Trim(); - + if (url == null || !url.StartsWith(UrlPrefix) || url.IndexOf(':') == -1 || url.IndexOf('/') == -1) { // Invalid URL host = null; @@ -225,11 +239,16 @@ return false; } + url = url.Trim(); + // Remove the "nmtcp://" url = url.Remove(0, UrlPrefix.Length); int cIndex = url.IndexOf(':'); int sIndex = url.IndexOf('/'); + if (sIndex == -1) { + sIndex = url.Length; + } host = new Host(url.Substring(0, cIndex)); port = Int32.Parse(url.Substring(cIndex + 1, sIndex - cIndex - 1)); objectURI = url.Substring(sIndex); @@ -319,4 +338,28 @@ } } #endregion + + [Serializable] + public class TcpUserPasswordPair { + public TcpUserPasswordPair(string username, string password) { + this.username = username; + this.password = password; + } + + private string username; + + public string Username { + get { + return this.username; + } + } + + private string password; + + public string Password { + get { + return this.password; + } + } + } } \ No newline at end of file Modified: NMail/trunk/NMail/IO/TcpClientChannel.cs =================================================================== --- NMail/trunk/NMail/IO/TcpClientChannel.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpClientChannel.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -17,13 +17,16 @@ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Text; +using NMail.Authentication; using NMail.DataTypes; namespace NMail.IO { @@ -34,16 +37,38 @@ /// <summary> /// The provider to use. /// </summary> - IClientChannelSinkProvider clientSinkProvider; + private IClientChannelSinkProvider clientSinkProvider; /// <summary> + /// The tranport sink provider. + /// </summary> + private TcpClientTransportSinkProvider transportSinkProvider; + + /// <summary> /// Creates a new client channel with the given provider. /// </summary> /// <param name="clientSinkProvider">The provider to use.</param> - public TcpClientChannel(IClientChannelSinkProvider clientSinkProvider) { + public TcpClientChannel(IClientChannelSinkProvider clientSinkProvider, GetAuthDetailsDelegate getAuthDetailsCallback, ChannelAuthComplete authCompleteCallback) { this.clientSinkProvider = clientSinkProvider; + + this.transportSinkProvider = new TcpClientTransportSinkProvider(getAuthDetailsCallback, null, authCompleteCallback); } + /// <summary> + /// Creates a new client channel with the given provider. + /// </summary> + /// <param name="clientSinkProvider">The provider to use.</param> + /// <param name="certValidationCallback">The certificate to use to validate the remote server's certificate.</param> + public TcpClientChannel(IClientChannelSinkProvider clientSinkProvider, GetAuthDetailsDelegate getAuthDetailsCallback, RemoteCertificateValidationCallback certValidationCallback, ChannelAuthComplete authCompleteCallback) { + this.clientSinkProvider = clientSinkProvider; + + this.transportSinkProvider = new TcpClientTransportSinkProvider(getAuthDetailsCallback, certValidationCallback, authCompleteCallback); + + if (this.clientSinkProvider == null) { + this.clientSinkProvider = new BinaryClientFormatterSinkProvider(); + } + } + #region IChannelSender Members /// <summary> /// Returns a channel message sink that delivers messages to the specified URL @@ -73,6 +98,9 @@ } if (TcpChannel.ValidUrl(url)) { + // Parse the object URI + TcpChannel.ParseUrl(url, out objectURI); + // Find the last provider IClientChannelSinkProvider provider = this.clientSinkProvider; while (provider.Next != null) { @@ -80,19 +108,16 @@ } // Add our transport to the end of the chain - provider.Next = new TcpClientTransportSinkProvider(); + provider.Next = this.transportSinkProvider; - // Parse out the object URI - TcpChannel.ParseUrl(url, out objectURI); - - // Return the new sink return (IMessageSink) this.clientSinkProvider.CreateSink(this, url, remoteChannelData); + } else { // The URL is not for our channel. objectURI = null; return null; } - } + } #endregion #region IChannel Members @@ -132,4 +157,8 @@ } #endregion } + + public delegate TcpUserPasswordPair GetAuthDetailsDelegate(object sender); + + public delegate void ChannelAuthComplete(IAuthenticationToken authToken); } Modified: NMail/trunk/NMail/IO/TcpClientTransportSink.cs =================================================================== --- NMail/trunk/NMail/IO/TcpClientTransportSink.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpClientTransportSink.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; @@ -28,6 +29,7 @@ using log4net; +using NMail.Authentication; using NMail.DataTypes; using NMail.Helper; @@ -52,11 +54,25 @@ private int port; /// <summary> + /// The callback to use to validate the remote certificate. + /// </summary> + RemoteCertificateValidationCallback certValidationCallback; + + GetAuthDetailsDelegate getAuthDetailsCallback; + + ChannelAuthComplete authCompleteCallback; + + /// <summary> /// Creates a new sink with the given url. /// </summary> /// <param name="url">The URL to connect to.</param> /// <param name="remoteChannelData">Channel data optionally containing the URL.</param> - public TcpClientTransportSink(string url, object remoteChannelData) { + /// <param name="certValidationCallback">The callback to use to validate the remote certificate.</param> + public TcpClientTransportSink(string url, object remoteChannelData, GetAuthDetailsDelegate getAuthDetailsCallback, RemoteCertificateValidationCallback certValidationCallback, ChannelAuthComplete authCompleteCallback) { + this.getAuthDetailsCallback = getAuthDetailsCallback; + this.certValidationCallback = certValidationCallback; + this.authCompleteCallback = authCompleteCallback; + if (TcpChannel.ValidUrl(url)) { string objectURI; TcpChannel.ParseUrl(url, out this.host, out this.port, out objectURI); @@ -176,6 +192,20 @@ } #endregion + IAuthenticationToken authToken; + + public IAuthenticationToken AuthToken { + get { + return this.authToken; + } + } + + public bool Connected { + get { + return this.connection.Connected; + } + } + /// <summary> /// The connection used to communicate with the server. /// </summary> @@ -194,7 +224,34 @@ string response = connection.ReadLine(); if (response.Trim().ToLower() == "nmail remoting channel") { this.connection.WriteLine("OK"); - this.connection.StartTlsAsClient(this.host.ToString()); + + // Go encrypted... + if (this.certValidationCallback == null) { + this.connection.StartTlsAsClient(this.host.ToString()); + } else { + this.connection.StartTlsAsClient(this.host.ToString(), this.certValidationCallback); + } + + if (this.connection.Encrypted) { + while (this.connection.Connected && this.authToken == null) { + // Get the auth details + TcpUserPasswordPair authDetails = this.getAuthDetailsCallback(this); + + // Send them to the server + this.connection.Write(authDetails); + this.authToken = (IAuthenticationToken) this.connection.Read(); + } + + if (this.authToken == null) { + throw new InvalidOperationException("Failed to authenticated to the server."); + } + + // Notify the caller that the auth token has arrived + this.authCompleteCallback(authToken); + + } else { + throw new InvalidOperationException("Failed to establish a secure connection to the server."); + } } } } Modified: NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs =================================================================== --- NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpClientTransportSinkProvider.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -17,18 +17,43 @@ using System; using System.Collections; +using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Text; +using NMail.Authentication; +using NMail.DataTypes; + namespace NMail.IO { /// <summary> /// A client transport sink provider for the NMail TCP channel. /// </summary> public class TcpClientTransportSinkProvider : IClientChannelSinkProvider { + + /// <summary> + /// The callback to use to validate the remote server's certificate. + /// </summary> + private RemoteCertificateValidationCallback certValidationCallback; + + private GetAuthDetailsDelegate getAuthDetailsCallback; + + private ChannelAuthComplete authCompleteCallback; + + /// <summary> + /// Creates a new provider with the given certificate validation callback. + /// </summary> + /// <param name="certValidationCallback">The callback to use to validation teh remote server's certificate null for the default.</param> + public TcpClientTransportSinkProvider(GetAuthDetailsDelegate getAuthDetailsCallback, RemoteCertificateValidationCallback certValidationCallback, ChannelAuthComplete authCompleteCallback) { + this.getAuthDetailsCallback = getAuthDetailsCallback; + this.certValidationCallback = certValidationCallback; + this.authCompleteCallback = authCompleteCallback; + } + #region IClientChannelSinkProvider Members /// <summary> /// Creates a sink chain. @@ -50,9 +75,31 @@ /// this endpoint. /// </returns> public IClientChannelSink CreateSink(IChannelSender channel, string url, object remoteChannelData) { - return new TcpClientTransportSink(url, remoteChannelData); + Host host; + int port; + string objectUri; + + TcpChannel.ParseUrl(url, out host, out port, out objectUri); + + string key = host.ToString() + ":" + port; + + lock (this) { + if (sinkMap.ContainsKey(key) && !sinkMap[key].Connected) { + // Transport has lost its connection + this.sinkMap.Remove(key); + } + + // Create a transport if needed + if (!sinkMap.ContainsKey(key)) { + this.sinkMap.Add(key, new TcpClientTransportSink(url, remoteChannelData, this.getAuthDetailsCallback, this.certValidationCallback, this.authCompleteCallback)); + } + + return this.sinkMap[key]; + } } + private Dictionary<string, TcpClientTransportSink> sinkMap = new Dictionary<string, TcpClientTransportSink>(); + /// <summary> /// Gets or sets the next sink provider in the channel sink provider chain. /// </summary> @@ -61,7 +108,7 @@ return null; } set { - throw new ArgumentException("This provider has to be the last in the chain."); + // Ignore: this provider has to be the last in the chain. } } #endregion Modified: NMail/trunk/NMail/IO/TcpServerChannel.cs =================================================================== --- NMail/trunk/NMail/IO/TcpServerChannel.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpServerChannel.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -29,6 +29,7 @@ using log4net; +using NMail.Authentication; using NMail.DataTypes; using NMail.Helper; @@ -48,11 +49,21 @@ private int port; /// <summary> + /// The bind IP address to report to report clients. + /// </summary> + private string bindAddress; + + /// <summary> /// The certificate to use for SSL. /// </summary> private X509Certificate2 certificate; /// <summary> + /// The authentication provider to use. + /// </summary> + private IAuthenticationProvider authProvider; + + /// <summary> /// The sink to pass any incoming messages to. /// </summary> private IServerChannelSink nextSink; @@ -63,11 +74,20 @@ /// <param name="port">The port to listen on.</param> /// <param name="certificate">The certificate to use for SSL.</param> /// <param name="serverSinkProvider">The provider.</param> - public TcpServerChannel(int port, X509Certificate2 certificate, IServerChannelSinkProvider serverSinkProvider) { + public TcpServerChannel(int port, X509Certificate2 certificate, IAuthenticationProvider authProvider, IServerChannelSinkProvider serverSinkProvider) { this.port = port; this.certificate = certificate; + this.authProvider = authProvider; - string[] urls = { TcpChannel.UrlPrefix + "0.0.0.0:" + this.port }; + // This is needed to report a valid IP to clients asking for channel data + IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName()); + if (hostEntry.AddressList.Length == 0) { + throw new Exception("IP address could not be determined for this host."); + } + this.bindAddress = hostEntry.AddressList[0].ToString(); + + string[] urls = new string[1]; + urls[0] = GetUrlForChannel(); this.channelData = new ChannelDataStore(urls); // Collect channel data for all providers @@ -108,10 +128,14 @@ objectURI = '/' + objectURI; } - urls[0] = TcpChannel.UrlPrefix + "0.0.0.0:" + this.port + objectURI; + urls[0] = GetUrlForChannel() + objectURI; return urls; } + public string GetUrlForChannel() { + return TcpChannel.UrlPrefix + this.bindAddress + ":" + this.port; + } + /// <summary> /// Instructs the current channel to start listening for requests. /// </summary> @@ -214,7 +238,7 @@ while (true) { Socket client = socket.AcceptSocket(); - new TcpServerTransportSink(this.nextSink, this.certificate, client); + new TcpServerTransportSink(this.nextSink, this.certificate, this.authProvider, client); } } catch (SocketException e) { // Ignore interrupted exception during shutdown Modified: NMail/trunk/NMail/IO/TcpServerTransportSink.cs =================================================================== --- NMail/trunk/NMail/IO/TcpServerTransportSink.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpServerTransportSink.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -28,6 +28,7 @@ using log4net; +using NMail.Authentication; using NMail.DataTypes; using NMail.Helper; @@ -51,17 +52,20 @@ /// </summary> protected IServerChannelSink nextSink; + protected IAuthenticationProvider authProvider; + /// <summary> /// Creates a new transport sink with the given details. /// </summary> /// <param name="nextSink">The next sink in the chain.</param> /// <param name="certificate">The certificate to use in SSL.</param> /// <param name="client">The socket to the remote client.</param> - public TcpServerTransportSink(IServerChannelSink nextSink, X509Certificate2 certificate, Socket client) { + public TcpServerTransportSink(IServerChannelSink nextSink, X509Certificate2 certificate, IAuthenticationProvider authProvider, Socket client) { this.nextSink = nextSink; this.connection.Create(client); this.connection.Certificate = certificate; - + this.authProvider = authProvider; + // Create a new thread to read requests with ThreadHelper th = new ThreadHelper(new WaitCallback(processConnection), null); Thread processThread = new Thread(new ThreadStart(th.CallDelegate)); @@ -74,56 +78,89 @@ /// </summary> /// <param name="unused">An unused argument.</param> private void processConnection(object unused) { - // Present the welcome message and await a valid response - this.connection.WriteLine("NMail Remoting Channel"); - string response = this.connection.ReadLine(); + Thread.CurrentThread.Name = "NMail TCP server remoting thread."; - // Check that we have a valid client - if (response.Trim().ToLower() != "ok") { - this.connection.Close(); - } + try { + // Present the welcome message and await a valid response + this.connection.WriteLine("NMail Remoting Channel"); + string response = this.connection.ReadLine(); - // Go encrypted... - this.connection.StartTlsAsServer(); + // Check that we have a valid client + if (response.Trim().ToLower() != "ok") { + this.connection.Close(); + } - while (this.connection.Connected) { - // Get the next request from the client - TcpMessage request = (TcpMessage) this.connection.Read(); - MemoryStream requestStream = new MemoryStream(request.Data); + // Go encrypted... + this.connection.StartTlsAsServer(); - // Get the message Id - string messageId = (string) request.Headers["__Id"]; + int authAttempts = 0; + bool authenticated = false; - // Strip off all of the Url except the object Uri - string uri = (string) request.Headers[CommonTransportKeys.RequestUri]; - TcpChannel.ParseUrl(uri, out uri); - if (uri != null) { - request.Headers[CommonTransportKeys.RequestUri] = uri; + // Try to authenticate the user + while (this.connection.Connected && !authenticated && authAttempts < 3) { + TcpUserPasswordPair authDetails = (TcpUserPasswordPair) this.connection.Read(); + + // Attempt to authenticate the user + IAuthenticationToken authToken = this.authProvider.Authenticate(authDetails.Username, authDetails.Password); + + authAttempts++; + authenticated = (authToken != null); + this.connection.Write(authToken); } - ServerChannelSinkStack sinkStack = new ServerChannelSinkStack(); - sinkStack.Push(this, messageId); + if (authAttempts >= 3) { + // Auth failed + this.connection.Close(); + return; + } - IMessage responseMessage; - ITransportHeaders responseHeaders; - Stream responseStream; + while (this.connection.Connected) { + // Get the next request from the client + TcpMessage request = (TcpMessage) this.connection.Read(); + MemoryStream requestStream = new MemoryStream(request.Data); - // Send the request down the chain - ServerProcessing processing = this.nextSink.ProcessMessage(sinkStack, - null, - request.Headers, - requestStream, - out responseMessage, - out responseHeaders, - out responseStream); + // Get the message Id + string messageId = (string) request.Headers["__Id"]; - // Check if a response is needed - if (processing == ServerProcessing.Complete) { - responseHeaders["__Id"] = messageId; + // Strip off all of the Url except the object Uri + string uri = (string) request.Headers[CommonTransportKeys.RequestUri]; + TcpChannel.ParseUrl(uri, out uri); + if (uri != null) { + request.Headers[CommonTransportKeys.RequestUri] = uri; + } - TcpMessage.SendMessage(this.connection, responseStream, responseHeaders); - this.connection.Flush(); + ServerChannelSinkStack sinkStack = new ServerChannelSinkStack(); + sinkStack.Push(this, messageId); + + IMessage responseMessage; + ITransportHeaders responseHeaders; + Stream responseStream; + + // Send the request down the chain + ServerProcessing processing = this.nextSink.ProcessMessage(sinkStack, + null, + request.Headers, + requestStream, + out responseMessage, + out responseHeaders, + out responseStream); + + // Check if a response is needed + if (processing == ServerProcessing.Complete) { + responseHeaders["__Id"] = messageId; + + TcpMessage.SendMessage(this.connection, responseStream, responseHeaders); + this.connection.Flush(); + } } + } catch (SocketException) { + // Ignore + + } catch (IOException) { + // Ignore + + } catch (Exception ex) { + log.Debug("Unhandled exception.", ex); } } Modified: NMail/trunk/NMail/IO/TcpTextConnection.cs =================================================================== --- NMail/trunk/NMail/IO/TcpTextConnection.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/IO/TcpTextConnection.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -524,21 +524,35 @@ } } + #region TLS + /// <summary> + /// Starts TLS negotiation as a client. + /// </summary> + /// <param name="host">The name of the remote host.</param> public void StartTlsAsClient(string host) { - this.sslStream = new SslStream(this.networkStream, true, new RemoteCertificateValidationCallback(certificateValidationCallback)); + this.sslStream = new SslStream(this.networkStream, true); this.sslStream.AuthenticateAsClient(host); } + /// <summary> + /// Starts TLS negotiation as a client. + /// </summary> + /// <param name="host">The name of the remote host.</param> + /// <param name="certValidationCallback">The callback used to validate the remote certificate.</param> + public void StartTlsAsClient(string host, RemoteCertificateValidationCallback certValidationCallback) { + this.sslStream = new SslStream(this.networkStream, true, certValidationCallback); + this.sslStream.AuthenticateAsClient(host); + } + + /// <summary> + /// Starts TLS negotiation as a server. + /// </summary> public void StartTlsAsServer() { - this.sslStream = new SslStream(this.networkStream, true, new RemoteCertificateValidationCallback(certificateValidationCallback)); + this.sslStream = new SslStream(this.networkStream, true); this.sslStream.AuthenticateAsServer(this.certificate); } + #endregion - private bool certificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { - - return true; - } - #region Properties /// <summary> /// Returns if the connection is encrypted. Modified: NMail/trunk/NMail/NMail.csproj =================================================================== --- NMail/trunk/NMail/NMail.csproj 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail/NMail.csproj 2006-05-06 15:33:43 UTC (rev 29) @@ -78,10 +78,6 @@ <Name>log4net</Name> <HintPath>..\References\log4net.dll</HintPath> </Reference> - <Reference Include="Mono.Security"> - <Name>Mono.Security</Name> - <HintPath>..\References\Mono.Security.dll</HintPath> - </Reference> <Reference Include="nunit.framework"> <Name>nunit.framework</Name> <HintPath>..\References\nunit.framework.dll</HintPath> @@ -113,7 +109,6 @@ <SubType>Code</SubType> </Compile> <Compile Include="Authentication\IHashAuthProvider.cs" /> - <Compile Include="Authentication\IPasswordAuthProvider.cs" /> <Compile Include="Authentication\NullAuthentication.cs"> <SubType>Code</SubType> </Compile> Modified: NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Command/AddUserCommand.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,6 +20,7 @@ using System.Text; using NMail; +using NMail.Authentication; using NMail.DataTypes; namespace NMail.Administration.Console.Command { @@ -27,8 +28,11 @@ private ILocalStore localStore; - internal AddUserCommand(ILocalStore localStore) { + private IAuthenticationToken authToken; + + internal AddUserCommand(ILocalStore localStore, IAuthenticationToken authToken) { this.localStore = localStore; + this.authToken = authToken; } #region IConsoleCommand Members @@ -89,7 +93,7 @@ } } - LocalStoreUserResult result = this.localStore.CreateUser(null, username, warnQuota, hardQuota, null); + LocalStoreUserResult result = this.localStore.CreateUser(this.authToken, username, warnQuota, hardQuota, null); if (result == LocalStoreUserResult.AlreadyExists) { System.Console.WriteLine("User with the the same username already exists."); Modified: NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Command/ListUsersCommand.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,6 +20,7 @@ using System.Text; using NMail; +using NMail.Authentication; using NMail.DataTypes; namespace NMail.Administration.Console.Command { @@ -27,8 +28,11 @@ private ILocalStore localStore; - internal ListUsersCommand(ILocalStore localStore) { + private IAuthenticationToken authToken; + + internal ListUsersCommand(ILocalStore localStore, IAuthenticationToken authToken) { this.localStore = localStore; + this.authToken = authToken; } #region IConsoleCommand Members @@ -50,7 +54,7 @@ } public void Process(string[] commandTokens) { - LocalStoreUser[] users = this.localStore.GetUsers(null); + LocalStoreUser[] users = this.localStore.GetUsers(this.authToken); System.Console.WriteLine(); System.Console.WriteLine(string.Format("{0,-7} {1,-25} {2,-10} {3,-10}", "User Id", "Username", "Warn Quota", "Hard Quota")); Modified: NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Context/LocalStoreContext.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -20,18 +20,19 @@ using System.Text; using NMail.Administration.Console.Command; +using NMail.Authentication; namespace NMail.Administration.Console.Context { class LocalStoreContext : AbstractContext { - internal LocalStoreContext(AbstractContext parentContext, ILocalStore localStore) { + internal LocalStoreContext(AbstractContext parentContext, ILocalStore localStore, IAuthenticationToken authToken) { this.parentContext = parentContext; this.localStore = localStore; this.name = "Local Store"; - this.commands.Add("listusers", new ListUsersCommand(this.localStore)); + this.commands.Add("listusers", new ListUsersCommand(this.localStore, authToken)); this.commands.Add("listaddresses", new ListUsersAddressesCommand(this.localStore)); - this.commands.Add("adduser", new AddUserCommand(this.localStore)); + this.commands.Add("adduser", new AddUserCommand(this.localStore, authToken)); this.commands.Add("deleteuser", new DeleteUserCommand(this.localStore)); } Modified: NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs =================================================================== --- NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/Context/TopLevelContext.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -16,26 +16,71 @@ */ using System; +using System.Collections; using System.Collections.Generic; +using System.Net.Security; using System.Runtime.Remoting; +using System.Runtime.Remoting.Channels; +using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Threading; using NMail; using NMail.Administration.Console.Command; +using NMail.Authentication; +using NMail.IO; using NMail.Server; namespace NMail.Administration.Console.Context { public class TopLevelContext : AbstractContext { protected RemoteAdministration remoteAdmin; + protected IAuthenticationToken authToken; + + private ManualResetEvent authCompleteEvent = new ManualResetEvent(false); + public TopLevelContext() { - this.remoteAdmin = (RemoteAdministration)RemotingServices.Connect(Type.GetType("NMail.Server.RemoteAdministration, NMail.Server"), "ipc://NMailAdministration/RemoteAdministration.rem"); + // Setup the remoting channel + IDictionary props = new Hashtable(); + props["port"] = "7877"; + props["certificateValidation"] = new RemoteCertificateValidationCallback(remoteCertificateValidation); + //TcpChannel channel = new TcpChannel(props, null, null); + TcpClientChannel channel = new TcpClientChannel(null, new GetAuthDetailsDelegate(GetAuthDetails), new RemoteCertificateValidationCallback(remoteCertificateValidation), new ChannelAuthComplete(AuthCompleteCallback)); + ChannelServices.RegisterChannel(channel, false); + + string url = "nmtcp://127.0.0.1:7877/RemoteAdministration.rem"; + this.remoteAdmin = (RemoteAdministration)RemotingServices.Connect(Type.GetType("NMail.Server.RemoteAdministration, NMail.Server"), url); + // Wait until the channel gives us an authentication token + this.authCompleteEvent.WaitOne(); + this.name = "NMail"; this.commands.Add("exit", new ExitCommand()); - this.contexts.Add("localstore", new LocalStoreContext(this, this.remoteAdmin.NMailServer.LocalStore)); + this.contexts.Add("localstore", new LocalStoreContext(this, this.remoteAdmin.NMailServer.LocalStore, this.authToken)); } + + public bool remoteCertificateValidation(object sender, X509Certificate certificate, X509Chain x509Chain, SslPolicyErrors policyErrors) { + // TODO: check with the user if the cert if ok... + return true; + } + + public TcpUserPasswordPair GetAuthDetails(object sender) { + System.Console.Write("Username: "); + string username = System.Console.ReadLine(); + + System.Console.Write("Password (will be visible): "); + string password = System.Console.ReadLine(); + + return new TcpUserPasswordPair(username, password); + } + + public void AuthCompleteCallback(IAuthenticationToken authToken) { + this.authToken = authToken; + + // Notify the main thread that we have a token + this.authCompleteEvent.Set(); + } } } Modified: NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj =================================================================== --- NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Administration.Console/NMail.Administration.Console.csproj 2006-05-06 15:33:43 UTC (rev 29) @@ -30,6 +30,7 @@ <ItemGroup> <Reference Include="System" /> <Reference Include="System.Data" /> + <Reference Include="System.Runtime.Remoting" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> Modified: NMail/trunk/NMail.ImapService/ImapServiceConnection.cs =================================================================== --- NMail/trunk/NMail.ImapService/ImapServiceConnection.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.ImapService/ImapServiceConnection.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -32,7 +32,7 @@ string certFile = ImapServiceConfiguration.Current.CertificateFile; if (certFile != null && certFile.Trim() != string.Empty) { - this.Certificate = new X509Certificate2(certFile); + this.Certificate = new X509Certificate2(certFile, ""); } // TODO: setup IMap specific options, eg line length = ????, etc Modified: NMail/trunk/NMail.ImapService/State/ConnectedState.cs =================================================================== --- NMail/trunk/NMail.ImapService/State/ConnectedState.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.ImapService/State/ConnectedState.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -85,7 +85,7 @@ public override void ProcessCommand(LoginCommand cmd) { if (Session.Connection.Encrypted) { - IPasswordAuthProvider authProvider = (IPasswordAuthProvider) NMailConfiguration.Current.AuthenticationProvider; + IAuthenticationProvider authProvider = (IAuthenticationProvider) NMailConfiguration.Current.AuthenticationProvider; IAuthenticationToken authToken = authProvider.Authenticate(cmd.Username, cmd.Password); if (authToken != null) { Modified: NMail/trunk/NMail.LocalStore/LocalStore.cs =================================================================== --- NMail/trunk/NMail.LocalStore/LocalStore.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.LocalStore/LocalStore.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -68,7 +68,7 @@ return new DeliveryResult(DeliveryResultType.PermanentError, "Invalid Folder."); } - BasicAuthToken authToken = new BasicAuthToken(username); + IAuthenticationToken authToken = NMailConfiguration.Current.AuthenticationProvider.CreateAuthToken(username); // Pass through the default chain DeliveryResult result; @@ -153,7 +153,8 @@ "User has no inbox in the local store."); } - BasicAuthToken authToken = new BasicAuthToken(username); + IAuthenticationToken authToken = NMailConfiguration.Current.AuthenticationProvider.CreateAuthToken(username); + LocalStoreDelivery lsd = new LocalStoreDelivery(recipient, inboxFolder); // Pass through the default chain Modified: NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql =================================================================== --- NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStore.sql 2006-05-06 15:33:43 UTC (rev 29) @@ -61,7 +61,7 @@ Identifier VARCHAR(100) NOT NULL, FolderId INT NOT NULL, Allow BOOLEAN NOT NULL, - Privilege INT NOT NULL, + Privilege INT UNSIGNED NOT NULL, PRIMARY KEY(FolderAclId), UNIQUE KEY (FolderId, Identifier), FOREIGN KEY (FolderId) REFERENCES Folder (FolderId) ON DELETE CASCADE @@ -73,7 +73,7 @@ Identifier VARCHAR(100) NOT NULL, Resource VARCHAR(100) NOT NULL, Allow BOOLEAN NOT NULL, - Privilege INT NOT NULL, + Privilege INT UNSIGNED NOT NULL, PRIMARY KEY (AclId), UNIQUE KEY (Resource, Identifier) ) TYPE=InnoDB; @@ -126,6 +126,6 @@ INSERT INTO User (UserName, Password, UserFolderId) VALUES ("Administrator", "changeme", 2); INSERT INTO Folder (NamespaceId, Name, OwnerUserId, NextMessageId) VALUES (1, "Administrator", 1, 1); INSERT INTO Folder (NamespaceId, Name, OwnerUserId, NextMessageId, ParentFolderId) VALUES (1, "Administrator.INBOX", 1, 1, 1); -INSERT INTO Acl (FolderId, Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv) VALUES (1, "Administrator", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); -INSERT INTO Acl (FolderId, Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv) VALUES (2, "Administrator", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); +INSERT INTO FolderAcl (FolderId, Identifier, Allow, Privilege) VALUES (1, "Administrator", 1, 0xffffff); -- All privs +INSERT INTO FolderAcl (FolderId, Identifier, Allow, Privilege) VALUES (2, "Administrator", 1, 0xffffff); -- All privs INSERT INTO Subscription (UserId, FolderId) VALUES (1, 2); \ No newline at end of file Modified: NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs =================================================================== --- NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -1274,20 +1274,10 @@ private void setStoreFolderAce(StoreFolder folder, StoreFolderAce ace, MySqlConnection cnn, MySqlTransaction transaction) { using (MySqlCommand cmd = cnn.CreateCommand()) { - cmd.CommandText = "REPLACE Acl (FolderId, Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv) VALUES (?FolderId, ?Identifier, ?AllowPrivs, ?LookupPriv, ?ReadPriv, ?SeenPriv, ?WritePriv, ?InsertPriv, ?PostPriv, ?CreatePriv, ?DeletePriv, ?AdminPriv)"; + cmd.CommandText = "REPLACE Acl (FolderId, Identifier, Allow, Privilege) VALUES (?FolderId, ?Identifier, ?AllowPrivs, ?LookupPriv, ?ReadPriv, ?SeenPriv, ?WritePriv, ?InsertPriv, ?PostPriv, ?CreatePriv, ?DeletePriv, ?AdminPriv)"; cmd.Parameters.Add("FolderId", folder.FolderId); cmd.Parameters.Add("Identifier", ace.Identifier); - cmd.Parameters.Add("AllowPrivs", (ace.AceType == AcePrivilegeType.Allow)); - cmd.Parameters.Add("LookupPriv", ((ace.Privilege & StoreFolderPrivilege.Lookup) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("ReadPriv", ((ace.Privilege & StoreFolderPrivilege.Read) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("SeenPriv", ((ace.Privilege & StoreFolderPrivilege.AlterSeenFlag) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("WritePriv", ((ace.Privilege & StoreFolderPrivilege.Write) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("InsertPriv", ((ace.Privilege & StoreFolderPrivilege.Insert) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("PostPriv", ((ace.Privilege & StoreFolderPrivilege.Post) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("CreatePriv", ((ace.Privilege & StoreFolderPrivilege.CreateFolders) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("DeletePriv", ((ace.Privilege & StoreFolderPrivilege.Delete) != StoreFolderPrivilege.None)); - cmd.Parameters.Add("AdminPriv", ((ace.Privilege & StoreFolderPrivilege.Admin) != StoreFolderPrivilege.None)); - + cmd.Parameters.Add("Privilege", Convert.ToUInt32(ace.Privilege)); int count = cmd.ExecuteNonQuery(); if (count != 1 && count != 2) { // Replace returns a count of 2 @@ -1319,43 +1309,15 @@ using (MySqlConnection cnn = GetConnection()) { using (MySqlCommand cmd = cnn.CreateCommand()) { - cmd.CommandText = "SELECT Identifier, AllowPrivs, LookupPriv, ReadPriv, SeenPriv, WritePriv, InsertPriv, PostPriv, CreatePriv, DeletePriv, AdminPriv FROM Acl WHERE FolderId = ?FolderId"; + cmd.CommandText = "SELECT Identifier, Allow, Privilege FROM Acl WHERE FolderId = ?FolderId"; cmd.Parameters.Add("FolderId", folder.FolderId); using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { string identifier = (string) reader["Identifier"]; - AcePrivilegeType aceType = (((sbyte)reader["AllowPrivs"]) == 1)? AcePrivilegeType.Allow : AcePrivilegeType.Deny; + AcePrivilegeType aceType = (((sbyte)reader["Allow"]) == 1)? AcePrivilegeType.Allow : AcePrivilegeType.Deny; + StoreFolderPrivilege privilege = (StoreFolderPrivilege) reader["Privilege"]; - StoreFolderPrivilege privilege = StoreFolderPrivilege.None; - if ((sbyte)reader["LookupPriv"] == 1) { - privilege |= StoreFolderPrivilege.Lookup; - } - if ((sbyte)reader["ReadPriv"] == 1) { - privilege |= StoreFolderPrivilege.Read; - } - if ((sbyte)reader["SeenPriv"] == 1) { - privilege |= StoreFolderPrivilege.AlterSeenFlag; - } - if ((sbyte)reader["WritePriv"] == 1) { - privilege |= StoreFolderPrivilege.Write; - } - if ((sbyte)reader["InsertPriv"] == 1) { - privilege |= StoreFolderPrivilege.Insert; - } - if ((sbyte)reader["PostPriv"] == 1) { - privilege |= StoreFolderPrivilege.Post; - } - if ((sbyte)reader["CreatePriv"] == 1) { - privilege |= StoreFolderPrivilege.CreateFolders; - } - if ((sbyte)reader["DeletePriv"] == 1) { - privilege |= StoreFolderPrivilege.Delete; - } - if ((sbyte)reader["AdminPriv"] == 1) { - privilege |= StoreFolderPrivilege.Admin; - } - StoreFolderAce ace = new StoreFolderAce(identifier, privilege, aceType); result.SetAce(ace); } @@ -1409,16 +1371,25 @@ #region Auth Provider #region IAuthProvider - public DateTime GetCredentialsExpiry(IAuthenticationToken user) { + public DateTime GetTokenExpiry(IAuthenticationToken user) { // TODO: fix this! return DateTime.MaxValue; } + public bool TokenExpired(IAuthenticationToken user) { + // TODO: fix this!! + return false; + } + + public bool ValidToken(IAuthenticationToken user) { + // TODO: fix this!! + return true; + } + public bool IsLockedOut(IAuthenticationToken user) { // TODO: fix this! return false; } - #endregion #region IHashAuthProvider Members @@ -1439,7 +1410,8 @@ if (dbHash == hash) { // Hashes match, return a valid token - return new BasicAuthToken(username); + // TODO: get the password expiry details + return new BasicAuthToken(username, DateTime.MaxValue); } } } @@ -1454,7 +1426,7 @@ #endregion - #region IPasswordAuthProvider Members + #region IAuthenticationProvider Members public IAuthenticationToken Authenticate(string username, string password) { // Get the hash stored in the database. @@ -1466,7 +1438,8 @@ if (dbHash == password) { // Hashes match, return a valid token - return new BasicAuthToken(username); + // TODO: get the password expiry details + return new BasicAuthToken(username, DateTime.MaxValue); } } } @@ -1475,6 +1448,24 @@ return null; } + public IAuthenticationToken CreateAuthToken(string username) { + // Get the hash stored in the database. + using (MySqlConnection cnn = GetConnection()) { + using (MySqlCommand cmd = cnn.CreateCommand()) { + cmd.CommandText = "SELECT COUNT(*) FROM User WHERE Username = ?Username"; + cmd.Parameters.Add("Username", username); + long count = (long) cmd.ExecuteScalar(); + + if (count == 1) { + // TODO: get the password expiry details + return new BasicAuthToken(username, DateTime.MaxValue); + } + } + } + + // No such user + return null; + } #endregion #endregion Modified: NMail/trunk/NMail.Server/RemoteAdministration.cs =================================================================== --- NMail/trunk/NMail.Server/RemoteAdministration.cs 2006-05-06 14:52:35 UTC (rev 28) +++ NMail/trunk/NMail.Server/RemoteAdministration.cs 2006-05-06 15:33:43 UTC (rev 29) @@ -17,11 +17,13 @@ using System; using System.Collections; +using System.Net.Security; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Serialization.Formatters; using System.Security.Cryptography.X509Certificates; +using NMail.Configuration; using NMail.IO; namespace NMail.Server { @@ -61,15 +63,15 @@ props["port"] = "7877"; props["isServer"] = "yes"; props["certificate"] = new X509Certificate2("NMail.pfx", ""); + props["authProvider"] = NMailConfiguration.Current.AuthenticationProvider; TcpChannel channel = new TcpChannel(props, null, provider); ChannelServices.RegisterChannel(channel, false); // Register our remote administration interface - RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteAdministration), "RemoteAdministration.rem", WellKnownObjectMode.Singleton); + RemoteAdministration ra = new RemoteAdministration(); + ra.NMailServer = server; + RemotingServices.Marshal(ra, "RemoteAdministration.rem", typeof(RemoteAdministration)); - // Connect to the remote admin object to ensure we link in the singleton into our server object. - RemoteAdministration ra = (RemoteAdministration) RemotingServices.Connect(typeof(RemoteAdministration), "nmtcp://127.0.0.1:7877/RemoteAdministration.rem"); - ra.NMailServer = server; return ra; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |