001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: /* $Id: AccessControlSitetreeTransformer.java 153561 2005-02-12 21:49:18Z gregor $ */
020:
021: package org.apache.lenya.cms.cocoon.transformation;
022:
023: import java.io.IOException;
024: import java.util.Map;
025:
026: import org.apache.avalon.framework.activity.Disposable;
027: import org.apache.avalon.framework.parameters.ParameterException;
028: import org.apache.avalon.framework.parameters.Parameters;
029: import org.apache.avalon.framework.service.ServiceException;
030: import org.apache.avalon.framework.service.ServiceSelector;
031: import org.apache.cocoon.ProcessingException;
032: import org.apache.cocoon.environment.ObjectModelHelper;
033: import org.apache.cocoon.environment.Request;
034: import org.apache.cocoon.environment.SourceResolver;
035: import org.apache.cocoon.transformation.AbstractSAXTransformer;
036: import org.apache.lenya.ac.AccessControlException;
037: import org.apache.lenya.ac.AccessController;
038: import org.apache.lenya.ac.AccessControllerResolver;
039: import org.apache.lenya.ac.AccreditableManager;
040: import org.apache.lenya.ac.Identity;
041: import org.apache.lenya.ac.PolicyManager;
042: import org.apache.lenya.ac.Role;
043: import org.apache.lenya.cms.site.tree.DefaultSiteTree;
044: import org.apache.lenya.cms.site.tree.SiteTreeNodeImpl;
045: import org.apache.lenya.util.ServletHelper;
046: import org.xml.sax.Attributes;
047: import org.xml.sax.SAXException;
048: import org.xml.sax.helpers.AttributesImpl;
049:
050: /**
051: * This transformer is applied to the sitetree. It marks the site element and all node elements the
052: * current identity is not allowed to access with a <code>protected="true"</code> attribute.
053: */
054: public class AccessControlSitetreeTransformer extends
055: AbstractSAXTransformer implements Disposable {
056:
057: /**
058: * <code>ATTRIBUTE_PROTECTED</code> The attribute for protected
059: */
060: public static final String ATTRIBUTE_PROTECTED = "protected";
061: /**
062: * <code>PARAMETER_PUBLICATION_ID</code> The publication id parameter
063: */
064: public static final String PARAMETER_PUBLICATION_ID = "publication-id";
065: /**
066: * <code>PARAMETER_AREA</code> The area parameter
067: */
068: public static final String PARAMETER_AREA = "area";
069:
070: private String documentId;
071: private ServiceSelector serviceSelector;
072: private PolicyManager policyManager;
073: private AccessControllerResolver acResolver;
074: private AccreditableManager accreditableManager;
075: private Identity identity;
076: private String urlPrefix;
077:
078: /**
079: * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver,
080: * java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
081: */
082: public void setup(SourceResolver _resolver, Map _objectModel,
083: String src, Parameters par) throws ProcessingException,
084: SAXException, IOException {
085: super .setup(_resolver, _objectModel, src, par);
086:
087: this .serviceSelector = null;
088: this .acResolver = null;
089: this .policyManager = null;
090:
091: this .identity = Identity.getIdentity(this .request
092: .getSession(false));
093:
094: try {
095: String publicationId = par
096: .getParameter(PARAMETER_PUBLICATION_ID);
097: String area = par.getParameter(PARAMETER_AREA);
098:
099: if (getLogger().isDebugEnabled()) {
100: getLogger().debug("Setting up transformer");
101: getLogger().debug(
102: " Identity: [" + this .identity + "]");
103: getLogger().debug(
104: " Publication ID: [" + publicationId + "]");
105: getLogger().debug(" Area: [" + area + "]");
106: }
107:
108: this .urlPrefix = "/" + publicationId + "/" + area;
109:
110: Request _request = ObjectModelHelper
111: .getRequest(_objectModel);
112:
113: this .serviceSelector = (ServiceSelector) this .manager
114: .lookup(AccessControllerResolver.ROLE + "Selector");
115:
116: this .acResolver = (AccessControllerResolver) this .serviceSelector
117: .select(AccessControllerResolver.DEFAULT_RESOLVER);
118:
119: if (getLogger().isDebugEnabled()) {
120: getLogger().debug(
121: " Resolved AC resolver [" + this .acResolver
122: + "]");
123: }
124:
125: String webappUrl = ServletHelper.getWebappURI(_request);
126: AccessController accessController = this .acResolver
127: .resolveAccessController(webappUrl);
128: this .accreditableManager = accessController
129: .getAccreditableManager();
130: this .policyManager = accessController.getPolicyManager();
131:
132: if (getLogger().isDebugEnabled()) {
133: getLogger().debug(
134: " Using policy manager ["
135: + this .policyManager + "]");
136: }
137: } catch (final ParameterException e) {
138: throw new ProcessingException(e);
139: } catch (final ServiceException e) {
140: throw new ProcessingException(e);
141: } catch (final AccessControlException e) {
142: throw new ProcessingException(e);
143: }
144:
145: }
146:
147: /**
148: * @see org.apache.avalon.framework.activity.Disposable#dispose()
149: */
150: public void dispose() {
151: if (getLogger().isDebugEnabled()) {
152: getLogger().debug("Disposing transformer");
153: }
154: if (this .serviceSelector != null) {
155: if (this .acResolver != null) {
156: this .serviceSelector.release(this .acResolver);
157: }
158: this .manager.release(this .serviceSelector);
159: }
160: }
161:
162: /**
163: * @see org.xml.sax.ContentHandler#startDocument()
164: */
165: public void startDocument() throws SAXException {
166: super .startDocument();
167: this .documentId = "";
168: }
169:
170: /**
171: * (non-Javadoc)
172: * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
173: * java.lang.String, org.xml.sax.Attributes)
174: */
175: public void startElement(String uri, String localName, String raw,
176: Attributes attr) throws SAXException {
177:
178: Attributes attributes = attr;
179:
180: if (isFragmentNode(uri, localName)) {
181: String area = attr.getValue("area"); // FIXME: don't hardcode
182: String base = attr.getValue("base");
183: if (area != null && base != null) {
184: this .documentId = "/" + area + base;
185: }
186: }
187: if (isNode(uri, localName)) {
188: String id = attr
189: .getValue(SiteTreeNodeImpl.ID_ATTRIBUTE_NAME);
190: if (id != null) {
191: this .documentId += "/" + id;
192: }
193:
194: if (getLogger().isDebugEnabled()) {
195: getLogger().debug("Checking node");
196: getLogger().debug(
197: " Document ID: [" + this .documentId + "]");
198: getLogger().debug(
199: " URL: [" + this .urlPrefix
200: + this .documentId + "]");
201: }
202:
203: try {
204: String url = this .urlPrefix + this .documentId;
205: Role[] roles = this .policyManager.getGrantedRoles(
206: this .accreditableManager, this .identity, url);
207:
208: getLogger().debug(
209: " Roles: [" + roles.length + "]");
210:
211: if (roles.length == 0) {
212: getLogger().debug(
213: " Adding attribute [protected='true']");
214:
215: AttributesImpl attributesImpl = new AttributesImpl(
216: attributes);
217: attributesImpl.addAttribute("",
218: ATTRIBUTE_PROTECTED, ATTRIBUTE_PROTECTED,
219: "", Boolean.toString(true));
220: attributes = attributesImpl;
221: }
222: } catch (AccessControlException e) {
223: throw new SAXException(e);
224: }
225: }
226:
227: super .startElement(uri, localName, raw, attributes);
228: }
229:
230: /**
231: * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
232: * java.lang.String)
233: */
234: public void endElement(String uri, String localName, String raw)
235: throws SAXException {
236: super .endElement(uri, localName, raw);
237: if (isNode(uri, localName) && this .documentId.length() > 0) {
238: this .documentId = this .documentId.substring(0,
239: this .documentId.lastIndexOf("/"));
240: }
241: }
242:
243: /**
244: * Returns if an element represents a sitetree node.
245: * @param uri The namespace URI.
246: * @param localName The local name.
247: * @return A boolean value.
248: */
249: protected boolean isNode(String uri, String localName) {
250: return uri.equals(DefaultSiteTree.NAMESPACE_URI)
251: && (localName.equals(SiteTreeNodeImpl.NODE_NAME) || localName
252: .equals("site"));
253: }
254:
255: /**
256: * Returns if an element represents a fragment node.
257: * @param uri The namespace URI.
258: * @param localName The local name.
259: * @return A boolean value.
260: */
261: protected boolean isFragmentNode(String uri, String localName) {
262: return uri.equals(DefaultSiteTree.NAMESPACE_URI)
263: && (localName.equals("fragment"));
264: }
265:
266: }
|