Aurynn Shaw
In this talk, we will cover Vertically Challenged, a plugin for repoze.who which utilizes the Postgres system roles for web application authorization.
We will be covering the underlying theory of Vertically Challenged, both in terms of benefits to your project, as well as the weaknesses of the concept, and how VC leverages database functionality to make your application easier to code and maintain.
We will also be covering how to design your database roles tree, how Vertically Challenged makes your roles tree available in the application layer, and how to integrate Vertically Challenged with repoze.who.
1. VERTICALLY
CHALLENGED
1
Saturday, March 27, 2010
2. Strong Application Permissions,
using PostgreSQL
Aurynn Shaw, Command Prompt, Inc.
PostgreSQL Conference West, 2009
2
Saturday, March 27, 2010
3. APPLICATION
ARCHITECTURE
Wherein
Basic Architecture
Limitations
Points of Authority
Why use DB permissions?
Implementation
3
Saturday, March 27, 2010
4. Basic Architecture
Web Server
Application Standard tiered design
Database
4
Saturday, March 27, 2010
5. Basic Architecture
Web Server
Standard tiered design
Application Standard ingress, logic,
egress cycle.
Database
5
Saturday, March 27, 2010
6. Layered Communications
Web Server
Limitations in
Application
communication
Database
6
Saturday, March 27, 2010
7. Layered Communications
Web Server
Limitations in
communication
Application
Influences on application
design
Database
7
Saturday, March 27, 2010
8. Application Authority
Web Server
The Application becomes
Application
permissions arbiter
Database
8
Saturday, March 27, 2010
9. Application Authority
Web Server
The Application becomes
Application permissions arbiter
Loss of Portability
Database
9
Saturday, March 27, 2010
10. Application Authority
Web Server
The Application becomes
permissions arbiter
Application Loss of Portability
Increased work for other
consumers
Database
10
Saturday, March 27, 2010
12. Using DB Permissions
Why ?
It’s better than what you have now
12
Saturday, March 27, 2010
13. Using DB Permissions
Why ?
It’s better than what you have now
Easy Integration
13
Saturday, March 27, 2010
14. Using DB Permissions
Why ?
It’s better than what you have now
Easy Integration
Once it’s set up, it’s easier to use
14
Saturday, March 27, 2010
15. Basic Mechanica
Entirely DB users
Why this is hard to implement
15
Saturday, March 27, 2010
16. Basic Mechanica
Entirely DB users
Why this is hard to implement
DB users, with an external auth store
Still hard
Why it’s Worthwhile
16
Saturday, March 27, 2010
17. Basic Mechanica
Entirely DB users
Why this is hard to implement
DB users, with an external auth store
Still hard
Why it’s Worthwhile The Hybrid approach - use
The Hybrid approach DB roles + rows in the
database, instead of DB
users.
17
Saturday, March 27, 2010
19. Componentry
Postgres Implementation
SET ROLE
GRANT / NOINHERIT Grant / noinherit - How
this works together to
NOLOGIN provide VC.
19
Saturday, March 27, 2010
20. Componentry
Postgres Implementation
SET ROLE
GRANT / NOINHERIT
NOLOGIN
Great for PCI
sudo for the Database compliance
20
Saturday, March 27, 2010
21. Setup
vc=# CREATE ROLE vc NOINHERIT;
CREATE ROLE
vc=# CREATE ROLE auth_level NOLOGIN;
CREATE ROLE
vc=# GRANT auth_level TO vc;
GRANT ROLE
vc=#
21
Saturday, March 27, 2010
22. Setup
vc=# CREATE TABLE auth_only();
CREATE
vc=# REVOKE SELECT ON auth_only FROM
PUBLIC, vc;
REVOKE
vc=# SET ROLE TO vc;
SET
vc=>
22
Saturday, March 27, 2010
23. sudo for Databases
vc=> SELECT * FROM auth_only;
ERROR: permission denied for relation
auth_only
vc=> SET ROLE auth_level;
SET
vc=> SELECT * FROM auth_only;
--
(0 rows)
23
Saturday, March 27, 2010
24. It’s How We Role
Basic roles
24
Saturday, March 27, 2010
25. It’s How We Role
Basic roles
Defines your permissions tree
25
Saturday, March 27, 2010
26. It’s How We Role
Basic Roles
Defines your permissions tree
Privileged Roles
The over-arching Container roles
User, Moderator, Admin, etc.
26
Saturday, March 27, 2010
27. It’s How We Role
Basic Roles
Defines your permissions tree
Privileged Roles
The over-arching permissions definitions
User, Moderator, Admin, etc. Entry point has
LOGIN granted.
Entry Point
27
Saturday, March 27, 2010
29. A Quick Check
IF users.can(user_id, ‘type.read’) THEN
RETURN QUERY
SELECT * FROM type;
ELSE
exceptable.permission_denied(‘User
lacks type.read permissions’);*
END IF;
* Exceptable function
29
Saturday, March 27, 2010
30. Wait.. I don’t know you.
users.can
users.validate
30
Saturday, March 27, 2010
31. User Legitimacy
CREATE OR REPLACE FUNCTION users.validate
(
in_username text,
in_password text
) RETURNS int
SELECT users.validate(‘vc’,‘password’);
31
Saturday, March 27, 2010
32. The Forge of Users
users.can
users.validate
users.create
32
Saturday, March 27, 2010
33. Creating Users
CREATE OR REPLACE FUNCTION users.create (
in_username text,
in_role text,
in_password text
) RETURNS int
SELECT users.create(‘user’,‘auth’,md5
(‘password’ || ‘your_salt’));
33
Saturday, March 27, 2010
34. Basic User Get
users.can
users.validate
users.create
users.get
34
Saturday, March 27, 2010
35. Collecting Users
CREATE OR REPLACE FUNCTION users.get (
in_user_id int This is a fairly limited user
model - a real model would
) RETURNS users.user include the personal
information &c that’s
needed.
CREATE TYPE users.user AS ( It does serve as a great
example on what is really
id int, *required* for vertically
challenged to work.
username text,
role text,
groups text[] -- Used for app checks
);
35
Saturday, March 27, 2010
36. STANDING ON PYLONS
Wherein
Exceptions
Permissions checks
Repoze.Who
36
Saturday, March 27, 2010
37. Exceptions
Repoze.who cares about 401s and 403s
37
Saturday, March 27, 2010
38. Exceptions
Repoze.who cares about 401s and 403s
Trap VC errors in the Application
Emit an appropriate 401 or 403
38
Saturday, March 27, 2010
39. Exceptions
Repoze.who cares about 401s and 403s
Trap VC errors in the Application
Emit an appropriate 401 or 403
Exceptions are handled ONCE
39
Saturday, March 27, 2010
40. Once
class BaseController(WSGIController):
def __call__(self, environ, start_response):
"""Invoke the Controller"""
# WSGIController.__call__ dispatches to the
Controller method
# the request will be routed to.
try:
return WSGIController.__call__(self, environ,
start_response)
except PermissionsError, e:
abort(403)
except NoSuchUserError, e:
abort(401)
40
Saturday, March 27, 2010
41. I have @needs too!
Easily Decorate Pylons Views - @needs(‘type.read’)
41
Saturday, March 27, 2010
42. I have @needs too!
Easily Decorate Pylons Views - @needs(‘type.read’)
Using DB permissions in the App layer
42
Saturday, March 27, 2010
43. What are our Roles?
CREATE OR REPLACE FUNCTION users.get (
in_user_id int
This is why we return the
) RETURNS users.user groups our user is able to
view.
CREATE TYPE users.user AS (
id int,
username text,
role text,
groups text[] -- Used for app checks
);
43
Saturday, March 27, 2010
44. I have @needs too!
Easily Decorate Pylons Views - @needs(‘type.read’)
Using DB permissions in the App layer
A single DB query - Not a query per controller call.
44
Saturday, March 27, 2010
45. I have @needs too!
Easily Decorate Pylons Views - @needs(‘type.read’)
Using DB permissions in the App layer
A single DB query - Not a query per object.
Why? Multiple tiers are good.
45
Saturday, March 27, 2010
46. Pylons in Repose
The Application Cycle
46
Saturday, March 27, 2010
47. Pylons in Repose
The Application Cycle
A Basic Repoze Configuration
47
Saturday, March 27, 2010
48. A Basic Configuration
[plugin:form]
use =
repoze.who.plugins.form:make_redirecting_plugin
login_form_url = /account/login
login_handler_path = /account/dologin
logout_handler_path = /account/logout
rememberer_name = auth_tkt
[plugin:auth_tkt]
use = repoze.who.plugins.auth_tkt:make_plugin
secret = ticket_secret
[mdproviders]
plugins = vc.repoze:MetadataProvider;browser
48
Saturday, March 27, 2010
49. Pylons in Repose
The Application Cycle
A Basic Repoze Configuration
The Permissions Swap
49
Saturday, March 27, 2010
50. The Permissions Swap
from vc.model import user
class MetadataProvider(object):
def add_metadata(self, environ, identity):
if userid:
try:
u = user.user(userid)
u.become(u.role)
except PermissionError, e:
if “model” in identity:
del identity[“model”]
return None
identity[“model”] = u
50
Saturday, March 27, 2010
51. And the Procedure
CREATE FUNCTION users.become (
in_user_id int, in_role text
) RETURNS VOID AS $$
BEGIN
IF users.can($1, $2) THEN
SET ROLE TO quote_literal($2);
ELSE
exceptable.permission_denied(‘User
cannot become specified permission level’);
END IF;
END;
$$ LANGUAGE PLPGSQL;
51
Saturday, March 27, 2010
52. Pylons in Repose
The Application Cycle
A Basic Repoze Configuration
The Permissions Swap
Anonymous Access
52
Saturday, March 27, 2010
53. Anonymous Access
A Wrapping Identifier
Test For an Identity
53
Saturday, March 27, 2010
54. Wrap the Identifier
class AnonymousWrapper(object):
def identify(self, environ):
i = environ['repoze.who.plugins']
['auth_tkt'].identify(environ)
if i:
# Not anonymous
return i
else:
# Is anonymous
# return a really basic anonymousness.
return {"repoze.who.userid":
anonymous_user_id} # custom UID
54
Saturday, March 27, 2010
55. Anonymous Access
A Wrapping Identifier
Test For an Identity
Return a User, or Anonymous
Anonymous users are otherwise identical
55
Saturday, March 27, 2010
56. An Anonymous User
SELECT users.create(
‘anonymous’, -- anonymous user
‘anonymous’, -- Basic, read-only role
NULL); -- No password
56
Saturday, March 27, 2010
58. Advantages
Same roles in your Procedures, as your Application code
Great for consistency
Can Implement Row-level Permissions
58
Saturday, March 27, 2010
59. Row-Level Example
PERFORM id FROM table WHERE id = i_id
AND owner_id = user_id;
IF NOT FOUND THEN
-- Some Procedural code.
ELSE
exceptable.permission_denied(‘User does
not own specified record.’);
END IF;
59
Saturday, March 27, 2010
60. Disadvantages
No PG-backed row-level authorization
60
Saturday, March 27, 2010
61. Disadvantages
No PG-backed row-level authorization
DDL permissions take work to implement
61
Saturday, March 27, 2010
62. Simple, but Timeconsuming
vc=# CREATE TABLE auth_only();
CREATE
vc=# REVOKE SELECT ON auth_only FROM
PUBLIC, vc;
REVOKE
For. Every. Object.
62
Saturday, March 27, 2010
63. Disadvantages
No direct row-level authorization
DDL permissions take work to implement
No ad-hoc Users
63
Saturday, March 27, 2010
64. Disadvantages
No direct row-level authorization
DDL permissions take work to implement
No ad-hoc Users
Custom permissions require new entry points
64
Saturday, March 27, 2010
65. Vulnerabilities
Any possible PG escalation attack
SET ROLE could switch to an Admin user
User errors a perennial favourite
65
Saturday, March 27, 2010
66. AND THUS
Questions?
66
Saturday, March 27, 2010
67. GET IT
https://projects.commandprompt.com/
public/verticallychallenged
67
Saturday, March 27, 2010