blob: c9b0c0c52e00505e5a6df8a0dfc441f4ef9f548b [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.
*
*/
/* $Id: UsecaseMenuTransformer.java 407248 2006-05-17 13:20:01Z andreas $ */
package org.apache.lenya.cms.cocoon.transformation;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.transformation.AbstractSAXTransformer;
import org.apache.lenya.ac.AccessController;
import org.apache.lenya.ac.AccessControllerResolver;
import org.apache.lenya.ac.Authorizer;
import org.apache.lenya.ac.Role;
import org.apache.lenya.cms.ac.PolicyUtil;
import org.apache.lenya.cms.ac.usecase.UsecaseAuthorizer;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.publication.PublicationUtil;
import org.apache.lenya.cms.usecase.Usecase;
import org.apache.lenya.cms.usecase.UsecaseMessage;
import org.apache.lenya.cms.usecase.UsecaseResolver;
import org.apache.lenya.util.ServletHelper;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* This transformer disables menu items (by removing the href attribute) which are not allowed with
* respect to the usecase policies.
*/
public class UsecaseMenuTransformer extends AbstractSAXTransformer implements Disposable {
/**
* <code>MENU_ELEMENT</code> The menu element
*/
public static final String MENU_ELEMENT = "menu";
/**
* The menu namespace.
*/
public static final String MENU_NAMESPACE = "http://apache.org/cocoon/lenya/menubar/1.0";
/**
* <code>ITEM_ELEMENT</code> The item element
*/
public static final String ITEM_ELEMENT = "item";
/**
* <code>USECASE_ATTRIBUTE</code> The usecase attribute
*/
public static final String USECASE_ATTRIBUTE = "usecase";
/**
* Comment for <code>HREF_ATTRIBUTE</code> The href attribute
*/
public static final String HREF_ATTRIBUTE = "href";
/**
* <code>NAMESPACE</code> The usecase namespace
*/
public static final String NAMESPACE = "http://apache.org/cocoon/lenya/usecase/1.0";
/**
* (non-Javadoc)
*
* @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
* java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localName, String raw, Attributes attr)
throws SAXException {
Attributes attributes = attr;
List messages = null;
UsecaseResolver usecaseResolver = null;
try {
usecaseResolver = (UsecaseResolver) this.manager.lookup(UsecaseResolver.ROLE);
if (this.authorizer != null && localName.equals(ITEM_ELEMENT)) {
String usecaseName = attr.getValue(NAMESPACE, USECASE_ATTRIBUTE);
// filter item if usecase not allowed
if (usecaseName != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Found usecase [" + usecaseName + "]");
}
if (!this.authorizer.authorizeUsecase(usecaseName,
this.roles,
this.publication)) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Usecase not authorized");
}
attributes = removeHrefAttribute(attr);
UsecaseMessage message = new UsecaseMessage("Access denied");
messages = Collections.singletonList(message);
}
}
if (usecaseResolver.isRegistered(this.sourceUrl, usecaseName)) {
Usecase usecase = null;
try {
usecase = usecaseResolver.resolve(this.sourceUrl, usecaseName);
usecase.setSourceURL(this.sourceUrl);
usecase.setName(usecaseName);
if (attr.getValue(HREF_ATTRIBUTE) != null) {
passRequestParameters(usecase, attr.getValue(HREF_ATTRIBUTE));
}
usecase.checkPreconditions();
if (usecase.hasErrors()) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Usecase preconditions not complied");
}
attributes = removeHrefAttribute(attr);
messages = usecase.getErrorMessages();
}
} finally {
if (usecase != null) {
usecaseResolver.release(usecase);
}
}
}
}
} catch (final Exception e) {
throw new SAXException(e);
} finally {
if (usecaseResolver != null) {
this.manager.release(usecaseResolver);
}
}
super.startElement(uri, localName, raw, attributes);
if (messages != null) {
addMessages(messages);
}
}
/**
* Removes the <code>href</code> attribute.
*
* @param attr The original attributes.
* @return An attributes object.
*/
protected Attributes removeHrefAttribute(Attributes attr) {
Attributes attributes = attr;
int hrefIndex = attributes.getIndex(HREF_ATTRIBUTE);
if (hrefIndex > -1) {
attributes = new AttributesImpl(attr);
((AttributesImpl) attributes).removeAttribute(hrefIndex);
}
return attributes;
}
protected void addMessages(List messages) throws SAXException {
for (Iterator i = messages.iterator(); i.hasNext();) {
UsecaseMessage message = (UsecaseMessage) i.next();
super.startElement(MENU_NAMESPACE, "message", "message", new AttributesImpl());
String messageString = message.getMessage();
super.characters(messageString.toCharArray(), 0, messageString.length());
if (message.hasParameters()) {
String[] parameters = message.getParameters();
for (int p = 0; p < parameters.length; p++) {
super.startElement(MENU_NAMESPACE,
"parameter",
"parameter",
new AttributesImpl());
super.characters(parameters[p].toCharArray(), 0, parameters[p].length());
super.endElement(MENU_NAMESPACE, "parameter", "parameter");
}
}
super.endElement(MENU_NAMESPACE, "message", "message");
}
}
/**
* Pass the request parameters from the <code>href</code> attribute to the usecase handler.
*
* @param usecase The usecase handler.
* @param href The value of the <code>href</code> attribute.
*/
void passRequestParameters(Usecase usecase, String href) {
int questionMarkIndex = href.indexOf("?");
if (questionMarkIndex > -1) {
String queryString = href.substring(questionMarkIndex + 1);
String[] nameValuePairs = queryString.split("&");
for (int i = 0; i < nameValuePairs.length; i++) {
String[] pair = nameValuePairs[i].split("=");
if (pair.length == 2) {
String name = pair[0];
String value = pair[1];
usecase.setParameter(name, value);
}
}
}
}
private UsecaseAuthorizer authorizer;
private ServiceSelector serviceSelector = null;
private Role[] roles;
private Publication publication;
private AccessControllerResolver acResolver;
private String sourceUrl;
/**
* @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver,
* java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
*/
public void setup(SourceResolver _resolver, Map _objectModel, String src, Parameters _parameters)
throws ProcessingException, SAXException, IOException {
super.setup(_resolver, _objectModel, src, _parameters);
getLogger().debug("Setting up transformer");
this.serviceSelector = null;
this.acResolver = null;
this.authorizer = null;
this.sourceUrl = ServletHelper.getWebappURI(this.request);
try {
this.roles = PolicyUtil.getRoles(this.request);
this.publication = PublicationUtil.getPublication(this.manager, _objectModel);
this.serviceSelector = (ServiceSelector) this.manager.lookup(AccessControllerResolver.ROLE
+ "Selector");
this.acResolver = (AccessControllerResolver) this.serviceSelector.select(AccessControllerResolver.DEFAULT_RESOLVER);
getLogger().debug("Resolved AC resolver [" + this.acResolver + "]");
String webappUrl = ServletHelper.getWebappURI(this.request);
AccessController accessController = this.acResolver.resolveAccessController(webappUrl);
Authorizer[] authorizers = accessController.getAuthorizers();
for (int i = 0; i < authorizers.length; i++) {
if (authorizers[i] instanceof UsecaseAuthorizer) {
this.authorizer = (UsecaseAuthorizer) authorizers[i];
}
}
getLogger().debug("Using authorizer [" + this.authorizer + "]");
} catch (final Exception e) {
throw new ProcessingException(e);
}
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
getLogger().debug("Disposing transformer");
if (this.serviceSelector != null) {
if (this.acResolver != null) {
this.serviceSelector.release(this.acResolver);
}
this.manager.release(this.serviceSelector);
}
}
}