IIS SSL updates, mostly SNI/CCS-related, but also a lot of UI fixes/improvements

This commit is contained in:
Olov Karlsson 2014-11-30 09:13:06 +01:00
parent 25fdedd221
commit eb9b311bba
5 changed files with 299 additions and 344 deletions

View file

@ -49,14 +49,6 @@ namespace WebsitePanel.Providers.Web.Iis
// We need to move it into "WebHosting" store // We need to move it into "WebHosting" store
// Get certificate // Get certificate
var servercert = GetServerCertificates(StoreName.My.ToString()).Single(c => c.FriendlyName == cert.FriendlyName); var servercert = GetServerCertificates(StoreName.My.ToString()).Single(c => c.FriendlyName == cert.FriendlyName);
if (UseCCS)
{
// Delete existing certificate, if any. This is needed to install a new binding
if (CheckCertificate(website))
{
DeleteCertificate(GetCurrentSiteCertificate(website), website);
}
}
// Get certificate data - the one we just added to "Personal" store // Get certificate data - the one we just added to "Personal" store
var storeMy = new X509Store(StoreName.My, StoreLocation.LocalMachine); var storeMy = new X509Store(StoreName.My, StoreLocation.LocalMachine);
@ -64,6 +56,7 @@ namespace WebsitePanel.Providers.Web.Iis
X509CertificateCollection existCerts2 = storeMy.Certificates.Find(X509FindType.FindBySerialNumber, servercert.SerialNumber, false); X509CertificateCollection existCerts2 = storeMy.Certificates.Find(X509FindType.FindBySerialNumber, servercert.SerialNumber, false);
var certData = existCerts2[0].Export(X509ContentType.Pfx); var certData = existCerts2[0].Export(X509ContentType.Pfx);
storeMy.Close(); storeMy.Close();
var x509Cert = new X509Certificate2(certData);
if (UseCCS) if (UseCCS)
{ {
@ -74,7 +67,6 @@ namespace WebsitePanel.Providers.Web.Iis
{ {
// Add new certificate to "WebHosting" store // Add new certificate to "WebHosting" store
var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine);
var x509Cert = new X509Certificate2(certData);
store.Open(OpenFlags.ReadWrite); store.Open(OpenFlags.ReadWrite);
store.Add(x509Cert); store.Add(x509Cert);
store.Close(); store.Close();
@ -85,6 +77,7 @@ namespace WebsitePanel.Providers.Web.Iis
X509CertificateCollection existCerts = storeMy.Certificates.Find(X509FindType.FindBySerialNumber, servercert.SerialNumber, false); X509CertificateCollection existCerts = storeMy.Certificates.Find(X509FindType.FindBySerialNumber, servercert.SerialNumber, false);
storeMy.Remove((X509Certificate2)existCerts[0]); storeMy.Remove((X509Certificate2)existCerts[0]);
storeMy.Close(); storeMy.Close();
// Fill object with certificate data // Fill object with certificate data
cert.SerialNumber = servercert.SerialNumber; cert.SerialNumber = servercert.SerialNumber;
cert.ValidFrom = servercert.ValidFrom; cert.ValidFrom = servercert.ValidFrom;
@ -99,7 +92,7 @@ namespace WebsitePanel.Providers.Web.Iis
DeleteCertificate(GetCurrentSiteCertificate(website), website); DeleteCertificate(GetCurrentSiteCertificate(website), website);
} }
AddBinding(cert, website); AddBinding(x509Cert, website);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -113,8 +106,10 @@ namespace WebsitePanel.Providers.Web.Iis
public new List<SSLCertificate> GetServerCertificates() public new List<SSLCertificate> GetServerCertificates()
{ {
// Use Web Hosting store - new for IIS 8.0 // Get certificates from both WebHosting and My (Personal) store
return GetServerCertificates(CertificateStoreName); var certificates = GetServerCertificates(CertificateStoreName);
certificates.AddRange(GetServerCertificates(StoreName.My.ToString()));
return certificates;
} }
public new SSLCertificate ImportCertificate(WebSite website) public new SSLCertificate ImportCertificate(WebSite website)
@ -134,12 +129,12 @@ namespace WebsitePanel.Providers.Web.Iis
}; };
} }
return certificate; return certificate ?? (new SSLCertificate {Success = false, Certificate = "No certificate in binding on server, please remove or edit binding"});
} }
public new SSLCertificate InstallPfx(byte[] certificate, string password, WebSite website) public new SSLCertificate InstallPfx(byte[] certificate, string password, WebSite website)
{ {
SSLCertificate newcert, oldcert = null; SSLCertificate newcert = null, oldcert = null;
// Ensure we perform operations safely and preserve the original state during all manipulations, save the oldcert if one is used // Ensure we perform operations safely and preserve the original state during all manipulations, save the oldcert if one is used
if (CheckCertificate(website)) if (CheckCertificate(website))
@ -170,7 +165,7 @@ namespace WebsitePanel.Providers.Web.Iis
writer.Write(certData); writer.Write(certData);
writer.Flush(); writer.Flush();
writer.Close(); writer.Close();
// Certificated saved // Certificate saved
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -189,7 +184,6 @@ namespace WebsitePanel.Providers.Web.Iis
try try
{ {
store.Open(OpenFlags.ReadWrite); store.Open(OpenFlags.ReadWrite);
store.Add(x509Cert); store.Add(x509Cert);
} }
catch (Exception ex) catch (Exception ex)
@ -205,82 +199,38 @@ namespace WebsitePanel.Providers.Web.Iis
} }
// Step 2: Instantiate a copy of new X.509 certificate // Step 2: Instantiate a copy of new X.509 certificate
try try
{ {
store.Open(OpenFlags.ReadWrite); newcert = GetSSLCertificateFromX509Certificate2(x509Cert);
newcert = GetSSLCertificateFromX509Certificate2(x509Cert); }
} catch (Exception ex)
catch (Exception ex) {
{ HandleExceptionAndRollbackCertificate(store, x509Cert, null, website, "SSLModuleService could not instantiate a copy of new X.509 certificate.", ex);
if (!UseCCS) }
{
// Rollback X.509 store changes
store.Remove(x509Cert);
}
// Log error
Log.WriteError("SSLModuleService could not instantiate a copy of new X.509 certificate. All previous changes have been rolled back.", ex);
// Re-throw
throw;
}
finally
{
store.Close();
}
if (!UseCCS) // Step 3: Remove old certificate from the web site if any
{ try
// Step 3: Remove old certificate from the web site if any {
try // Check if certificate already exists, remove it.
{ if (oldcert != null)
store.Open(OpenFlags.ReadWrite); {
// Check if certificate already exists, remove it. DeleteCertificate(oldcert, website);
if (oldcert != null) }
DeleteCertificate(oldcert, website); }
} catch (Exception ex)
catch (Exception ex) {
{ HandleExceptionAndRollbackCertificate(store, x509Cert, null, website, string.Format("SSLModuleService could not remove existing certificate from '{0}' web site.", website.Name), ex);
// Rollback X.509 store changes }
store.Remove(x509Cert);
// Log the error
Log.WriteError(
String.Format("SSLModuleService could not remove existing certificate from '{0}' web site. All changes have been rolled back.", website.Name), ex);
// Re-throw
throw;
}
finally
{
store.Close();
}
}
// Step 4: Register new certificate with HTTPS binding on the web site // Step 4: Register new certificate with HTTPS binding on the web site
try try
{ {
//if (!UseCCS) AddBinding(x509Cert, website);
//{ }
// store.Open(OpenFlags.ReadWrite); catch (Exception ex)
//} {
HandleExceptionAndRollbackCertificate(store, x509Cert, oldcert, website, String.Format("SSLModuleService could not add new X.509 certificate to '{0}' web site.", website.Name), ex);
AddBinding(newcert, website); }
}
catch (Exception ex)
{
if (!UseCCS)
{
// Install old certificate back if any
store.Open(OpenFlags.ReadWrite);
if (oldcert != null)
InstallCertificate(oldcert, website);
// Rollback X.509 store changes
store.Remove(x509Cert);
store.Close();
}
// Log the error
Log.WriteError(
String.Format("SSLModuleService could not add new X.509 certificate to '{0}' web site. All changes have been rolled back.", website.Name), ex);
// Re-throw
throw;
}
return newcert; return newcert;
} }
@ -319,32 +269,44 @@ namespace WebsitePanel.Providers.Web.Iis
} }
public new void AddBinding(SSLCertificate certificate, WebSite website) public void AddBinding(X509Certificate2 certificate, WebSite website)
{ {
using (var srvman = GetServerManager()) using (var srvman = GetServerManager())
{ {
var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
// Look for dedicated ip // Look for dedicated ip
var dedicatedIp = SiteHasBindingWithDedicatedIp(srvman, website); var dedicatedIp = SiteHasBindingWithDedicatedIp(srvman, website);
var bindingInformation = string.Format("{0}:443:{1}", website.SiteIPAddress, dedicatedIp ? "" : certificate.Hostname); // Look for all the hostnames this certificate is valid for if we are using SNI
var hostNames = new List<string>();
Binding siteBinding = UseCCS ? if (!dedicatedIp)
srvman.Sites[website.SiteId].Bindings.Add(bindingInformation, "https") : {
srvman.Sites[website.SiteId].Bindings.Add(bindingInformation, certificate.Hash, store.Name); hostNames.AddRange(from extension in certificate.Extensions.Cast<X509Extension>() where extension.Oid.FriendlyName == "Subject Alternative Name" select extension.Format(true));
}
if (!hostNames.Any())
{
hostNames.Add(certificate.GetNameInfo(X509NameType.SimpleName, false));
}
// For every hostname (only one if using old school dedicated IP binding)
foreach (var hostName in hostNames)
{
var bindingInformation = string.Format("{0}:443:{1}", website.SiteIPAddress ?? "*", dedicatedIp ? "" : hostName);
Binding siteBinding = UseCCS ?
srvman.Sites[website.SiteId].Bindings.Add(bindingInformation, "https") :
srvman.Sites[website.SiteId].Bindings.Add(bindingInformation, certificate.GetCertHash(), CertificateStoreName);
if (UseSNI) if (UseSNI && !dedicatedIp)
{ {
siteBinding.SslFlags |= SslFlags.Sni; siteBinding.SslFlags |= SslFlags.Sni;
}
if (UseCCS)
{
siteBinding.SslFlags |= SslFlags.CentralCertStore;
}
} }
if (UseCCS)
{
siteBinding.SslFlags |= SslFlags.CentralCertStore;
}
store.Close();
srvman.CommitChanges(); srvman.CommitChanges();
} }
@ -352,7 +314,9 @@ namespace WebsitePanel.Providers.Web.Iis
public new ResultObject DeleteCertificate(SSLCertificate certificate, WebSite website) public new ResultObject DeleteCertificate(SSLCertificate certificate, WebSite website)
{ {
var result = new ResultObject() { IsSuccess = true }; // This method removes all https bindings and all certificates associated with them.
// Old implementation (IIS70) removed a single binding (there could not be more than one) and the first certificate that matched via serial number
var result = new ResultObject { IsSuccess = true };
if (certificate == null) if (certificate == null)
{ {
@ -361,35 +325,70 @@ namespace WebsitePanel.Providers.Web.Iis
try try
{ {
// Regardless of the CCS setting on the server, we try to find and remove the certificate from both CCS and WebHosting Store. var certificatesAndStoreNames = new List<Tuple<string, byte[]>>();
// This is because we don't know how this was set when the certificate was added
if (!string.IsNullOrWhiteSpace(CCSUncPath) && Directory.Exists(CCSUncPath)) // User servermanager to get aLL SSL-bindings on this website and try to remove the certificates used
using (var srvman = GetServerManager())
{ {
// This is where it will be if CCS is used
var path = GetCCSPath(certificate.Hostname); var site = srvman.Sites[website.Name];
if (File.Exists(path)) var bindings = site.Bindings.Where(b => b.Protocol == "https");
foreach (Binding binding in bindings.ToList())
{ {
File.Delete(path); if (binding.SslFlags.HasFlag(SslFlags.CentralCertStore))
{
if (!string.IsNullOrWhiteSpace(CCSUncPath) && Directory.Exists(CCSUncPath))
{
// This is where it will be if CCS is used
var path = GetCCSPath(certificate.Hostname);
if (File.Exists(path))
{
File.Delete(path);
}
// If binding with hostname, also try to delete with the hostname in the binding
// This is because if SNI is used, several bindings are created for every valid name in the cerificate, but only one name exists in the SSLCertificate
if (!string.IsNullOrEmpty(binding.Host))
{
path = GetCCSPath(binding.Host);
if (File.Exists(path))
{
File.Delete(path);
}
}
}
}
else
{
var certificateAndStoreName = new Tuple<string, byte[]>(binding.CertificateStoreName, binding.CertificateHash);
if (!string.IsNullOrEmpty(binding.CertificateStoreName) && !certificatesAndStoreNames.Contains(certificateAndStoreName))
{
certificatesAndStoreNames.Add(certificateAndStoreName);
}
}
// Remove binding from site
site.Bindings.Remove(binding);
} }
}
// Now delete all certs with the same serialnumber in WebHosting Store srvman.CommitChanges();
var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine);
store.Open(OpenFlags.MaxAllowed);
var certs = store.Certificates.Find(X509FindType.FindBySerialNumber, certificate.SerialNumber, false); foreach (var certificateAndStoreName in certificatesAndStoreNames)
foreach (var cert in certs) {
{ // Delete all certs with the same serialnumber in Store
store.Remove(cert); var store = new X509Store(certificateAndStoreName.Item1, StoreLocation.LocalMachine);
} store.Open(OpenFlags.MaxAllowed);
store.Close(); var certs = store.Certificates.Find(X509FindType.FindByThumbprint, BitConverter.ToString(certificateAndStoreName.Item2).Replace("-", ""), false);
foreach (var cert in certs)
{
store.Remove(cert);
}
// Remove binding from site store.Close();
if (CheckCertificate(website)) }
{
RemoveBinding(certificate, website);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -409,9 +408,7 @@ namespace WebsitePanel.Providers.Web.Iis
var site = srvman.Sites[website.SiteId]; var site = srvman.Sites[website.SiteId];
var sslBinding = site.Bindings.First(b => b.Protocol == "https"); var sslBinding = site.Bindings.First(b => b.Protocol == "https");
X509Certificate2 cert = null; // If the certificate is in the central store
// If the certificate is in the central store
if (((SslFlags)Enum.Parse(typeof(SslFlags), sslBinding["sslFlags"].ToString())).HasFlag(SslFlags.CentralCertStore)) if (((SslFlags)Enum.Parse(typeof(SslFlags), sslBinding["sslFlags"].ToString())).HasFlag(SslFlags.CentralCertStore))
{ {
// Let's try to match binding host and certificate filename // Let's try to match binding host and certificate filename
@ -423,23 +420,19 @@ namespace WebsitePanel.Providers.Web.Iis
// Read certificate data from file // Read certificate data from file
var certData = new byte[fileStream.Length]; var certData = new byte[fileStream.Length];
fileStream.Read(certData, 0, (int) fileStream.Length); fileStream.Read(certData, 0, (int) fileStream.Length);
cert = new X509Certificate2(certData, CCSCommonPassword); var cert = new X509Certificate2(certData, CCSCommonPassword);
fileStream.Close(); fileStream.Close();
return GetSSLCertificateFromX509Certificate2(cert);
} }
} }
else else
{ {
var currentHash = sslBinding.CertificateHash; var currentHash = Convert.ToBase64String(sslBinding.CertificateHash);
var store = new X509Store(CertificateStoreName, StoreLocation.LocalMachine); return GetServerCertificates().FirstOrDefault(c => Convert.ToBase64String(c.Hash) == currentHash);
store.Open(OpenFlags.ReadOnly);
cert = store.Certificates.Cast<X509Certificate2>().Single(c => Convert.ToBase64String(c.GetCertHash()) == Convert.ToBase64String(currentHash));
store.Close();
} }
return GetSSLCertificateFromX509Certificate2(cert);
} }
return null;
} }
private static List<SSLCertificate> GetServerCertificates(string certificateStoreName) private static List<SSLCertificate> GetServerCertificates(string certificateStoreName)
@ -504,5 +497,33 @@ namespace WebsitePanel.Providers.Web.Iis
return false; return false;
} }
} }
private void HandleExceptionAndRollbackCertificate(X509Store store, X509Certificate2 x509Cert, SSLCertificate oldCert, WebSite webSite, string errorMessage, Exception ex)
{
if (!UseCCS)
{
try
{
// Rollback X.509 store changes
store.Open(OpenFlags.ReadWrite);
store.Remove(x509Cert);
store.Close();
}
catch (Exception)
{
Log.WriteError("SSLModuleService could not rollback and remove certificate from store", ex);
}
// Install old certificate back if any
if (oldCert != null)
InstallCertificate(oldCert, webSite);
}
// Log the error
Log.WriteError(errorMessage + " All changes have been rolled back.", ex);
// Re-throw
throw ex;
}
} }
} }

View file

@ -109,7 +109,7 @@ namespace WebsitePanel.Portal
{ {
var filteredTabs = TabsList.FilterTabsByHostingPlanQuotas(PackageId).ToList(); var filteredTabs = TabsList.FilterTabsByHostingPlanQuotas(PackageId).ToList();
// remove "SSL" tab for a site with dynamic IP // remove "SSL" tab for a site with dynamic IP and not SNI enabled
var sslTab = filteredTabs.SingleOrDefault(t => t.Id == "SSL"); var sslTab = filteredTabs.SingleOrDefault(t => t.Id == "SSL");
if (!AllowSsl && sslTab != null) if (!AllowSsl && sslTab != null)
filteredTabs.Remove(sslTab); filteredTabs.Remove(sslTab);
@ -1071,6 +1071,7 @@ namespace WebsitePanel.Portal
sharedIP.Visible = false; sharedIP.Visible = false;
switchToDedicatedIP.Visible = true; switchToDedicatedIP.Visible = true;
WebsitesSSLControl.InstalledCert = null;
} }
protected void cmdSwitchToSharedIP_Click(object sender, EventArgs e) protected void cmdSwitchToSharedIP_Click(object sender, EventArgs e)
@ -1090,6 +1091,7 @@ namespace WebsitePanel.Portal
dlTabs.SelectedIndex = 0; dlTabs.SelectedIndex = 0;
WebsitesSSLControl.InstalledCert = null;
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -141,6 +141,8 @@
<p class="Normal"> <p class="Normal">
<asp:Localize ID="SSLImportDescription" runat="server" meta:resourcekey="SSLImportDescription" /></p> <asp:Localize ID="SSLImportDescription" runat="server" meta:resourcekey="SSLImportDescription" /></p>
<asp:Button ID="btnImport" meta:resourcekey="btnImport" CssClass="Button1" runat="server" OnClick="btnImport_click" /> <asp:Button ID="btnImport" meta:resourcekey="btnImport" CssClass="Button1" runat="server" OnClick="btnImport_click" />
<asp:Button ID="btnDeleteAll" runat="server" Text="Delete" meta:resourcekey="btnDelete"
CssClass="Button1" OnClick="btnDeleteAll_Click" />
</div> </div>
</asp:Panel> </asp:Panel>
@ -151,13 +153,7 @@
<tr> <tr>
<td class="SubHead"> <td class="SubHead">
<asp:Localize ID="SelectCertType" runat="server" meta:resourcekey="SelectCertType" /></td> <asp:Localize ID="SelectCertType" runat="server" meta:resourcekey="SelectCertType" /></td>
<td class="NormalBold" ><asp:radiobutton id="rbSiteCertificate" GroupName="Content" Runat="server" Checked="True"></asp:radiobutton></td> <td class="NormalBold" ><asp:DropDownList id="ddlbSiteCertificate" GroupName="Content" Runat="server" Checked="True"></asp:DropDownList></td>
</tr>
<tr>
<td></td>
<td class="NormalBold" ><asp:radiobutton id="rbDomainCertificate" GroupName="Content" Runat="server" ></asp:radiobutton></td>
</tr>
<tr> <tr>
<td class="SubHead"> <td class="SubHead">
<asp:Localize ID="sslBitLength" runat="server" meta:resourcekey="sslBitLength" /></td> <asp:Localize ID="sslBitLength" runat="server" meta:resourcekey="sslBitLength" /></td>
@ -173,7 +169,7 @@
<asp:Localize ID="sslOrganization" runat="server" meta:resourcekey="sslOrganization" /></td> <asp:Localize ID="sslOrganization" runat="server" meta:resourcekey="sslOrganization" /></td>
<td class="Normal"> <td class="Normal">
<asp:TextBox ID="txtCompany" runat="server" /><asp:RequiredFieldValidator ID="SSLCompanyReq" Display="Dynamic" ValidationGroup="SSL" runat="server" <asp:TextBox ID="txtCompany" runat="server" /><asp:RequiredFieldValidator ID="SSLCompanyReq" Display="Dynamic" ValidationGroup="SSL" runat="server"
ControlToValidate="txtCompany" ErrorMessage="RequiredFieldValidator" /></td> ControlToValidate="txtCompany" ErrorMessage="*" /></td>
</tr> </tr>
<tr> <tr>
<td class="SubHead"> <td class="SubHead">
@ -196,7 +192,7 @@
<asp:DropDownList ID="ddlStates" Runat="server" DataTextField="Text" DataValueField="Value" CssClass="NormalTextBox" <asp:DropDownList ID="ddlStates" Runat="server" DataTextField="Text" DataValueField="Value" CssClass="NormalTextBox"
Width="200px" Visible="false" /> Width="200px" Visible="false" />
<asp:RequiredFieldValidator ID="SSLSSLStateReq" ValidationGroup="SSL" runat="server" <asp:RequiredFieldValidator ID="SSLSSLStateReq" ValidationGroup="SSL" runat="server"
ControlToValidate="txtState" Display="Dynamic" /></td> ControlToValidate="txtState" Display="Dynamic" ErrorMessage="*" /></td>
</tr> </tr>
<tr> <tr>
<td class="SubHead"> <td class="SubHead">
@ -204,7 +200,7 @@
<td class="Normal"> <td class="Normal">
<asp:TextBox ID="txtCity" runat="server" /> <asp:TextBox ID="txtCity" runat="server" />
<asp:RequiredFieldValidator ID="SSLCityReq" ValidationGroup="SSL" runat="server" <asp:RequiredFieldValidator ID="SSLCityReq" ValidationGroup="SSL" runat="server"
ControlToValidate="txtCity" ErrorMessage="RequiredFieldValidator" /></td> ControlToValidate="txtCity" ErrorMessage="*" /></td>
</tr> </tr>
</table> </table>
<br /> <br />
@ -254,6 +250,8 @@
<br /> <br />
<asp:Button ID="btnInstallCertificate" meta:resourcekey="btnInstallCertificate" runat="server" <asp:Button ID="btnInstallCertificate" meta:resourcekey="btnInstallCertificate" runat="server"
CssClass="Button1" Text="Install" OnClick="btnInstallCertificate_Click" /> CssClass="Button1" Text="Install" OnClick="btnInstallCertificate_Click" />
<asp:Button ID="btnCancelRequest" runat="server" OnClientClick="return confirm('Are you Sure? This will delete the current request.');"
CssClass="Button1" Text="Cancel request" OnClick="btnCancelRequest_Click" />
</div> </div>
</asp:Panel> </asp:Panel>
</ContentTemplate> </ContentTemplate>

View file

@ -135,10 +135,18 @@ namespace WebsitePanel.Portal
} }
} }
private void BindListOfAvailableSslDomains(string websiteName, string domainName) private void BindListOfAvailableSslDomains(string defaultBindingName)
{ {
rbSiteCertificate.Text = websiteName; var domains = ES.Services.WebServers.GetWebSitePointers(SiteId).ToList();
rbDomainCertificate.Text = "*." + domainName;
// If no pointers at all, add website default domain
if (domains.All(d => d.DomainName != defaultBindingName))
{
domains.Add(new DomainInfo() { DomainName = defaultBindingName, IsDomainPointer = false});
}
ddlbSiteCertificate.Items.AddRange(domains.Select(d => new ListItem(d.DomainName)).ToArray());
ddlbSiteCertificate.Items.AddRange(domains.Where(d => !d.IsDomainPointer).Select(d => new ListItem("*." + d.DomainName)).ToArray());
} }
public void BindWebItem(WebVirtualDirectory item) public void BindWebItem(WebVirtualDirectory item)
@ -148,106 +156,10 @@ namespace WebsitePanel.Portal
// Skip processing virtual directories, otherwise we will likely run into a trouble // Skip processing virtual directories, otherwise we will likely run into a trouble
if (webSite == null) if (webSite == null)
return; return;
//
bool hasactive = false;
bool haspending = false;
SiteId = item.Id; SiteId = item.Id;
//
try
{
SSLCertificate[] certificates = ES.Services.WebServers.GetCertificatesForSite(item.Id);
SSLNotInstalled.Visible = true; RefreshControlLayout();
DomainInfo[] domains = ES.Services.Servers.GetDomains(PanelSecurity.PackageId);
string zoneName = string.Empty;
foreach (DomainInfo d in domains)
{
if (d.WebSiteId == SiteId)
{
zoneName = d.ZoneName;
break;
}
}
//
BindListOfAvailableSslDomains(webSite.Name, zoneName);
if (certificates.Length > 0)
{
foreach (SSLCertificate cert in certificates)
{
if (cert.Installed)
{
hasactive = true;
}
else
{
haspending = true;
}
}
}
// Web site has active certificate
if (hasactive)
{
tabInstalled.Visible = true;
tabInstalled.Enabled = true;
tabInstalled.HeaderText = GetLocalizedString("tabInstalled.Text");
InstalledCert = (from c in certificates
where c.Installed == true
select c).SingleOrDefault();
//
BindCertificateFields();
// Attention please, the certificate is about to expire!
TimeSpan daystoexp = DateTime.Now - InstalledCert.ExpiryDate;
if (daystoexp.Days < 30)
{
lblInstalledExpiration.ForeColor = System.Drawing.Color.Red;
}
// Put some data to the ViewState
ViewState["SSLID"] = InstalledCert.id;
ViewState["SSLSerial"] = InstalledCert.SerialNumber;
//
if (!haspending)
{
btnShowpnlCSR.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');");
btnShowUpload.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');");
SSLNotInstalledHeading.Text = GetLocalizedString("SSLInstalledNewHeading.Text");
SSLNotInstalledDescription.Text = GetLocalizedString("SSLInstalledNewDescription.Text");
}
}
// Web site has pending certificate
if (haspending)
{
tabCSR.HeaderText = GetLocalizedString("tabPendingCertificate.HeaderText");//"Pending Certificate";
SSLNotInstalled.Visible = false;
pnlInstallCertificate.Visible = true;
SSLCertificate pending = (from c in certificates
where c.Installed == false
select c).Single();
ViewState["CSRID"] = pending.id;
txtCSR.Text = pending.CSR;
txtCSR.Attributes.Add("onfocus", "this.select();");
if (InstalledCert != null)
{
btnInstallCertificate.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');");
}
}
if (!hasactive && ES.Services.WebServers.CheckCertificate(item.Id).IsSuccess)
{
SSLNotInstalled.Visible = false;
SSLImport.Visible = true;
}
}
catch (Exception ex)
{
messageBox.ShowErrorMessage("WEB_GET_SSL", ex);
}
} }
protected void btnShowpnlCSR_click(object sender, EventArgs e) protected void btnShowpnlCSR_click(object sender, EventArgs e)
@ -271,7 +183,8 @@ namespace WebsitePanel.Portal
L={3}, L={3},
S={4}, S={4},
C={5}", C={5}",
rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text, //rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text,
ddlbSiteCertificate.SelectedValue,
txtCompany.Text, txtCompany.Text,
txtOU.Text, txtOU.Text,
txtCity.Text, txtCity.Text,
@ -279,7 +192,7 @@ namespace WebsitePanel.Portal
lstCountries.SelectedValue); lstCountries.SelectedValue);
SSLCertificate certificate = new SSLCertificate(); SSLCertificate certificate = new SSLCertificate();
certificate.Hostname = rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text; certificate.Hostname = ddlbSiteCertificate.SelectedValue; //rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text;
certificate.DistinguishedName = distinguishedName; certificate.DistinguishedName = distinguishedName;
certificate.CSRLength = Convert.ToInt32(lstBits.SelectedValue); certificate.CSRLength = Convert.ToInt32(lstBits.SelectedValue);
certificate.Organisation = txtCompany.Text; certificate.Organisation = txtCompany.Text;
@ -336,7 +249,7 @@ namespace WebsitePanel.Portal
OU={2}, OU={2},
L={3}, L={3},
S={4}, S={4},
C={5}", rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text, C={5}", ddlbSiteCertificate.SelectedValue, //rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text,
txtCompany.Text, txtCompany.Text,
txtOU.Text, txtOU.Text,
txtCity.Text, txtCity.Text,
@ -344,7 +257,7 @@ namespace WebsitePanel.Portal
lstCountries.SelectedValue); lstCountries.SelectedValue);
SSLCertificate certificate = new SSLCertificate(); SSLCertificate certificate = new SSLCertificate();
certificate.Hostname = rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text; certificate.Hostname = ddlbSiteCertificate.SelectedValue; //rbSiteCertificate.Checked ? rbSiteCertificate.Text : rbDomainCertificate.Text;
certificate.DistinguishedName = distinguishedName; certificate.DistinguishedName = distinguishedName;
certificate.CSRLength = Convert.ToInt32(lstBits.SelectedValue); certificate.CSRLength = Convert.ToInt32(lstBits.SelectedValue);
certificate.Organisation = txtCompany.Text; certificate.Organisation = txtCompany.Text;
@ -369,7 +282,7 @@ namespace WebsitePanel.Portal
pnlCSR.Visible = false; pnlCSR.Visible = false;
ViewState["CSRID"] = certificate.id; ViewState["CSRID"] = certificate.id;
txtCSR.Attributes.Add("onfocus", "this.select();"); txtCSR.Attributes.Add("onfocus", "this.select();");
RefreshControlLayout(PanelRequest.ItemID); RefreshControlLayout();
TabContainer1.ActiveTab = TabContainer1.Tabs[0]; TabContainer1.ActiveTab = TabContainer1.Tabs[0];
messageBox.ShowSuccessMessage(WEB_GEN_CSR); messageBox.ShowSuccessMessage(WEB_GEN_CSR);
} }
@ -402,7 +315,7 @@ namespace WebsitePanel.Portal
// //
TabContainer1.ActiveTab = tabInstalled; TabContainer1.ActiveTab = tabInstalled;
RefreshControlLayout(webSiteId); RefreshControlLayout();
} }
protected void btnInstallPFX_Click(object sender, EventArgs e) protected void btnInstallPFX_Click(object sender, EventArgs e)
@ -428,13 +341,14 @@ namespace WebsitePanel.Portal
if (result.IsSuccess.Equals(false)) if (result.IsSuccess.Equals(false))
{ {
messageBox.ShowErrorMessage("WEB_INSTALL_CSR"); messageBox.ShowErrorMessage("WEB_INSTALL_CSR");
return; RefreshControlLayout();
return;
} }
// //
messageBox.ShowSuccessMessage("WEB_INSTALL_CSR"); messageBox.ShowSuccessMessage("WEB_INSTALL_CSR");
SSLNotInstalled.Visible = false; SSLNotInstalled.Visible = false;
tabInstalled.Visible = true; tabInstalled.Visible = true;
RefreshControlLayout(SiteId); RefreshControlLayout();
} }
protected void BindCertificateFields() protected void BindCertificateFields()
@ -560,43 +474,43 @@ namespace WebsitePanel.Portal
if (!result.IsSuccess) if (!result.IsSuccess)
{ {
messageBox.ShowErrorMessage("WEB_INSTALL_CSR"); messageBox.ShowErrorMessage("WEB_INSTALL_CSR");
RefreshControlLayout();
return; return;
} }
// Show success message and display appropriate controls // Show success message and display appropriate controls
messageBox.ShowSuccessMessage("WEB_INSTALL_CSR"); messageBox.ShowSuccessMessage("WEB_INSTALL_CSR");
SSLNotInstalled.Visible = false;
tabInstalled.Visible = true; RefreshControlLayout();
//
RefreshControlLayout(webSiteId);
} }
protected void RefreshControlLayout(int webSiteId) public void RefreshControlLayout()
{ {
bool hasActiveCert = false; //
bool hasPendingCert = false; bool hasactive = false;
// bool haspending = false;
try try
{ {
SSLCertificate[] certificates = ES.Services.WebServers.GetCertificatesForSite(webSiteId); var webSite = ES.Services.WebServers.GetWebSite(SiteId);
WebSite item = ES.Services.WebServers.GetWebSite(webSiteId); // Get all certificate infos stored in database
SSLCertificate[] certificates = ES.Services.WebServers.GetCertificatesForSite(SiteId);
SSLNotInstalled.Visible = true; // Set some default visible values, states and texts
// tabInstalled.Visible = false;
tabInstalled.Enabled = false;
SSLNotInstalled.Visible = true;
SSLImport.Visible = false;
pnlCSR.Visible = false;
pnlShowUpload.Visible = false;
pnlInstallCertificate.Visible = false;
DomainInfo[] domains = ES.Services.Servers.GetDomains(PanelSecurity.PackageId); btnShowpnlCSR.Attributes.Remove("OnClientClick");
string zoneName = string.Empty; btnShowUpload.Attributes.Remove("OnClientClick");
foreach (DomainInfo d in domains) SSLNotInstalledHeading.Text = GetLocalizedString("SSLNotInstalledHeading.Text");
{ SSLNotInstalledDescription.Text = GetLocalizedString("SSLNotInstalledDescription.Text");
if (d.WebSiteId == item.Id)
{
zoneName = d.ZoneName;
break;
}
}
// BindListOfAvailableSslDomains(webSite.Name);
BindListOfAvailableSslDomains(item.Name, zoneName);
if (certificates.Length > 0) if (certificates.Length > 0)
{ {
@ -604,16 +518,17 @@ namespace WebsitePanel.Portal
{ {
if (cert.Installed) if (cert.Installed)
{ {
hasActiveCert = true; hasactive = true;
} }
else else
{ {
hasPendingCert = true; haspending = true;
} }
} }
} }
if (hasActiveCert) // Web site has active certificate
if (hasactive)
{ {
tabInstalled.Visible = true; tabInstalled.Visible = true;
tabInstalled.Enabled = true; tabInstalled.Enabled = true;
@ -622,18 +537,19 @@ namespace WebsitePanel.Portal
InstalledCert = (from c in certificates InstalledCert = (from c in certificates
where c.Installed == true where c.Installed == true
select c).SingleOrDefault(); select c).SingleOrDefault();
TimeSpan daystoexp = DateTime.Now - InstalledCert.ExpiryDate;
BindCertificateFields();
// //
bool certAbout2Exp = daystoexp.Days < 30 BindCertificateFields();
? lblInstalledExpiration.ForeColor == System.Drawing.Color.Red // Attention please, the certificate is about to expire!
: lblInstalledExpiration.ForeColor == System.Drawing.Color.Black; TimeSpan daystoexp = InstalledCert.ExpiryDate - DateTime.Now;
if (daystoexp.Days < 30)
{
lblInstalledExpiration.ForeColor = System.Drawing.Color.Red;
}
// Put some data to the ViewState
ViewState["SSLID"] = InstalledCert.id; ViewState["SSLID"] = InstalledCert.id;
ViewState["SSLSerial"] = InstalledCert.SerialNumber; ViewState["SSLSerial"] = InstalledCert.SerialNumber;
//
if (!hasPendingCert) if (!haspending)
{ {
btnShowpnlCSR.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');"); btnShowpnlCSR.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');");
btnShowUpload.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');"); btnShowUpload.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');");
@ -642,9 +558,10 @@ namespace WebsitePanel.Portal
} }
} }
if (hasPendingCert) // Web site has pending certificate
if (haspending)
{ {
tabCSR.HeaderText = GetLocalizedString("tabPendingCertificate.HeaderText"); tabCSR.HeaderText = GetLocalizedString("tabPendingCertificate.HeaderText");//"Pending Certificate";
SSLNotInstalled.Visible = false; SSLNotInstalled.Visible = false;
pnlInstallCertificate.Visible = true; pnlInstallCertificate.Visible = true;
SSLCertificate pending = (from c in certificates SSLCertificate pending = (from c in certificates
@ -653,12 +570,17 @@ namespace WebsitePanel.Portal
ViewState["CSRID"] = pending.id; ViewState["CSRID"] = pending.id;
txtCSR.Text = pending.CSR; txtCSR.Text = pending.CSR;
txtCSR.Attributes.Add("onfocus", "this.select();"); txtCSR.Attributes.Add("onfocus", "this.select();");
if (InstalledCert != null) if (InstalledCert != null)
{ {
btnInstallCertificate.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');"); btnInstallCertificate.Attributes.Add("OnClientClick", "return confirm('" + GetLocalizedString("btnInstallConfirm.Text") + "');");
} }
} }
if (!hasactive && ES.Services.WebServers.CheckCertificate(SiteId).IsSuccess)
{
SSLNotInstalled.Visible = false;
SSLImport.Visible = true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -668,7 +590,10 @@ namespace WebsitePanel.Portal
protected void SetCertHostnameSelection(string hostname) protected void SetCertHostnameSelection(string hostname)
{ {
rbSiteCertificate.Checked = (rbSiteCertificate.Text == hostname); if (ddlbSiteCertificate.Items.Contains(new ListItem(hostname)))
{
ddlbSiteCertificate.SelectedValue = hostname;
}
} }
protected void SetCertCountrySelection(string country) protected void SetCertCountrySelection(string country)
@ -701,5 +626,33 @@ namespace WebsitePanel.Portal
listCtl.ClearSelection(); listCtl.ClearSelection();
li.Selected = true; li.Selected = true;
} }
}
protected void btnCancelRequest_Click(object sender, EventArgs e)
{
ResultObject result = null;
try
{
result = ES.Services.WebServers.DeleteCertificateRequest(SiteId, (int)ViewState["CSRID"]);
}
catch (Exception ex)
{
messageBox.ShowErrorMessage(WEB_SSL_DELETE, ex);
}
//
if (!result.IsSuccess)
{
messageBox.ShowErrorMessage(WEB_SSL_DELETE);
return;
}
//
SSLNotInstalled.Visible = true;
pnlCSR.Visible = false;
pnlInstallCertificate.Visible = false;
}
protected void btnDeleteAll_Click(object sender, EventArgs e)
{
DeleteCertificate(SiteId, new SSLCertificate());
}
}
} }

View file

@ -1,32 +1,4 @@
// Copyright (c) 2014, Outercurve Foundation. //------------------------------------------------------------------------------
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// //
@ -355,6 +327,15 @@ namespace WebsitePanel.Portal {
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Button btnImport; protected global::System.Web.UI.WebControls.Button btnImport;
/// <summary>
/// btnDeleteAll control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnDeleteAll;
/// <summary> /// <summary>
/// pnlCSR control. /// pnlCSR control.
/// </summary> /// </summary>
@ -374,22 +355,13 @@ namespace WebsitePanel.Portal {
protected global::System.Web.UI.WebControls.Localize SelectCertType; protected global::System.Web.UI.WebControls.Localize SelectCertType;
/// <summary> /// <summary>
/// rbSiteCertificate control. /// ddlbSiteCertificate control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Auto-generated field. /// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.RadioButton rbSiteCertificate; protected global::System.Web.UI.WebControls.DropDownList ddlbSiteCertificate;
/// <summary>
/// rbDomainCertificate control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RadioButton rbDomainCertificate;
/// <summary> /// <summary>
/// sslBitLength control. /// sslBitLength control.
@ -678,5 +650,14 @@ namespace WebsitePanel.Portal {
/// To modify move field declaration from designer file to code-behind file. /// To modify move field declaration from designer file to code-behind file.
/// </remarks> /// </remarks>
protected global::System.Web.UI.WebControls.Button btnInstallCertificate; protected global::System.Web.UI.WebControls.Button btnInstallCertificate;
/// <summary>
/// btnCancelRequest control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnCancelRequest;
} }
} }