-
Notifications
You must be signed in to change notification settings - Fork 4
GSIP 74 Finer Grained Admin Security
The ability to provide limited administrative access to non administrator accounts.
Justin Deoliveira
2.2
Under Discussion, In Progress, Completed, Rejected, Deferred
The current model of administration in GeoServer is that admin users can do everything, and non-admin users can do nothing. This proposal adds the ability to have semi-administrative accounts that allow for a limited set of administrative functionality.
The current security subsystem allows for an administrator to lock down access to an entire workspace, or a subset of layers within that workspace. The level of access (access mode) is either “read” or “write”. This proposal adds a third access mode named “admin” which is meant to signify administrative access privileges.
The “admin” access mode is the highest level of access, and implies
read/write, the same way write access implies read access. Admin access
rules are specified in layers.properties
. For example:
topp.*.a=ROLE_TOPP_ADMIN,ROLE_ADMINISTRATOR
The above would grant administrative access to the topp
workspace to
any user granted the ROLE*TOPP*ADMIN
role, and to the full
administrator.
This proposal does not allow for setting admin access on anything below a workspace, for example setting admin access to a specific layer. However this could be a future improvement.
The current read and write access modes are meant to be applied to
services, and not to administrative scenarios such as access via the web
app or via the REST config api. In order to determine how security rules
should be applied GeoServer must be able to tell if a request is an
administrative one, or a “normal” service request. To do this we
introduce a thread local variable named AdminRequest
that is used to
flag the current request as an administrative one.
The class is a simple one:
/**
* Thread local that maintains the state of an administrative request.
* <p>
* Such requests are typically used to configure the server, be it via the web ui, restconfig,
* etc...
* </p>
*/
public class AdminRequest {
static ThreadLocal<Object> REQUEST = new ThreadLocal<Object>();
public static void start(Object request) {
REQUEST.set(request);
}
public static Object get() {
return REQUEST.get();
}
public static void finish() {
REQUEST.remove();
}
}
The thread local must be set by any application that provides administrative access to GeoServer. Currently this is only the web ui, and the restconfig api. Achieving this via the web admin ui is a straight forward wicket callback:
/**
* Wicket callback that sets the {@link AdminRequest} thread local.
*
*/
public class AdminRequestWicketCallback implements WicketCallback {
@Override
public void onBeginRequest() {
AdminRequest.start(this);
}
@Override
public void onEndRequest() {
AdminRequest.finish();
}
}
A similar callback for the rest api is employed, although in that case we must explicitly check for access via restconfig.
/**
* Rest callback that sets the {@link AdminRequest} thread local.
*/
public class AdminRequestCallback implements DispatcherCallback {
@Override
public void dispatched(Request request, Response response, Restlet restlet) {
if (restlet instanceof AbstractCatalogFinder) {
//restconfig request
AdminRequest.start(this);
}
}
@Override
public void finished(Request request, Response response) {
AdminRequest.finish();
}
}
In the wicket web ui components such as menu items and pages are
protected by an authorizer that allow for access control to the
component based on the current authenticated user. Most pages use the
“admin” component authorizer, meaning that the component is accessible
to a user with the role ROLE\_ADMINISTRATOR
.
A new type of ComponentAuthorizer
is added that simply checks if the
user authenticated.
/**
* Authorizer that allows access if the user has authenticated.
*/
public class AuthenticatedComponentAuthorizer implements ComponentAuthorizer {
@Override
public boolean isAccessAllowed(Class componentClass, Authentication authentication) {
return authentication != null && authentication.isAuthenticated();
}
}
For convenience an instance of the authorizer is made available as a
static constant on the ComponentAuthorizer
itself.
public interface ComponentAuthorizer extends Serializable {
...
/**
* authorizer that grants access if the user has authenticated
*/
static ComponentAuthorizer AUTHENTICATED = new AuthenticatedComponentAuthorizer();
}
With the menu items in the spring context and the pages themselves for all the data pages (workspaces, stores, etc…) are then modified to use the authenticated component authorizer. For example:
<!-- the authorizer itself -->
<bean id="authenticatedAuthorizer"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField" value="org.geoserver.web.ComponentAuthorizer.AUTHENTICATED"/>
</bean>
<!-- workspace page menu item -->
<bean id="workspaceMenuPage" class="org.geoserver.web.MenuPageInfo">
<property name="id" value="workspaces" />
<property name="titleKey" value="WorkspacePage.title" />
<property name="descriptionKey" value="WorkspacePage.description" />
<property name="componentClass"
value="org.geoserver.web.data.workspace.WorkspacePage" />
<property name="category" ref="dataCategory" />
<property name="icon" value="../../img/icons/silk/folder.png" />
<property name="order" value="10" />
<!-- user the authenticated authorizer -->
<property name="authorizer" ref="authenticatedAuthorizer"/>
</bean>
public class WorkspacePage extends GeoServerSecuredPage {
...
@Override
protected ComponentAuthorizer getPageAuthorizer() {
return ComponentAuthorizer.AUTHENTICATED;
}
}
With that a non administrative user sees a limited view of the catalog
based on the rules allowing/disallowing admin accesss in
layers.properties
.
Issue/Concern | Resolution |
---|---|
WorkspaceAccessLimits broken constructor, add an additional constructor | |
coming up with a good default for the “adminable” flag | Came up with |
default for adminable flag by checking for admin role in current | |
authentication | |
Later adding ability to set admin rights to layers/styles,etc… without | |
breaking ResourceAccessManager | |
Better gui component authorization, only show menu items if user does | |
actually have admin rights to any workspace, and disable any links to | |
add new workspaces | Added |
In terms of configuration format work is backward compatible but changes
the format of layers.properties
. However going back to an older data
directory those rules that use an admin access mode should simply be
ignored, so this should be forward compatible as well.
Andrea Aime: +1 Alessio Fabiani: +0 Ben Caradoc Davies: +1 Gabriel Roldan: Justin Deoliveira: +1 Jody Garnett: +1 Mark Leslie: Rob Atkinson: Simone Giannecchini:+0
JIRA Task Email Discussion Wiki Page