How to prevent table from being dropped? - postgresql

In PostgreSQL, how can I prevent anyone (including superusers) from dropping some specific table?
EDIT: Whoa, did we have some misunderstanding here. Let's say there is a big, shared QA database. Sometimes people run destructive things like hibernate-generated schema on it by mistake, and I'm looking for ways to prevent such mistakes.

anyone (including superusers) from dropping some specific table?
Trust your peers.

You can do that by writing some C code that attaches to ProcessUtility_hook. If you have never done that sort of thing, it won't be exactly trivial, but it's possible.
Another option might be looking into sepgsql, but I don't have any experience with that.

A superuser is precisely that. If you don't want them to be able to drop things, don't make them a superuser.
There's no need to let users run as superusers pretty much ever. Certainly not automated tools like schema migrations.
Your applications should connect as users with the minimum required user rights. They should not own the tables that they operate on, so they can't make schema changes to them or drop them.
When you want to make schema changes, run the application with a user that does have ownership of the tables of interest, but is not a superuser. The table owner can drop and modify tables, but only the tables it owns.
If you really, truly need to do something beyond the standard permissions model you will need to write a ProcessUtility_hook. See this related answer for a few details on that. Even then a superuser might be able to get around it by loading an extension that skips your hook, you'll just slow them down a bit.
Don't run an application as a superuser in production. Ever.
See the PostgreSQL documentation on permissions for more guidance on using the permissions model.

I don't think you can do that. You could perhaps have super super users who are going to manage the dropping of everything first. OR have backups constantly, so the higher member of the hierarchy will always have the possibility of retrieving the table.

I don't know what the real original intention of this question is... but a lot of people seem to have hypothetical answers like trusting your peers or using least permissions models appropriately. Personally, this misses the point altogether and instead answers with something everyone probably knew already, which isn't particularly helpful.
So let me attempt a question + answer of my own: How do you put in safety locks to prevent yourself or others from accidentally doing something you shouldn't? If you think that this "should never happen" then I think your imagination is too narrow. Or perhaps you are more perfect than me (and possibly a lot of other people).
For the rest of us, here is a solution that works for me. It is just a little lock that is put wherever you want it to - using event triggers. Obviously, this would be implemented by a super-user of some sort. But the point of it is that it has no bearing on permissions because it is error-based not permission based.
Obviously, you shouldn't implement this sort of thing if production behavior is dependent on it. It only makes sense to use in situations where it makes sense to use. Don't use it to replace what should be solved using permissions and don't use it to undermine your team. Use common sense - individual results may vary.
CREATE SCHEMA testst;
CREATE OR REPLACE FUNCTION manual_override_required() RETURNS event_trigger AS
$$
DECLARE
obj record;
BEGIN
FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()
LOOP
RAISE INFO 'object_oid: %, object_type: %', obj.objid, obj.object_type;
RAISE info '%', obj.object_name;
IF obj.object_type = 'schema' and obj.object_name = 'testst' THEN
RAISE EXCEPTION 'You have attempted to DROP something which has been hyper-locked and requires manual override to proceed.';
END IF;
END LOOP;
END
$$
LANGUAGE plpgsql
;
DROP EVENT TRIGGER IF EXISTS lock_schema;
CREATE EVENT TRIGGER lock_schema
ON sql_drop
EXECUTE FUNCTION manual_override_required();
DROP SCHEMA testst;
-- produces error: "ERROR: You have attempted to DROP something which has been admin-locked and requires manual override to proceed."
-- To override the admin-lock (you have the permission to do this, it just requires two turns of a key and positive confirmation):
ALTER EVENT TRIGGER lock_schema DISABLE;
DROP SCHEMA testst;
-- now it works!
An example of how I use this is in automation workflows. I have to switch between dev and prod environments a dozen times a day and I can (i.e. have) easily lost track of which is which despite the giant flags and banners I've put up to remind myself. Dropping certain schemas should be a rare and special event in Prod (thus the benefit of a active-confirmation approach) whereas in dev I rebuild them all the time. If I maintain the same permission structures in Dev as in Prod (which I do) then I wouldn't be able to solve this.

Related

Check for object ownership with Prisma

I'm new to working with Prisma. One aspect that is unclear to me is the right way to check if a user has permission on an object. Let's assume we have Book and Author models. Every book has an author (one-to-many). Only authors have permission to delete books.
An easy way to enforce this would be this:
prismaClient.book.deleteMany({
id: bookId, <-- id is known
author: {
id: userId <-- id is known
}
})
But this way it's very hard to show an UnauthorizedError to the user. Instead, the response will be a 500 status code since we can't know the exact reason why the query failed.
The other approach would be to query the book first and check the author of the book instance, which would result in one more query.
Is there a best practice for this in Prisma?
Assuming you are using PostgreSQL, the best approach would be to use row-level-security(RLS) - but unfortunately, it is not yet officially supported by Prisma.
There is a discussion about this subject here
https://github.com/prisma/prisma/issues/5128
As for the current situation, to my opinion, it is better to use an additional query and provide the users with informative feedback rather than using the other method you suggested without knowing why it was not deleted.
Eventually, it is up to you to decide based on your use case - whether or not it is important for you to know the reason for failure.
So this question is more generic than prisma - it is also true when running updates/deletes in raw SQL.
When you have extra where clauses to check for ownership, it's difficult to infer which of the clause(s) caused that if the update does not happen, without further queries.
You can achieve this with row level security in postgres, but even that does not come out the box and involves custom configuration to throw specific exceptions when rows are not found due to row level security rules. See this answer for more detail.
I tend to think that doing customised stuff like this is rarely worth the tradeoff, unless you need specialised UX for an uncommon circumstance.
What I would suggest instead in this case is to keep it simple and just use extra queries to check for ownership, but optimise the UX optimistically for the case where the user does own the entity and keep that common and legitimate usecase to a single query.
That is, catch the exception from primsa (or the fact that the update returns 0 rows, or whatever it is in different cases), and only then run a specific select for ownership, to check if that was the reason the update failed.
This is a nice tradeoff because it keeps things simple, and only runs extra queries in the (usually) far less common failure case.
Even having said all that, the broader caveat as always is that probably the extra queries simply won't matter regardless! It's, in 99% of cases, probably best to just always run the extra ownership query upfront as a pattern to keep things as simple as possible, which is what you really want to optimise for over performance until you're running at significant scale.

Drop/replace access method?

As of PostgresSQL 9.6, access methods were introduced for core functionality. I have been making some modifications to PostgreSQL and I would like to recreate an access method- but there is nothing like CREATE OR REPLACE so I wanted to perform DROP ACCESS METHOD btree; and then create it again.
But I am presented with:
ERROR: cannot drop access method btree because it is required by the database system
Maybe I can drop this restriction since I am planning to create it again? How can I achieve my goal?
UPDATE: I suppose something interesting would be to create the same access method under a different name - but then how can I be sure that this is being used over the other is not clear to me.
There is no need to drop btree, and fortunately the system keeps you from doing so.
If you want to write a substitute for it, that's fine. Add it as a new access method and use it throughout. The presence of btree won't bother you or slow you down.
As pozs said, if you think you can improve PostgreSQL's B-tree implementation so that it would be a benefit for everybody, get in touch with pgsql-hackers.

Is it possible to create permanent object aliases

I recently found myself using some rather lengthy names for the tables and views involved in a development piece, which got me wondering whether it's possible to create client/database/server level aliases for objects.
Say for example I have a view named dbo.vAlphaBetaGammaDelta . Is there a way (with or without Intellisense) to create a reference to it named dbo.vABGD ?
If not, would there be any downfalls to creating a view of a view or single table aside from maintenance necessary if/when the table schema changes?
I should note that these aliases/views would not be intended for use in other objects, but for alleviation and prevention of carpal tunnel during day-to-day troubleshooting and delving xD
SQL Server allows for the creation of synonyms. That seems to be what you are looking for: http://msdn.microsoft.com/en-us/library/ms177544.aspx
However, as #MitchWheat mentioned. this seems to be going in the wrong direction. There are a few quite good SSMS plugins available that provide auto completion of long object names (e.g. SQL Prompt). Incidentally those products have trouble with synonyms...
There are many cases where you would like to have synonyms.
Let me state just one for start:
You have a well defined hypothetical name of a table: GlobalStatisticalRecord. Hundreds of lines of code and objects (keys, indexes, etc.) in SQL and elsewhere are referring to this table name.
After 5 years of usage, the abbreviation GSR was accustomed not only among the technical people, but also among the business users. So, to stress again, GSR is now even more recognizable than GlobalStatisticalRecord. However, for the new people that come into the technical team, it is good to keep the name GlobalStatisticalRecord as a table name, since it nicely describes what is the table all about. Now, when writing a quick adhoc query - and that may not be from your tool of choice with all the Intellisense features you are accustom to - then these aliases are really saving your time (and "life" at 2am in the morning when you are frantically trying to diagnose a production problem).
Please, if you never faced a case when you would need this, just don't assume that there is none.
I stressed the adhoc adjective, since I agree that in permanent queries (stored procedures, etc.), for the reasons you pointed out, it is advisable to use the full table names.

Creating restricted temporary Subroutines in ABAP

I would like to offer the possibility to create advanced selects, more profound than the left joins that can be created via quickviewer.
The easiest way would be to allow the user to insert some source code via "GENERATE SUBROUTINE POOL".
But it would be neccesary for me to ensure that this source code doesn't change any data, start other programms or does anything than evaluating data.
My idea would be to restict the inserted source code to some key-worlds like SELECT, LOOP, IF etc. In this case I would need to find all key words in the inserted source code and check it against some white list.
How could I do this? Are there any ways to circumvent my restrictions in order to do some real damage? Are there other ways to reach my goal?
Securing stuff like this is really hard to do, and it's not a personal limitation or an issue with the platform. You can't get the machine to understand what the programmer is doing - see Halting Problem. Doing a keyword scan for yourself is tedious work. You might want to try SCAN ABAP-SOURCE and take a look at the tables the scanner throws out. However, limiting to the most basic language elements will only get you so far, because for any substantial programming, you'll have to allow for external subroutine calls, and then you're vulnerable to about anything. In my opinion, it's better to hand the specifications to a developer and have the report developed with no dynamic stuff whatsoever. This way, you can also ensure that no incorrect reports are created just because the user hacking away at the SELECT statements didn't know about that cancellation flag...

Qualified naming

I'm currently doing some maintenance on an application and I've come across a big issue regarding the qualified name in tsql. I wondering if someone could clear my confusion up for me.
From my understanding you want to use USE [DatabaseName] to declare which database you are using. I notice if u "rename" the databse it automatically updates these references in your code.
However, the developer who originally wrote this code used the USE [DatabaseName]. Then in later statements he wrote: SELECT * FROM [DatabaseName].[dbo].[Table]. Well this obviously breaks if I change the Database's name. From what i've read you want to qualify names only to the owner such as: [dbo].[TableName] so it knows where to look which increases performance.
Is there a reason he included the Database name in each statement?
From what i've read you want to qualify names only to the owner such as: [dbo].[TableName] so it knows where to look which increases performance.
Not that I'm aware of, rather it looks like someone is lazy.
I always use the three name format (unless accessing a linked server instance, then it's four).
The benefit is that the correct table from the correct database & schema will be used without concern for an errant USE [appropriate database] statement. As long as the object exists, and the permissions are valid based on the need, you can recreate a stored procedure, function, view, etc in other databases without needing to address the USE [appropriate database] statement each time.
But I'm working with data spread over numerous databases on the same instance. I wouldn't have necessarily designed it that way, but it wouldn't change that I use three (or four) part qualified name format.