Skip to content

Commit 7e51e56

Browse files
committed
1 parent 6f89f87 commit 7e51e56

File tree

8 files changed

+112
-20
lines changed

8 files changed

+112
-20
lines changed

LetsEncrypt.Azure.DotNetCore.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1616
Dockerfile = Dockerfile
1717
EndProjectSection
1818
EndProject
19+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LetsEncrypt.Azure.FunctionV2", "examples\LetsEncrypt.Azure.FunctionV2\LetsEncrypt.Azure.FunctionV2.csproj", "{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}"
20+
EndProject
21+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{33597FE6-D5E9-4F8E-9009-294BFC3D5F9A}"
22+
EndProject
1923
Global
2024
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2125
Debug|Any CPU = Debug|Any CPU
@@ -62,10 +66,25 @@ Global
6266
{6C89066E-0418-4303-809D-9F3F9BBB1013}.Release|x64.Build.0 = Release|Any CPU
6367
{6C89066E-0418-4303-809D-9F3F9BBB1013}.Release|x86.ActiveCfg = Release|Any CPU
6468
{6C89066E-0418-4303-809D-9F3F9BBB1013}.Release|x86.Build.0 = Release|Any CPU
69+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
70+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Debug|Any CPU.Build.0 = Debug|Any CPU
71+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Debug|x64.ActiveCfg = Debug|Any CPU
72+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Debug|x64.Build.0 = Debug|Any CPU
73+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Debug|x86.ActiveCfg = Debug|Any CPU
74+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Debug|x86.Build.0 = Debug|Any CPU
75+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Release|Any CPU.ActiveCfg = Release|Any CPU
76+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Release|Any CPU.Build.0 = Release|Any CPU
77+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Release|x64.ActiveCfg = Release|Any CPU
78+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Release|x64.Build.0 = Release|Any CPU
79+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Release|x86.ActiveCfg = Release|Any CPU
80+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079}.Release|x86.Build.0 = Release|Any CPU
6581
EndGlobalSection
6682
GlobalSection(SolutionProperties) = preSolution
6783
HideSolutionNode = FALSE
6884
EndGlobalSection
85+
GlobalSection(NestedProjects) = preSolution
86+
{FF8A14C9-8AC7-4057-A2EC-BA31C3965079} = {33597FE6-D5E9-4F8E-9009-294BFC3D5F9A}
87+
EndGlobalSection
6988
GlobalSection(ExtensibilityGlobals) = postSolution
7089
SolutionGuid = {5AC649FA-BB48-4484-993B-2BBCFC05742D}
7190
EndGlobalSection

LetsEncrypt.SiteExtension.Core/ArmHelper.cs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
using Microsoft.Rest;
66
using Polly;
77
using System;
8+
using System.Diagnostics;
89
using System.Linq;
910
using System.Net;
1011
using System.Net.Http;
12+
using System.Text;
1113
using System.Threading;
1214
using System.Threading.Tasks;
1315

@@ -16,11 +18,11 @@ namespace LetsEncrypt.Azure.Core
1618
public static class ArmHelper
1719
{
1820
public static async Task<WebSiteManagementClient> GetWebSiteManagementClient(IAzureWebAppEnvironment model)
19-
{
21+
{
2022
AuthenticationResult token = await GetToken(model);
2123
var creds = new TokenCredentials(token.AccessToken);
2224

23-
var websiteClient = new WebSiteManagementClient(model.ManagementEndpoint, creds);
25+
var websiteClient = new WebSiteManagementClient(model.ManagementEndpoint, creds, new TraceLoggingHandler());
2426
websiteClient.SubscriptionId = model.SubscriptionId.ToString();
2527
return websiteClient;
2628
}
@@ -44,7 +46,7 @@ private static async Task<AuthenticationResult> GetToken(IAzureEnvironment model
4446
}
4547

4648
public static async Task<HttpClient> GetHttpClient(IAzureWebAppEnvironment model)
47-
{
49+
{
4850
AuthenticationResult token = await GetToken(model);
4951

5052
var client = HttpClientFactory.Create(new HttpClientHandler(), new TimeoutHandler());
@@ -60,7 +62,7 @@ public static Polly.Retry.RetryPolicy<HttpResponseMessage> ExponentialBackoff(in
6062
.HandleResult<HttpResponseMessage>((resp) =>
6163
{
6264
return IsTransient(resp.StatusCode);
63-
65+
6466
})
6567
.WaitAndRetryAsync(retryCount, retryAttempt =>
6668
TimeSpan.FromSeconds(Math.Pow(firstBackOffDelay, retryAttempt))
@@ -103,4 +105,60 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
103105
}
104106
}
105107
}
108+
109+
public abstract class MessageHandler : DelegatingHandler
110+
{
111+
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
112+
{
113+
var corrId = string.Format("{0}{1}", DateTime.Now.Ticks, Thread.CurrentThread.ManagedThreadId);
114+
var requestInfo = string.Format("{0} {1}, headers {2}", request.Method, request.RequestUri, string.Join(",", request.Headers
115+
.Where(s => !string.Equals(s.Key, "Authorization", StringComparison.InvariantCultureIgnoreCase))
116+
.Select(s => $"{s.Key} = {string.Join("|", s.Value)}")
117+
));
118+
119+
byte[] requestMessage = null;
120+
if (request.Content != null)
121+
{
122+
requestMessage = await request.Content.ReadAsByteArrayAsync().ConfigureAwait(continueOnCapturedContext: false);
123+
}
124+
125+
LogIncommingMessage(corrId, requestInfo, requestMessage);
126+
127+
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
128+
129+
byte[] responseMessage = null;
130+
if (response.Content != null)
131+
{
132+
responseMessage = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(continueOnCapturedContext: false);
133+
}
134+
135+
LogOutgoingMessage(corrId, requestInfo, responseMessage);
136+
137+
return response;
138+
}
139+
140+
141+
protected abstract void LogIncommingMessage(string correlationId, string requestInfo, byte[] message);
142+
protected abstract void LogOutgoingMessage(string correlationId, string requestInfo, byte[] message);
143+
}
144+
145+
146+
147+
public class TraceLoggingHandler : MessageHandler
148+
{
149+
150+
public TraceLoggingHandler()
151+
{
152+
}
153+
protected override void LogIncommingMessage(string correlationId, string requestInfo, byte[] message)
154+
{
155+
Trace.TraceInformation(string.Format("{0} - Request: {1}\r\n{2}", correlationId, requestInfo, message != null ? Encoding.UTF8.GetString(message) : String.Empty));
156+
}
157+
158+
159+
protected override void LogOutgoingMessage(string correlationId, string requestInfo, byte[] message)
160+
{
161+
Trace.TraceInformation(string.Format("{0} - Response: {1}\r\n{2}", correlationId, requestInfo, message != null ? Encoding.UTF8.GetString(message) : String.Empty));
162+
}
163+
}
106164
}
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
using LetsEncrypt.Azure.Core.Models;
22
using Microsoft.Azure.Management.WebSites;
33
using System;
4-
using System.Collections.Generic;
5-
using System.Linq;
6-
using System.Text;
7-
using System.Threading.Tasks;
84

95
namespace LetsEncrypt.Azure.Core
106
{
@@ -13,8 +9,22 @@ public static class KuduHelper
139
public static KuduRestClient GetKuduClient(this WebSiteManagementClient client, IAzureWebAppEnvironment settings)
1410
{
1511
var user = client.WebApps.GetPublsihingCredentialSiteOrSlot(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName);
12+
var site = client.WebApps.GetSiteOrSlot(settings.ResourceGroupName, settings.WebAppName, settings.SiteSlotName);
13+
var defaultHostName = site.DefaultHostName;
1614

17-
return new KuduRestClient(settings, user.PublishingUserName, user.PublishingPassword);
15+
return new KuduRestClient(MakeScmUri(defaultHostName,settings), user.PublishingUserName, user.PublishingPassword);
16+
}
17+
18+
/// <summary>
19+
/// TODO; should also work for APP service environment, which uses a different format for scm site uri https://blogs.msdn.microsoft.com/benjaminperkins/2017/11/08/how-to-access-kudu-scm-for-an-azure-app-service-environment-ase/
20+
/// </summary>
21+
/// <param name="defaultHostName"></param>
22+
/// <param name="settings"></param>
23+
/// <returns></returns>
24+
public static Uri MakeScmUri(string defaultHostName, IAzureWebAppEnvironment settings)
25+
{
26+
var i = defaultHostName.IndexOf("." + settings.AzureWebSitesDefaultDomainName);
27+
return new Uri($"https://{defaultHostName.Insert(i, ".scm")}");
1828
}
1929
}
2030
}

LetsEncrypt.SiteExtension.Core/KuduRestClient.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using LetsEncrypt.Azure.Core.Models;
2-
using Newtonsoft.Json;
1+
using Newtonsoft.Json;
32
using System;
43
using System.Diagnostics;
54
using System.IO;
@@ -14,17 +13,14 @@ public class KuduRestClient
1413
private readonly string baseUri;
1514
private HttpClient client;
1615
private string publishingPassword;
17-
private string publishingUserName;
18-
private string webAppName;
16+
private string publishingUserName;
1917

20-
public KuduRestClient(IAzureWebAppEnvironment azureEnvironment, string publishingUserName, string publishingPassword)
18+
public KuduRestClient(Uri scmUri, string publishingUserName, string publishingPassword)
2119
{
22-
this.webAppName = string.IsNullOrEmpty(azureEnvironment.SiteSlotName) ? azureEnvironment.WebAppName : azureEnvironment.WebAppName + "-" + azureEnvironment.SiteSlotName;
2320
this.publishingUserName = publishingUserName;
2421
this.publishingPassword = publishingPassword;
25-
this.baseUri = $"https://{this.webAppName}.scm.{azureEnvironment.AzureWebSitesDefaultDomainName}";
2622
this.client = new HttpClient();
27-
client.BaseAddress = new System.Uri(baseUri);
23+
client.BaseAddress = scmUri;
2824
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", CreateToken());
2925
}
3026

LetsEncrypt.SiteExtension.Core/LetsEncrypt.Azure.Core.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<metadata>
44
<id>letsencrypt.azure.core</id>
55
<title>Azure Let's Encrypt</title>
6-
<version>0.9.0</version>
6+
<version>0.9.3</version>
77
<authors>SJKP</authors>
88
<licenseUrl>http://opensource.org/licenses/Apache-2.0</licenseUrl>
99
<projectUrl>https://github.com/sjkp/letsencrypt-siteextension</projectUrl>

LetsEncrypt.SiteExtension.Test/PublishingCrendentialsTest.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,14 @@ public async Task GetPublishingCredentials()
3737
}
3838

3939
}
40+
41+
[TestMethod]
42+
public void TestScmUri()
43+
{
44+
var model = new AppSettingsAuthConfig();
45+
var uri = "letsencrypt.azurewebsites.net";
46+
var result = KuduHelper.MakeScmUri(uri, model);
47+
Assert.AreEqual(new Uri("https://letsencrypt.scm.azurewebsites.net"), result);
48+
}
4049
}
4150
}

LetsEncrypt.WebAppOnly.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<metadata>
44
<id>letsencrypt.webapponly</id>
55
<title>Azure Let's Encrypt (No Web Jobs)</title>
6-
<version>0.9.2</version>
6+
<version>0.9.3</version>
77
<authors>SJKP</authors>
88
<licenseUrl>http://opensource.org/licenses/Apache-2.0</licenseUrl>
99
<projectUrl>https://github.com/sjkp/letsencrypt-siteextension</projectUrl>

LetsEncrypt.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<metadata>
44
<id>letsencrypt</id>
55
<title>Azure Let's Encrypt</title>
6-
<version>0.9.2</version>
6+
<version>0.9.3</version>
77
<authors>SJKP</authors>
88
<licenseUrl>http://opensource.org/licenses/Apache-2.0</licenseUrl>
99
<projectUrl>https://github.com/sjkp/letsencrypt-siteextension</projectUrl>

0 commit comments

Comments
 (0)