/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.security;
import java.util.List;
import java.util.Set;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.InsufficientAuthenticationException;
import org.springframework.security.context.SecurityContextHolder;
import org.geoserver.ows.DispatcherCallback;
import org.geoserver.ows.Request;
import org.geoserver.ows.Response;
import org.geoserver.platform.Operation;
import org.geoserver.platform.Service;
import org.geoserver.platform.ServiceException;
import org.geoserver.security.impl.ServiceAccessRule;
import org.geoserver.security.impl.ServiceAccessRuleDAO;
/**
* This callback performs security access checks at the service/method
* level based on rules provided by the {@link ServiceAccessRuleDAO}
*/
public class OperationSecurityCallback implements DispatcherCallback {
ServiceAccessRuleDAO dao;
public OperationSecurityCallback(ServiceAccessRuleDAO dao) {
this.dao = dao;
}
public void finished(Request request) {
// nothing to do
}
public Request init(Request request) {
return request;
}
public Operation operationDispatched(Request request, Operation operation) {
String service = request.getService();
String method = request.getRequest();
// find the best matching rule. Rules are sorted by specificity so any rule matching
// last will be more specific than the ones matching earlier (e.g., wms.GetMap is moer
// specific than just wms.* which is more specific than *.*)
List<ServiceAccessRule> rules = dao.getRules();
ServiceAccessRule bestMatch = null;
for (ServiceAccessRule rule : rules) {
if(rule.getService().equals(ServiceAccessRule.ANY) || rule.getService().equalsIgnoreCase(service)) {
if(rule.getMethod().equals(ServiceAccessRule.ANY) || rule.getMethod().equalsIgnoreCase(method)) {
bestMatch = rule;
}
}
}
// if there is a matching rule apply it
if(bestMatch != null) {
Set<String> allowedRoles = bestMatch.getRoles();
// if the rule is not the kind that allows everybody in check if the current
// user is authenticated and has one of the required roles
if(!allowedRoles.contains(ServiceAccessRule.ANY) && !allowedRoles.isEmpty()) {
Authentication user = SecurityContextHolder.getContext().getAuthentication();
if (user == null || user.getAuthorities().length == 0)
throw new InsufficientAuthenticationException("Cannot access "
+ service + "." + method + " as anonymous");
boolean roleFound = false;
for (GrantedAuthority role : user.getAuthorities()) {
if(allowedRoles.contains(role.getAuthority())) {
roleFound = true;
break;
}
}
if(!roleFound) {
throw new AccessDeniedException("Cannot access "
+ service + "." + method + " with the current privileges");
}
}
}
return operation;
}
public Object operationExecuted(Request request, Operation operation, Object result) {
// nothing to do
return result;
}
public Response responseDispatched(Request request, Operation operation, Object result,
Response response) {
return response;
}
public Service serviceDispatched(Request request, Service service) throws ServiceException {
return service;
}
}