/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.impl;
import static org.geoserver.security.impl.DataAccessRule.*;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.security.core.Authentication;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.security.AccessMode;
import org.geoserver.security.CatalogMode;
import org.geoserver.security.DataAccessManager;
import org.geotools.util.logging.Logging;
/**
* Default implementation of {@link DataAccessManager}, loads simple access
* rules from a properties file or a Properties object. The format of each
* property is:<br>
* <code>workspace.layer.mode=[role]*</code><br>
* where:
* <ul>
* <li> workspace: either a workspace name or a * to indicate any workspace (in
* this case, the layer must also be *) </li>
* <li> layer: either a layer name (feature type, coverage, layer group) or * to
* indicate any layer </li>
* <li> mode: the access mode, at the time or writing, either "r"
* (read) or "w" (write) </li>
* <li> role: a user role</li>
* </ul>
* A special line is used to specify the security mode in which GeoServer operates:
* <code>mode=HIDE|CHALLENGE|MIDEX</code>
* For the meaning of these three constants see {@link CatalogMode}<p>
* For more details on how the security rules are applied, see the <a
* href="http://geoserver.org/display/GEOS/GSIP+19+-+Per+layer+security"/>per
* layer security proposal</a> on the <a
* href="www.geoserver.org">GeoServer</a> web site.
* <p>
* If no {@link Properties} is provided, one will be looked upon in
* <code>GEOSERVER_DATA_DIR/security/layers.properties, and the class will
* keep up to date vs changes in the file</code>
*
* @author Andrea Aime - TOPP
*/
public class DefaultDataAccessManager implements DataAccessManager {
static final Logger LOGGER = Logging.getLogger(DataAccessManager.class);
SecureTreeNode root;
// Catalog catalog;
DataAccessRuleDAO dao;
long lastLoaded = Long.MIN_VALUE;
public DefaultDataAccessManager(DataAccessRuleDAO dao) {
this.dao = dao;
this.root = buildAuthorizationTree(dao);
}
public CatalogMode getMode() {
return dao.getMode();
}
public boolean canAccess(Authentication user, WorkspaceInfo workspace, AccessMode mode) {
checkPropertyFile();
SecureTreeNode node = root.getDeepestNode(new String[] { workspace.getName() });
return node.canAccess(user, mode);
}
public boolean canAccess(Authentication user, LayerInfo layer, AccessMode mode) {
checkPropertyFile();
if (layer.getResource() == null) {
LOGGER.log(Level.FINE, "Layer " + layer + " has no attached resource, "
+ "assuming it's possible to access it");
// it's a layer whose resource we don't know about
return true;
} else {
return canAccess(user, layer.getResource(), mode);
}
}
public boolean canAccess(Authentication user, ResourceInfo resource, AccessMode mode) {
checkPropertyFile();
String workspace;
try {
workspace = resource.getStore().getWorkspace().getName();
} catch (Exception e) {
LOGGER.log(Level.FINE, "Errors occurred trying to gather workspace of resource "
+ resource.getName());
// it's a layer whose resource we don't know about
return true;
}
SecureTreeNode node = root.getDeepestNode(new String[] { workspace, resource.getName() });
return node.canAccess(user, mode);
}
void checkPropertyFile() {
long daoLastModified = dao.getLastModified();
if(lastLoaded < daoLastModified) {
root = buildAuthorizationTree(dao);
lastLoaded = daoLastModified;
}
}
SecureTreeNode buildAuthorizationTree(DataAccessRuleDAO dao) {
SecureTreeNode root = new SecureTreeNode();
for(DataAccessRule rule : dao.getRules()) {
String workspace = rule.getWorkspace();
String layer = rule.getLayer();
AccessMode accessMode = rule.getAccessMode();
// look for the node where the rules will have to be set
SecureTreeNode node;
// check for the * ws definition
if (ANY.equals(workspace)) {
node = root;
} else {
// get or create the workspace
SecureTreeNode ws = root.getChild(workspace);
if (ws == null) {
ws = root.addChild(workspace);
}
// if layer is "*" the rule applies to the ws, otherwise
// get/create the layer
if ("*".equals(layer)) {
node = ws;
} else {
SecureTreeNode layerNode = ws.getChild(layer);
if (layerNode == null)
layerNode = ws.addChild(layer);
node = layerNode;
}
}
// actually set the rule, but don't complain for the default root contents
if (node.getAuthorizedRoles(accessMode) != null && node.getAuthorizedRoles(accessMode).size() > 0 && node != root) {
LOGGER.warning("Rule " + rule
+ " is overriding another rule targetting the same resource");
}
node.setAuthorizedRoles(accessMode, rule.getRoles());
}
return root;
}
}