Skip to content

Commit de1546c

Browse files
authored
Use Managed Identity & AzureBlobFileSystem when loading html, not proxied unauthenticated http. (#154)
* speculative synchronous authenticated proxy code * disable public access on new container * Get rid of async on UrlExists * Get HTTP headers as Azure properties and inject * base64 encode the hash, don't just ToString() (which gives Byte[])
1 parent d6a55e4 commit de1546c

File tree

7 files changed

+45
-85
lines changed

7 files changed

+45
-85
lines changed

deployment/upload-index-to-container.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ $newContainerName = "index-$((New-Guid).ToString("N"))"
1010

1111
Write-Host "Creating new container '$newContainerName'..."
1212
{
13-
az storage container create --name "$newContainerName" --auth-mode login --public-access container --fail-on-exist --account-name $StorageAccountName
13+
az storage container create --name "$newContainerName" --auth-mode login --public-access off --fail-on-exist --account-name $StorageAccountName
1414
} | Check-Failure
1515

1616
Write-Output "##vso[task.setvariable variable=NEW_CONTAINER_NAME]$newContainerName"

src/SourceBrowser/src/Directory.Packages.props

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464

6565
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
6666
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
67+
<PackageVersion Include="Microsoft.Extensions.Logging.AzureAppServices" Version="8.0.6" />
6768
<PackageVersion Include="System.Resources.Extensions" Version="8.0.0" />
6869
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
6970
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />

src/SourceBrowser/src/SourceIndexServer/Helpers.cs

+17-79
Original file line numberDiff line numberDiff line change
@@ -3,93 +3,31 @@
33
using System.Net.Http;
44
using System.Threading.Tasks;
55
using Microsoft.AspNetCore.Http;
6+
using Microsoft.Extensions.Logging;
7+
using Microsoft.SourceBrowser.SourceIndexServer.Models;
68

79
namespace Microsoft.SourceBrowser.SourceIndexServer
810
{
911
public static class Helpers
1012
{
11-
public static async Task ProxyRequestAsync(this HttpContext context, HttpClient client, string targetUrl, Action<HttpRequestMessage> configureRequest = null)
13+
public static async Task ProxyRequestAsync(this HttpContext context, string targetPath, Action<HttpRequestMessage> configureRequest = null)
1214
{
13-
using (var req = new HttpRequestMessage(HttpMethod.Get, targetUrl))
15+
var fs = new AzureBlobFileSystem(IndexProxyUrl);
16+
var props = fs.FileProperties(targetPath);
17+
context.Response.Headers.Append("Content-Md5", Convert.ToBase64String(props.ContentHash));
18+
context.Response.Headers.Append("Content-Type", props.ContentType);
19+
context.Response.Headers.Append("Etag", props.ETag.ToString());
20+
context.Response.Headers.Append("Last-Modified", props.LastModified.ToString("R"));
21+
using (var data = fs.OpenSequentialReadStream(targetPath))
1422
{
15-
foreach (var (key, values) in context.Request.Headers)
16-
{
17-
switch (key.ToLower())
18-
{
19-
// We shouldn't copy any of these request headers
20-
case "host":
21-
case "authorization":
22-
case "cookie":
23-
case "content-length":
24-
case "content-type":
25-
continue;
26-
default:
27-
req.Headers.TryAddWithoutValidation(key, values.ToArray());
28-
break;
29-
}
30-
}
31-
32-
configureRequest?.Invoke(req);
33-
34-
HttpResponseMessage res = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
35-
context.Response.RegisterForDispose(res);
36-
37-
foreach (var (key, values) in res.Headers)
38-
{
39-
switch (key.ToLower())
40-
{
41-
// Remove headers that the response doesn't need
42-
case "set-cookie":
43-
case "x-powered-by":
44-
case "x-aspnet-version":
45-
case "server":
46-
case "transfer-encoding":
47-
case "access-control-expose-headers":
48-
case "access-control-allow-origin":
49-
continue;
50-
default:
51-
if (!context.Response.Headers.ContainsKey(key))
52-
{
53-
context.Response.Headers[key] = values.ToArray();
54-
}
55-
56-
break;
57-
}
58-
}
59-
60-
context.Response.StatusCode = (int)res.StatusCode;
61-
if (res.Content != null)
62-
{
63-
foreach (var (key, values) in res.Content.Headers)
64-
{
65-
if (!context.Response.Headers.ContainsKey(key))
66-
{
67-
context.Response.Headers[key] = values.ToArray();
68-
}
69-
}
70-
71-
using (var data = await res.Content.ReadAsStreamAsync().ConfigureAwait(false))
72-
{
73-
await data.CopyToAsync(context.Response.Body).ConfigureAwait(false);
74-
}
75-
}
23+
await data.CopyToAsync(context.Response.Body).ConfigureAwait(false);
7624
}
7725
}
7826

79-
private static readonly HttpClient s_client = new HttpClient(new HttpClientHandler() { CheckCertificateRevocationList = true });
80-
81-
private static async Task<bool> UrlExistsAsync(string proxyRequestUrl)
27+
private static bool UrlExists(string proxyRequestPath)
8228
{
83-
using (var res = new HttpRequestMessage(HttpMethod.Head, proxyRequestUrl))
84-
using (var req = await s_client.SendAsync(res).ConfigureAwait(false))
85-
{
86-
if (req.IsSuccessStatusCode)
87-
{
88-
return true;
89-
}
90-
}
91-
92-
return false;
29+
var fs = new AzureBlobFileSystem(IndexProxyUrl);
30+
return fs.FileExists(proxyRequestPath);
9331
}
9432

9533
public static async Task ServeProxiedIndex(HttpContext context, Func<Task> next)
@@ -109,15 +47,15 @@ public static async Task ServeProxiedIndex(HttpContext context, Func<Task> next)
10947
return;
11048
}
11149

112-
var proxyRequestUrl = proxyUri + (path.StartsWith("/", StringComparison.Ordinal) ? path : "/" + path).ToLowerInvariant();
50+
var proxyRequestPathSuffix = (path.StartsWith("/", StringComparison.Ordinal) ? path : "/" + path).ToLowerInvariant();
11351

114-
if (!await UrlExistsAsync(proxyRequestUrl).ConfigureAwait(false))
52+
if (!UrlExists(proxyRequestPathSuffix))
11553
{
11654
await next().ConfigureAwait(false);
11755
return;
11856
}
11957

120-
await context.ProxyRequestAsync(s_client, proxyRequestUrl).ConfigureAwait(false);
58+
await context.ProxyRequestAsync(proxyRequestPathSuffix).ConfigureAwait(false);
12159
}
12260

12361
public static string IndexProxyUrl => Environment.GetEnvironmentVariable("SOURCE_BROWSER_INDEX_PROXY_URL");

src/SourceBrowser/src/SourceIndexServer/Models/AzureBlobFileSystem.cs

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Azure.Identity;
22
using Azure.Storage.Blobs;
3+
using Azure.Storage.Blobs.Models;
34
using System;
45
using System.Collections.Generic;
56
using System.IO;
@@ -55,17 +56,27 @@ public bool FileExists(string name)
5556
return blob.Exists();
5657
}
5758

59+
public BlobProperties FileProperties(string name)
60+
{
61+
name = name.ToLowerInvariant();
62+
BlobClient blob = container.GetBlobClient(name);
63+
64+
return blob.GetProperties();
65+
}
66+
5867
public Stream OpenSequentialReadStream(string name)
5968
{
6069
name = name.ToLowerInvariant();
6170
BlobClient blob = container.GetBlobClient(name);
71+
6272
return blob.OpenRead();
6373
}
6474

6575
public IEnumerable<string> ReadLines(string name)
6676
{
6777
name = name.ToLowerInvariant();
6878
BlobClient blob = container.GetBlobClient(name);
79+
6980
using Stream stream = blob.OpenRead();
7081
using StreamReader reader = new (stream);
7182

src/SourceBrowser/src/SourceIndexServer/Program.cs

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Hosting;
22
using Microsoft.Extensions.Hosting;
3+
using Microsoft.Extensions.Logging;
34

45
namespace Microsoft.SourceBrowser.SourceIndexServer
56
{
@@ -10,11 +11,19 @@ public static void Main(string[] args)
1011
BuildWebHost(args).Run();
1112
}
1213

14+
public static ILogger Logger { get; set; }
15+
1316
public static IHost BuildWebHost(string[] args) =>
1417
Host.CreateDefaultBuilder(args)
1518
.ConfigureWebHostDefaults(
1619
builder => { builder
1720
.UseStartup<Startup>(); })
21+
.ConfigureLogging(logging =>
22+
{
23+
logging.ClearProviders();
24+
logging.AddConsole();
25+
logging.AddAzureWebAppDiagnostics();
26+
})
1827
.UseWindowsService()
1928
.Build();
2029
}

src/SourceBrowser/src/SourceIndexServer/SourceIndexServer.csproj

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010
<ItemGroup>
1111
<PackageReference Include="Azure.Identity" />
1212
<PackageReference Include="Azure.Storage.Blobs" />
13+
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" />
14+
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" />
1315
</ItemGroup>
1416

1517
<ItemGroup>
1618
<ProjectReference Include="..\Common\Common.csproj" />
1719
</ItemGroup>
1820

19-
<ItemGroup>
20-
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" />
21-
</ItemGroup>
22-
2321
</Project>

src/SourceBrowser/src/SourceIndexServer/Startup.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.Extensions.FileProviders;
66
using Microsoft.Extensions.FileProviders.Physical;
77
using Microsoft.Extensions.Hosting;
8+
using Microsoft.Extensions.Logging;
89
using Microsoft.SourceBrowser.SourceIndexServer.Models;
910

1011
namespace Microsoft.SourceBrowser.SourceIndexServer
@@ -64,12 +65,14 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
6465
app.UseStaticFiles();
6566
app.UseRouting();
6667

67-
6868
app.UseEndpoints(endPoints =>
6969
{
7070
endPoints.MapRazorPages();
7171
endPoints.MapControllers();
7272
});
73+
74+
// Retrieve and store the logger
75+
Program.Logger = app.ApplicationServices.GetService<ILogger<Program>>();
7376
}
7477
}
7578
}

0 commit comments

Comments
 (0)