Hi,

I wanted to give a heads up about the large group of security related
changes that are slated to come into the trunk in the near future.  This
work impacts both geoserver and django and integrates work by aaime, groldan
and myself.

The current state of these currently lives on this branch:

http://github.com/ltucker/geonode/tree/security

I strongly encourage anyone with an inclination to have a look, test it,
holler about anything that looks funny or there is any other objection.
 This is especially true for anyone who has recently created new views or
heavily modified a view.  I have tried to keep up with adding security to
views, but please double check if you can.

Note: You will almost certainly need to rebuild your database and run a
build after pulling these changes -- also note that in a clean installation
it is necessary to create a django administrator between building and
running host for the first time.

10k ft. view
============

* Geoserver authentication / authorization defers to django model
* Per object permissions on layers and maps
* Views check fine grained permissions

1k ft. view
===========

User interface
--------------

Providing you are are a user with rights to manage a layer or map, you will
see a link to 'Edit Permissions' in the 'Manage' section of the sidebar on
the detail page for the map or layer. From here you can assign levels of
access to anonymous users, all registered users or to specific users. This
interface is currently rudimentary currently -- additional work will follow
after these changes have been merged.  Permissions are the union of
permissions from any category an accessing user belongs to -- you cannot
subtract permissions from a specific user.

When layers or maps are created, they are assigned default permissions.
 Administrative rights are granted to the creator. For maps, anyone can
read, registered users can read and modify.  For layers, the data is
read-only for everyone.

Checking Permission in views
----------------------------

Checking permissions uses the standard django api for object permissions,
for example:

request.user.has_perm('maps.change_layer', obj=some_layer)

The current permissions available for maps are:
maps.view_map
maps.change_map
maps.delete_map
maps.change_map_permissions

The current permissions available for layers are:
maps.view_layer
maps.change_layer
maps.delete_layer
maps.change_layer_permissions

(here the prefix 'maps' refers to the django app label that they belong to)

Please make appropriate checks for fine grained permissions in new views.

Permission checking in templates
--------------------------------

Since django templates make it exceedingly annoying for both developers and
designers to do anything that requires arguments to a function, this is a
bit ugly. I included a template tag to ease this slightly -- the following
pattern is the best I've come up with:

{% load geonode_auth %}

...

{% has_obj_perm user layer "maps.delete_layer" as can_delete %}
...
{% if can_delete %}
<a href="...">{% trans "Delete Layer" %}</a></li>
{% endif %}

You could also place relevant permission values into the template context if
you know what you need.


How is geoserver affected ?
---------------------------

To obtain permission information, geoserver consults a special django view
/data/acls that returns a json structure describing the requesting user's
permissions.

Geoserver is able to authenticate with django based on:

* credentials the user obtained by logging into django (django session
cookie)
* credentials provided as HTTP basic auth which correspond to the
username/password of a django user
* credentials provided as HTTP basic auth which correspond to the
GEOSERVER_CREDENTIALS django setting (see below)

Other changes of note
=====================

The development web server changes to paster
--------------------------------------------

This was changed in order to support multiple concurrent requests -- such as
a geoserver authentication request stemming from a django request to
geoserver.  This change should be transparent when running paver host.  If
you are running django and jetty separately, you can use the following
instead of django-admin runserver:

paster serve --reload shared/dev-paste.ini


Special wacky geoserver_token file
----------------------------------

The GEOSERVER_CREDENTIALS django setting now references a special file
called 'geoserver_token'.  The first line of this file is used as a special
administrative password for use by django when administratively accessing
geoserver.  A random string is placed in this file during a build to avoid
having a well known default.  The credentials to not correspond to a geonode
login, but can be used to access geoserver as a superuser.  so, like
settings.py, it's best to make sure access to this file is limited.

This was chosen as an alternative to requiring the user to keep settings.py
synchronized with the username/password of a django administrative user
(since all geoserver auth otherwise derives from django auth).

You can generate a new token by removing the geoserver_token file and
running:

paver generate_geoserver_token

Per-object permissions design
-----------------------------

Django does not currently provide an auth backend that supports per object
permissions (although it does provide an api for querying them)  As such,
these changes include a custom auth backend and models that represent
per-object or "row-level" permissions. These are housed in the geonode.core
app models.py, auth.py and admin.py.  The auth backend is rigged into
settings.py via the AUTHENTICATION_BACKENDS setting.


There are 3 model classes of note:

* ObjectRole - a named bundle of django.contrib.auth.models.Permission
objects
* UserObjectRoleMapping: an assignment of an ObjectRole to a User in the
context of an object.
* GenericObjectRoleMapping: this represents assigning a role to an implicit
collection of users like 'all registered users' or 'all users'

Users are assigned permissions on an object by being assigned a "role" which
points to a set of particular django.contrib.auth.model.Permission objects.

The current geonode logical security model for Maps and Layers allows
exactly one role to be assigned to a particular user for a particular object
-- representing a security "level" such as 'read-only' 'read-write' and
'administrative'.  These levels are explicitly represented by ObjectRole
objects populated in the initial_data fixture.

Phew
=====

Okay, well please feel free to ask followup questions or point out anything
that I've missed.


Enjoy,

- Luke

Reply via email to