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
