public async Task TestRequestAndInstallDnsCertificate()
        {
            var config     = new AppSettingsAuthConfig();
            var client     = ArmHelper.GetWebSiteManagementClient(config);
            var kuduClient = KuduHelper.GetKuduClient(client, config);

            var body = new DnsAzureInstallModel()
            {
                AzureWebAppEnvironment = new AzureWebAppEnvironment(config.Tenant, config.SubscriptionId, config.ClientId, config.ClientSecret, config.ResourceGroupName, config.WebAppName),
                AcmeConfig             = new AcmeConfig()
                {
                    Host              = "letsencrypt.ai4bots.com",
                    PFXPassword       = "******",
                    RegistrationEmail = "*****@*****.**",
                    RSAKeyLength      = 2048
                },
                RelativeRecordSetName = "letsencrypt",
                ZoneName            = "ai4bots.com",
                ResourceGroupName   = "dns",
                SubscriptionId      = new Guid("14fe4c66-c75a-4323-881b-ea53c1d86a9d"),
                CertificateSettings = new CertificateServiceSettings()
            };

            var res = await kuduClient.HttpClient.PostAsync(
                "https://webappcfmv5fy7lcq7o.scm.azurewebsites.net/letsencrypt/api/certificates/challengeprovider/dns/azure/certificateinstall/azurewebapp?api-version=2017-09-01",
                new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"));

            await ValidateResponse(body.AcmeConfig, res);
        }
        public static async Task <IReadOnlyList <string> > GetLetsEncryptHostNames(IAzureWebAppEnvironment webAppEnvironment, bool staging)
        {
            Site site;

            using (var client = await ArmHelper.GetWebSiteManagementClient(webAppEnvironment))
            {
                Trace.TraceInformation(
                    "Getting Web App '{0}' (slot '{1}') from resource group '{2}'",
                    webAppEnvironment.WebAppName,
                    webAppEnvironment.SiteSlotName,
                    webAppEnvironment.ResourceGroupName);

                site = client.WebApps.GetSiteOrSlot(webAppEnvironment.ResourceGroupName, webAppEnvironment.WebAppName, webAppEnvironment.SiteSlotName);
            }

            using (var httpClient = await ArmHelper.GetHttpClient(webAppEnvironment))
            {
                var certRequestUri = $"/subscriptions/{webAppEnvironment.SubscriptionId}/providers/Microsoft.Web/certificates?api-version=2016-03-01";
                Trace.TraceInformation("GET {0}", certRequestUri);
                var response = await ArmHelper.ExponentialBackoff().ExecuteAsync(async() => await httpClient.GetAsync(certRequestUri));

                Trace.TraceInformation("Reading ARM certificate query response");
                var body = await response.EnsureSuccessStatusCode().Content.ReadAsStringAsync();

                var letsEncryptCerts = ExtractCertificates(body).Where(s => s.Issuer.Contains(staging ? "Fake LE" : "Let's Encrypt"));

                var leCertThumbprints = new HashSet <string>(letsEncryptCerts.Select(c => c.Thumbprint));
                return(site.HostNameSslStates.Where(ssl => leCertThumbprints.Contains(ssl.Thumbprint)).Select(ssl => ssl.Name).ToArray());
            }
        }
Пример #3
0
        private async Task EnsureVirtualDirectorySetup()
        {
            if (virtualDirectorySetup)
            {
                Trace.TraceInformation("/.well-known already configured, skipping");
                return;
            }
            using (var client = await ArmHelper.GetWebSiteManagementClient(this.azureEnvironment))
            {
                var siteConfig = client.WebApps.GetSiteConfigurationOrSlot(azureEnvironment.ResourceGroupName, azureEnvironment.WebAppName, azureEnvironment.SiteSlotName);

                if (!IsVirtualDirectorySetup(siteConfig))
                {
                    var app = siteConfig.VirtualApplications.First();
                    if (app.VirtualDirectories == null)
                    {
                        app.VirtualDirectories = new List <VirtualDirectory>();
                    }
                    app.VirtualDirectories.Add(new VirtualDirectory()
                    {
                        PhysicalPath = wellKnownPhysicalPath,
                        VirtualPath  = "/.well-known",
                    });
                    client.WebApps.UpdateSiteConfigurationOrSlot(azureEnvironment.ResourceGroupName, azureEnvironment.WebAppName, azureEnvironment.SiteSlotName, siteConfig);
                }
                virtualDirectorySetup = true;
            }
        }
Пример #4
0
        public ActionResult Index(AuthenticationModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    using (var client = ArmHelper.GetWebSiteManagementClient(model))
                    {
                        //Update web config.
                        var site           = client.Sites.GetSite(model.ResourceGroupName, model.WebAppName);
                        var webappsettings = client.Sites.ListSiteAppSettings(model.ResourceGroupName, model.WebAppName);
                        if (model.UpdateAppSettings)
                        {
                            var newAppSettingsValues = new Dictionary <string, string> {
                                { AppSettingsAuthConfig.clientIdKey, model.ClientId.ToString() },
                                { AppSettingsAuthConfig.clientSecretKey, model.ClientSecret.ToString() },
                                { AppSettingsAuthConfig.subscriptionIdKey, model.SubscriptionId.ToString() },
                                { AppSettingsAuthConfig.tenantKey, model.Tenant },
                                { AppSettingsAuthConfig.resourceGroupNameKey, model.ResourceGroupName },
                                { AppSettingsAuthConfig.servicePlanResourceGroupNameKey, model.ServicePlanResourceGroupName }
                            };
                            foreach (var appsetting in newAppSettingsValues)
                            {
                                if (!webappsettings.Properties.ContainsKey(appsetting.Key))
                                {
                                    webappsettings.Properties.Add(appsetting.Key, appsetting.Value);
                                }
                                else
                                {
                                    webappsettings.Properties[appsetting.Key] = appsetting.Value;
                                }
                            }
                            client.Sites.UpdateSiteAppSettings(model.ResourceGroupName, model.WebAppName, webappsettings);
                        }
                        else
                        {
                            var appSetting = new AppSettingsAuthConfig();
                            if (!ValidateModelVsAppSettings("ClientId", model.ClientId.ToString(), appSetting.ClientId.ToString()) ||
                                !ValidateModelVsAppSettings("ClientSecret", appSetting.ClientSecret, model.ClientSecret) ||
                                !ValidateModelVsAppSettings("ResourceGroupName", appSetting.ResourceGroupName, model.ResourceGroupName) ||
                                !ValidateModelVsAppSettings("SubScriptionId", appSetting.SubscriptionId.ToString(), model.SubscriptionId.ToString()) ||
                                !ValidateModelVsAppSettings("Tenant", appSetting.Tenant, model.Tenant) ||
                                !ValidateModelVsAppSettings("ServicePlanResourceGroupName", appSetting.ServicePlanResourceGroupName, model.ServicePlanResourceGroupName))
                            {
                                model.ErrorMessage = "One or more app settings are different from the values entered, do you want to update the app settings?";
                                return(View(model));
                            }
                        }
                    }
                    return(RedirectToAction("Hostname"));
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.ToString());
                    model.ErrorMessage = ex.ToString();
                }
            }

            return(View(model));
        }
        public ActionResult Hostname(string id)
        {
            var settings = new AppSettingsAuthConfig();
            var model    = new HostnameModel();
            List <ValidationResult> validationResult = null;

            if (settings.IsValid(out validationResult))
            {
                var client = ArmHelper.GetWebSiteManagementClient(settings);

                var site = client.Sites.GetSiteOrSlot(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName);
                model.HostNames         = site.HostNames;
                model.HostNameSslStates = site.HostNameSslStates;
                model.Certificates      = client.Certificates.GetCertificates(settings.ServicePlanResourceGroupName).Value;
                model.InstalledCertificateThumbprint = id;
                if (model.HostNames.Count == 1)
                {
                    model.ErrorMessage = "No custom host names registered. At least one custom domain name must be registed for the web site to request a letsencrypt certificate.";
                }
            }
            else
            {
                var errorMessage = string.Join(" ,", validationResult.Select(s => s.ErrorMessage));
                model.ErrorMessage = $"Application settings was invalid, please wait a little and try to reload page if you just updated appsettings. Validation errors: {errorMessage}";
            }

            return(View(model));
        }
Пример #6
0
        public async Task TestRequestDnsCertificate()
        {
            var config = new AppSettingsAuthConfig();
            var client = await ArmHelper.GetWebSiteManagementClient(config);

            var kuduClient = KuduHelper.GetKuduClient(client, config);

            var body = new DnsAzureModel()
            {
                AzureDnsEnvironment = new AzureDnsEnvironment(config.Tenant, new Guid("14fe4c66-c75a-4323-881b-ea53c1d86a9d"), config.ClientId, config.ClientSecret, "dns", "ai4bots.com", "@"),
                AcmeConfig          = new AcmeConfig()
                {
                    Host              = "ai4bots.com",
                    PFXPassword       = "******",
                    RegistrationEmail = "*****@*****.**",
                    RSAKeyLength      = 2048
                }
            };

            var res = await kuduClient.HttpClient.PostAsync(
                "https://webappcfmv5fy7lcq7o.scm.azurewebsites.net/letsencrypt/api/certificates/challengeprovider/dns/azure?api-version=2017-09-01",
                new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"));

            await ValidateResponse(body.AcmeConfig, res);
        }
        public async Task TestRequestAndInstallCertificate()
        {
            var config     = new AppSettingsAuthConfig();
            var client     = ArmHelper.GetWebSiteManagementClient(config);
            var kuduClient = KuduHelper.GetKuduClient(client, config);

            var body = new HttpKuduInstallModel()
            {
                AzureEnvironment = new AzureWebAppEnvironment(config.Tenant, config.SubscriptionId, config.ClientId, config.ClientSecret, config.ResourceGroupName, config.WebAppName),
                AcmeConfig       = new AcmeConfig()
                {
                    Host              = "letsencrypt.sjkp.dk",
                    PFXPassword       = "******",
                    RegistrationEmail = "*****@*****.**",
                    RSAKeyLength      = 2048
                },
                AuthorizationChallengeProviderConfig = new AuthorizationChallengeProviderConfig(),
                CertificateSettings = new CertificateServiceSettings()
            };

            var res = await kuduClient.HttpClient.PostAsync(
                "https://webappcfmv5fy7lcq7o.scm.azurewebsites.net/letsencrypt/api/certificates/challengeprovider/http/kudu/certificateinstall/azurewebapp?api-version=2017-09-01",
                new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"));

            await ValidateResponse(body.AcmeConfig, res);
        }
        public KuduFileSystemAuthorizationChallengeProvider(IAzureWebAppEnvironment azureEnvironment, IAuthorizationChallengeProviderConfig config)
        {
            this.config = config;
            var website = ArmHelper.GetWebSiteManagementClient(azureEnvironment);

            this.kuduClient = KuduHelper.GetKuduClient(website, azureEnvironment);
        }
Пример #9
0
        public void Install(ICertificateInstallModel model)
        {
            var cert = model.CertificateInfo;
            using (var webSiteClient = ArmHelper.GetWebSiteManagementClient(azureEnvironment))
            {


                var s = webSiteClient.WebApps.GetSiteOrSlot(azureEnvironment.ResourceGroupName, azureEnvironment.WebAppName, azureEnvironment.SiteSlotName);

                Trace.TraceInformation(String.Format("Installing certificate {0} on azure with server farm id {1}", cert.Name, s.ServerFarmId));
                var newCert = new Certificate()
                {
                    PfxBlob = cert.PfxCertificate,
                    Password = cert.Password,
                    Location = s.Location,
                    ServerFarmId = s.ServerFarmId,
                    Name = model.Host + "-" + cert.Certificate.Thumbprint

                };
                //BUG https://github.com/sjkp/letsencrypt-siteextension/issues/99
                //using this will not install the certificate with the correct webSpace property set, 
                //and the app service will be unable to find the certificate if the app service plan has been moved between resource groups.
                //webSiteClient.Certificates.CreateOrUpdate(azureEnvironment.ServicePlanResourceGroupName, cert.Certificate.Subject.Replace("CN=", ""), newCert);

                var client = ArmHelper.GetHttpClient(azureEnvironment);

                var body = JsonConvert.SerializeObject(newCert, JsonHelper.DefaultSerializationSettings);

                var t = client.PutAsync($"/subscriptions/{azureEnvironment.SubscriptionId}/resourceGroups/{azureEnvironment.ServicePlanResourceGroupName}/providers/Microsoft.Web/certificates/{newCert.Name}?api-version=2016-03-01", new StringContent(body, Encoding.UTF8, "application/json")).Result;

                t.EnsureSuccessStatusCode();


                foreach (var dnsName in model.AllDnsIdentifiers)
                {
                    var sslState = s.HostNameSslStates.FirstOrDefault(g => g.Name == dnsName);

                    if (sslState == null)
                    {
                        sslState = new HostNameSslState()
                        {
                            Name = model.Host,
                            SslState = settings.UseIPBasedSSL ? SslState.IpBasedEnabled : SslState.SniEnabled,
                        };
                        s.HostNameSslStates.Add(sslState);
                    }
                    else
                    {
                        //First time setting the HostNameSslState it is set to disabled.
                        sslState.SslState = settings.UseIPBasedSSL ? SslState.IpBasedEnabled : SslState.SniEnabled;
                    }
                    sslState.ToUpdate = true;
                    sslState.Thumbprint = cert.Certificate.Thumbprint;
                }
                webSiteClient.WebApps.BeginCreateOrUpdateSiteOrSlot(azureEnvironment.ResourceGroupName, azureEnvironment.WebAppName, azureEnvironment.SiteSlotName, s);
            }


        }
        public async Task <bool> IsVirtualDirectorySetup()
        {
            using (var client = await ArmHelper.GetWebSiteManagementClient(this.azureEnvironment))
            {
                var siteConfig = client.WebApps.GetSiteConfigurationOrSlot(azureEnvironment.ResourceGroupName, azureEnvironment.WebAppName, azureEnvironment.SiteSlotName);

                return(IsVirtualDirectorySetup(siteConfig));
            }
        }
 /// <summary>
 /// Used for automatic installation of letsencrypt certificate
 /// </summary>
 public void AddCertificate()
 {
     Trace.TraceInformation("Staring add certificate");
     using (var client = ArmHelper.GetWebSiteManagementClient(settings))
     {
         Trace.TraceInformation($"Add certificate for acmeConfig hostname {string.Join(", ", acmeConfig.Hostnames)}");
         if (acmeConfig.Hostnames.Any())
         {
             RequestAndInstallInternal(this.acmeConfig);
         }
     }
 }
        public async Task <List <AcmeConfig> > RenewCertificate(bool skipInstallCertificate = false, int renewXNumberOfDaysBeforeExpiration = 0)
        {
            Trace.TraceInformation("Checking certificate");
            var ss = SettingsStore.Instance.Load();

            using (var client = ArmHelper.GetWebSiteManagementClient(settings))
                using (var httpClient = ArmHelper.GetHttpClient(settings))
                {
                    //Cant just get certificates by resource group, because sites that have been moved, have their certs sitting in the old RG.
                    //Also cant use client.Certificates.List() due to bug in the nuget
                    var response = await httpClient.GetAsync($"/subscriptions/{settings.SubscriptionId}/providers/Microsoft.Web/certificates?api-version=2016-03-01");

                    response.EnsureSuccessStatusCode();
                    var body = await response.Content.ReadAsStringAsync();

                    IEnumerable <Certificate> certs = JsonConvert.DeserializeObject <Certificate[]>(body, JsonHelper.DefaultSerializationSettings);

                    var expiringCerts = certs.Where(s => s.ExpirationDate < DateTime.UtcNow.AddDays(renewXNumberOfDaysBeforeExpiration) && (s.Issuer.Contains("Let's Encrypt") || s.Issuer.Contains("Fake LE")));

                    if (expiringCerts.Count() == 0)
                    {
                        Trace.TraceInformation(string.Format("No certificates installed issued by Let's Encrypt that are about to expire within the next {0} days. Skipping.", renewXNumberOfDaysBeforeExpiration));
                    }
                    var res = new List <AcmeConfig>();
                    foreach (var toExpireCert in expiringCerts)
                    {
                        Trace.TraceInformation("Starting renew of certificate " + toExpireCert.Name + " expiration date " + toExpireCert.ExpirationDate);
                        var site      = client.WebApps.Get(settings.ResourceGroupName, settings.WebAppName);
                        var sslStates = site.HostNameSslStates.Where(s => s.Thumbprint == toExpireCert.Thumbprint);
                        if (!sslStates.Any())
                        {
                            Trace.TraceInformation(String.Format("Certificate {0} was not assigned any hostname, skipping update", toExpireCert.Thumbprint));
                            continue;
                        }
                        var target = new AcmeConfig()
                        {
                            RegistrationEmail = this.acmeConfig.RegistrationEmail ?? ss.FirstOrDefault(s => s.Name == "email").Value,
                            Host           = sslStates.First().Name,
                            BaseUri        = this.acmeConfig.BaseUri ?? ss.FirstOrDefault(s => s.Name == "baseUri").Value,
                            AlternateNames = sslStates.Skip(1).Select(s => s.Name).ToList(),
                            PFXPassword    = this.acmeConfig.PFXPassword,
                            RSAKeyLength   = this.acmeConfig.RSAKeyLength
                        };
                        if (!skipInstallCertificate)
                        {
                            await RequestAndInstallInternalAsync(target);
                        }
                        res.Add(target);
                    }
                    return(res);
                }
        }
        public List <string> RemoveExpired(int removeXNumberOfDaysBeforeExpiration = 0)
        {
            using (var webSiteClient = ArmHelper.GetWebSiteManagementClient(azureEnvironment))
            {
                var certs = webSiteClient.Certificates.ListByResourceGroup(azureEnvironment.ServicePlanResourceGroupName);

                var tobeRemoved = certs.Where(s => s.ExpirationDate < DateTime.UtcNow.AddDays(removeXNumberOfDaysBeforeExpiration) && (s.Issuer.Contains("Let's Encrypt") || s.Issuer.Contains("Fake LE"))).ToList();

                tobeRemoved.ForEach(s => RemoveCertificate(webSiteClient, s));

                return(tobeRemoved.Select(s => s.Thumbprint).ToList());
            }
        }
Пример #14
0
        public IEnumerable <Target> RenewCertificate(bool debug = false)
        {
            Trace.TraceInformation("Checking certificate");
            var settings = new AppSettingsAuthConfig();
            var ss       = SettingsStore.Instance.Load();

            using (var client = ArmHelper.GetWebSiteManagementClient(settings))
            {
                var certs         = client.Certificates.GetCertificates(settings.ServicePlanResourceGroupName).Value;
                var expiringCerts = certs.Where(s => s.ExpirationDate < DateTime.UtcNow.AddDays(settings.RenewXNumberOfDaysBeforeExpiration) && (s.Issuer.Contains("Let's Encrypt") || s.Issuer.Contains("Fake LE")));

                if (expiringCerts.Count() == 0)
                {
                    Trace.TraceInformation(string.Format("No certificates installed issued by Let's Encrypt that are about to expire within the next {0} days. Skipping.", settings.RenewXNumberOfDaysBeforeExpiration));
                }

                foreach (var toExpireCert in expiringCerts)
                {
                    Trace.TraceInformation("Starting renew of certificate " + toExpireCert.Name + " expiration date " + toExpireCert.ExpirationDate);
                    var site      = client.Sites.GetSite(settings.ResourceGroupName, settings.WebAppName);
                    var sslStates = site.HostNameSslStates.Where(s => s.Thumbprint == toExpireCert.Thumbprint);
                    if (!sslStates.Any())
                    {
                        Trace.TraceInformation(String.Format("Certificate {0} was not assigned any hostname, skipping update", toExpireCert.Thumbprint));
                        continue;
                    }
                    var target = new Target()
                    {
                        WebAppName        = settings.WebAppName,
                        Tenant            = settings.Tenant,
                        SubscriptionId    = settings.SubscriptionId,
                        ClientId          = settings.ClientId,
                        ClientSecret      = settings.ClientSecret,
                        ResourceGroupName = settings.ResourceGroupName,
                        Email             = settings.Email ?? ss.FirstOrDefault(s => s.Name == "email").Value,
                        Host    = sslStates.First().Name,
                        BaseUri = settings.BaseUri ?? ss.FirstOrDefault(s => s.Name == "baseUri").Value,
                        ServicePlanResourceGroupName = settings.ServicePlanResourceGroupName,
                        AlternativeNames             = sslStates.Skip(1).Select(s => s.Name).ToList(),
                        UseIPBasedSSL = settings.UseIPBasedSSL,
                        SiteSlotName  = settings.SiteSlotName
                    };
                    if (!debug)
                    {
                        RequestAndInstallInternal(target);
                    }
                    yield return(target);
                }
            }
        }
        private void SetViewBagHostnames()
        {
            var settings = new AppSettingsAuthConfig();
            var client   = ArmHelper.GetWebSiteManagementClient(settings);

            var site  = client.Sites.GetSiteOrSlot(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName);
            var model = new HostnameModel();

            ViewBag.HostNames = site.HostNames.Where(s => !s.EndsWith(settings.AzureWebSitesDefaultDomainName)).Select(s => new SelectListItem()
            {
                Text  = s,
                Value = s
            });
        }
        public async Task <List <string> > RemoveExpired(int removeXNumberOfDaysBeforeExpiration = 0)
        {
            using (var webSiteClient = await ArmHelper.GetWebSiteManagementClient(azureEnvironment))
            {
                var certs = webSiteClient.Certificates.ListByResourceGroup(azureEnvironment.ServicePlanResourceGroupName);
                var site  = webSiteClient.WebApps.GetSiteOrSlot(azureEnvironment.ResourceGroupName, azureEnvironment.WebAppName, azureEnvironment.SiteSlotName);

                var tobeRemoved = certs.Where(s => s.ExpirationDate < DateTime.UtcNow.AddDays(removeXNumberOfDaysBeforeExpiration) && (s.Issuer.Contains("Let's Encrypt") || s.Issuer.Contains("Fake LE")) && !site.HostNameSslStates.Any(hostNameBindings => hostNameBindings.Thumbprint == s.Thumbprint)).ToList();
                foreach (var cert in tobeRemoved)
                {
                    await RemoveCertificate(webSiteClient, cert);
                }

                return(tobeRemoved.Select(s => s.Thumbprint).ToList());
            }
        }
        public async Task TestRenewCertificate()
        {
            var config     = new AppSettingsAuthConfig();
            var client     = ArmHelper.GetWebSiteManagementClient(config);
            var kuduClient = KuduHelper.GetKuduClient(client, config);

            var res = await kuduClient.HttpClient.PostAsync("https://webappcfmv5fy7lcq7o-vnext.scm.azurewebsites.net/letsencrypt/api/certificates/renew?api-version=2017-09-01", new StringContent(""));

            Assert.AreEqual(System.Net.HttpStatusCode.OK, res.StatusCode);

            var model = JsonConvert.DeserializeObject <CertificateInstallModel[]>(await res.Content.ReadAsStringAsync());

            Assert.AreEqual(1, model.Count());

            File.WriteAllBytes(Path.GetFileName(model.First().CertificateInfo.Name), model.First().CertificateInfo.PfxCertificate);
        }
Пример #18
0
        /// <summary>
        /// Used for automatic installation of hostnames bindings and certificate
        /// upon first installation on the site extension and if hostnames are specified in app settings
        /// </summary>
        public void SetupHostnameAndCertificate()
        {
            Trace.TraceInformation("Setup hostname and certificates");
            var settings = new AppSettingsAuthConfig();

            using (var client = ArmHelper.GetWebSiteManagementClient(settings))
            {
                var s = client.Sites.GetSite(settings.ResourceGroupName, settings.WebAppName);
                foreach (var hostname in settings.Hostnames)
                {
                    if (s.HostNames.Any(existingHostname => string.Equals(existingHostname, hostname, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        Trace.TraceInformation("Hostname already configured skipping installation");
                        continue;
                    }
                    Trace.TraceInformation("Setting up hostname and lets encrypt certificate for " + hostname);
                    client.Sites.CreateOrUpdateSiteOrSlotHostNameBinding(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName, hostname, new HostNameBinding()
                    {
                        CustomHostNameDnsRecordType = CustomHostNameDnsRecordType.CName,
                        HostNameType = HostNameType.Verified,
                        SiteName     = settings.WebAppName,
                        Location     = s.Location
                    });
                }
                if (settings.Hostnames.Any())
                {
                    RequestAndInstallInternal(new Target()
                    {
                        BaseUri                      = settings.BaseUri,
                        ClientId                     = settings.ClientId,
                        ClientSecret                 = settings.ClientSecret,
                        Email                        = settings.Email,
                        Host                         = settings.Hostnames.First(),
                        ResourceGroupName            = settings.ResourceGroupName,
                        SubscriptionId               = settings.SubscriptionId,
                        Tenant                       = settings.Tenant,
                        WebAppName                   = settings.WebAppName,
                        ServicePlanResourceGroupName = settings.ServicePlanResourceGroupName,
                        AlternativeNames             = settings.Hostnames.Skip(1).ToList(),
                        SiteSlotName                 = settings.SiteSlotName,
                        UseIPBasedSSL                = settings.UseIPBasedSSL
                    });
                }
            }
        }
Пример #19
0
        public ActionResult Hostname(string id)
        {
            var settings = new AppSettingsAuthConfig();
            var client   = ArmHelper.GetWebSiteManagementClient(settings);

            var site  = client.Sites.GetSite(settings.ResourceGroupName, settings.WebAppName);
            var model = new HostnameModel();

            model.HostNames         = site.HostNames;
            model.HostNameSslStates = site.HostNameSslStates;
            model.Certificates      = client.Certificates.GetCertificates(settings.ServicePlanResourceGroupName).Value;
            model.InstalledCertificateThumbprint = id;
            if (model.HostNames.Count == 1)
            {
                model.ErrorMessage = "No custom host names registered. At least one custom domain name must be registed for the web site to request a letsencrypt certificate.";
            }

            return(View(model));
        }
Пример #20
0
        public async Task <ActionResult> AddHostname()
        {
            var settings = new AppSettingsAuthConfig();

            using (var client = await ArmHelper.GetWebSiteManagementClient(settings))
            {
                var s = client.WebApps.GetSiteOrSlot(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName);
                foreach (var hostname in settings.Hostnames)
                {
                    client.WebApps.CreateOrUpdateSiteOrSlotHostNameBinding(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName, hostname, new HostNameBinding
                    {
                        CustomHostNameDnsRecordType = CustomHostNameDnsRecordType.CName,
                        HostNameType = HostNameType.Verified,
                        SiteName     = settings.WebAppName,
                    });
                }
            }
            return(View());
        }
Пример #21
0
        public ActionResult AddHostname()
        {
            var settings = new AppSettingsAuthConfig();

            using (var client = ArmHelper.GetWebSiteManagementClient(settings))
            {
                var s = client.Sites.GetSite(settings.ResourceGroupName, settings.WebAppName);
                foreach (var hostname in settings.Hostnames)
                {
                    client.Sites.CreateOrUpdateSiteHostNameBinding(settings.ResourceGroupName, settings.WebAppName, hostname, new Microsoft.Azure.Management.WebSites.Models.HostNameBinding()
                    {
                        CustomHostNameDnsRecordType = Microsoft.Azure.Management.WebSites.Models.CustomHostNameDnsRecordType.CName,
                        HostNameType = Microsoft.Azure.Management.WebSites.Models.HostNameType.Verified,
                        SiteName     = settings.WebAppName,
                        Location     = s.Location
                    });
                }
            }
            return(View());
        }
        public async Task GetPublishingCredentials()
        {
            var model  = new AppSettingsAuthConfig();
            var helper = ArmHelper.GetWebSiteManagementClient(model);

            var kuduClient = KuduHelper.GetKuduClient(helper, model);

            //var res = await kuduClient.GetScmInfo();

            var dir = await kuduClient.GetFile("site/wwwroot/host.json");

            using (var ms = new MemoryStream())
            {
                var sw = new StreamWriter(ms);
                sw.WriteLine("Hell asd asd asd ");
                sw.Flush();

                await kuduClient.PutFile("site/wwwroot/.well-known/acme-challenge2/test.json", ms);
            }
        }
        public static async Task<IReadOnlyList<string>> GetNonExpiringLetsEncryptHostNames(IAzureWebAppEnvironment webAppEnvironment, bool staging, int renewXNumberOfDaysBeforeExpiration)
        {
            Site site;
            using (var client = await ArmHelper.GetWebSiteManagementClient(webAppEnvironment).ConfigureAwait(false))
            {
                var webAppName = webAppEnvironment.WebAppName;
                var resourceGroupName = webAppEnvironment.ResourceGroupName;
                var siteSlotName = webAppEnvironment.SiteSlotName;
                Trace.TraceInformation(
                    "Getting Web App '{0}' (slot '{1}') from resource group '{2}'",
                    webAppName,
                    siteSlotName,
                    resourceGroupName);

                site = client.WebApps.GetSiteOrSlot(resourceGroupName, webAppName, siteSlotName);
                if (site == null)
                {
                    throw new InvalidOperationException(
                        $"Could not find web app '{webAppName}' (slot '{siteSlotName}') under Resource Groups '{resourceGroupName}'");
                }
            }

            using (var httpClient = await ArmHelper.GetHttpClient(webAppEnvironment).ConfigureAwait(false))
            {
                var certRequestUri = $"/subscriptions/{webAppEnvironment.SubscriptionId}/providers/Microsoft.Web/certificates?api-version=2016-03-01";
                Trace.TraceInformation("GET {0}", certRequestUri);
                var response = await ArmHelper.ExponentialBackoff().ExecuteAsync(() => httpClient.GetAsync(new Uri(certRequestUri, UriKind.Relative))).ConfigureAwait(false);

                Trace.TraceInformation("Reading ARM certificate query response");
                var body = await response.EnsureSuccessStatusCode().Content.ReadAsStringAsync().ConfigureAwait(false);

                var letsEncryptIssuerNames = staging ? s_letsEncrypStagingtIssuerNames : s_letsEncryptIssuerNames;

                var letsEncryptNonExpiringCerts = ExtractCertificates(body).Where(cert =>
                    letsEncryptIssuerNames.Contains(cert.Issuer) &&
                    cert.ExpirationDate > DateTime.UtcNow.AddDays(renewXNumberOfDaysBeforeExpiration));

                var letsEncryptNonExpiringThumbprints = new HashSet<string>(letsEncryptNonExpiringCerts.Select(c => c.Thumbprint));
                return site.HostNameSslStates.Where(ssl => letsEncryptNonExpiringThumbprints.Contains(ssl.Thumbprint)).Select(ssl => ssl.Name).ToArray();
            }
        }
        public ActionResult Index(AuthenticationModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    using (var client = ArmHelper.GetWebSiteManagementClient(model))
                    {
                        //Update web config.
                        var site = client.Sites.GetSiteOrSlot(model.ResourceGroupName, model.WebAppName, model.SiteSlotName);
                        //Validate that the service plan resource group name is correct, to avoid more issues on this specific problem.
                        var azureServerFarmResourceGroup = site.ServerFarmResourceGroup();
                        if (!string.Equals(azureServerFarmResourceGroup, model.ServicePlanResourceGroupName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            ModelState.AddModelError("ServicePlanResourceGroupName", string.Format("The Service Plan Resource Group registered on the Web App in Azure in the ServerFarmId property '{0}' does not match the value you entered here {1}", azureServerFarmResourceGroup, model.ServicePlanResourceGroupName));
                            return(View(model));
                        }
                        var webappsettings = client.Sites.ListSiteOrSlotAppSettings(model.ResourceGroupName, model.WebAppName, model.SiteSlotName);
                        if (model.UpdateAppSettings)
                        {
                            var newAppSettingsValues = new Dictionary <string, string> {
                                { AppSettingsAuthConfig.clientIdKey, model.ClientId.ToString() },
                                { AppSettingsAuthConfig.clientSecretKey, model.ClientSecret.ToString() },
                                { AppSettingsAuthConfig.subscriptionIdKey, model.SubscriptionId.ToString() },
                                { AppSettingsAuthConfig.tenantKey, model.Tenant },
                                { AppSettingsAuthConfig.resourceGroupNameKey, model.ResourceGroupName },
                                { AppSettingsAuthConfig.siteSlotNameKey, model.SiteSlotName },
                                { AppSettingsAuthConfig.servicePlanResourceGroupNameKey, model.ServicePlanResourceGroupName },
                                { AppSettingsAuthConfig.useIPBasedSSL, model.UseIPBasedSSL.ToString().ToLowerInvariant() }
                            };
                            foreach (var appsetting in newAppSettingsValues)
                            {
                                if (!webappsettings.Properties.ContainsKey(appsetting.Key))
                                {
                                    webappsettings.Properties.Add(appsetting.Key, appsetting.Value);
                                }
                                else
                                {
                                    webappsettings.Properties[appsetting.Key] = appsetting.Value;
                                }
                            }

                            client.Sites.UpdateSiteOrSlotAppSettings(model.ResourceGroupName, model.WebAppName, model.SiteSlotName, webappsettings);
                            ConfigurationManager.RefreshSection("appSettings");
                        }
                        else
                        {
                            var appSetting = new AppSettingsAuthConfig();
                            if (!ValidateModelVsAppSettings("ClientId", appSetting.ClientId.ToString(), model.ClientId.ToString()) ||
                                !ValidateModelVsAppSettings("ClientSecret", appSetting.ClientSecret, model.ClientSecret) ||
                                !ValidateModelVsAppSettings("ResourceGroupName", appSetting.ResourceGroupName, model.ResourceGroupName) ||
                                !ValidateModelVsAppSettings("SubScriptionId", appSetting.SubscriptionId.ToString(), model.SubscriptionId.ToString()) ||
                                !ValidateModelVsAppSettings("Tenant", appSetting.Tenant, model.Tenant) ||
                                !ValidateModelVsAppSettings("SiteSlotName", appSetting.SiteSlotName, model.SiteSlotName) ||
                                !ValidateModelVsAppSettings("ServicePlanResourceGroupName", appSetting.ServicePlanResourceGroupName, model.ServicePlanResourceGroupName) ||
                                !ValidateModelVsAppSettings("UseIPBasedSSL", appSetting.UseIPBasedSSL.ToString().ToLowerInvariant(), model.UseIPBasedSSL.ToString().ToLowerInvariant()))
                            {
                                model.ErrorMessage = "One or more app settings are different from the values entered, do you want to update the app settings?";
                                return(View(model));
                            }
                        }
                    }
                    return(RedirectToAction("PleaseWait"));
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.ToString());
                    model.ErrorMessage = ex.ToString();
                }
            }

            return(View(model));
        }
Пример #25
0
        public static string RequestAndInstallInternal(Target target)
        {
            BaseURI    = target.BaseUri ?? "https://acme-staging.api.letsencrypt.org/";
            configPath = ConfigPath(BaseURI);
            try
            {
                webSiteClient = ArmHelper.GetWebSiteManagementClient(target);
            }
            catch (Exception ex)
            {
                Trace.TraceError("Unabled to create Azure Web Site Management client " + ex.ToString());
                throw;
            }

            if (!Directory.Exists(configPath))
            {
                Directory.CreateDirectory(configPath);
            }
            var email = target.Email;

            try
            {
                using (var signer = new RS256Signer())
                {
                    signer.Init();

                    var signerPath = Path.Combine(configPath, "Signer");
                    if (File.Exists(signerPath))
                    {
                        Trace.TraceInformation($"Loading Signer from {signerPath}");
                        using (var signerStream = File.OpenRead(signerPath))
                            signer.Load(signerStream);
                    }

                    using (client = new AcmeClient(new Uri(BaseURI), new AcmeServerDirectory(), signer))
                    {
                        client.Init();
                        Trace.TraceInformation("\nGetting AcmeServerDirectory");
                        client.GetDirectory(true);

                        var registrationPath = Path.Combine(configPath, "Registration");
                        if (File.Exists(registrationPath))
                        {
                            Trace.TraceInformation($"Loading Registration from {registrationPath}");
                            using (var registrationStream = File.OpenRead(registrationPath))
                                client.Registration = AcmeRegistration.Load(registrationStream);
                        }
                        else
                        {
                            var contacts = new string[] { };
                            if (!String.IsNullOrEmpty(email))
                            {
                                email    = "mailto:" + email;
                                contacts = new string[] { email };
                            }

                            Trace.TraceInformation("Calling Register");
                            var registration = client.Register(contacts);


                            Trace.TraceInformation("Updating Registration");
                            client.UpdateRegistration(true, true);

                            Trace.TraceInformation("Saving Registration");
                            using (var registrationStream = File.OpenWrite(registrationPath))
                                client.Registration.Save(registrationStream);

                            Trace.TraceInformation("Saving Signer");
                            using (var signerStream = File.OpenWrite(signerPath))
                                signer.Save(signerStream);
                        }

                        //                        if (Options.Renew)
                        //                        {
                        //                            CheckRenewals();
                        //#if DEBUG
                        //                            Trace.TraceInformation("Press enter to continue.");
                        //                            Trace.ReadLine();
                        //#endif
                        //                            return;
                        //                        }
                        return(Auto(target));
                    }
                }
            }
            catch (Exception e)
            {
                var acmeWebException = e as AcmeClient.AcmeWebException;
                if (acmeWebException != null)
                {
                    Trace.TraceError(acmeWebException.Message);
                    Trace.TraceError("ACME Server Returned:");
                    Trace.TraceError(acmeWebException.Response.ContentAsString);
                }
                else
                {
                    Trace.TraceError(e.ToString());
                }
                throw;
            }
        }
        private async Task <KuduRestClient> GetKuduRestClient()
        {
            var website = await ArmHelper.GetWebSiteManagementClient(azureEnvironment);

            return(KuduHelper.GetKuduClient(website, azureEnvironment));
        }
Пример #27
0
        public async Task <ActionResult> Index(AuthenticationModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    using (var client = await ArmHelper.GetWebSiteManagementClient(model))
                    {
                        //Update web config.
                        var site = client.WebApps.GetSiteOrSlot(model.ResourceGroupName, model.WebAppName, model.SiteSlotName);
                        if (site == null)
                        {
                            ModelState.AddModelError(nameof(model.ResourceGroupName), string.Format("No web app could be found, please validate that Resource Group Name and/or Site Slot Name are correct"));
                            return(View(model));
                        }
                        //Validate that the service plan resource group name is correct, to avoid more issues on this specific problem.
                        var azureServerFarmResourceGroup = site.ServerFarmResourceGroup();
                        if (!string.Equals(azureServerFarmResourceGroup, model.ServicePlanResourceGroupName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            ModelState.AddModelError("ServicePlanResourceGroupName", string.Format("The Service Plan Resource Group registered on the Web App in Azure in the ServerFarmId property '{0}' does not match the value you entered here {1}", azureServerFarmResourceGroup, model.ServicePlanResourceGroupName));
                            return(View(model));
                        }
                        var appServicePlan = client.AppServicePlans.Get(model.ServicePlanResourceGroupName, site.ServerFarmName());
                        if (appServicePlan.Sku.Tier.Equals("Free") || appServicePlan.Sku.Tier.Equals("Shared"))
                        {
                            ModelState.AddModelError("ServicePlanResourceGroupName", $"The Service Plan is using the {appServicePlan.Sku.Tier} which doesn't support SSL certificates");
                            return(View(model));
                        }
                        var path = new PathProvider(model);
                        if (model.RunFromPackage && !await path.IsVirtualDirectorySetup() && !model.UpdateAppSettings)
                        {
                            ModelState.AddModelError("UpdateAppSettings", string.Format("The site is using Run From Package. You need to to allow the site-extension to update app settings to setup the virtual directory."));
                            return(View(model));
                        }
                        var webappsettings = client.WebApps.ListSiteOrSlotAppSettings(model.ResourceGroupName, model.WebAppName, model.SiteSlotName);
                        if (model.UpdateAppSettings)
                        {
                            var newAppSettingsValues = new Dictionary <string, string> {
                                { AppSettingsAuthConfig.clientIdKey, model.ClientId.ToString() },
                                { AppSettingsAuthConfig.clientSecretKey, model.ClientSecret.ToString() },
                                { AppSettingsAuthConfig.subscriptionIdKey, model.SubscriptionId.ToString() },
                                { AppSettingsAuthConfig.tenantKey, model.Tenant },
                                { AppSettingsAuthConfig.resourceGroupNameKey, model.ResourceGroupName },
                                { AppSettingsAuthConfig.siteSlotNameKey, model.SiteSlotName },
                                { AppSettingsAuthConfig.servicePlanResourceGroupNameKey, model.ServicePlanResourceGroupName },
                                { AppSettingsAuthConfig.useIPBasedSSL, model.UseIPBasedSSL.ToString().ToLowerInvariant() }
                            };
                            foreach (var appsetting in newAppSettingsValues)
                            {
                                if (!webappsettings.Properties.ContainsKey(appsetting.Key))
                                {
                                    webappsettings.Properties.Add(appsetting.Key, appsetting.Value);
                                }
                                else
                                {
                                    webappsettings.Properties[appsetting.Key] = appsetting.Value;
                                }
                            }

                            client.WebApps.UpdateSiteOrSlotAppSettings(model.ResourceGroupName, model.WebAppName, model.SiteSlotName, webappsettings);
                            ConfigurationManager.RefreshSection("appSettings");

                            await path.ChallengeDirectory(true);
                        }
                        else
                        {
                            var appSetting = new AppSettingsAuthConfig();
                            if (!ValidateModelVsAppSettings("ClientId", appSetting.ClientId.ToString(), model.ClientId.ToString()) ||
                                !ValidateModelVsAppSettings("ClientSecret", appSetting.ClientSecret, model.ClientSecret) ||
                                !ValidateModelVsAppSettings("ResourceGroupName", appSetting.ResourceGroupName, model.ResourceGroupName) ||
                                !ValidateModelVsAppSettings("SubScriptionId", appSetting.SubscriptionId.ToString(), model.SubscriptionId.ToString()) ||
                                !ValidateModelVsAppSettings("Tenant", appSetting.Tenant, model.Tenant) ||
                                !ValidateModelVsAppSettings("SiteSlotName", appSetting.SiteSlotName, model.SiteSlotName) ||
                                !ValidateModelVsAppSettings("ServicePlanResourceGroupName", appSetting.ServicePlanResourceGroupName, model.ServicePlanResourceGroupName) ||
                                !ValidateModelVsAppSettings("UseIPBasedSSL", appSetting.UseIPBasedSSL.ToString().ToLowerInvariant(), model.UseIPBasedSSL.ToString().ToLowerInvariant()))
                            {
                                model.ErrorMessage = "One or more app settings are different from the values entered, do you want to update the app settings?";
                                return(View(model));
                            }
                        }
                    }
                    return(RedirectToAction("PleaseWait"));
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.ToString());
                    model.ErrorMessage = ex.ToString();
                }
            }

            return(View(model));
        }
Пример #28
0
        private async Task <int> RenewCore(RenewalParameters renewalParams)
        {
            Trace.TraceInformation("Generating SSL certificate with parameters: {0}", renewalParams);

            Trace.TraceInformation("Generating secure PFX password for '{0}'...", renewalParams.WebApp);
            var pfxPassData = new byte[32];

            s_randomGenerator.GetBytes(pfxPassData);

            Trace.TraceInformation(
                "Adding SSL cert for '{0}{1}'...",
                renewalParams.WebApp,
                renewalParams.GroupName == null ? String.Empty : $"[{renewalParams.GroupName}]");

            azureEnvironment = new AzureWebAppEnvironment(
                renewalParams.TenantId,
                renewalParams.SubscriptionId,
                renewalParams.ClientId,
                renewalParams.ClientSecret,
                renewalParams.ResourceGroup,
                renewalParams.WebApp,
                renewalParams.ServicePlanResourceGroup,
                renewalParams.SiteSlotName)
            {
                WebRootPath = renewalParams.WebRootPath,
                AzureWebSitesDefaultDomainName = renewalParams.AzureDefaultWebsiteDomainName ?? DefaultWebsiteDomainName,
                AuthenticationEndpoint         = renewalParams.AuthenticationUri ?? new Uri(DefaultAuthenticationUri),
                ManagementEndpoint             = renewalParams.AzureManagementEndpoint ?? new Uri(DefaultManagementEndpoint),
                TokenAudience = renewalParams.AzureTokenAudience ?? new Uri(DefaultAzureTokenAudienceService),
            };

            var manager = CertificateManager.CreateKuduWebAppCertificateManager(
                azureEnvironment,
                new AcmeConfig
            {
                Host              = renewalParams.Hosts[0],
                AlternateNames    = renewalParams.Hosts.Skip(1).ToList(),
                RegistrationEmail = renewalParams.Email,
                RSAKeyLength      = renewalParams.RsaKeyLength,
                PFXPassword       = Convert.ToBase64String(pfxPassData),
                BaseUri           = (renewalParams.AcmeBaseUri ?? new Uri(DefaultAcmeBaseUri)).ToString(),
            },
                new CertificateServiceSettings {
                UseIPBasedSSL = renewalParams.UseIpBasedSsl
            },
                new AuthProviderConfig());

            var certificatesRenewed = 0;

            using (webSiteClient = await ArmHelper.GetWebSiteManagementClient(azureEnvironment))
            {
                var isWebAppRunning = IsWebAppRunning();

                if (!isWebAppRunning && !await StartWebApp())
                {
                    string errorMessage = string.Format("Could not start WebApp '{0}' to renew certificate", renewalParams.WebApp);
                    Trace.TraceError(errorMessage);
                    throw new WebAppException(renewalParams.WebApp, "Could not start WebApp");
                }

                if (await HasCertificate())
                {
                    var result = await manager.RenewCertificate(false, renewalParams.RenewXNumberOfDaysBeforeExpiration);

                    certificatesRenewed = result.Count;
                }
                else
                {
                    var result = await manager.AddCertificate();

                    if (result != null)
                    {
                        certificatesRenewed = 1;
                    }
                }

                if (!isWebAppRunning && !await StopWebApp())
                {
                    Trace.TraceWarning("Could not stop WebApp '{0}' after renewing certificate", renewalParams.WebApp);
                }
            }

            Trace.TraceInformation("SSL cert added successfully to '{0}'", renewalParams.WebApp);

            return(certificatesRenewed);
        }