For the impatient - I can summarize this question as:
What practical approach can be used to leverage role-based privileges in PostgreSQL when using an Access Front End that employs ODBC linked-tables?
And now for the longer version:
I've inherited the unsavory task of upgrading an Access 2000 / PG 7 application to Access 2013 / PG 9. I'm new to PostgreSQL but have used Oracle and Microsoft Access quite a bit.
EDIT: The production server is running PostgreSQL on Mac OS X Lion. My Test machine is running PostgreSQL on Oracle Linux 7.
This Access DB is linking to tables in the PG Database via ODBC, connecting using an single PG login role (application_user). Every user connects with this login role, and it is only the conditions in the Forms / VBA that limits the user's rights. If, however, a user can get into the navigation pane - they can access the linked tables directly and bypass all security restrictions. While upgrading this database, I'd like to see if I can tighten that up.
I could set up each user with their own login role on PostgreSQL, but then it would mean (from the way I'm looking at it) a hefty amount of retooling the database. I'd rather not make such large changes on a production database - incremental changes are more desired.
Looking at the database's security needs - I can think of only five roles that would be needed.
- Order Entry
- Customer Entry
- Order and Customer Entry
- Read-Only
- Not Authorized - No Access
I can set up these as Group Roles in PGSQL and each table with the necessary ACL for each role.
What I'm missing is how I can go from a single login-role (application_user) to all of the above roles?
My initial thought was to set the application_user (logon role) to have no group roles (essentially resulting in "Not Authorized - No Access"), and then use a call to a PL/pgSQL function authorize(Username, MD5PassWord) to authorize and elevate the role. The function would check if the supplied MD5 hash matches the MD5 hash stored in the users table - and if so - it would issue a SET SESSION ROLE for the appropriate Group Role.
If this would work, it would let me track user names that are logging in, and then using the pg_backend_pid() function, I can associate it back with the user for the business logic or logging or whatever. It also means I don't need to worry if some user goes into the Linked Table - because their access would be restricted by whatever role they are currently authorized for in that database session.
So I whipped up a plpgsql script, set its owner to OrderCustomerEntryGroup and gave it SECURITY DEFINER rights.
DECLARE
v_Status integer;
BEGIN
v_Status := 0;
IF pin_username = 'username' AND MD5('foo') = pin_pwmd5 THEN
SET SESSION AUTHORIZATION OrderEntryGroup;
v_Status := 1;
END IF;
RETURN v_Status;
END;
Only problem however with my implementation is that
SELECT authenticate('username',MD5('foo'));
gives:
ERROR: cannot set parameter "session_authorization" within security-definer function
SQL state: 42501
Context: SQL statement "SET SESSION AUTHORIZATION OrderEntryGroup"
PL/pgSQL function authenticate(character varying,text) line 7 at SQL statement
So I read up on this - and from what I can tell, you used to be able to do this, but for whatever reason it was removed. I haven't been able to find an alternative - other than using the built in roles on a per-user level.
So what I'm asking is .. What am I missing to make my approach (an easy solution) work, or is there a better way of doing this that won't involve ripping apart the existing access database?