In my last
post, I described a rather tedious and error prone method for configuring One To One client certificate mappings in IIS 7.5, so with a little bit of
help I created a small WPF application that should ensure the smooth configuration of one to one client certificate mappings.
There is no validation as this is simply a developer tool and I'm too lazy to add it, you can have a look at this
post for an example of textbox validation in WPF.
Xaml
<Window x:Class="IISCERTTOOL.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="302" Width="477">
<Grid>
<Button Content="Add One to One Certificate Mapping" Height="23" HorizontalAlignment="Left" Margin="242,212,0,0" Name="Add" VerticalAlignment="Top" Width="191" Click="Add_Click" />
<Label Content="UserName" Height="28" HorizontalAlignment="Left" Margin="46,50,0,0" Name="label1" VerticalAlignment="Top" Width="81" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="163,50,0,0" Name="UserName" VerticalAlignment="Top" Width="241" />
<Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="46,84,0,0" Name="label2" VerticalAlignment="Top" Width="81" />
<PasswordBox Height="23" HorizontalAlignment="Left" Margin="163,89,0,0" Name="Password" VerticalAlignment="Top" Width="241" />
<Label Content="Certificate" Height="28" HorizontalAlignment="Left" Margin="46,118,0,0" Name="label3" VerticalAlignment="Top" Width="81" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="163,123,0,0" Name="Certificate" VerticalAlignment="Top" Width="241" />
<Label Content="WebSite" Height="28" HorizontalAlignment="Left" Margin="46,152,0,0" Name="label4" VerticalAlignment="Top" Width="81" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="163,152,0,0" Name="WebSite" VerticalAlignment="Top" Width="241" />
<Button Content="..." Height="20" HorizontalAlignment="Left" Margin="416,123,0,0" Name="SelectCertificate" VerticalAlignment="Top" Width="17" FontStyle="Normal" Click="SelectCertificate_Click" />
</Grid>
</Window>
Code behind.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Web.Administration;
using System.IO;
using System.Diagnostics;
namespace IISCERTTOOL
{
<summary>
</summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LoadWebSites();
}
private void SelectCertificate_Click(object sender, RoutedEventArgs e)
{
try
{
Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
dialog.AddExtension = true;
dialog.CheckFileExists = true;
dialog.Filter = "cer files (*.cer)|*.cer";
dialog.Multiselect = false;
if ((bool)dialog.ShowDialog())
{
Certificate.Text = dialog.FileName;
}
}
catch (Exception ex)
{
DisplayException(ex);
}
}
private void Add_Click(object sender, RoutedEventArgs e)
{
try
{
string publicKey = ReadKey(Certificate.Text.Trim());
if (!string.IsNullOrEmpty(publicKey) && ConfigureOneToOneCertMapping(UserName.Text.Trim(), Password.Password.Trim(), publicKey, WebSite.SelectedValue.ToString()))
{
MessageBox.Show("One to One Mapping successfully added");
}
else
{
MessageBox.Show("One to One Mapping was not added");
}
}
catch (Exception ex)
{
DisplayException(ex);
}
}
<summary>
</summary>
private string ReadKey(string path)
{
StringBuilder publicKey = new StringBuilder();
try
{
string[] file = File.ReadAllLines(path).Skip(1).ToArray();
for (int i = 0; i < file.Length - 1; i++)
{
publicKey.Append(file[i]);
}
}
catch (Exception ex)
{
DisplayException(ex);
}
return publicKey.ToString();
}
<summary>
</summary>
private void LoadWebSites()
{
try
{
List<string> sites = new List<string>();
using (ServerManager serverManager = new ServerManager())
{
foreach (Site s in serverManager.Sites)
{
sites.Add(s.Name);
}
}
WebSite.ItemsSource = sites;
}
catch (Exception ex)
{
DisplayException(ex);
}
}
<summary>
</summary>
private bool ConfigureOneToOneCertMapping(string UserName, string Password, string PublicKey, string WebSiteName)
{
bool result = false;
using (ServerManager serverManager = new ServerManager())
{
try
{
Configuration config = serverManager.GetApplicationHostConfiguration();
ConfigurationSection iisClientCertificateMappingAuthenticationSection = config.GetSection("system.webServer/security/authentication/iisClientCertificateMappingAuthentication", WebSiteName);
iisClientCertificateMappingAuthenticationSection["enabled"] = true;
iisClientCertificateMappingAuthenticationSection["oneToOneCertificateMappingsEnabled"] = true;
ConfigurationElementCollection oneToOneMappingsCollection = iisClientCertificateMappingAuthenticationSection.GetCollection("oneToOneMappings");
ConfigurationElement addElement = oneToOneMappingsCollection.CreateElement("add");
addElement["enabled"] = true;
addElement["userName"] = UserName;
addElement["password"] = Password;
addElement["certificate"] = PublicKey;
oneToOneMappingsCollection.Add(addElement);
ConfigurationSection accessSection = config.GetSection("system.webServer/security/access", WebSiteName);
accessSection["sslFlags"] = @"Ssl, SslNegotiateCert";
serverManager.CommitChanges();
result = true;
}
catch (Exception ex)
{
DisplayException(ex);
}
return result;
}
}
<summary>
</summary>
private static void DisplayException(Exception ex)
{
StringBuilder sb = new StringBuilder();
StackTrace trace = new StackTrace();
sb.AppendLine("Exception Occurred.");
sb.AppendLine(string.Format("{0}.{1}",
trace.GetFrame(1).GetMethod().ReflectedType.Name, trace.GetFrame(1).GetMethod().Name));
sb.AppendLine(string.Format("Source: {0}.", ex.Source));
sb.AppendLine(string.Format("Type: {0}.", ex.GetType()));
sb.AppendLine(string.Format("Message: {0}.", ex.Message));
if (ex.InnerException != null)
{
sb.AppendLine(string.Format("Inner Exception: {0}.", ex.InnerException.Message));
}
MessageBox.Show(sb.ToString());
}
}
}