Skip to content

AccessControlProvider does not receive correct entity #171

@ryxxxx

Description

@ryxxxx

Describe the bug

The entity that is passed to the AccessControlProvider does not have any properties that are only stored server-side (such as a UserId), when it is passed from a PUT request. Accordingly, all PUT-requests comparing the UserId of the entity to the user making the request will return "Unauthorized". DELETE requests function as expected. The difference can be explained by examining the source (I only included the relevant lines):

TableController.Update.cs:

public virtual async Task<IActionResult> ReplaceAsync([FromRoute] string id, CancellationToken cancellationToken = default)
{
    TEntity entity = await DeserializeJsonContent(cancellationToken).ConfigureAwait(false);

    TEntity existing = await Repository.ReadAsync(id, cancellationToken).ConfigureAwait(false);

    if (!AccessControlProvider.EntityIsInView(existing))
    {
        Logger.LogWarning("ReplaceAsync: {id} statusCode=404 not in view", id);
        throw new HttpException(StatusCodes.Status404NotFound);
    }

    await AuthorizeRequestAsync(TableOperation.Update, entity, cancellationToken).ConfigureAwait(false);
}

TableController.Delete.cs:

public virtual async Task<IActionResult> DeleteAsync([FromRoute] string id, CancellationToken cancellationToken = default)
{
    TEntity entity = await Repository.ReadAsync(id, cancellationToken).ConfigureAwait(false);

    if (!AccessControlProvider.EntityIsInView(entity))
    {
        Logger.LogWarning("DeleteAsync: {id} statusCode=404 not in view", id);
        throw new HttpException(StatusCodes.Status404NotFound);
    }

    await AuthorizeRequestAsync(TableOperation.Delete, entity, cancellationToken).ConfigureAwait(false);
}

In Delete.cs "AuthorizeRequestAsync" is called with the entity retrieved from "Repository.ReadAsync", whereas in Update.cs it is called with the entity retrieved from "DeserializeJsonContent". I doubt that this is intentional, because the other AccessControlProvider function call to "EntityIsInView" is made with the correct entity (named "existing").

If I am correct, the fix would be very simple: replace "AuthorizeRequestAsync(TableOperation.Update, entity" with "AuthorizeRequestAsync(TableOperation.Update, existing".

To Reproduce

Steps to reproduce the behavior:

  1. Add a simple AccessControlProvider as detailed in the documentation, that uses a UsedId property to restrict editing access to entities that were created by the user.

Expected behavior

The entity passed to the AccessControlProvider should have all fields that are contained in the database and not just those that were passed with the PUT request.

What platforms?

Note: Any bug or feature request that is opened for an unsupported environment will be automatically closed.

Server:
Version of dotnet being used to compile? net 8.0
Library versions? 8.0.4
What database are you using? sqlite for testing purposes
Where are you running the server? Azure App Service

Additional context

This problem might be related to #162, but I'm not sure

Metadata

Metadata

Assignees

No one assigned

    Labels

    ServerImprovements or additions to the server code

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions