question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Permission denied when deleting entity

See original GitHub issue

Hello,

we are facing an issue in our application when deleting a User record from our production database. Apart from the Users table, there are other tables such as BillingInformation, Addresses and Activities related to the User. We are trying to delete a single User record from the database, and we are sure that the User has no Activities assigned. Every Activity record has a ProviderId property that is non-nullable and references the UserId in the Users table. We are connecting to the database using test_user account without access to the Activities table (REVOKE DELETE ON “Activities” FROM test_user). When the deletion transaction is committed, we get an error: “permission denied for table Activities”, although there are no Activities related to the User.

From the logs we can see multiple SQL queries being executed, most of them are related to the Address and BillingInformation and one of them is the delete query: DELETE FROM "Users"\r\nWHERE "Id" = @p0;"

We are hosting our database on AMAZON RDS and connecting using a connection string:
User ID=test_user;Password=OUR-PASSWORD;Server=OUR-SERVER;Port=5432;Database=our-database; SSL Mode=Require Unfortunately, we were not able to reproduce this issue locally nor remotely using another AWS database (we copied the whole production database to another DB server for debugging purposes, but the error message can’t be reproduced, for unknown reasons).

Within the inner exception is a Where property that indicates that the Activities table is reached by the generated SQL query, even though the User being deleted is not linked to any Activity record. Note: the test_user is prevented from deleting Activities records, but not from other operations.

More details about the exception follow:

When the transaction is committed, the resulting exception is “An error occurred while updating the entries. See the inner exception for details.” The inner exception:

Message: 42501: permission denied for table Activities, Source: Npgsql, Statement: {DELETE FROM “Users” WHERE “Id” = $1} Where: SQL statement “DELETE FROM ONLY “public”.“Activities” WHERE $1 OPERATOR(pg_catalog.=) “ProviderId””

StackTrace:   
 At Npgsql.NpgsqlConnector.<>c__DisplayClass160_0.<<DoReadMessage>g__ReadMessageLong|0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Npgsql.NpgsqlConnector.<>c__DisplayClass160_0.<<DoReadMessage>g__ReadMessageLong|0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Npgsql.NpgsqlDataReader.<NextResult>d__44.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlCommand.<ExecuteReaderAsync>d__102.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Npgsql.NpgsqlCommand.<ExecuteDbDataReaderAsync>d__97.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__17.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__17.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__17.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__29.MoveNext()

Our Entities models are as follows:

public class Activity { 
[Key]
public long Id { get; set; }

public long ProviderId { get; set; }
public User Provider { get; set; } = null!;

public long? AddressId { get; set; }
public Address? Address { get; set; } = null!;
}

public class User {
[Key]
public long Id { get; set; }

public long? AddressId { get; set; }
public Address? Address { get; set; } = null!;

public long? BillingInformationId { get; set; }
public BillingInformation? BillingInformation { get; set; }
}

public class BillingInformation {
[Key]
public long Id { get; set; }
public long AddressId { get; set; }
public Address Address { get; set; } = null!;
}

public class Address {
[Key]
public long Id { get; set; }
public User? User { get; set; } = null!;
public BillingInformation? BillingInformation { get; set; } = null!;
}

The User we are trying to delete has one Address assigned and one BillingInformation. The Billing Information of the User has also an Address assigned. The User has no Activities assigned.

The test_user was created this way:

create role test_user with 
LOGIN 
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
inherit
NOREPLICATION
connection limit -1
password '***'

grant usage on schema public to test_user;

grant all privileges on all tables in schema public to test_user;

revoke delete on "Activities" from test_user;

From the logs we were able to extract additional information:

// Excecuted SQL

DELETE FROM \"Address\"\r\nWHERE \"Id\" = @p3;"
DELETE FROM \"Address\"\r\nWHERE \"Id\" = @p1
DELETE FROM \"BillingInformation\"\r\nWHERE \"Id\" = @p2;"
DELETE FROM \"Users\"\r\nWHERE \"Id\" = @p0;"

// Entity tracker logs
{ "date": "2021-02-17 10:30:55.7664", "level": "Debug", "message": "The 'User' entity with key '{Id: 34617}' tracked by 'CmcContext' changed from 'Deleted' to 'Detached'." }
{ "date": "2021-02-17 10:30:55.7664", "level": "Debug", "message": "The 'Address' entity with key '{Id: 39353}' tracked by 'CmcContext' changed from 'Deleted' to 'Detached'." }
{ "date": "2021-02-17 10:30:55.7664", "level": "Debug", "message": "The 'BillingInformation' entity with key '{Id: 11975}' tracked by 'CmcContext' changed from 'Deleted' to 'Detached'." }
{ "date": "2021-02-17 10:30:55.7664", "level": "Debug", "message": "The 'Address' entity with key '{Id: 39354}' tracked by 'CmcContext' changed from 'Deleted' to 'Detached'." }

We have also tried to create a new database user - just to make sure the test_user is not misconfigured, but in the production application the exception is still thrown. Using a copy of our production database, we have also verified that no Activities are deleted, when the test_user has sufficient rights to delete from the Activities table.

Environment EF Core version: 3.1.11 Database provider: Npgsql.EntityFrameworkCore.PostgreSQL, v. 3.1.11 Target framework: .NET Core 3.1 IDE: Microsoft Visual Studio Enterprise 2019, Version 16.8.5

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:12 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
vonzshikcommented, Mar 9, 2021

Okay, I’ve finally got some time to take a look. And it’s very interesting, so: a) If the owner of the database attempts to delete a row with cascade delete on, the exception is always thrown b) If some user attempts to delete a row with cascade delete on, the exception is thrown only if there is anything to delete

Can’t really say that makes a lot of sense. But anyway, I’m closing this issue as this is mostly how PG behaves. @kejdajar @pikausp thank you for your research, I’m really curious why it was done so…

1reaction
vonzshikcommented, Feb 17, 2021

Made this repro:

static void Main(string[] args)
{
	using var context = new BloggingContext();

	context.Database.EnsureDeleted();
	context.Database.EnsureCreated();

	try
	{
		context.Database.ExecuteSqlRaw("REVOKE DELETE ON \"Posts\" FROM efcore");

		var blog = new Blog
		{
			BlogId = 1,
			Rating = 0,
			Url = "someurl"
		};
		context.Blogs.Add(blog);
		context.SaveChanges();

		context.Blogs.Remove(blog);

		try
		{
			context.SaveChanges();
		}
		catch (DbUpdateException)
		{
			Console.WriteLine("No perms to delete from posts");
		}
	}
	finally
	{
		context.Database.EnsureDeleted();
	}
}

public class BloggingContext : DbContext
{
	public DbSet<Blog> Blogs { get; set; }
	public DbSet<Post> Posts { get; set; }

	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
	{
		optionsBuilder.UseNpgsql("Host=localhost; Database=efcore; User ID=efcore; Password=Master1234; Pooling=true; MaxPoolSize=100");
	}
}

public class Blog
{
	public int BlogId { get; set; }
	public string Url { get; set; }
	public int Rating { get; set; }
	public List<Post> Posts { get; set; }
}

public class Post
{
	public int PostId { get; set; }
	public string Title { get; set; }
	public string Content { get; set; }

	public int BlogId { get; set; }
	public Blog Blog { get; set; }
}

And it always throws due to a lack of permissions to delete from table Posts. I can only assume the other database lacks the restrictions. Can you confirm they’re actually there?

Read more comments on GitHub >

github_iconTop Results From Across the Web

EF record Remove works on my computer, but not when ...
The DELETE permission was denied on the object 'SteelOrderLines', ... the 'INSERT' permissions, but in order to use the REMOVE entity ...
Read more >
Permission denied while trying to delete even when ...
I recently had this issue where I created a database user and gave delete and update permission. Yet, I was getting permission denied...
Read more >
Delete operation doesn't work in an entity when you enable ...
Fixes an issue in which Delete operation doesn't work in an entity when you enable Approval Required permission in SQL Server 2017 Master...
Read more >
Octane Rest API permission denied : Issue with deleting an ...
I am trying to delete an entity of type "scm_branch". However, when I try to do so, I receive an error message saying...
Read more >
There is no way to delete file entities of other users
Currently it's only possible to delete a file entity by the owner of an file entity. There is no additional condition defined for...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found