Skip to content

Commit 078f1e2

Browse files
authored
CloudAuditService preparing for secret refresh (#8486)
* Audit service registration does not require passing a configuration object anymore. * CloudAuditingService using CloudBlobClientWrapper
1 parent 54b7ae6 commit 078f1e2

3 files changed

Lines changed: 66 additions & 57 deletions

File tree

src/NuGetGallery.Core/Auditing/CloudAuditingService.cs

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ public class CloudAuditingService : AuditingService, ICloudStorageStatusDependen
2121
{
2222
public static readonly string DefaultContainerName = "auditing";
2323

24-
private CloudBlobContainer _auditContainer;
24+
private Func<ICloudBlobContainer> _auditContainerFactory;
2525
private Func<Task<AuditActor>> _getOnBehalfOf;
2626

27-
public CloudAuditingService(string storageConnectionString, bool readAccessGeoRedundant, Func<Task<AuditActor>> getOnBehalfOf)
28-
: this(GetContainer(storageConnectionString, readAccessGeoRedundant), getOnBehalfOf)
27+
public CloudAuditingService(Func<ICloudBlobClient> cloudBlobClientFactory, Func<Task<AuditActor>> getOnBehalfOf)
28+
: this(() => GetContainer(cloudBlobClientFactory), getOnBehalfOf)
2929
{
3030
}
3131

32-
public CloudAuditingService(CloudBlobContainer auditContainer, Func<Task<AuditActor>> getOnBehalfOf)
32+
public CloudAuditingService(Func<ICloudBlobContainer> auditContainerFactory, Func<Task<AuditActor>> getOnBehalfOf)
3333
{
34-
_auditContainer = auditContainer;
34+
_auditContainerFactory = auditContainerFactory;
3535
_getOnBehalfOf = getOnBehalfOf;
3636
}
3737

@@ -52,7 +52,8 @@ protected override async Task SaveAuditRecordAsync(string auditData, string reso
5252
$"{filePath.Replace(Path.DirectorySeparatorChar, '/')}/" +
5353
$"{Guid.NewGuid().ToString("N")}-{action.ToLowerInvariant()}.audit.v1.json";
5454

55-
var blob = _auditContainer.GetBlockBlobReference(fullPath);
55+
var container = _auditContainerFactory();
56+
var blob = container.GetBlobReference(fullPath);
5657
bool retry = false;
5758
try
5859
{
@@ -74,37 +75,23 @@ protected override async Task SaveAuditRecordAsync(string auditData, string reso
7475
{
7576
// Create the container and try again,
7677
// this time we let exceptions bubble out
77-
await Task.Factory.FromAsync(
78-
(cb, s) => _auditContainer.BeginCreateIfNotExists(cb, s),
79-
ar => _auditContainer.EndCreateIfNotExists(ar),
80-
null);
78+
await container.CreateIfNotExistAsync(permissions: null);
8179
await WriteBlob(auditData, fullPath, blob);
8280
}
8381
}
8482

85-
private static CloudBlobContainer GetContainer(string storageConnectionString, bool readAccessGeoRedundant)
83+
private static ICloudBlobContainer GetContainer(Func<ICloudBlobClient> cloudBlobClientFactory)
8684
{
87-
var cloudBlobClient = CloudStorageAccount.Parse(storageConnectionString).CreateCloudBlobClient();
88-
if (readAccessGeoRedundant)
89-
{
90-
cloudBlobClient.DefaultRequestOptions.LocationMode = LocationMode.PrimaryThenSecondary;
91-
}
85+
var cloudBlobClient = cloudBlobClientFactory();
9286
return cloudBlobClient.GetContainerReference(DefaultContainerName);
9387
}
9488

95-
private static async Task WriteBlob(string auditData, string fullPath, CloudBlockBlob blob)
89+
private static async Task WriteBlob(string auditData, string fullPath, ISimpleCloudBlob blob)
9690
{
9791
try
9892
{
99-
var strm = await Task.Factory.FromAsync(
100-
(cb, s) => blob.BeginOpenWrite(
101-
AccessCondition.GenerateIfNoneMatchCondition("*"),
102-
new BlobRequestOptions(),
103-
new OperationContext(),
104-
cb, s),
105-
ar => blob.EndOpenWrite(ar),
106-
null);
107-
using (var writer = new StreamWriter(strm))
93+
using (var stream = await blob.OpenWriteAsync(AccessCondition.GenerateIfNoneMatchCondition("*")))
94+
using (var writer = new StreamWriter(stream))
10895
{
10996
await writer.WriteAsync(auditData);
11097
}
@@ -125,7 +112,7 @@ private static async Task WriteBlob(string auditData, string fullPath, CloudBloc
125112

126113
public Task<bool> IsAvailableAsync(BlobRequestOptions options, OperationContext operationContext)
127114
{
128-
return _auditContainer.ExistsAsync(options, operationContext);
115+
return _auditContainerFactory().ExistsAsync(options, operationContext);
129116
}
130117

131118
public override string RenderAuditEntry(AuditEntry entry)

src/NuGetGallery/App_Start/DefaultDependenciesModule.cs

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public static class BindingKeys
7878
public const string EmailPublisherTopic = "EmailPublisherBindingKey";
7979

8080
public const string PreviewSearchClient = "PreviewSearchClientBindingKey";
81+
82+
public const string AuditKey = "AuditKey";
8183
}
8284

8385
public static class ParameterNames
@@ -468,24 +470,20 @@ protected override void Load(ContainerBuilder builder)
468470
.As<IPrincipal>()
469471
.InstancePerLifetimeScope();
470472

471-
IAuditingService defaultAuditingService = null;
472-
473473
switch (configuration.Current.StorageType)
474474
{
475475
case StorageType.FileSystem:
476476
case StorageType.NotSpecified:
477477
ConfigureForLocalFileSystem(builder, configuration);
478-
defaultAuditingService = GetAuditingServiceForLocalFileSystem(configuration);
479478
break;
480479
case StorageType.AzureStorage:
481480
ConfigureForAzureStorage(builder, configuration, telemetryService);
482-
defaultAuditingService = GetAuditingServiceForAzureStorage(builder, configuration);
483481
break;
484482
}
485483

486484
RegisterAsynchronousValidation(builder, loggerFactory, configuration, secretInjector);
487485

488-
RegisterAuditingServices(builder, defaultAuditingService);
486+
RegisterAuditingServices(builder, configuration.Current.StorageType);
489487

490488
RegisterCookieComplianceService(configuration, loggerFactory);
491489

@@ -1376,10 +1374,10 @@ private static void ConfigureForLocalFileSystem(ContainerBuilder builder, IGalle
13761374
.SingleInstance();
13771375
}
13781376

1379-
private static IAuditingService GetAuditingServiceForLocalFileSystem(IGalleryConfigurationService configuration)
1377+
private static IAuditingService GetAuditingServiceForLocalFileSystem(IAppConfiguration configuration)
13801378
{
13811379
var auditingPath = Path.Combine(
1382-
FileSystemFileStorageService.ResolvePath(configuration.Current.FileStorageDirectory),
1380+
FileSystemFileStorageService.ResolvePath(configuration.FileStorageDirectory),
13831381
FileSystemAuditingService.DefaultContainerName);
13841382

13851383
return new FileSystemAuditingService(auditingPath, AuditActor.GetAspNetOnBehalfOfAsync);
@@ -1449,17 +1447,6 @@ private static void ConfigureForAzureStorage(ContainerBuilder builder, IGalleryC
14491447
.SingleInstance();
14501448
}
14511449

1452-
private static IAuditingService GetAuditingServiceForAzureStorage(ContainerBuilder builder, IGalleryConfigurationService configuration)
1453-
{
1454-
var service = new CloudAuditingService(configuration.Current.AzureStorage_Auditing_ConnectionString, configuration.Current.AzureStorageReadAccessGeoRedundant, AuditActor.GetAspNetOnBehalfOfAsync);
1455-
1456-
builder.RegisterInstance(service)
1457-
.As<ICloudStorageStatusDependency>()
1458-
.SingleInstance();
1459-
1460-
return service;
1461-
}
1462-
14631450
private static IAuditingService CombineAuditingServices(IEnumerable<IAuditingService> services)
14641451
{
14651452
if (!services.Any())
@@ -1491,19 +1478,54 @@ private static IEnumerable<T> GetAddInServices<T>(Action<RuntimeServiceProvider>
14911478
}
14921479
}
14931480

1494-
private static void RegisterAuditingServices(ContainerBuilder builder, IAuditingService defaultAuditingService)
1481+
private static void RegisterAuditingServices(ContainerBuilder builder, string storageType)
14951482
{
1496-
var auditingServices = GetAddInServices<IAuditingService>();
1497-
var services = new List<IAuditingService>(auditingServices);
1498-
1499-
if (defaultAuditingService != null)
1483+
if (storageType == StorageType.AzureStorage)
15001484
{
1501-
services.Add(defaultAuditingService);
1485+
builder.Register(c =>
1486+
{
1487+
var configuration = c.Resolve<IAppConfiguration>();
1488+
return new CloudBlobClientWrapper(configuration.AzureStorage_Auditing_ConnectionString, configuration.AzureStorageReadAccessGeoRedundant);
1489+
})
1490+
.SingleInstance()
1491+
.Keyed<ICloudBlobClient>(BindingKeys.AuditKey);
1492+
1493+
builder.Register(c =>
1494+
{
1495+
var blobClientFactory = c.ResolveKeyed<Func<ICloudBlobClient>>(BindingKeys.AuditKey);
1496+
return new CloudAuditingService(blobClientFactory, AuditActor.GetAspNetOnBehalfOfAsync);
1497+
})
1498+
.SingleInstance()
1499+
.AsSelf()
1500+
.As<ICloudStorageStatusDependency>();
15021501
}
15031502

1504-
var service = CombineAuditingServices(services);
1503+
builder.Register(c =>
1504+
{
1505+
var configuration = c.Resolve<IAppConfiguration>();
1506+
IAuditingService defaultAuditingService = null;
1507+
switch (storageType)
1508+
{
1509+
case StorageType.FileSystem:
1510+
case StorageType.NotSpecified:
1511+
defaultAuditingService = GetAuditingServiceForLocalFileSystem(configuration);
1512+
break;
1513+
1514+
case StorageType.AzureStorage:
1515+
defaultAuditingService = c.Resolve<CloudAuditingService>();
1516+
break;
1517+
}
1518+
1519+
var auditingServices = GetAddInServices<IAuditingService>();
1520+
var services = new List<IAuditingService>(auditingServices);
1521+
1522+
if (defaultAuditingService != null)
1523+
{
1524+
services.Add(defaultAuditingService);
1525+
}
15051526

1506-
builder.RegisterInstance(service)
1527+
return CombineAuditingServices(services);
1528+
})
15071529
.AsSelf()
15081530
.As<IAuditingService>()
15091531
.SingleInstance();

tests/NuGetGallery.Core.Facts/Auditing/CloudAuditingServiceTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ public class CloudAuditingServiceTests
1717
public void CloudAuditServiceObfuscateAuditRecord()
1818
{
1919
// Arrange
20-
CloudBlobContainer nullBlobContainer = null;
21-
var service = new CloudAuditingService(nullBlobContainer, AuditActor.GetCurrentMachineActorAsync);
20+
ICloudBlobContainer nullBlobContainer = null;
21+
var service = new CloudAuditingService(() => nullBlobContainer, AuditActor.GetCurrentMachineActorAsync);
2222

2323
AuditActor onBehalfOf = new AuditActor("machineName", "3.3.3.3", "userName1", "NoAuthentication", "someKey", DateTime.Now, null);
2424
AuditActor auditActor = new AuditActor("machineName", "2.2.2.2", "userName1", "NoAuthentication", "someKey", DateTime.Now, onBehalfOf);
@@ -56,8 +56,8 @@ public void CloudAuditServiceObfuscateAuditRecord()
5656
public void OnlyPackageAuditRecordsWillBeSaved(AuditRecord record, bool expectedResult)
5757
{
5858
// Arrange
59-
CloudBlobContainer nullBlobContainer = null;
60-
var service = new CloudAuditingService(nullBlobContainer, AuditActor.GetCurrentMachineActorAsync);
59+
ICloudBlobContainer nullBlobContainer = null;
60+
var service = new CloudAuditingService(() => nullBlobContainer, AuditActor.GetCurrentMachineActorAsync);
6161

6262
// Act + Assert
6363
Assert.Equal<bool>(expectedResult, service.RecordWillBePersisted(record));

0 commit comments

Comments
 (0)