Skip to content

Commit

Permalink
[Organizations] Fixes and unit tests for API upload for organizations (
Browse files Browse the repository at this point in the history
  • Loading branch information
Scott Bommarito authored Jan 22, 2018
1 parent 5d29d53 commit 7a33bc3
Show file tree
Hide file tree
Showing 19 changed files with 1,070 additions and 670 deletions.
44 changes: 44 additions & 0 deletions src/NuGetGallery/Authentication/ApiScopeEvaluationResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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.Authentication
{

/// <summary>
/// The result of evaluating the current user's scopes by using <see cref="ApiScopeEvaluator"/>.
/// </summary>
public class ApiScopeEvaluationResult
{
/// <summary>
/// True IFF any scope's subject (<see cref="Scope.Subject"/>) and allowed action (<see cref="Scope.AllowedAction"/>) match the subject being acted upon and the action being performed.
/// </summary>
public bool ScopesAreValid { get; }

/// <summary>
/// If <see cref="ScopesAreValid"/> is true, the <see cref="PermissionsCheckResult"/> returned by checking the permission of the scope's owner (<see cref="Scope.Owner"/>).
/// Otherwise, <see cref="PermissionsCheckResult.Unknown"/>.
/// </summary>
public PermissionsCheckResult PermissionsCheckResult { get; }

/// <summary>
/// The owner of the scope as acquired from <see cref="Scope.Owner"/>.
/// </summary>
public User Owner { get; }

public ApiScopeEvaluationResult(User owner, PermissionsCheckResult permissionsCheckResult, bool scopesAreValid)
{
ScopesAreValid = scopesAreValid;
PermissionsCheckResult = permissionsCheckResult;
Owner = owner;
}

/// <summary>
/// Returns whether or not this <see cref="ApiScopeEvaluationResult"/> represents a successful authentication.
/// If this <see cref="ApiScopeEvaluationResult"/> does not represent a successful authentication, the current user should be denied from performing the action they are attempting to perform.
/// </summary>
public bool IsSuccessful()
{
return ScopesAreValid && PermissionsCheckResult == PermissionsCheckResult.Allowed;
}
}
}
81 changes: 81 additions & 0 deletions src/NuGetGallery/Authentication/ApiScopeEvaluator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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;

namespace NuGetGallery.Authentication
{
public class ApiScopeEvaluator : IApiScopeEvaluator
{
private readonly IUserService _userService;

public ApiScopeEvaluator(IUserService userService)
{
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
}

public ApiScopeEvaluationResult Evaluate(
User currentUser,
IEnumerable<Scope> scopes,
IActionRequiringEntityPermissions<PackageRegistration> action,
PackageRegistration packageRegistration,
params string[] requestedActions)
{
return Evaluate(currentUser, scopes, action, packageRegistration, pr => pr.Id, requestedActions);
}

public ApiScopeEvaluationResult Evaluate(
User currentUser,
IEnumerable<Scope> scopes,
IActionRequiringEntityPermissions<ActionOnNewPackageContext> action,
ActionOnNewPackageContext context,
params string[] requestedActions)
{
return Evaluate(currentUser, scopes, action, context, c => c.PackageId, requestedActions);
}

/// <remarks>This method is internal because it is tested directly.</remarks>
internal ApiScopeEvaluationResult Evaluate<TEntity>(
User currentUser,
IEnumerable<Scope> scopes,
IActionRequiringEntityPermissions<TEntity> action,
TEntity entity,
Func<TEntity, string> getSubjectFromEntity,
params string[] requestedActions)
{
User ownerInScope = null;

if (scopes == null || !scopes.Any())
{
// Legacy V1 API key without scopes.
// Evaluate it as if it has an unlimited scope.
scopes = new[] { new Scope(ownerKey: null, subject: NuGetPackagePattern.AllInclusivePattern, allowedAction: NuGetScopes.All) };
}

// Check that all scopes provided have the same owner scope.
var ownerScopes = scopes.Select(s => s.OwnerKey);
var ownerScope = ownerScopes.FirstOrDefault();
if (ownerScopes.Any(o => o != ownerScope))
{
throw new ArgumentException("All scopes provided must have the same owner scope.");
}

var matchingScope = scopes
.FirstOrDefault(scope =>
scope.AllowsSubject(getSubjectFromEntity(entity)) &&
scope.AllowsActions(requestedActions));

ownerInScope = ownerScope.HasValue ? _userService.FindByKey(ownerScope.Value) : currentUser;

if (matchingScope == null)
{
return new ApiScopeEvaluationResult(ownerInScope, PermissionsCheckResult.Unknown, scopesAreValid: false);
}

var isActionAllowed = action.CheckPermissions(currentUser, ownerInScope, entity);
return new ApiScopeEvaluationResult(ownerInScope, isActionAllowed, scopesAreValid: true);
}
}
}
40 changes: 40 additions & 0 deletions src/NuGetGallery/Authentication/IApiScopeEvaluator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;

namespace NuGetGallery.Authentication
{
public interface IApiScopeEvaluator
{
/// <summary>
/// Evaluates the whether or not an action is allowed given a set of <paramref name="scopes"/>, an <paramref name="action"/>, and the <paramref name="requestedActions"/>.
/// </summary>
/// <param name="currentUser">The current user attempting to do the action with the given <paramref name="scopes"/>.</param>
/// <param name="scopes">The scopes being evaluated.</param>
/// <param name="action">The action that the scopes being evaluated are checked for permission to do.</param>
/// <param name="packageRegistration">The <see cref="PackageRegistration"/> that the scopes being evaluated are checked for permission to <paramref name="action"/> on.</param>
/// <param name="requestedActions">A list of actions that the scopes must match.</param>
/// <returns>A <see cref="ApiScopeEvaluationResult"/> that describes the evaluation of the <see cref="Scope"/>s.</returns>
ApiScopeEvaluationResult Evaluate(
User currentUser,
IEnumerable<Scope> scopes,
IActionRequiringEntityPermissions<PackageRegistration> action,
PackageRegistration packageRegistration,
params string[] requestedActions);

/// <summary>
/// Evaluates the whether or not an action is allowed given a set of <paramref name="scopes"/>, an <paramref name="action"/>, and the <paramref name="requestedActions"/>.
/// </summary>
/// <param name="currentUser">The current user attempting to do the action with the given <paramref name="scopes"/>.</param>
/// <param name="scopes">The scopes being evaluated.</param>
/// <param name="action">The action that the scopes being evaluated are checked for permission to do.</param>
/// <param name="context">The <see cref="ActionOnNewPackageContext"/> that the scopes being evaluated are checked for permission to <paramref name="action"/> on.</param>
/// <param name="requestedActions">A list of actions that the scopes must match.</param>
/// <returns>A <see cref="ApiScopeEvaluationResult"/> that describes the evaluation of the <see cref="Scope"/>s.</returns>
ApiScopeEvaluationResult Evaluate(
User currentUser,
IEnumerable<Scope> scopes,
IActionRequiringEntityPermissions<ActionOnNewPackageContext> action,
ActionOnNewPackageContext context,
params string[] requestedActions);
}
}
Loading

0 comments on commit 7a33bc3

Please sign in to comment.