Send mail via SMTP with System.Web.Mail

I was looking for a way to send reports from an web application and I found a lot of code on the net, but the new System.Net.Mail from .NET 2.0 doesn't work with Gmail... so I've searched more and found a lot of good stuff on CodeProject. So here it is the class that I write based on those articles, simple and easy. The only problem is that it can’t send attachments. If anywone knows a way to send attachments using Gmail please let me know.
public sealed class SmtpMailer
{
    private string senderAddress;
    private string senderName;
    private string server;
    private string userName;
    private string password;
    private bool enableAuth;
    private bool enableSsl;
    private int port;

    private string errorMsg;
    public string ErrorMsg
    {
        get { return this.errorMsg; }
    }

    /// <summary>
    /// For public SMTP servers with no authentication
    /// </summary>
    public SmtpMailer(string senderAddress, string senderName, string server)
        : this(senderAddress, senderName, server, null, null, false, false, 25)
    { }

    /// <summary>
    /// For secure SMTP servers with authentication and SSL
    /// </summary>
    public SmtpMailer(string senderAddress, string senderName, string server, 
        string userName, string password, bool enableAuth, bool enableSsl, int port)
    {
        this.senderAddress = senderAddress;
        this.senderName = senderName;
        this.server = server;
        this.userName = userName;
        this.password = password;
        this.enableAuth = enableAuth;
        this.enableSsl = enableSsl;
        this.port = port;
    }

    public bool Send(string toAddress, string subject, string body, bool isHtml)
    {
        try

        {
            MailMessage mailMsg = new MailMessage();

            mailMsg.To = toAddress;
            mailMsg.Headers.Add("From", string.Format("{0} <{1}>", senderName, senderAddress));
            mailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"] = server;
            mailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"] = port;
            mailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2;

            if (enableAuth)
            {
                mailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1;
                mailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/sendusername"] = userName;
                mailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/sendpassword"] = password;
            }

            if (enableSsl)
            {
                mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", "true");
            }

            if (isHtml)
            {
                mailMsg.BodyFormat = MailFormat.Html;
            }

            mailMsg.BodyEncoding = Encoding.UTF8;
            mailMsg.Subject = subject;
            mailMsg.Body = body;

            SmtpMail.SmtpServer = server;
            SmtpMail.Send(mailMsg);

            return true;
        }
        catch (Exception ex)
        {
            this.errorMsg = ex.Message;
            return false;
        }
    }
}

Filed under ,

Code access protection using Evidence

If you work with multiple assemblies and you want to make sure no one uses your code by calling methods from other applications you can use strong names, first you have to sign with your private key all your components and application that you deploy to the client. If you want your code to be safe obfuscation is required too. So lets suppose I have an assembly that is validating the product serial number at installation time and I want only my application to able to instantiate it. This is the piece of code I must put in the constructor:
public class Activator
{
    public Activator()
    {
        Assembly callerAsm = Assembly.GetCallingAssembly();
        StrongName callerSn = GetStrongName(callerAsm.Evidence);

        Assembly thisAsm = Assembly.GetExecutingAssembly();
        StrongName thisSn = GetStrongName(thisAsm.Evidence);

        if (callerSn == null || thisSn == null || callerSn.PublicKey.ToString() != thisSn.PublicKey.ToString())
        {
            throw new SecurityException("Unauthorized execution detected, caller assemby unknown.");
        }
    }

    private static StrongName GetStrongName(Evidence evidence)
    {
        foreach (object o in evidence)
        {
            if (o is StrongName)
            {
                return o as StrongName;
            }
        }
        return null;
    }

    //protected methods 

}
So when I call Activator a = new Activator(); if my app is not signed with the same strong name as the Activator.dll the security exception will pop up.

Filed under

[AlephFS] File checksum using Adler32

Like the hash provider I need a function that will check for the integrity of the files managed by the web service. But CRC, MD5 and other checksum algorithms eat up a lot of CPU time and memory.
For my checksum function I've decided to use the Adler32 algorithm.The method that I am posting here works with any file size, as a remark, if you have a lot of memory on the server where you are doing checksums, make the buffer as big as you can, it will move faster but will eat more resources.
public static long Adler32Checksum(string filePath, int bufferLenght)
{
    long output = 0;
    int read = 0;

    Adler32 alder = new Adler32();

    byte[] buffer = new byte[bufferLenght];
    if (File.Exists(filePath))
    {
        using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            while ((read = fs.Read(buffer, 0, bufferLenght)) > 0)
            {
                alder.Update(buffer, 0, read);
            }
        }
    }
    output = alder.Value;
    return output;
}

Filed under ,

[AlephFS] Custom Soap Header Authentication

If you are looking at IFileServer interface you will notice that I use two types of security in AlephFS web service. The custom authentication is used when you don’t want to relay on the windows security like active directory. This scenario will need a user database or an XML file that the service can use to make decision based on the user role or group. For this scenario I created a SoapHeader that looks like this:

using System.Web.Services.Protocols;

/// <summary>
/// Authentication Custom Soap Header
/// </summary>
public class AuthHeader : SoapHeader
{
    public string UserName;
    public string Password;
}

The clients that access the web service must use the custom header for authentication every time a method is called. In the web service the methods that use custom security must use the soap header. Here is an example:

public class Service : WebService, IFileServer
{
    public AuthHeader Credentials;
	
[WebMethod, SoapHeader("Credentials", Direction=SoapHeaderDirection.In)]
    public void CreateDir(string dirName)
    {
        ValidateUser(Credentials);
        try
        {
            Directory.CreateDirectory(dirName);
        }
        catch (IOException iox)
        {
		//log error
        }
    }
}

Every time a method is called we must make sure that the client is authorized. To validate the client credential before executing the body of the method we must call ValidateUser.Inside ValidateUser method we can connect to the database for user name and password validation, maybe get the rolls of the user and so on.

private void ValidateUser(AuthHeader Credentials)
{
	if (Credentials.UserName.Length < 1 ||
		Credentials.Password.Length < 1)
	{
		throw new SoapException("Unauthorized", SoapException.ClientFaultCode);
	}
	try
	{
		//TODO: Validate user & pass using database or xml
		if (Credentials.Password != "password")
		{
			throw new SoapException("Unauthorized", SoapException.ClientFaultCode);
		}
	}
	catch
	{
		throw new SoapException("Unauthorized", SoapException.ClientFaultCode);
	}
}

Now that we have implemented the custom authentication on the web server side let’s see how the client can communicate with AlephFS. I am using for testing a windows application. Here comes the client code:

private void CallWs()
{
	//proxy
	AlephFS.AlephFileServerWse ws;
	ws = new Client.AlephFS.AlephFileServerWse();

	//custom header
	AlephFS.AuthHeader authHeader = new Client.AlephFS.AuthHeader();
	authHeader.UserName = "user_name";
	authHeader.Password = "password";
	ws.AuthHeaderValue = authHeader;

	//call method
	try
	{
		ws.CreateDir("MyDocs");
	}
	catch (SoapException ex)
	{
		//log error
	}
}

Filed under

[AlephFS] Research Project

Project Name: AlephFS
Start Date: 08 May 2006
Technologies used: ASP.NET 2.0 & WSE 3.0 & MTOM

I've stated a new research project based on Web Services Enhancements Version 3.0. The goal is to make a FTP server like application but on Soap. I have tried this before on the Net Framework 1.1 using DIME Attachments.
The problem was that Dime could not be used with WS-* because the binary content of the message was sent outside the SoapEnvelope of the XML message. Even if the message is secure the binary attachment is not.WSE 3.0 comes with MTOM (Message Transmission Optimization Mechanism), MTOM fully complies with WS-Security so the entire message is secure.
As long as the project will go on I will post here code that maybe you'll find useful.
The web service is based on the IFileServer interface but this is just the start point.

/// <summary>
/// File Server Interface
/// </summary>
public interface IFileServer
{
    //
    //CUSTOM SECURITY
    //

    /// <summary>
    /// Create a new directory
    /// </summary>
    /// <param name="dirName">Folder name</param>
    void CreateDir(string dirName);
    /// <summary>
    /// Returns the folders within the directory(first level not recursive)
    /// </summary>
    /// <param name="dirName"></param>
    /// <returns></returns>
    StringCollection ListDirs(string dirName);
    /// <summary>
    /// Delete an existing directory and all the content inside it
    /// </summary>
    /// <param name="dirName">Folder name</param>
    void DeleteDir(string dirName);
    /// <summary>
    /// Returns the files within the directory(first level not recursive)
    /// </summary>
    /// <param name="dirName">Folder name</param>
    /// <returns>files list</returns>
    StringCollection ListFiles(string dirName);
    /// <summary>
    /// Returns the files within the directory(recursive)
    /// </summary>
    /// <param name="dirName"></param>
    /// <returns>files list</returns>
    StringCollection ListFilesRecursive(string dirName);
    /// <summary>
    /// Uploads file to specific directory
    /// </summary>
    /// <param name="path">destination folder</param>
    /// <param name="fileName"> file name</param>
    void UploadFile(string path, string fileName, byte[] data);
    /// <summary>
    /// Downloads file from server
    /// </summary>
    /// <param name="path">server relative path to file</param>
    /// <returns>binary data</returns>
    byte[] DownloadFile(string path);
    /// <summary>
    /// Deletes a specific file from the server
    /// </summary>
    /// <param name="path">server relative path to file</param>
    void DeleteFile(string path);

    //
    //WINDOWS IMPERSONATION
    //

    /// <summary>
    /// Create a new directory
    /// </summary>
    /// <param name="dirName">Folder name</param>
    void CreateDirImp(string user, string domain, string password, string dirName);
    /// <summary>
    /// Returns the folders within the directory(first level not recursive)
    /// </summary>
    /// <param name="dirName"></param>
    /// <returns></returns>
    StringCollection ListDirsImp(string user, string domain, string password, string dirName);
    /// <summary>
    /// Delete an existing directory and all the content inside it
    /// </summary>
    /// <param name="dirName">Folder name</param>
    void DeleteDirImp(string user, string domain, string password, string dirName);
    /// <summary>
    /// Returns the files within the directory(first level not recursive)
    /// </summary>
    /// <param name="dirName">Folder name</param>
    /// <returns>files list</returns>
    StringCollection ListFilesImp(string user, string domain, string password, string dirName);
    /// <summary>
    /// Returns the files within the directory(recursive)
    /// </summary>
    /// <param name="dirName"></param>
    /// <returns>files list</returns>
    StringCollection ListFilesRecursiveImp(string user, string domain, string password, string dirName);
    /// <summary>
    /// Uploads file to specific directory
    /// </summary>
    /// <param name="path">destination folder</param>
    /// <param name="fileName"> file name</param>
    void UploadFileImp(string user, string domain, string password, string path, string fileName, byte[] data);
    /// <summary>
    /// Downloads file from server
    /// </summary>
    /// <param name="path">server relative path to file</param>
    /// <returns>binary data</returns>
    byte[] DownloadFileImp(string user, string domain, string password, string path);
    /// <summary>
    /// Deletes a specific file from the server
    /// </summary>
    /// <param name="path">server relative path to file</param>
    void DeleteFileImp(string user, string domain, string password, string path);
}

Filed under

Hash Provider

When dealing with message into an application, and the message that you are receiving or sending is over a not trusted channel you should think about a way to make sure that the message has not been altered. This is why cryptographic hash functions are used.
More on cryptographic hash function you can find here.
Here is a function in C# that can generate for you the hash of a string based on your favorite algorithm.

using System;
using System.Text;
using System.Security.Cryptography;

/// <summary>
/// Hash algorithms
/// </summary>
public enum HashType : int
{
    SHA1,
    SHA256,
    SHA384,
    SHA512,
    MD5,
    RIPEMD160
}

public static class Hash
{
    public static string FromString(string input, HashType hashtype)
    {
        Byte[] clearBytes;
        Byte[] hashedBytes;
        string output = String.Empty;

        switch (hashtype)
        {
            case HashType.RIPEMD160:
                clearBytes = new UTF8Encoding().GetBytes(input);
                RIPEMD160 myRIPEMD160 = RIPEMD160Managed.Create();
                hashedBytes = myRIPEMD160.ComputeHash(clearBytes);
                output = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
                break;
            case HashType.MD5:
                clearBytes = new UTF8Encoding().GetBytes(input);
                hashedBytes = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(clearBytes);
                output = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
                break;
            case HashType.SHA1:
                clearBytes = Encoding.UTF8.GetBytes(input);
                SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
                sha1.ComputeHash(clearBytes);
                hashedBytes = sha1.Hash;
                sha1.Clear();
                output = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
                break;
            case HashType.SHA256:
                clearBytes = Encoding.UTF8.GetBytes(input);
                SHA256 sha256 = new SHA256Managed();
                sha256.ComputeHash(clearBytes);
                hashedBytes = sha256.Hash;
                sha256.Clear();
                output = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
                break;
            case HashType.SHA384:
                clearBytes = Encoding.UTF8.GetBytes(input);
                SHA384 sha384 = new SHA384Managed();
                sha384.ComputeHash(clearBytes);
                hashedBytes = sha384.Hash;
                sha384.Clear();
                output = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
                break;
            case HashType.SHA512:
                clearBytes = Encoding.UTF8.GetBytes(input);
                SHA512 sha512 = new SHA512Managed();
                sha512.ComputeHash(clearBytes);
                hashedBytes = sha512.Hash;
                sha512.Clear();
                output = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
                break;
        }
        return output;
    }
}

Filed under

IIS v6 Manager Class

Handy class if you plan to create sites from your .net application. There are xml comments on it, so if you need more details on how to use it let me know, I'll give you an example.
Here comes the code :)
using System;
using System.DirectoryServices;
using System.ServiceProcess;

/// <summary>
/// IIS Services Schema
/// </summary>
public enum Schema : int
{
	/// <summary>MSFTPSVC</summary>
	FTP = 1,
	/// <summary>W3SVC</summary>

	WEB = 2
}
/// <summary>
/// IIS Virtual Directory manager
/// </summary>
public class IISManager
{
    private static string ftpSchema = "IIsFtpVirtualDir";
    private static string ftpRoot = "/MSFTPSVC/";
    private static string webSchema = "IIsWebVirtualDir";
    private static string webRoot = "/W3SVC/";
    private int serverId = 1;
    private string serverName = "localhost";
    private string root;
    private Schema schema = Schema.WEB;
    private DirectoryEntry deRoot;
    private string errorMessage = string.Empty;

    /// <summary>
    /// Returns last error
    /// </summary>
    public string ErrorMessage
    {
        get { return this.errorMessage; }
    }

    /// <summary>
    /// Default constructor, 
    /// IIS://localhost/W3SVC/1/Root
    /// </summary>
    public IISManager()
    {
        root = "IIS://" + this.serverName + webRoot + this.serverId + "/Root";
        this.deRoot = new DirectoryEntry(this.root);
    }

    /// <summary>
    /// Custom Constructor
    /// </summary>
    /// <param name="serverName">localhost</param>
    /// <param name="serverId">1</param>
    /// <param name="schema">WEB</param>
    public IISManager(string serverName, int serverId, Schema schema)
    {
        this.serverName = serverName;
        this.serverId = serverId;
        this.schema = schema;
        if (this.schema == Schema.FTP)
        {
            root = "IIS://" + this.serverName + ftpRoot + this.serverId + "/Root";
        }
        else

        {
            root = "IIS://" + this.serverName + webRoot + this.serverId + "/Root";
        }

        this.deRoot = new DirectoryEntry(this.root);
    }

    /// <summary>
    /// Check for existing virtual directory
    /// </summary>
    /// <param name="name">virtual directory name</param>
    /// <returns></returns>
    public bool IsDirectory(string name)
    {
        try

        {
            return DirectoryEntry.Exists(root + "/" + name);
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Create a virtual directory
    /// </summary>
    /// <param name="name">virtual directory name</param>
    /// <param name="folderPath">local directory path</param>
    /// <param name="isApplication">create application for web virtual directory</param>
    /// <returns></returns>
    public bool CreateDirectory(string name, string folderPath, bool isApplication)
    {
        if (IsDirectory(name))
        {
            this.errorMessage = "Directory " + name + " exist";
            return false;
        }

        bool ok = true;

        DirectoryEntry deNewVDir;

        try

        {
            deRoot.RefreshCache();

            if (this.schema == Schema.FTP)
            {
                deNewVDir = deRoot.Children.Add(name, ftpSchema);
            }
            else
            {
                deNewVDir = deRoot.Children.Add(name, webSchema);
            }

            deNewVDir.Properties["Path"].Insert(0, folderPath);
            deNewVDir.CommitChanges();
            deRoot.CommitChanges();

            // Create a Web Application
            if (schema == Schema.WEB)
            {
                deNewVDir.Invoke("AppCreate", isApplication);
            }

            // Save Changes

            deNewVDir.CommitChanges();
            deRoot.CommitChanges();
            deNewVDir.Close();
            deRoot.Close();
        }
        catch (Exception ex)
        {
            this.errorMessage = ex.Message;
            ok = false;
        }
        return ok;
    }

    /// <summary>
    /// Delete a virtual directory
    /// </summary>
    /// <param name="name">virtual directory name</param>
    /// <returns></returns>
    public bool DeleteDirectory(string name)
    {
        bool ok = true;

        if (!IsDirectory(name))
        {
            this.errorMessage = "Directory " + name + " does not exist";
            return false;
        }

        Object[] parameters;

        try

        {
            if (this.schema == Schema.FTP)
            {
                parameters = new object[] { ftpSchema, name };
            }
            else
            {
                parameters = new object[] { webSchema, name };
            }
            deRoot.Invoke("Delete", parameters);
            deRoot.CommitChanges();
            deRoot.Close();
        }
        catch (Exception ex)
        {
            this.errorMessage = ex.Message;
            ok = false;
        }
        return ok;

    }

    /// <summary>
    /// Stop IIS Services
    /// </summary>
    /// <param name="schema">MSFTPSVC or W3SVC</param>
    public static void StopIIS(Schema schema)
    {
        ServiceController myServiceController;

        if (schema == Schema.FTP)
        {
            myServiceController = new ServiceController("MSFTPSVC");
        }
        else

        {
            myServiceController = new ServiceController("W3SVC");
        }
        if (null != myServiceController)
        {
            do
            {
                myServiceController.Refresh();
            }
            while

                (myServiceController.Status == ServiceControllerStatus.ContinuePending ||
                myServiceController.Status == ServiceControllerStatus.PausePending ||
                myServiceController.Status == ServiceControllerStatus.StartPending ||
                myServiceController.Status == ServiceControllerStatus.StopPending);

            if (ServiceControllerStatus.Running == myServiceController.Status ||
                ServiceControllerStatus.Paused == myServiceController.Status)
            {
                myServiceController.Stop();
                myServiceController.WaitForStatus(ServiceControllerStatus.Stopped);
            }
            myServiceController.Close();
        }
    }

    /// <summary>
    /// Start IIS Services
    /// </summary>
    /// <param name="schema">MSFTPSVC or W3SVC</param>
    public static void StartIIS(Schema schema)
    {

        ServiceController myServiceController;

        if (schema == Schema.FTP)
        {
            myServiceController = new ServiceController("MSFTPSVC");
        }
        else
        {
            myServiceController = new ServiceController("W3SVC");
        }

        if (null != myServiceController)
        {
            do

            {
                myServiceController.Refresh();
            }
            while
                (myServiceController.Status == ServiceControllerStatus.ContinuePending ||
                myServiceController.Status == ServiceControllerStatus.PausePending ||
                myServiceController.Status == ServiceControllerStatus.StartPending ||
                myServiceController.Status == ServiceControllerStatus.StopPending);

            if (ServiceControllerStatus.Stopped == myServiceController.Status)
            {
                myServiceController.Start();
                myServiceController.WaitForStatus(ServiceControllerStatus.Running);
            }
            else
            {
                if (ServiceControllerStatus.Paused == myServiceController.Status)
                {
                    myServiceController.Continue();
                    myServiceController.WaitForStatus(ServiceControllerStatus.Running);
                }
            }
            myServiceController.Close();
        }
    }
}

Filed under