Skip to content

Commit

Permalink
[Prefix] Add auditing for reserved namespaces (#4940)
Browse files Browse the repository at this point in the history
  • Loading branch information
shishirx34 committed Nov 2, 2017
1 parent 02cb908 commit ff2cbd9
Show file tree
Hide file tree
Showing 20 changed files with 373 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ public class AuditedPackageRegistration
public string Id { get; private set; }
public int DownloadCount { get; private set; }
public int Key { get; private set; }
public bool IsVerified { get; private set; }

public static AuditedPackageRegistration CreateFrom(PackageRegistration packageRegistration)
{
return new AuditedPackageRegistration
{
Id = packageRegistration.Id,
DownloadCount = packageRegistration.DownloadCount,
Key = packageRegistration.Key
Key = packageRegistration.Key,
IsVerified = packageRegistration.IsVerified
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace NuGetGallery.Auditing.AuditedEntities
{
public class AuditedReservedNamespace
{
public string Value { get; private set; }
public bool IsPrefix { get; private set; }
public bool IsSharedNamespace { get; private set; }

public static AuditedReservedNamespace CreateFrom(ReservedNamespace reservedNamespace)
{
return new AuditedReservedNamespace
{
Value = reservedNamespace.Value,
IsSharedNamespace = reservedNamespace.IsSharedNamespace,
IsPrefix = reservedNamespace.IsPrefix,
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace NuGetGallery.Auditing
public enum AuditedPackageRegistrationAction
{
AddOwner,
RemoveOwner
RemoveOwner,
MarkVerified,
MarkUnverified
}
}
13 changes: 13 additions & 0 deletions src/NuGetGallery.Core/Auditing/AuditedReservedNamespaceAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace NuGetGallery.Auditing
{
public enum AuditedReservedNamespaceAction
{
ReserveNamespace,
UnreserveNamespace,
AddOwner,
RemoveOwner
}
}
35 changes: 27 additions & 8 deletions src/NuGetGallery.Core/Auditing/PackageAuditRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class PackageAuditRecord : AuditRecord<AuditedPackageAction>

public PackageAuditRecord(
string id, string version, string hash,
AuditedPackage packageRecord, AuditedPackageRegistration registrationRecord,
AuditedPackage packageRecord, AuditedPackageRegistration registrationRecord,
AuditedPackageAction action, string reason)
: base(action)
{
Expand All @@ -30,23 +30,42 @@ public PackageAuditRecord(
Reason = reason;
}

public PackageAuditRecord(
Package package, AuditedPackageAction action, string reason)
: this(package.PackageRegistration.Id, package.Version, package.Hash,
packageRecord: null, registrationRecord: null, action: action, reason: reason)
public PackageAuditRecord(string id, string version, AuditedPackageAction action, string reason)
: this(id,
version,
hash: "",
packageRecord: null,
registrationRecord: null,
action: action,
reason: reason)
{ }

public PackageAuditRecord(Package package, AuditedPackageAction action, string reason)
: this(package.PackageRegistration.Id,
package.Version,
package.Hash,
packageRecord: null,
registrationRecord: null,
action: action,
reason: reason)
{
PackageRecord = AuditedPackage.CreateFrom(package);
RegistrationRecord = AuditedPackageRegistration.CreateFrom(package.PackageRegistration);
}

public PackageAuditRecord(Package package, AuditedPackageAction action)
: this(package.PackageRegistration.Id, package.Version, package.Hash,
packageRecord: null, registrationRecord: null, action: action, reason: null)
: this(package.PackageRegistration.Id,
package.Version,
package.Hash,
packageRecord: null,
registrationRecord: null,
action: action,
reason: null)
{
PackageRecord = AuditedPackage.CreateFrom(package);
RegistrationRecord = AuditedPackageRegistration.CreateFrom(package.PackageRegistration);
}

public override string GetPath()
{
return $"{Id}/{NuGetVersionFormatter.Normalize(Version)}"
Expand Down
72 changes: 72 additions & 0 deletions src/NuGetGallery.Core/Auditing/ReservedNamespaceAuditRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Linq;
using System.Collections.Generic;
using NuGetGallery.Auditing.AuditedEntities;

namespace NuGetGallery.Auditing
{
public class ReservedNamespaceAuditRecord : AuditRecord<AuditedReservedNamespaceAction>
{
public string Value;

public AuditedReservedNamespace AffectedReservedNamespace;

public string AffectedOwner;

public PackageRegistrationAuditRecord[] AffectedRegistrations;

public ReservedNamespaceAuditRecord(ReservedNamespace reservedNamespace, AuditedReservedNamespaceAction action)
: this(reservedNamespace, action, username: null, registrations: null)
{ }

public ReservedNamespaceAuditRecord(ReservedNamespace reservedNamespace,
AuditedReservedNamespaceAction action,
string username,
IEnumerable<PackageRegistration> registrations)
: base(action)
{
if (reservedNamespace == null)
{
throw new ArgumentNullException(nameof(reservedNamespace));
}

Value = reservedNamespace.Value;
AffectedReservedNamespace = AuditedReservedNamespace.CreateFrom(reservedNamespace);
Action = action;

if (!string.IsNullOrWhiteSpace(username))
{
AffectedOwner = username;

if (registrations != null && registrations.Any())
{
var registrationAction = GetPackageRegistrationAction(action);
AffectedRegistrations = registrations
.Select(pr => new PackageRegistrationAuditRecord(pr, registrationAction, username))
.ToArray();
}
}
}

public override string GetPath()
{
return Value.ToLowerInvariant();
}

private static AuditedPackageRegistrationAction GetPackageRegistrationAction(AuditedReservedNamespaceAction action)
{
switch (action)
{
case AuditedReservedNamespaceAction.AddOwner:
return AuditedPackageRegistrationAction.MarkVerified;
case AuditedReservedNamespaceAction.RemoveOwner:
return AuditedPackageRegistrationAction.MarkUnverified;
default:
throw new ArgumentException($"Invalid value specified for {nameof(action)}");
}
}
}
}
3 changes: 3 additions & 0 deletions src/NuGetGallery.Core/NuGetGallery.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,16 @@
<Compile Include="Auditing\AuditedEntities\AuditedPackage.cs" />
<Compile Include="Auditing\AuditedEntities\AuditedPackageIdentifier.cs" />
<Compile Include="Auditing\AuditedAuthenticatedOperationAction.cs" />
<Compile Include="Auditing\AuditedEntities\AuditedReservedNamespace.cs" />
<Compile Include="Auditing\AuditedEntities\AuditedUserSecurityPolicy.cs" />
<Compile Include="Auditing\AuditedSecurityPolicyAction.cs" />
<Compile Include="Auditing\AuditedReservedNamespaceAction.cs" />
<Compile Include="Auditing\AuditEntry.cs" />
<Compile Include="Auditing\AuditActor.cs" />
<Compile Include="Auditing\AuditingService.cs" />
<Compile Include="Auditing\AuditRecord.cs" />
<Compile Include="Auditing\FailedAuthenticatedOperationAuditRecord.cs" />
<Compile Include="Auditing\ReservedNamespaceAuditRecord.cs" />
<Compile Include="Auditing\UserSecurityPolicyAuditRecord.cs" />
<Compile Include="Auditing\FileSystemAuditingService.cs" />
<Compile Include="Auditing\CloudAuditingService.cs" />
Expand Down
3 changes: 3 additions & 0 deletions src/NuGetGallery/Controllers/ApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ private async Task<ActionResult> CreatePackageInternal()
var isPushAllowed = ReservedNamespaceService.IsPushAllowed(id, user, out userOwnedNamespaces);
if (!isPushAllowed)
{
var version = nuspec.GetVersion().ToNormalizedString();
TelemetryService.TrackPackagePushNamespaceConflictEvent(id, version, user, User.Identity);

return new HttpStatusCodeWithBodyResult(HttpStatusCode.Conflict, Strings.UploadPackage_IdNamespaceConflict);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/NuGetGallery/Controllers/PackagesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ public virtual async Task<JsonResult> UploadPackage(HttpPostedFileBase uploadFil
ModelState.AddModelError(
string.Empty, string.Format(CultureInfo.CurrentCulture, Strings.UploadPackage_IdNamespaceConflict));

var version = nuspec.GetVersion().ToNormalizedString();
_telemetryService.TrackPackagePushNamespaceConflictEvent(id, version, currentUser, User.Identity);

return Json(409, new string[] { string.Format(CultureInfo.CurrentCulture, Strings.UploadPackage_IdNamespaceConflict) });
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/NuGetGallery/Services/ITelemetryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public interface ITelemetryService

void TrackCreatePackageVerificationKeyEvent(string packageId, string packageVersion, User user, IIdentity identity);

void TrackPackagePushNamespaceConflictEvent(string packageId, string packageVersion, User user, IIdentity identity);

void TrackVerifyPackageKeyEvent(string packageId, string packageVersion, User user, IIdentity identity, int statusCode);

/// <summary>
Expand Down
20 changes: 15 additions & 5 deletions src/NuGetGallery/Services/ReservedNamespaceService.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using NuGet.Packaging;
using NuGetGallery.Auditing;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Globalization;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NuGetGallery.Auditing;

namespace NuGetGallery
{
Expand Down Expand Up @@ -67,6 +65,9 @@ public async Task AddReservedNamespaceAsync(ReservedNamespace newNamespace)

ReservedNamespaceRepository.InsertOnCommit(newNamespace);
await ReservedNamespaceRepository.CommitChangesAsync();

await AuditingService.SaveAuditRecordAsync(
new ReservedNamespaceAuditRecord(newNamespace, AuditedReservedNamespaceAction.ReserveNamespace));
}

public async Task DeleteReservedNamespaceAsync(string existingNamespace)
Expand Down Expand Up @@ -99,6 +100,9 @@ public async Task DeleteReservedNamespaceAsync(string existingNamespace)
await ReservedNamespaceRepository.CommitChangesAsync();

transaction.Commit();

await AuditingService.SaveAuditRecordAsync(
new ReservedNamespaceAuditRecord(namespaceToDelete, AuditedReservedNamespaceAction.UnreserveNamespace));
}
}

Expand Down Expand Up @@ -162,6 +166,9 @@ public async Task AddOwnerToReservedNamespaceAsync(string prefix, string usernam
await ReservedNamespaceRepository.CommitChangesAsync();

transaction.Commit();

await AuditingService.SaveAuditRecordAsync(
new ReservedNamespaceAuditRecord(namespaceToModify, AuditedReservedNamespaceAction.AddOwner, username, packageRegistrationsMatchingNamespace));
}
}

Expand Down Expand Up @@ -218,6 +225,9 @@ public async Task DeleteOwnerFromReservedNamespaceAsync(string prefix, string us
await ReservedNamespaceRepository.CommitChangesAsync();

transaction.Commit();

await AuditingService.SaveAuditRecordAsync(
new ReservedNamespaceAuditRecord(namespaceToModify, AuditedReservedNamespaceAction.RemoveOwner, username, packageRegistrationsToMarkUnverified));
}
}

Expand Down
Loading

0 comments on commit ff2cbd9

Please sign in to comment.