/// <summary> /// Handles the Click event of the lbAccountRegisterSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbAccountRegisterSave_Click(object sender, EventArgs e) { var email = tbAccountEmail.Text; if (!cbTOSAgree.Checked) { divTOS.Attributes["class"] = "alert alert-danger"; return; } var account = AcmeHelper.LoadAccountData(); account.Email = email; account.TestMode = cbTestMode.Checked; var acme = new AcmeService(account.TestMode); acme.Register(email, hlTOS.NavigateUrl); account.Key = Convert.ToBase64String(acme.RSA); AcmeHelper.SaveAccountData(account); ltAccountEmail.Text = email; pnlAccountRegister.Visible = false; pnlAccountDetail.Visible = true; HideSecondaryBlocks(false); ShowDetails(); }
/// <summary> /// Handles the Click event of the lbEnableSiteRedirects control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbEnableSiteRedirects_Click(object sender, EventArgs e) { var siteNames = hfEnableSiteRedirects.Value.Split(','); var targetUrl = GetRedirectUrl(); var errors = new List <string>(); // // For each site that was detected as not properly configured, try to configure it. // foreach (var siteName in siteNames) { try { AcmeHelper.EnableIISSiteRedirect(siteName, targetUrl); } catch (Exception ex) { errors.Add(ex.Message); } } if (errors.Any()) { nbIISError.Text = string.Format("Failed to enable the redirect on one or more sites. This may be due to insufficient permissions to make modifications to the other sites. <ul><li>{0}</li></ul>", string.Join("</li><li>", errors)); } CheckIISState(); }
/// <summary> /// Handles the Click event of the lbEnableRedirectModule control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbEnableRedirectModule_Click(object sender, EventArgs e) { if (!AcmeHelper.EnableIISHttpRedirectModule()) { nbIISError.Text = "Failed to enable the IIS Http Redirect module. Rock may not have enough permissions to perform this task. Please manually enable the IIS Http Redirect module."; } else { NavigateToCurrentPage(); } }
/// <summary> /// Configure this block for display. /// </summary> protected void ShowDetails() { var account = AcmeHelper.LoadAccountData(); ltAccountEmail.Text = account.Email; ltTestMode.Text = account.TestMode.ToString(); ltOfflineMode.Text = account.OfflineMode.ToString(); lbRegister.CssClass = string.IsNullOrWhiteSpace(account.Key) ? "btn btn-primary" : "btn btn-default"; lbEdit.Visible = !string.IsNullOrWhiteSpace(account.Key); }
/// <summary> /// Handles the Click event of the lbEdit control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbEdit_Click(object sender, EventArgs e) { HideSecondaryBlocks(true); pnlAccountDetail.Visible = false; pnlAccountEdit.Visible = true; var account = AcmeHelper.LoadAccountData(); cbOfflineMode.Checked = account.OfflineMode; }
/// <summary> /// Handles the Click event of the lbAccountEditSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbAccountEditSave_Click(object sender, EventArgs e) { var account = AcmeHelper.LoadAccountData(); account.OfflineMode = cbOfflineMode.Checked; AcmeHelper.SaveAccountData(account); pnlAccountEdit.Visible = false; pnlAccountDetail.Visible = true; HideSecondaryBlocks(false); ShowDetails(); }
/// <summary> /// Handles the Click event of the lbRegister control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbRegister_Click(object sender, EventArgs e) { HideSecondaryBlocks(true); pnlAccountDetail.Visible = false; pnlAccountRegister.Visible = true; var account = AcmeHelper.LoadAccountData(); tbAccountEmail.Text = account.Email; cbTestMode.Checked = account.TestMode; nbExistingAccount.Visible = !string.IsNullOrWhiteSpace(account.Email); var acme = new AcmeService(false); hlTOS.NavigateUrl = hlTOS.Text = acme.TermsOfServiceUrl; divTOS.Attributes["class"] = "alert alert-info"; }
/// <summary> /// Handles the Renew event of the gCertificates control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gCertificates_Renew(object sender, RowEventArgs e) { try { string errorMessage; // // Attempt to renew the certificate, new bindings will be created as needed. // var tuple = AcmeHelper.RenewCertificate(e.RowKeyId, true, out errorMessage); if (tuple == null) { nbRenewStatus.NotificationBoxType = NotificationBoxType.Danger; nbRenewStatus.Text = errorMessage; } else { if (AcmeHelper.LoadAccountData().OfflineMode) { string certData = Convert.ToBase64String(tuple.Item1) + "|" + string.Join("|", tuple.Item2.Select(c => Convert.ToBase64String(c))); hfCertificate.Value = Rock.Security.Encryption.EncryptString(certData); pnlDownloadCertificate.Visible = true; } else { nbRenewStatus.NotificationBoxType = NotificationBoxType.Success; nbRenewStatus.Text = "Certificate was renewed."; } } BindGrid(); } catch (Exception ex) { ExceptionLogService.LogException(ex, Context); throw; } }
/// <summary> /// Handles the Click event of the lbPrepareCertificate control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbPrepareCertificate_Click(object sender, EventArgs e) { // // Decode the data in the hidden field into the raw certificate data. // var certData = Rock.Security.Encryption.DecryptString(hfCertificate.Value) .Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries) .Select(v => Convert.FromBase64String(v)) .ToList(); var pkcs12 = AcmeHelper.GetPkcs12Certificate(tbCertificatePassword.Text, certData.First(), certData.Skip(1).ToList()); // // Store the password protected PKCS12 data as a binary file. // var rockContext = new RockContext(); var outputBinaryFile = new BinaryFile { IsTemporary = true, ContentStream = new System.IO.MemoryStream(pkcs12), FileName = "Certfificate.p12", MimeType = "application/x-pkcs12", BinaryFileTypeId = new BinaryFileTypeService(rockContext).Get(Rock.SystemGuid.BinaryFiletype.DEFAULT.AsGuid()).Id }; new BinaryFileService(rockContext).Add(outputBinaryFile); rockContext.SaveChanges(); // // Present a download link to the user. // pnlDownloadCertificate.Visible = false; nbRenewStatus.Text = string.Format("Your <a href='/GetFile.ashx?guid={0}'>certificate</a> is ready for download.", outputBinaryFile.Guid); nbRenewStatus.NotificationBoxType = NotificationBoxType.Success; }
/// <summary> /// Handles the OnLoad event of the block. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (!IsPostBack) { var account = AcmeHelper.LoadAccountData(); pnlCertificates.Visible = !string.IsNullOrWhiteSpace(account.Key); if (!string.IsNullOrWhiteSpace(account.Key)) { CheckIISState(); } BindGrid(); } else { nbIISError.Text = string.Empty; nbRenewStatus.Text = string.Empty; pnlDownloadCertificate.Visible = false; } }
/// <summary> /// Show the specified binding for editing. /// </summary> /// <param name="binding">The binding data to be edited or null to add a new binding.</param> protected void ShowBinding(BindingData binding) { ddlEditBindingSite.Items.Clear(); ddlEditBindingSite.Items.Add(new ListItem()); try { AcmeHelper.GetSites().ToList().ForEach(s => ddlEditBindingSite.Items.Add(s)); } catch { /* Intentionally left blank */ } ddlEditBindingIPAddress.Items.Clear(); ddlEditBindingIPAddress.Items.Add(new ListItem()); try { AcmeHelper.GetIPv4Addresses().ToList().ForEach(a => ddlEditBindingIPAddress.Items.Add(a)); } catch { /* Intentionally left blank */ } ddlEditBindingSite.SetValue(binding != null ? binding.Site : System.Web.Hosting.HostingEnvironment.SiteName); ddlEditBindingIPAddress.SetValue(binding != null ? binding.IPAddress : string.Empty); nbEditBindingPort.Text = binding != null?binding.Port.ToString() : "443"; tbEditBindingDomain.Text = binding != null ? binding.Domain : string.Empty; }
/// <summary> /// Performs various checks on IIS to ensure it is configured correctly for the certificates that /// have been setup for processing. /// </summary> protected void CheckIISState() { var rockContext = new RockContext(); var targetUrl = GetRedirectUrl(); var groupTypeId = GroupTypeCache.Read(com.blueboxmoon.AcmeCertificate.SystemGuid.GroupType.ACME_CERTIFICATES).Id; var bindings = new List <BindingData>(); var groups = new GroupService(rockContext).Queryable() .Where(g => g.GroupTypeId == groupTypeId); var siteNames = new List <string>(); // // Determine if we have any certificates that edit bindings of a site other than the Rock site. // foreach (var group in groups) { var currentSiteName = System.Web.Hosting.HostingEnvironment.SiteName; group.LoadAttributes(rockContext); bindings.AddRange(group.GetAttributeValue("Bindings") .Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries) .Select(b => new BindingData(b)) .Where(b => b.Site != currentSiteName)); siteNames.AddRange(bindings.Where(b => !AcmeHelper.IsIISSiteRedirectEnabled(b.Site, targetUrl)).Select(b => b.Site)); } // // If we have non-Rock sites to configure, ensure that the Http Redirect module has been // installed in IIS. // if (bindings.Any() && !AcmeHelper.IsHttpRedirectModuleEnabled()) { pnlIISRedirectModuleWarning.Visible = true; pnlIISRedirectSiteWarning.Visible = false; } else { pnlIISRedirectModuleWarning.Visible = false; } // // If the redirect module has been installed but we have sites that need to be // configured, then present a notice about those sites. // if (siteNames.Any() && !pnlIISRedirectModuleWarning.Visible) { siteNames = siteNames.Distinct().ToList(); hfEnableSiteRedirects.Value = siteNames.AsDelimited(","); ltEnableSiteRedirects.Text = "<li>" + siteNames.AsDelimited("</li><li>") + "</li>"; ltTargetRedirect.Text = targetUrl; pnlIISRedirectSiteWarning.Visible = true; } else { pnlIISRedirectSiteWarning.Visible = false; } }
/// <summary> /// Called when another block on the page requests secondary blocks to hide or become visible. /// </summary> /// <param name="visible">True if this block should become visible.</param> public void SetVisible(bool visible) { var account = AcmeHelper.LoadAccountData(); pnlCertificates.Visible = visible && !string.IsNullOrWhiteSpace(account.Key); }
private static async Task FetchAndCreateDnsRecords(ILogger log, string subscriptionId, CertificateRenewalInputModel certifcate, AcmeHelper acmeHelper, string domainName) { var dnsHelper = new DnsHelper(subscriptionId); log.LogInformation("Fetching DNS authorization"); var dnsText = await acmeHelper.GetDnsAuthorizationTextAsync(); var dnsName = ("_acme-challenge." + domainName).Replace("." + certifcate.DnsZoneName, "").Trim(); log.LogInformation($"Got DNS challenge {dnsText} for {dnsName}"); await CreateDnsTxtRecordsIfNecessary(log, certifcate, dnsHelper, dnsText, dnsName); log.LogInformation("Waiting 60 seconds for DNS propagation"); await Task.Delay(60 * 1000); }
public static async Task Run([TimerTrigger("0 17 23 * * *")] TimerInfo myTimer, ILogger log, ExecutionContext executionContext) { log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); string subscriptionId = Environment.GetEnvironmentVariable("SubscriptionId"); var config = new ConfigurationBuilder() .SetBasePath(executionContext.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); var certificateDetails = new List <CertificateRenewalInputModel>(); config.GetSection("CertificateDetails").Bind(certificateDetails); foreach (var certifcate in certificateDetails) { log.LogInformation($"Processing certificate - {certifcate.DomainName}"); var acmeHelper = new AcmeHelper(log); var certificateHelper = new KeyVaultCertificateHelper(certifcate.KeyVaultName); await InitAcme(log, certifcate, acmeHelper); string domainName = certifcate.DomainName; if (domainName.StartsWith("*")) { domainName = domainName.Substring(1); } log.LogInformation($"Calculated domain name is {domainName}"); string keyVaultCertificateName = domainName.Replace(".", ""); log.LogInformation($"Getting expiry for {keyVaultCertificateName} in Key Vault certifictes"); var certificateExpiry = await certificateHelper.GetCertificateExpiryAsync(keyVaultCertificateName); if (certificateExpiry.HasValue && certificateExpiry.Value.Subtract(DateTime.UtcNow).TotalDays > 7) { log.LogInformation("No certificates to renew."); continue; } log.LogInformation("Creating order for certificates"); await acmeHelper.CreateOrderAsync(certifcate.DomainName); log.LogInformation("Authorization created"); await FetchAndCreateDnsRecords(log, subscriptionId, certifcate, acmeHelper, domainName); log.LogInformation("Validating DNS challenge"); await acmeHelper.ValidateDnsAuthorizationAsync(); log.LogInformation("Challenge validated"); string password = Guid.NewGuid().ToString(); var pfx = await acmeHelper.GetPfxCertificateAsync(password, certifcate.CertificateCountryName, certifcate.CertificateState, certifcate.CertificateLocality, certifcate.CertificateOrganization, certifcate.CertificateOrganizationUnit, certifcate.DomainName, domainName); log.LogInformation("Certificate built"); (string certificateName, string certificateVerison) = await certificateHelper.ImportCertificate(keyVaultCertificateName, pfx, password); log.LogInformation("Certificate imported"); var cdnHelper = new CdnHelper(subscriptionId); await cdnHelper.EnableHttpsForCustomDomain(certifcate.CdnResourceGroup, certifcate.CdnProfileName, certifcate.CdnEndpointName, certifcate.CdnCustomDomainName, certificateName, certificateVerison, certifcate.KeyVaultName); log.LogInformation("HTTPS enabling started"); } }
private static async Task InitAcme(ILogger log, CertificateRenewalInputModel certifcate, AcmeHelper acmeHelper) { var secretHelper = new KeyVaultSecretHelper(certifcate.KeyVaultName); var acmeAccountPem = await secretHelper.GetSecretAsync("AcmeAccountKeyPem"); if (string.IsNullOrWhiteSpace(acmeAccountPem)) { log.LogInformation("Acme Account not found."); string pem = await acmeHelper.InitWithNewAccountAsync(Environment.GetEnvironmentVariable("AcmeAccountEmail")); log.LogInformation("Acme account created"); await secretHelper.SetSecretAsync("AcmeAccountKeyPem", pem); log.LogInformation("Secret uploaded to key vault"); } else { acmeHelper.InitWithExistingAccount(acmeAccountPem); } }