Permalink
Browse files

Merge pull request #3997 from NuGet/dev

[ReleasePrep][2017.05.19]RI of dev into master
  • Loading branch information...
2 parents 7a586a6 + 3ac8517 commit f8c924628ee48e30a7141a240cef5211878671a1 @ryuyu ryuyu committed on GitHub May 22, 2017
Showing with 3,750 additions and 1,081 deletions.
  1. +1 −1 README.md
  2. +22 −0 src/NuGetGallery.Core/Auditing/AuditedEntities/AuditedUserSecurityPolicy.cs
  3. +1 −2 src/NuGetGallery.Core/Auditing/AuditedPackageAction.cs
  4. +11 −0 src/NuGetGallery.Core/Auditing/AuditedSecurityPolicyAction.cs
  5. +3 −1 src/NuGetGallery.Core/Auditing/AuditedUserAction.cs
  6. +0 −16 src/NuGetGallery.Core/Auditing/UserAuditAction.cs
  7. +18 −1 src/NuGetGallery.Core/Auditing/UserAuditRecord.cs
  8. +50 −0 src/NuGetGallery.Core/Auditing/UserSecurityPolicyAuditRecord.cs
  9. +1 −0 src/NuGetGallery.Core/Entities/EntitiesContext.cs
  10. +2 −1 src/NuGetGallery.Core/Entities/IEntitiesContext.cs
  11. +40 −3 src/NuGetGallery.Core/Entities/UserSecurityPolicy.cs
  12. +3 −1 src/NuGetGallery.Core/NuGetGallery.Core.csproj
  13. +3 −0 src/NuGetGallery/App_Start/DefaultDependenciesModule.cs
  14. +10 −0 src/NuGetGallery/App_Start/Routes.cs
  15. +122 −0 src/NuGetGallery/Areas/Admin/Controllers/SecurityPolicyController.cs
  16. +28 −0 src/NuGetGallery/Areas/Admin/ViewModels/SecurityPolicyViewModel.cs
  17. +23 −0 src/NuGetGallery/Areas/Admin/ViewModels/UserSecurityPolicySearchResult.cs
  18. +22 −0 src/NuGetGallery/Areas/Admin/ViewModels/UserSecurityPolicySubscriptions.cs
  19. +11 −0 src/NuGetGallery/Areas/Admin/Views/Home/Index.cshtml
  20. +168 −0 src/NuGetGallery/Areas/Admin/Views/SecurityPolicy/Index.cshtml
  21. +0 −1 src/NuGetGallery/Authentication/Providers/ApiKey/ApiKeyAuthenticationHandler.cs
  22. +2 −2 src/NuGetGallery/Constants.cs
  23. +336 −307 src/NuGetGallery/Content/Site.css
  24. +33 −19 src/NuGetGallery/Controllers/ApiController.cs
  25. +8 −2 src/NuGetGallery/Controllers/PackagesController.cs
  26. +68 −21 src/NuGetGallery/Controllers/StatisticsController.cs
  27. +11 −0 src/NuGetGallery/ExtensionMethods.cs
  28. +3 −55 src/NuGetGallery/Filters/ApiAuthorizeAttribute.cs
  29. +8 −6 src/NuGetGallery/Helpers/AccordeonHelper.cs
  30. +1 −1 src/NuGetGallery/Infrastructure/ApplicationVersionHelper.cs
  31. +29 −0 src/NuGetGallery/Migrations/201705031714183_AddIndexSemVerLevelKey.Designer.cs
  32. +18 −0 src/NuGetGallery/Migrations/201705031714183_AddIndexSemVerLevelKey.cs
  33. +126 −0 src/NuGetGallery/Migrations/201705031714183_AddIndexSemVerLevelKey.resx
  34. +29 −0 src/NuGetGallery/Migrations/201705032101231_SecurityPoliciesFix.Designer.cs
  35. +45 −0 src/NuGetGallery/Migrations/201705032101231_SecurityPoliciesFix.cs
  36. +126 −0 src/NuGetGallery/Migrations/201705032101231_SecurityPoliciesFix.resx
  37. +29 −0 src/NuGetGallery/Migrations/201705041614287_UserSecurityPolicies_SubscriptionColumn.Designer.cs
  38. +18 −0 src/NuGetGallery/Migrations/201705041614287_UserSecurityPolicies_SubscriptionColumn.cs
  39. +126 −0 src/NuGetGallery/Migrations/201705041614287_UserSecurityPolicies_SubscriptionColumn.resx
  40. +31 −2 src/NuGetGallery/NuGetGallery.csproj
  41. +2 −0 src/NuGetGallery/RouteNames.cs
  42. +7 −5 src/NuGetGallery/Scripts/nugetgallery.js
  43. +47 −3 src/NuGetGallery/Scripts/statsdimensions.js
  44. +28 −4 src/NuGetGallery/Security/ISecurityPolicyService.cs
  45. +35 −0 src/NuGetGallery/Security/IUserSecurityPolicySubscription.cs
  46. +18 −3 src/NuGetGallery/Security/RequireMinClientVersionForPushPolicy.cs
  47. +1 −1 src/NuGetGallery/Security/RequirePackageVerifyScopePolicy.cs
  48. +100 −0 src/NuGetGallery/Security/SecurePushSubscription.cs
  49. +1 −1 src/NuGetGallery/{Filters → Security}/SecurityPolicyAction.cs
  50. +178 −11 src/NuGetGallery/Security/SecurityPolicyService.cs
  51. +5 −15 src/NuGetGallery/Security/{UserSecurityPolicyContext.cs → UserSecurityPolicyEvaluationContext.cs}
  52. +1 −1 src/NuGetGallery/Security/UserSecurityPolicyHandler.cs
  53. +23 −0 src/NuGetGallery/Security/UserSecurityPolicySubscriptionContext.cs
  54. +10 −0 src/NuGetGallery/Services/TelemetryService.cs
  55. +0 −1 src/NuGetGallery/ViewModels/ReportAbuseViewModel.cs
  56. +1 −1 src/NuGetGallery/ViewModels/ReportPackageReason.cs
  57. +3 −9 src/NuGetGallery/ViewModels/StatisticsPackagesViewModel.cs
  58. +9 −9 src/NuGetGallery/Views/Authentication/_Register.cshtml
  59. +17 −1 src/NuGetGallery/Views/Packages/ReportAbuse.cshtml
  60. +2 −2 src/NuGetGallery/Views/Packages/UploadPackage.cshtml
  61. +12 −2 src/NuGetGallery/Views/Packages/VerifyPackage.cshtml
  62. +4 −29 src/NuGetGallery/Views/Statistics/PackageDownloadsByVersion.cshtml
  63. +5 −31 src/NuGetGallery/Views/Statistics/PackageDownloadsDetail.cshtml
  64. +75 −87 src/NuGetGallery/Views/Statistics/_PivotTable.cshtml
  65. +6 −6 src/NuGetGallery/Views/Users/Account.cshtml
  66. +52 −31 src/NuGetGallery/Views/Users/ApiKeys.cshtml
  67. +2 −2 src/NuGetGallery/Views/Users/Packages.cshtml
  68. +2 −1 tests/NuGetGallery.Core.Facts/Auditing/AuditRecordTests.cs
  69. +2 −1 tests/NuGetGallery.Core.Facts/Auditing/AuditedPackageActionTests.cs
  70. +3 −1 tests/NuGetGallery.Core.Facts/Auditing/AuditedUserActionTests.cs
  71. +52 −0 tests/NuGetGallery.Core.Facts/Auditing/UserAuditRecordTests.cs
  72. +97 −0 tests/NuGetGallery.Core.Facts/Auditing/UserSecurityPolicyAuditRecordFacts.cs
  73. +76 −0 tests/NuGetGallery.Core.Facts/Entities/UserSecurityPolicyFacts.cs
  74. +2 −0 tests/NuGetGallery.Core.Facts/NuGetGallery.Core.Facts.csproj
  75. +205 −0 tests/NuGetGallery.Facts/Areas/Admin/Controllers/SecurityPolicyControllerFacts.cs
  76. +58 −29 tests/NuGetGallery.Facts/Controllers/ApiControllerFacts.cs
  77. +166 −167 tests/NuGetGallery.Facts/Controllers/PackagesControllerFacts.cs
  78. +62 −27 tests/NuGetGallery.Facts/Controllers/StatisticsControllerFacts.cs
  79. +41 −0 tests/NuGetGallery.Facts/ExtensionMethodsFacts.cs
  80. +3 −44 tests/NuGetGallery.Facts/Filters/ApiAuthorizeAttributeFacts.cs
  81. +4 −0 tests/NuGetGallery.Facts/NuGetGallery.Facts.csproj
  82. +6 −35 tests/NuGetGallery.Facts/Security/RequireMinClientVersionForPushPolicyFacts.cs
  83. +5 −6 tests/NuGetGallery.Facts/Security/RequirePackageVerifyScopePolicyFacts.cs
  84. +156 −0 tests/NuGetGallery.Facts/Security/SecurePushSubscriptionFacts.cs
  85. +373 −56 tests/NuGetGallery.Facts/Security/SecurityPolicyServiceFacts.cs
  86. +69 −0 tests/NuGetGallery.Facts/Security/TestSecurityPolicyService.cs
  87. +90 −0 tests/NuGetGallery.Facts/Security/TestUserSecurityPolicyData.cs
  88. +12 −0 tests/NuGetGallery.Facts/TestUtils/FakeEntitiesContext.cs
  89. +16 −1 tests/NuGetGallery.Facts/TestUtils/MockExtensions.cs
  90. +15 −15 tests/NuGetGallery.FunctionalTests/PackageCreation/SecurityPolicyTests.cs
  91. +5 −1 tools/Setup-DevEnvironment.ps1
View
@@ -17,7 +17,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
2. PowerShell 4.0
2. Clone it!
- ```PS C:\Code> git clone git@github.com:NuGet/NuGetGallery.git```
+ ```PS C:\Code> git clone https://github.com/NuGet/NuGetGallery.git```
3. Build it!
```
@@ -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
+{
+ /// <summary>
+ /// Auditing details for UserSecurityPolicy entity.
+ /// </summary>
+ public class AuditedUserSecurityPolicy
+ {
+ public string Name { get; }
+ public string Subscription { get; }
+ public string Value { get; }
+
+ public AuditedUserSecurityPolicy(UserSecurityPolicy policy)
+ {
+ Name = policy.Name;
+ Subscription = policy.Subscription;
+ Value = policy.Value;
+ }
+ }
+}
@@ -12,7 +12,6 @@ public enum AuditedPackageAction
Unlist,
Edit,
UndoEdit,
-
-
+ Verify
}
}
@@ -0,0 +1,11 @@
+// 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 AuditedSecurityPolicyAction
+ {
+ Create,
+ Verify
+ }
+}
@@ -14,6 +14,8 @@ public enum AuditedUserAction
ChangeEmail,
CancelChangeEmail,
ConfirmEmail,
- Login
+ Login,
+ SubscribeToPolicies,
+ UnsubscribeFromPolicies
}
}
@@ -1,16 +0,0 @@
-// 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 UserAuditAction
- {
- Registered,
- AddedCredential,
- RemovedCredential,
- RequestedPasswordReset,
- ChangeEmail,
- CancelChangeEmail,
- ConfirmEmail,
- }
-}
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using NuGetGallery.Auditing.AuditedEntities;
namespace NuGetGallery.Auditing
{
@@ -17,6 +18,11 @@ public class UserAuditRecord : AuditRecord<AuditedUserAction>
public CredentialAuditRecord[] AffectedCredential { get; }
public string AffectedEmailAddress { get; }
+ /// <summary>
+ /// Subset of user policies affected by the action (subscription / unsubscription).
+ /// </summary>
+ public AuditedUserSecurityPolicy[] AffectedPolicies { get; }
+
public UserAuditRecord(User user, AuditedUserAction action)
: this(user, action, Enumerable.Empty<Credential>())
{
@@ -55,7 +61,18 @@ public UserAuditRecord(User user, AuditedUserAction action, string affectedEmail
{
AffectedEmailAddress = affectedEmailAddress;
}
-
+
+ public UserAuditRecord(User user, AuditedUserAction action, IEnumerable<UserSecurityPolicy> affectedPolicies)
+ : this(user, action, Enumerable.Empty<Credential>())
+ {
+ if (affectedPolicies == null || affectedPolicies.Count() == 0)
+ {
+ throw new ArgumentException(nameof(affectedPolicies));
+ }
+
+ AffectedPolicies = affectedPolicies.Select(p => new AuditedUserSecurityPolicy(p)).ToArray();
+ }
+
public override string GetPath()
{
return Username.ToLowerInvariant();
@@ -0,0 +1,50 @@
+// 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.Collections.Generic;
+using System.Linq;
+using NuGetGallery.Auditing.AuditedEntities;
+
+namespace NuGetGallery.Auditing
+{
+ /// <summary>
+ /// Audit record for user security policy evaluations.
+ /// </summary>
+ public class UserSecurityPolicyAuditRecord : AuditRecord<AuditedSecurityPolicyAction>
+ {
+ public string Username { get; }
+
+ public AuditedUserSecurityPolicy[] AffectedPolicies { get; }
+
+ public bool Success { get; set; }
+
+ public string ErrorMessage { get; }
+
+ public UserSecurityPolicyAuditRecord(string username,
+ AuditedSecurityPolicyAction action,
+ IEnumerable<UserSecurityPolicy> affectedPolicies,
+ bool success, string errorMessage = null)
+ :base(action)
+ {
+ if (string.IsNullOrEmpty(username))
+ {
+ throw new ArgumentNullException(nameof(username));
+ }
+ if (affectedPolicies == null || affectedPolicies.Count() == 0)
+ {
+ throw new ArgumentException(nameof(affectedPolicies));
+ }
+
+ Username = username;
+ AffectedPolicies = affectedPolicies.Select(p => new AuditedUserSecurityPolicy(p)).ToArray();
+ Success = success;
+ ErrorMessage = errorMessage;
+ }
+
+ public override string GetPath()
+ {
+ return Username.ToLowerInvariant();
+ }
+ }
+}
@@ -42,6 +42,7 @@ public EntitiesContext(string connectionString, bool readOnly)
public IDbSet<Credential> Credentials { get; set; }
public IDbSet<Scope> Scopes { get; set; }
public IDbSet<User> Users { get; set; }
+ public IDbSet<UserSecurityPolicy> UserSecurityPolicies { get; set; }
IDbSet<T> IEntitiesContext.Set<T>()
{
@@ -13,8 +13,9 @@ public interface IEntitiesContext
IDbSet<PackageRegistration> PackageRegistrations { get; set; }
IDbSet<Credential> Credentials { get; set; }
IDbSet<Scope> Scopes { get; set; }
-
IDbSet<User> Users { get; set; }
+ IDbSet<UserSecurityPolicy> UserSecurityPolicies { get; set; }
+
Task<int> SaveChangesAsync();
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Set", Justification="This is to match the EF terminology.")]
IDbSet<T> Set<T>() where T : class;
@@ -1,22 +1,30 @@
// 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.ComponentModel.DataAnnotations;
namespace NuGetGallery
{
/// <summary>
/// User-subscribed security policy.
/// </summary>
- public class UserSecurityPolicy : IEntity
+ public class UserSecurityPolicy : IEntity, IEquatable<UserSecurityPolicy>
{
public UserSecurityPolicy()
{
}
- public UserSecurityPolicy(string name)
+ public UserSecurityPolicy(UserSecurityPolicy policy)
+ : this(policy.Name, policy.Subscription, policy.Value)
{
- Name = name;
+ }
+
+ public UserSecurityPolicy(string name, string subscription, string value = null)
+ {
+ Name = name ?? throw new ArgumentNullException(nameof(name));
+ Subscription = subscription ?? throw new ArgumentNullException(nameof(subscription));
+ Value = value;
}
/// <summary>
@@ -38,11 +46,40 @@ public UserSecurityPolicy(string name)
/// Type name for the policy handler that provides policy behavior.
/// </summary>
[Required]
+ [StringLength(256)]
public string Name { get; set; }
/// <summary>
+ /// Name of subscription that added this policy.
+ /// </summary>
+ [Required]
+ [StringLength(256)]
+ public string Subscription { get; set; }
+
+ /// <summary>
/// Support for JSON-serialized properties for specific policies.
/// </summary>
public string Value { get; set; }
+
+ /// <summary>
+ /// Determine if two policies are equal.
+ /// </summary>
+ public bool Equals(UserSecurityPolicy other)
+ {
+ return Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase) &&
+ Subscription.Equals(other.Subscription, StringComparison.OrdinalIgnoreCase) &&
+ (
+ (string.IsNullOrEmpty(Value) && string.IsNullOrEmpty(other.Value)) ||
+ (Value.Equals(other.Value, StringComparison.OrdinalIgnoreCase))
+ );
+ }
+
+ private static readonly Func<object, long, long> _hash = (i, hash) => ((hash << 5) + hash) ^ (i?.GetHashCode() ?? 0);
+ private const long _seed = 0x1505L;
+
+ public override int GetHashCode()
+ {
+ return _hash(Value, _hash(Subscription, _hash(Name, _seed))).GetHashCode();
+ }
}
}
@@ -122,11 +122,14 @@
<Compile Include="Auditing\AuditedEntities\AuditedPackage.cs" />
<Compile Include="Auditing\AuditedEntities\AuditedPackageIdentifier.cs" />
<Compile Include="Auditing\AuditedAuthenticatedOperationAction.cs" />
+ <Compile Include="Auditing\AuditedEntities\AuditedUserSecurityPolicy.cs" />
+ <Compile Include="Auditing\AuditedSecurityPolicyAction.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\UserSecurityPolicyAuditRecord.cs" />
<Compile Include="Auditing\FileSystemAuditingService.cs" />
<Compile Include="Auditing\CloudAuditingService.cs" />
<Compile Include="Auditing\CredentialAuditRecord.cs" />
@@ -139,7 +142,6 @@
<Compile Include="Auditing\AuditedUserAction.cs" />
<Compile Include="Auditing\PackageAuditRecord.cs" />
<Compile Include="Auditing\ScopeAuditRecord.cs" />
- <Compile Include="Auditing\UserAuditAction.cs" />
<Compile Include="Auditing\UserAuditRecord.cs" />
<Compile Include="CoreConstants.cs" />
<Compile Include="CredentialTypes.cs" />
@@ -207,6 +207,9 @@ protected override void Load(ContainerBuilder builder)
.As<ISecurityPolicyService>()
.InstancePerLifetimeScope();
+ builder.RegisterType<SecurePushSubscription>()
+ .SingleInstance();
+
var mailSenderThunk = new Lazy<IMailSender>(
() =>
{
@@ -70,11 +70,21 @@ public static void RegisterUIRoutes(RouteCollection routes)
new { controller = "Statistics", action = "PackageDownloadsDetail" });
routes.MapRoute(
+ RouteName.StatisticsPackageDownloadsDetailReport,
+ "stats/reports/packages/{id}/{version}",
+ new { controller = "Statistics", action = "PackageDownloadsDetailReport" });
+
+ routes.MapRoute(
RouteName.StatisticsPackageDownloadsByVersion,
"stats/packages/{id}",
new { controller = "Statistics", action = "PackageDownloadsByVersion" });
routes.MapRoute(
+ RouteName.StatisticsPackageDownloadsByVersionReport,
+ "stats/reports/packages/{id}",
+ new { controller = "Statistics", action = "PackageDownloadsByVersionReport" });
+
+ routes.MapRoute(
RouteName.JsonApi,
"json/{action}",
new { controller = "JsonApi" });
Oops, something went wrong.

0 comments on commit f8c9246

Please sign in to comment.