[GIS] Create custom Authentication filter in GeoServer 2.3.0

filtergeoserverSecurity

Context

In my current project, I've the requirement to validate that requests coming to GeoServer (2.3.0) are allowed.

The project holds those facts:

  • the GS client cannot provide the principal information (the password
    for instance), GS itself has no connection with a user/role repo

So we took the opportunity to use the auth filter mechanism in order to check that:

  • a valid request (to a specific WFS' layer) contains a special HTTP Header (let's say X-CUSTOM-VALID)
  • This header is a JSON encoded message holding enough information to validate the fact that the request was initiated by a client that was connected to a valid third system (a username, a secret, stuffs like that)

Status

The documentation is telling us that we should be able to do so…

However, the documentation is not clear how to create such components and how they should be configured.

Debugging GeoServer I managed to find that to configure such a filter, it requires a dedicated Authentication Provider. That, in order to have a panel in the web admin interface (under authentications, in the Authentication Filters list)

Panel

Thus my code is composed of those files:

  • ProducteurAuthFilterPanel.java
  • ProducteurAuthFilterPanelInfo.java
  • ProducteurAuthenticationFilterConfig.java
  • ProducteurAuthenticationFilterPanel.html

These are require to add a panel in the Web Admin Interface. ProducteurAuthFilterPanelInfo is glueing the two other along with the ProducteurAuthenticationFilter here-after (THE filter ^^).

The ProducteurAuthenticationFilterConfig declares that in its constructor:

setClassName(ProducteurAnonymousAuthenticationProvider.class.getName());
setName("producteur");

Filter (and Provider)

Now, the classes needed to create a filter to be included in a chain (I guess):

  • ProducteurAuthenticationFilter : the filter implementation extending GeoServerSecurityFilter and implementing GeoServerAuthenticationFilter
  • ProducteurAnonymousAuthenticationProvider: somehow required by the Panel (above) to define the new filter
  • ProducteurAuthenticationException: used in the AuthenticationEntryPoint (only Http403ForbiddenEntryPoint for now)

Finally, the beans are defined like so:

<bean id="yaanonymousFilterProvider" class="dgarne.java.geoserver.security.ProducteurAnonymousAuthenticationProvider"/>

<bean id="producteurAuthPanelInfo" class="dgarne.java.geoserver.security.ProducteurAuthFilterPanelInfo">
    <property name="id" value="security.producteurAuthFilter" />
    <property name="shortTitleKey" value="ProducteurAuthFilterPanel.short"/>
    <property name="titleKey" value="ProducteurAuthFilterPanel.title"/>
    <property name="descriptionKey" value="ProducteurAuthFilterPanel.description"/>
</bean>

At the end of the game, in the Web Admin Interface I've a new Item in the filter panel, and I used it in the default mapping (see image below for references):
enter image description here

Problem description

Here we are…

None of my WFS request issued by a client (OpenLayers) which are matching the default mapping (/**) is going through the defined Filter.
While debugging I found that the filter chains defined in the Spring Context are never including my definition, but rather are always including the classical one using either anonymous, digest or basic…

Question

So is there anyone able to point me out with a (much ^^) more complete documentation about how I have to do it?

Best Answer

I do it by implementing a Proxy like this that could verify a users credentials as logged in using session variables and only allow them to access resources they are entitled to, ie: check the url for the layers that are being called and deny access if user is not authorized to view them.

If you want to restrict the users to a particular area or feature set, there are two approaches ..

  1. Use Parameterized SQL Views to control what data the user would see. You could use the Proxy to change the url before it is passed to Geoserver with the parameters specific to that user. You could also send the parameters back to Openlayers via an Ajax Call after the user is authenticated and supply the parameters as part of the WMS getMAP call in OpenLayers. The actual data displayed could be handled by Variable substitution in SLD to filter data displayed or by using External Styles in your WMS getMap calls to change the SLD a user uses to display a given layer.

  2. Use an Ajax Call after User Authentication to specify Map Extents to only allow the user to mover around a specified area. You could also use layerVisibility() to restrict what data could be displayed as well.