blob: d4267c47fa533d3b5b6677f57d8ad51e8937af1b [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: AccessControlSitetreeTransformer.java 153561 2005-02-12 21:49:18Z gregor $ */
package org.apache.lenya.cms.cocoon.transformation;
import java.io.IOException;
import java.util.Map;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.transformation.AbstractSAXTransformer;
import org.apache.lenya.ac.AccessControlException;
import org.apache.lenya.ac.AccessController;
import org.apache.lenya.ac.AccessControllerResolver;
import org.apache.lenya.ac.AccreditableManager;
import org.apache.lenya.ac.Identity;
import org.apache.lenya.ac.PolicyManager;
import org.apache.lenya.ac.Role;
import org.apache.lenya.cms.site.tree.DefaultSiteTree;
import org.apache.lenya.cms.site.tree.SiteTreeNodeImpl;
import org.apache.lenya.util.ServletHelper;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* This transformer is applied to the sitetree. It marks the site element and all node elements the
* current identity is not allowed to access with a <code>protected="true"</code> attribute.
*/
public class AccessControlSitetreeTransformer extends AbstractSAXTransformer implements Disposable {
/**
* <code>ATTRIBUTE_PROTECTED</code> The attribute for protected
*/
public static final String ATTRIBUTE_PROTECTED = "protected";
/**
* <code>PARAMETER_PUBLICATION_ID</code> The publication id parameter
*/
public static final String PARAMETER_PUBLICATION_ID = "publication-id";
/**
* <code>PARAMETER_AREA</code> The area parameter
*/
public static final String PARAMETER_AREA = "area";
private String documentId;
private ServiceSelector serviceSelector;
private PolicyManager policyManager;
private AccessControllerResolver acResolver;
private AccreditableManager accreditableManager;
private Identity identity;
private String urlPrefix;
/**
* @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 par)
throws ProcessingException, SAXException, IOException {
super.setup(_resolver, _objectModel, src, par);
this.serviceSelector = null;
this.acResolver = null;
this.policyManager = null;
this.identity = Identity.getIdentity(this.request.getSession(false));
try {
String publicationId = par.getParameter(PARAMETER_PUBLICATION_ID);
String area = par.getParameter(PARAMETER_AREA);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Setting up transformer");
getLogger().debug(" Identity: [" + this.identity + "]");
getLogger().debug(" Publication ID: [" + publicationId + "]");
getLogger().debug(" Area: [" + area + "]");
}
this.urlPrefix = "/" + publicationId + "/" + area;
Request _request = ObjectModelHelper.getRequest(_objectModel);
this.serviceSelector = (ServiceSelector) this.manager.lookup(AccessControllerResolver.ROLE
+ "Selector");
this.acResolver = (AccessControllerResolver) this.serviceSelector.select(AccessControllerResolver.DEFAULT_RESOLVER);
if (getLogger().isDebugEnabled()) {
getLogger().debug(" Resolved AC resolver [" + this.acResolver + "]");
}
String webappUrl = ServletHelper.getWebappURI(_request);
AccessController accessController = this.acResolver.resolveAccessController(webappUrl);
this.accreditableManager = accessController.getAccreditableManager();
this.policyManager = accessController.getPolicyManager();
if (getLogger().isDebugEnabled()) {
getLogger().debug(" Using policy manager [" + this.policyManager + "]");
}
} catch (final ParameterException e) {
throw new ProcessingException(e);
} catch (final ServiceException e) {
throw new ProcessingException(e);
} catch (final AccessControlException e) {
throw new ProcessingException(e);
}
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Disposing transformer");
}
if (this.serviceSelector != null) {
if (this.acResolver != null) {
this.serviceSelector.release(this.acResolver);
}
this.manager.release(this.serviceSelector);
}
}
/**
* @see org.xml.sax.ContentHandler#startDocument()
*/
public void startDocument() throws SAXException {
super.startDocument();
this.documentId = "";
}
/**
* (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;
if (isFragmentNode(uri, localName)) {
String area = attr.getValue("area"); // FIXME: don't hardcode
String base = attr.getValue("base");
if (area != null && base != null) {
this.documentId = "/" + area + base;
}
}
if (isNode(uri, localName)) {
String id = attr.getValue(SiteTreeNodeImpl.ID_ATTRIBUTE_NAME);
if (id != null) {
this.documentId += "/" + id;
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Checking node");
getLogger().debug(" Document ID: [" + this.documentId + "]");
getLogger().debug(" URL: [" + this.urlPrefix + this.documentId + "]");
}
try {
String url = this.urlPrefix + this.documentId;
Role[] roles = this.policyManager.getGrantedRoles(this.accreditableManager, this.identity, url);
getLogger().debug(" Roles: [" + roles.length + "]");
if (roles.length == 0) {
getLogger().debug(" Adding attribute [protected='true']");
AttributesImpl attributesImpl = new AttributesImpl(attributes);
attributesImpl.addAttribute("",
ATTRIBUTE_PROTECTED,
ATTRIBUTE_PROTECTED,
"",
Boolean.toString(true));
attributes = attributesImpl;
}
} catch (AccessControlException e) {
throw new SAXException(e);
}
}
super.startElement(uri, localName, raw, attributes);
}
/**
* @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
* java.lang.String)
*/
public void endElement(String uri, String localName, String raw) throws SAXException {
super.endElement(uri, localName, raw);
if (isNode(uri, localName) && this.documentId.length() > 0) {
this.documentId = this.documentId.substring(0, this.documentId.lastIndexOf("/"));
}
}
/**
* Returns if an element represents a sitetree node.
* @param uri The namespace URI.
* @param localName The local name.
* @return A boolean value.
*/
protected boolean isNode(String uri, String localName) {
return uri.equals(DefaultSiteTree.NAMESPACE_URI)
&& (localName.equals(SiteTreeNodeImpl.NODE_NAME) || localName.equals("site"));
}
/**
* Returns if an element represents a fragment node.
* @param uri The namespace URI.
* @param localName The local name.
* @return A boolean value.
*/
protected boolean isFragmentNode(String uri, String localName) {
return uri.equals(DefaultSiteTree.NAMESPACE_URI) && (localName.equals("fragment"));
}
}