Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
GNIP: GeoServer A&A Improvements #2374
This proposal aims to reuse as much as possible the GeoServer components, plugins and capabilities already in place in order to implement the A&A layer for the GeoNode resources.
This proposal aims at refactoring of the security integration between GeoServer and GeoNode reusing, where possible, available GeoServer capabilities either via the core version or via existing plugins or creating extensions that would live in the GeoServer codebase where needed. The goal is to improve the maintainability and compatibility of the integration between GeoServer and Geonode by having GeoNode rely as much as possible on standard GeoServer plugins.
The basic idea is the following one:
It is worth noting that the GeoNode command-line APIs should also be updated in order to synchronize and clean-up the permissions on GeoServer whenever some issue occurs and/or the Authorization rules are out of sync.
Assigned to release
As briefly introduced in the “Overview” the current implementation of the GeoNode/GeoServer security relies into an heavy customization of the GeoServer “Resource Access Manager”
The “geoserver-geonode-ext” (https://github.com/GeoNode/geoserver-geonode-ext) GeoNode subproject contains the current authentication and authorization implementations of the custom GeoServer modules for GeoNode. Without going into very technical details, the A&A implemented protocol currently works like below:
The two main issues with the previous approach are the following ones:
The solution proposed here aims at:
The proposal is split into two main topics: “Authentication” and “Authorization”.
Moreover, among this proposal, we intend to improve the existing GeoNode authentication mechanism, allowing it to recognize users which have been trusted by other system like Google or Facebook. In other words this proposals aims to propose the “OpenID Connect” protocol as identity recognition system between GeoNode and GeoServer instead of the cookie based in place on the current implementation.
GeoNode as OpenID Connect Provider (OP) and Relying Party (RP)
OpenID Connect is an identity framework built on OAuth 2.0 protocol which extends the authorization of OAuth 2.0 processes to implement its authentication mechanism. OpenID Connect adds a discovery mechanism allowing users to use an external trusted authority as an identity provider. From another point of view, this can be seen as a single sign on (SSO) system.
OAuth 2.0 is an authorization framework which is capable of providing a way for clients to access a resource with restricted access on behalf of the resource owner. OpenID Connect allows clients to verify the users with an authorization server based authentication.
Currently there exists several DJango extensions and apps allowing to transform a DJango based web app like GeoNode into both an OpenID Connect Consumer (or Relying Party - RP) or Provider (OP). Among the scopes of GeoNode, our interest is to allow it becoming both an OP and an RP.
As an RP, GeoNode will be able to delegate the authentication mechanism to external trusted identity providers (OPs). This would facilitate new users to create their account on GeoNode, without having to insert again their profile information on the system.
As an OP, GeoNode will be able to act as trusted identity provider, thus allowing the system working on an isolated environment and/or allow GeoNode to authenticate private users managed by the local DJango auth subsystem.
GeoServer as OpenID Connect Relying Party (RP)
GeoServer auth subsystem is based on Spring Security. The proposal is to enable GeoServer to be a OpenID Connect Relying Party (RP) through ad hoc Spring Security AuthProviders plugged into the system.
How the OpenID Connect Protocol works:
Allowing GeoServer to make use of a Spring AuthProvider in order to act as an OpenID Connect RP, is not sufficient to map a user identity to its roles though.
On GeoServer side we will still need to implement a “UserRoleService” which would be able to talk to GeoNode and transform the tokens into a User Principal to be used within the GeoServer Security subsystem itself.
We can envisage two possible instances of UserRoleServices which may be used accordingly to the GeoNode administrator needs:
Solutions 1 is more generic and would work even if there is no shared database between GeoServer and GeoNode. Solution 2 should be faster to implement (i.e. it should be only configuration work) but it requires to have a shared database between GeoServer and GeoNode. Solution 1 could be in addition to Solution 2 to support more sophisticated set-up.
On GeoNode side:
This section focuses on the process of allowing GeoServer to associate the access permissions (READ/WRITE) for a specific Resource to the requesting end user, once the authentication has been performed as described before.
The GeoServer Authorization is based on Roles only, therefore for each authenticated user we need also to know:
The Authentication mechanism above allows GeoServer to get information about the User and his Roles, which addresses point 1.
About point 2, the proposal is to make use of the GeoFence Embedded plugin on GeoServer and have GeoNode managing access policies via REST calls through the GeoFence REST Interface.
GeoFence has its own rules database for the management of Authorization rules, and overrides the standard GeoServer security management system by implementing a sophisticated Resource Access Manager.
The advantages using such plugin are multiple:
GeoFence can be run either as a standalone web application, or embedded in GeoServer. As a standalone webapp, a single GeoFence instance may handle the authorization and authentication to one or more GeoServer instances. Such GeoServer instances may be configured as a cluster or not, making no difference to GeoFence. The embedded architecture will only provide authorization services to the local GeoServer, and will use the users and roles information provided by the local GeoServer. It is possible to find more details on GeoFence installation and capabilities at the following URL:
GeoNode interaction with GeoFence
Our proposal is to allow GeoNode to push/manage Authorization rules to GeoServer through the GeoFence REST API acting as an administrator for GeoServer. GeoNode should be improved in order to be able to properly configure the GeoFence rules anytime it is needed, i.e. the permissions of a Resource are updated.
The same logic must also be implemented into the GeoNode command line tools “updatelayers” and “importlayers” in order to allow an Administrator to re-sync/fix the Layers’ permissions both on GeoNode and GeoServer side.
A command for recreating the whole GeoFence rules set should be implemented, in case it gets de-synchronized with GeoNode.
Clustering and caching
Having one or more instance of GeoNode being able to control a cluster of instances of GeoServer is possible with out approach, although there are a few minor nuances to describe and tackle.
The figure below represents the current implementation of GeoFence, in a configuration where the engine is embedded in a single GeoServer instance. Notice the Guava (in-memory) cache which we are using for avoiding too many round trips with the rule DB; moreover by default the Embedded GeoFence uses an embedded database for persisting the rules.
In an environment having multiple GeoServer instances configured as a cluster, the GeoFence databases won’t interact. This means that the calls to the REST API will update only a single instance in the cluster. Even worse, if the REST calls are balanced, the various calls can be received by the different instances, thus having the authorization rules sets completely broken in all the instances.
Shared database and pluggable Hazelcast Cache
Our proposal to address the problems above is to improve the GeoFence plugin in order to:
By following this approach any GeoServer instance in the cluster will be able to receive the REST updates from GeoNode and will update the shared DBMS. At the same time the cache will be shared among all the nodes automatically (see picture below).
Interaction with external clients and tools
The current authentication/authorization approach using cookies does not allow to use desktop clients or other external clients, unless we provide them with the administrator account for GeoServer (this is a simplification but it provides an acceptable picture of the situation) . As an instance, it is not possible to use QGis desktop with the GeoServer WMS unless the administrator creates specific users and roles into the GeoServer catalog which are then not linked to GeoNode users; alternative is to give away the GeoServer admin credentials which is of course not what we want.
The OpenID Connect approach presented in this proposal suffer from the same problem as it does not easily allow GeoServer to expose the Layers to external GIS Desktop clients and tools. The OpenID Connect authentication works well only if the client implements the protocol somehow but currently, to our knowledge, the most popular desktop applications are not able to use such mechanism to authenticate the requests.
It would be possible to work around this problem in different ways, all quite complex to implement. A possible solution is to allow the BASIC Authentication in GeoServer by duplicating all the GeoNode users and bridging the OpenID Connect protocol with a custom Spring AuthProvider; but, as one can imagine, this is not an optimal solution due to the intrinsic duplication.
A more sound proposal is to allow throw in the mix the GeoServer “authKey” authentication mechanism as explained here below. This would work in parallel with respect to the OpenID proposal described above. It is worth to point out that this whole proposal can be skipped if we don’t want to tackle the desktop client problem for the time being.
GeoNode/GeoServer Access Token Authentication
Where access_token=ef18d7e7-963b-470f-9230-c7f9de166888 is associated to a specific user.
Every time a user successfully access GeoNode, an “ACCESS_TOKEN” is generated and associated to him by GeoNode itself through a specific service to be created. This key will uniquely identify the user’s session and GeoNode will take care of its validity.
Whenever GeoServer will receive a request with an “ACCESS_TOKEN” attached, it will validate the token through the OAuth2 Protocol and Plugin.
The OAuth2 Plugin will rely on a “UserGroupService” (which can be based either on JDBC or HTTP-REST as there can be more than implementation accordingly to the system needs) in order to validate the “ACCESS_TOKEN-USER” couple and get back the user’s roles.
GeoNode should be enhanced to generate and manage expiring access tokens associated to the logged in users and to expose a protected REST service (hereby called Authentication) which allows to retrieve a user and role for a valid access token.
The proposed approach allows to use the same credentials everywhere. Once the user obtained an authkey from GeoNode, it can be used as WMS query parameter on every client without taking care of cookies or other session headers.
It is worth noting that the access tokens have a limited life and must be renewed whenever the session expires. It is the responsibility of GeoNode to check the session duration and validity.
On future improvements we could also envisage permalinks or the possibility for the Administrator of GeoNode to assign static tokens which are unique and always valid (unless manually deleted) in order to avoid changing the client configuration every time a new access tokens is generated via GeoNode login procedure.
The components which must be developed and/or improved for this proposal are summarized on the following spreadsheet: