Skip to content

Commit

Permalink
Setup AD based auth (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexMacocian authored Nov 28, 2023
1 parent 9a7b1e7 commit 5dffe46
Show file tree
Hide file tree
Showing 18 changed files with 99 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/content-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ jobs:
- name: Build and push content
run: |
cd GuildWarsPartySearch.FrontEnd
.\BuildAndUploadContent.ps1 -ConnectionString "${{ secrets.AZURE_TABLESTORAGE_CONNECTIONSTRING }}" -ContainerName "content" -SourceFolderPath Content
.\BuildAndUploadContent.ps1 -ContainerName content -SourceFolderPath Content -ClientId "${{ secrets.AZURE_CLIENT_ID }}" -ClientSecret "${{ secrets.AZURE_CLIENT_SECRET }}" -TenantId "${{ secrets.AZURE_TENANT_ID }}" -StorageAccountName "guildwarspartysearch"
shell: pwsh
6 changes: 4 additions & 2 deletions .github/workflows/docker-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ jobs:
cd GuildWarsPartySearch
$content = Get-Content Config.Release.json
$content = $content.Replace("[APIKEY]", "${{ secrets.APIKEY }}")
$content = $content.Replace("[AZURE_TABLESTORAGE_CONNECTIONSTRING]", "${{ secrets.AZURE_TABLESTORAGE_CONNECTIONSTRING }}")
$content = $content.Replace("[CERTIFICATE_BASE64]", "${{ secrets.CERTIFICATE_BASE64 }}")
$content = $content.Replace("[AZURE_INSIGHTS_INSTRUMENTATIONKEY]", "${{ secrets.AZURE_INSIGHTS_INSTRUMENTATIONKEY }}")
$content = $content.Replace("[AZURE_CLIENT_SECRET]", "${{ secrets.AZURE_CLIENT_SECRET }}")
$content = $content.Replace("[AZURE_CLIENT_ID]", "${{ secrets.AZURE_CLIENT_ID }}")
$content = $content.Replace("[AZURE_TENANT_ID]", "${{ secrets.AZURE_TENANT_ID }}")
Set-Content -Path Config.Release.json -Value $content
Write-Host "Placeholder replaced successfully in Config.Release.json"
Expand All @@ -55,7 +57,7 @@ jobs:
- name: Login to Azure
shell: pwsh
run: |
az login --service-principal -u "${{ secrets.AZURE_CLIENTID }}" -p "${{ secrets.AZURE_SECRET }}" --tenant "${{ secrets.AZURE_TENANT }}"
az login --service-principal -u "${{ secrets.AZURE_CLIENT_ID }}" -p "${{ secrets.AZURE_CLIENT_SECRET }}" --tenant "${{ secrets.AZURE_TENANT_ID }}"
- name: Check and Delete Existing Container Instance
shell: pwsh
Expand Down
17 changes: 13 additions & 4 deletions GuildWarsPartySearch.FrontEnd/BuildAndUploadContent.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
param(
[Parameter(Mandatory=$true)]
[string]$ConnectionString,
[string]$ClientId,

[Parameter(Mandatory=$true)]
[string]$ClientSecret,

[Parameter(Mandatory=$true)]
[string]$TenantId,

[Parameter(Mandatory=$true)]
[string]$StorageAccountName,

[Parameter(Mandatory=$true)]
[string]$ContainerName,
Expand All @@ -9,6 +18,6 @@ param(
[string]$SourceFolderPath
)


az storage blob delete-batch --source $ContainerName --connection-string $ConnectionString --pattern '*'
az storage blob upload-batch --destination $ContainerName --source $SourceFolderPath --connection-string $ConnectionString
az login --service-principal -u $ClientId -p $ClientSecret --tenant $TenantId
az storage blob delete-batch --source $ContainerName --pattern '*' --account-name $StorageAccountName
az storage blob upload-batch --destination $ContainerName --source $SourceFolderPath --account-name $StorageAccountName
7 changes: 6 additions & 1 deletion GuildWarsPartySearch/Config.Debug.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"HeartbeatFrequency": "0:0:1"
},
"StorageAccountOptions": {
"ConnectionString": "[AZURE_TABLESTORAGE_CONNECTIONSTRING]"
"Name": "guildwarspartysearch"
},
"PartySearchTableOptions": {
"TableName": "searches"
Expand All @@ -62,5 +62,10 @@
404,
429
]
},
"AzureCredentialsOptions": {
"ClientSecret": "[AZURE_CLIENT_SECRET]",
"ClientId": "[AZURE_CLIENT_ID]",
"TenantId": "[AZURE_TENANT_ID]"
}
}
7 changes: 6 additions & 1 deletion GuildWarsPartySearch/Config.Release.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"HeartbeatFrequency": "0:0:1"
},
"StorageAccountOptions": {
"ConnectionString": "[AZURE_TABLESTORAGE_CONNECTIONSTRING]"
"Name": "guildwarspartysearch"
},
"PartySearchTableOptions": {
"TableName": "searches"
Expand All @@ -62,5 +62,10 @@
404,
429
]
},
"AzureCredentialsOptions": {
"ClientSecret": "[AZURE_CLIENT_SECRET]",
"ClientId": "[AZURE_CLIENT_ID]",
"TenantId": "[AZURE_TENANT_ID]"
}
}
16 changes: 11 additions & 5 deletions GuildWarsPartySearch/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using GuildWarsPartySearch.Server.Options;
using Azure.Core;
using GuildWarsPartySearch.Server.Options;
using GuildWarsPartySearch.Server.Options.Azure;
using GuildWarsPartySearch.Server.Services.Azure;
using Microsoft.Extensions.Options;
using System.Core.Extensions;
Expand All @@ -13,10 +15,11 @@ public static IServiceCollection AddSingletonTableClient<TOptions>(this IService
services.ThrowIfNull()
.AddSingleton(sp =>
{
var tokenCredential = sp.GetRequiredService<TokenCredential>();
var storageOptions = sp.GetRequiredService<IOptions<StorageAccountOptions>>();
var clientOptions = sp.GetRequiredService<IOptions<TOptions>>();
var logger = sp.GetRequiredService<ILogger<NamedTableClient<TOptions>>>();
return new NamedTableClient<TOptions>(logger, storageOptions.Value.ConnectionString!, clientOptions.Value.TableName);
return new NamedTableClient<TOptions>(logger, new Uri($"https://{storageOptions.Value.Name}.table.core.windows.net"), clientOptions.Value.TableName, tokenCredential, default);
});

return services;
Expand All @@ -28,10 +31,11 @@ public static IServiceCollection AddScopedTableClient<TOptions>(this IServiceCol
services.ThrowIfNull()
.AddScoped(sp =>
{
var tokenCredential = sp.GetRequiredService<TokenCredential>();
var storageOptions = sp.GetRequiredService<IOptions<StorageAccountOptions>>();
var clientOptions = sp.GetRequiredService<IOptions<TOptions>>();
var logger = sp.GetRequiredService<ILogger<NamedTableClient<TOptions>>>();
return new NamedTableClient<TOptions>(logger, storageOptions.Value.ConnectionString!, clientOptions.Value.TableName);
return new NamedTableClient<TOptions>(logger, new Uri($"https://{storageOptions.Value.Name}.table.core.windows.net"), clientOptions.Value.TableName, tokenCredential, default);
});

return services;
Expand All @@ -43,9 +47,10 @@ public static IServiceCollection AddSingletonBlobContainerClient<TOptions>(this
services.ThrowIfNull()
.AddSingleton(sp =>
{
var tokenCredential = sp.GetRequiredService<TokenCredential>();
var storageOptions = sp.GetRequiredService<IOptions<StorageAccountOptions>>();
var clientOptions = sp.GetRequiredService<IOptions<TOptions>>();
return new NamedBlobContainerClient<TOptions>(storageOptions.Value.ConnectionString!, clientOptions.Value.ContainerName);
return new NamedBlobContainerClient<TOptions>(new Uri($"https://{storageOptions.Value.Name}.blob.core.windows.net/{clientOptions.Value.ContainerName}"), tokenCredential, default);
});

return services;
Expand All @@ -57,9 +62,10 @@ public static IServiceCollection AddScopedBlobContainerClient<TOptions>(this ISe
services.ThrowIfNull()
.AddScoped(sp =>
{
var tokenCredential = sp.GetRequiredService<TokenCredential>();
var storageOptions = sp.GetRequiredService<IOptions<StorageAccountOptions>>();
var clientOptions = sp.GetRequiredService<IOptions<TOptions>>();
return new NamedBlobContainerClient<TOptions>(storageOptions.Value.ConnectionString!, clientOptions.Value.ContainerName);
return new NamedBlobContainerClient<TOptions>(new Uri($"https://{storageOptions.Value.Name}.blob.core.windows.net/{clientOptions.Value.ContainerName}"), tokenCredential, default);
});

return services;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
using GuildWarsPartySearch.Server.Attributes;
using Azure.Core;
using Azure.Identity;
using GuildWarsPartySearch.Server.Attributes;
using GuildWarsPartySearch.Server.Options.Azure;
using Microsoft.Extensions.Options;
using System.Core.Extensions;
using System.Extensions;

namespace GuildWarsPartySearch.Server.Extensions;

public static class WebApplicationBuilderExtensions
{
public static WebApplicationBuilder ConfigureAzureClientSecretCredentials<TOptions>(this WebApplicationBuilder builder)
where TOptions : class, IAzureClientSecretCredentialOptions, new()
{
builder.ThrowIfNull()
.ConfigureExtended<TOptions>()
.Services.AddSingleton<TokenCredential>(sp =>
{
var options = sp.GetRequiredService<IOptions<TOptions>>().Value;
return new ClientSecretCredential(options.TenantId, options.ClientId, options.ClientSecret);
});

return builder;
}

public static WebApplicationBuilder ConfigureExtended<TOptions>(this WebApplicationBuilder builder)
where TOptions : class, new()
{
Expand Down
1 change: 1 addition & 0 deletions GuildWarsPartySearch/GuildWarsPartySearch.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Azure.Data.Tables" Version="12.8.2" />
<PackageReference Include="Azure.Identity" Version="1.10.4" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.21.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
Expand Down
4 changes: 1 addition & 3 deletions GuildWarsPartySearch/Launch/ServerConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using AspNetCoreRateLimit;
using Azure.Data.Tables;
using GuildWarsPartySearch.Common.Converters;
using GuildWarsPartySearch.Server.Endpoints;
using GuildWarsPartySearch.Server.Extensions;
Expand All @@ -13,8 +12,6 @@
using GuildWarsPartySearch.Server.Services.PartySearch;
using GuildWarsPartySearch.Server.Telemetry;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Options;
using System.Core.Extensions;
using System.Extensions;
using System.Text.Json.Serialization;
Expand Down Expand Up @@ -65,6 +62,7 @@ public static ILoggingBuilder SetupLogging(this ILoggingBuilder builder)
public static WebApplicationBuilder SetupOptions(this WebApplicationBuilder builder)
{
return builder.ThrowIfNull()
.ConfigureAzureClientSecretCredentials<AzureCredentialsOptions>()
.ConfigureExtended<EnvironmentOptions>()
.ConfigureExtended<ContentOptions>()
.ConfigureExtended<PartySearchTableOptions>()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace GuildWarsPartySearch.Server.Options;
namespace GuildWarsPartySearch.Server.Options.Azure;

public interface IAzureBlobStorageOptions
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace GuildWarsPartySearch.Server.Options.Azure;

public interface IAzureClientSecretCredentialOptions : IAzureCredentialOptions
{
string ClientSecret { get; set; }
}
8 changes: 8 additions & 0 deletions GuildWarsPartySearch/Options/Azure/IAzureCredentialOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GuildWarsPartySearch.Server.Options.Azure;

public interface IAzureCredentialOptions
{
string ClientId { get; set; }

string TenantId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace GuildWarsPartySearch.Server.Options;
namespace GuildWarsPartySearch.Server.Options.Azure;

public interface IAzureTableStorageOptions
{
Expand Down
16 changes: 16 additions & 0 deletions GuildWarsPartySearch/Options/AzureCredentialsOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using GuildWarsPartySearch.Server.Options.Azure;
using System.Text.Json.Serialization;

namespace GuildWarsPartySearch.Server.Options;

public sealed class AzureCredentialsOptions : IAzureClientSecretCredentialOptions
{
[JsonPropertyName(nameof(ClientSecret))]
public string ClientSecret { get; set; } = default!;

[JsonPropertyName(nameof(ClientId))]
public string ClientId { get; set; } = default!;

[JsonPropertyName(nameof(TenantId))]
public string TenantId { get; set; } = default!;
}
1 change: 1 addition & 0 deletions GuildWarsPartySearch/Options/ContentOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using GuildWarsPartySearch.Server.Options.Azure;

namespace GuildWarsPartySearch.Server.Options;

Expand Down
3 changes: 1 addition & 2 deletions GuildWarsPartySearch/Options/PartySearchTableOptions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System.Text.Json.Serialization;
using GuildWarsPartySearch.Server.Options.Azure;

namespace GuildWarsPartySearch.Server.Options;

public class PartySearchTableOptions : IAzureTableStorageOptions
{
[JsonPropertyName(nameof(TableName))]
public string TableName { get; set; } = default!;
}
10 changes: 2 additions & 8 deletions GuildWarsPartySearch/Options/StorageAccountOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ namespace GuildWarsPartySearch.Server.Options;

public sealed class StorageAccountOptions
{
[JsonPropertyName(nameof(TableName))]
public string? TableName { get; set; }

[JsonPropertyName(nameof(ConnectionString))]
public string? ConnectionString { get; set; }

[JsonPropertyName(nameof(ContainerName))]
public string? ContainerName { get; set; }
[JsonPropertyName(nameof(Name))]
public string? Name { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using GuildWarsPartySearch.Server.Options;
using GuildWarsPartySearch.Server.Options.Azure;

namespace GuildWarsPartySearch.Server.Services.Azure;

Expand Down

0 comments on commit 5dffe46

Please sign in to comment.