blob: 6b080143d3b8b2e7d60a869f5fc83b29ca5d4f7c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.apache.lenya.ac.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.*;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.lenya.ac.AccessControlException;
import org.apache.lenya.ac.AccessController;
import org.apache.lenya.ac.Accreditable;
import org.apache.lenya.ac.AccreditableManager;
import org.apache.lenya.ac.AccreditableManagerFactory;
import org.apache.lenya.ac.Authenticator;
import org.apache.lenya.ac.Authorizer;
import org.apache.lenya.ac.IPRange;
import org.apache.lenya.ac.Identity;
import org.apache.lenya.ac.Item;
import org.apache.lenya.ac.ItemManagerListener;
import org.apache.lenya.ac.Machine;
import org.apache.lenya.ac.PolicyManager;
import org.apache.lenya.ac.Role;
import org.apache.lenya.util.ServletHelper;
/**
* Default access controller implementation.
* @version $Id: DefaultAccessController.java 563459 2007-08-07 12:00:20Z
* nettings $
*/
public class DefaultAccessController extends AbstractLogEnabled implements AccessController,
Configurable, Serviceable, Disposable, ItemManagerListener {
protected static final String AUTHORIZER_ELEMENT = "authorizer";
protected static final String TYPE_ATTRIBUTE = "type";
protected static final String ACCREDITABLE_MANAGER_ELEMENT = "accreditable-manager";
protected static final String POLICY_MANAGER_ELEMENT = "policy-manager";
private static final String VALID_IP = "([0-9]{1,3}\\.){3}[0-9]{1,3}";
private ServiceManager manager;
private ServiceSelector authorizerSelector;
private ServiceSelector policyManagerSelector;
private AccreditableManager accreditableManager;
private PolicyManager policyManager;
private Map authorizers = new HashMap();
private List authorizerKeys = new ArrayList();
private Authenticator authenticator;
/**
* @see org.apache.lenya.ac.AccessController#authenticate(org.apache.cocoon.environment.Request)
*/
public boolean authenticate(Request request) throws AccessControlException {
assert request != null;
boolean authenticated = getAuthenticator().authenticate(getAccreditableManager(), request);
return authenticated;
}
/**
* @see org.apache.lenya.ac.AccessController#authorize(org.apache.cocoon.environment.Request)
*/
public boolean authorize(Request request) throws AccessControlException {
assert request != null;
boolean authorized = false;
getLogger().debug("=========================================================");
getLogger().debug("Beginning authorization.");
resolveRoles(request);
if (hasAuthorizers()) {
Authorizer[] _authorizers = getAuthorizers();
int i = 0;
authorized = true;
while ((i < _authorizers.length) && authorized) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("---------------------------------------------------------");
getLogger().debug("Invoking authorizer [" + _authorizers[i] + "]");
}
authorized = authorized && _authorizers[i].authorize(request);
if (getLogger().isDebugEnabled()) {
getLogger().debug(
"Authorizer [" + _authorizers[i] + "] returned [" + authorized + "]");
}
i++;
}
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("=========================================================");
getLogger().debug("Authorization complete, result: [" + authorized + "]");
getLogger().debug("=========================================================");
}
return authorized;
}
protected void resolveRoles(Request request) throws AccessControlException {
String webappUrl = ServletHelper.getWebappURI(request);
Session session = request.getSession(true);
Identity identity = (Identity) session.getAttribute(Identity.class.getName());
Role[] roles;
if (identity.belongsTo(this.accreditableManager)) {
roles = this.policyManager.getGrantedRoles(this.accreditableManager, identity, webappUrl);
} else {
roles = new Role[0];
getLogger().debug(
"No roles resolved for identity [" + identity
+ "] - belongs to wrong accreditable manager.");
}
saveRoles(request, roles);
}
/**
* Saves the roles of the current identity to the request.
* @param request The request.
* @param roles The roles.
*/
protected void saveRoles(Request request, Role[] roles) {
if(getLogger().isDebugEnabled()) {
StringBuffer rolesBuffer = new StringBuffer();
for (int i = 0; i < roles.length; i++) {
rolesBuffer.append(" ").append(roles[i]);
}
getLogger().debug("Adding roles [" + rolesBuffer + " ] to request [" + request + "]");
}
request.setAttribute(Role.class.getName(), Arrays.asList(roles));
}
/**
* Configures or parameterizes a component, depending on the implementation
* as Configurable or Parameterizable.
* @param component The component.
* @param configuration The configuration to use.
* @throws ConfigurationException when an error occurs during configuration.
* @throws ParameterException when an error occurs during parameterization.
*/
public static void configureOrParameterize(Component component, Configuration configuration)
throws ConfigurationException, ParameterException {
if (component instanceof Configurable) {
((Configurable) component).configure(configuration);
}
if (component instanceof Parameterizable) {
Parameters parameters = Parameters.fromConfiguration(configuration);
((Parameterizable) component).parameterize(parameters);
}
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(Configuration conf) throws ConfigurationException {
try {
setupAccreditableManager(conf);
setupAuthorizers(conf);
setupPolicyManager(conf);
setupAuthenticator();
} catch (ConfigurationException e) {
throw e;
} catch (Exception e) {
throw new ConfigurationException("Configuration failed: ", e);
}
}
/**
* Creates the accreditable manager.
*
* @param configuration The access controller configuration.
* @throws ConfigurationException when the configuration failed.
* @throws ServiceException when something went wrong.
* @throws ParameterException when something went wrong.
*/
protected void setupAccreditableManager(Configuration configuration)
throws ConfigurationException, ServiceException, ParameterException {
Configuration config = configuration.getChild(ACCREDITABLE_MANAGER_ELEMENT, false);
if (config != null) {
AccreditableManagerFactory factory = null;
try {
factory = (AccreditableManagerFactory) this.manager
.lookup(AccreditableManagerFactory.ROLE);
this.accreditableManager = factory.getAccreditableManager(config);
this.accreditableManager.addItemManagerListener(this);
} finally {
if (factory != null) {
this.manager.release(factory);
}
}
}
}
/**
* Creates the authorizers.
*
* @param configuration The access controller configuration.
* @throws ConfigurationException when the configuration failed.
* @throws ServiceException when something went wrong.
* @throws ParameterException when something went wrong.
*/
protected void setupAuthorizers(Configuration configuration) throws ServiceException,
ConfigurationException, ParameterException {
Configuration[] authorizerConfigurations = configuration.getChildren(AUTHORIZER_ELEMENT);
if (authorizerConfigurations.length > 0) {
this.authorizerSelector = (ServiceSelector) this.manager.lookup(Authorizer.ROLE
+ "Selector");
for (int i = 0; i < authorizerConfigurations.length; i++) {
String type = authorizerConfigurations[i].getAttribute(TYPE_ATTRIBUTE);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Adding authorizer [" + type + "]");
}
Authorizer authorizer = (Authorizer) this.authorizerSelector.select(type);
this.authorizerKeys.add(type);
this.authorizers.put(type, authorizer);
configureOrParameterize(authorizer, authorizerConfigurations[i]);
}
}
}
/**
* Creates the policy manager.
*
* @param configuration The access controller configuration.
* @throws ConfigurationException when the configuration failed.
* @throws ServiceException when something went wrong.
* @throws ParameterException when something went wrong.
*/
protected void setupPolicyManager(Configuration configuration) throws ServiceException,
ConfigurationException, ParameterException {
Configuration policyManagerConfiguration = configuration.getChild(POLICY_MANAGER_ELEMENT,
false);
if (policyManagerConfiguration != null) {
String policyManagerType = policyManagerConfiguration.getAttribute(TYPE_ATTRIBUTE);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Adding policy manager type: [" + policyManagerType + "]");
}
this.policyManagerSelector = (ServiceSelector) this.manager.lookup(PolicyManager.ROLE
+ "Selector");
this.policyManager = (PolicyManager) this.policyManagerSelector
.select(policyManagerType);
configureOrParameterize(this.policyManager, policyManagerConfiguration);
}
}
/**
* Sets up the authenticator.
* @throws ServiceException when something went wrong.
*/
protected void setupAuthenticator() throws ServiceException {
this.authenticator = (Authenticator) this.manager.lookup(Authenticator.ROLE);
}
/**
* Set the global component manager.
*
* @param _manager The global component manager
* @throws ServiceException when something went wrong.
*/
public void service(ServiceManager _manager) throws ServiceException {
this.manager = _manager;
}
/**
* Returns the service manager.
* @return A service manager.
*/
protected ServiceManager getManager() {
return this.manager;
}
/**
* Returns the authorizers of this action.
* @return An array of authorizers.
*/
public Authorizer[] getAuthorizers() {
Authorizer[] authorizerArray = new Authorizer[this.authorizers.size()];
for (int i = 0; i < this.authorizers.size(); i++) {
String key = (String) this.authorizerKeys.get(i);
authorizerArray[i] = (Authorizer) this.authorizers.get(key);
}
return authorizerArray;
}
/**
* Returns if this action has authorizers.
* @return A boolean value.
*/
protected boolean hasAuthorizers() {
return !this.authorizers.isEmpty();
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
if (this.accreditableManager != null) {
this.accreditableManager.removeItemManagerListener(this);
}
if (this.policyManagerSelector != null) {
if (this.policyManager != null) {
this.policyManagerSelector.release(this.policyManager);
}
getManager().release(this.policyManagerSelector);
}
if (this.authorizerSelector != null) {
Authorizer[] _authorizers = getAuthorizers();
for (int i = 0; i < _authorizers.length; i++) {
this.authorizerSelector.release(_authorizers[i]);
}
getManager().release(this.authorizerSelector);
}
if (this.authenticator != null) {
getManager().release(this.authenticator);
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Disposing [" + this + "]");
}
}
/**
* Returns the accreditable manager.
* @return An accreditable manager.
*/
public AccreditableManager getAccreditableManager() {
return this.accreditableManager;
}
/**
* Returns the policy manager.
* @return A policy manager.
*/
public PolicyManager getPolicyManager() {
return this.policyManager;
}
/**
* Returns the authenticator.
* @return The authenticator.
*/
public Authenticator getAuthenticator() {
return this.authenticator;
}
/**
* Checks if this identity was initialized by this access controller.
*
* @param identity An identity.
* @return A boolean value.
* @throws AccessControlException when something went wrong.
*/
public boolean ownsIdenity(Identity identity) throws AccessControlException {
return identity.belongsTo(getAccreditableManager());
}
/**
* @see org.apache.lenya.ac.AccessController#setupIdentity(org.apache.cocoon.environment.Request)
*/
public void setupIdentity(Request request) throws AccessControlException {
Session session = request.getSession(true);
if (!hasValidIdentity(session)) {
Identity identity = new Identity(getLogger());
identity.initialize();
String remoteAddress = request.getRemoteAddr();
String clientAddress = request.getHeader("x-forwarded-for");
if (clientAddress != null) {
Pattern p = Pattern.compile(VALID_IP);
Matcher m = p.matcher(clientAddress);
if (m.find()) {
remoteAddress = m.group();
}
}
getLogger().info("Remote Address to use: [" + remoteAddress + "]");
Machine machine = new Machine(remoteAddress);
IPRange[] ranges = this.accreditableManager.getIPRangeManager().getIPRanges();
for (int i = 0; i < ranges.length; i++) {
if (ranges[i].contains(machine)) {
machine.addIPRange(ranges[i]);
}
}
identity.addIdentifiable(machine);
session.setAttribute(Identity.class.getName(), identity);
}
}
/**
* Checks if the session contains an identity that is not null and belongs
* to the used access controller.
*
* @param session The current session.
* @return A boolean value.
* @throws AccessControlException when something went wrong.
*/
protected boolean hasValidIdentity(Session session) throws AccessControlException {
boolean valid = true;
Identity identity = (Identity) session.getAttribute(Identity.class.getName());
if (identity == null || !ownsIdenity(identity)) {
valid = false;
}
return valid;
}
/**
* @see org.apache.lenya.ac.ItemManagerListener#itemAdded(org.apache.lenya.ac.Item)
*/
public void itemAdded(Item item) throws AccessControlException {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Item was added: [" + item + "]");
getLogger().debug("Notifying policy manager");
}
if (item instanceof Accreditable) {
getPolicyManager().accreditableAdded(getAccreditableManager(), (Accreditable) item);
}
}
/**
* @see org.apache.lenya.ac.ItemManagerListener#itemRemoved(org.apache.lenya.ac.Item)
*/
public void itemRemoved(Item item) throws AccessControlException {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Item was removed: [" + item + "]");
getLogger().debug("Notifying policy manager");
}
if (!(item instanceof Role)) {
getPolicyManager().accreditableRemoved(getAccreditableManager(), (Accreditable) item);
}
}
}