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: PublicationAccessControllerResolver.java 568041 2007-08-21 09:47:23Z andreas $ */
020:
021: package org.apache.lenya.cms.ac;
022:
023: import java.io.File;
024:
025: import org.apache.avalon.framework.activity.Initializable;
026: import org.apache.avalon.framework.configuration.Configurable;
027: import org.apache.avalon.framework.configuration.Configuration;
028: import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
029: import org.apache.cocoon.environment.Request;
030: import org.apache.excalibur.source.Source;
031: import org.apache.excalibur.source.SourceResolver;
032: import org.apache.excalibur.source.SourceUtil;
033: import org.apache.lenya.ac.AccessControlException;
034: import org.apache.lenya.ac.AccessController;
035: import org.apache.lenya.ac.impl.AbstractAccessControllerResolver;
036: import org.apache.lenya.cms.cocoon.components.context.ContextUtility;
037: import org.apache.lenya.cms.publication.DocumentFactory;
038: import org.apache.lenya.cms.publication.DocumentUtil;
039: import org.apache.lenya.cms.publication.Publication;
040: import org.apache.lenya.cms.publication.URLInformation;
041:
042: /**
043: * Resolves the access controller according to the <code>access-control.xml</code> file of a publication.
044: */
045: public class PublicationAccessControllerResolver extends
046: AbstractAccessControllerResolver implements Initializable {
047:
048: protected static final String AC_CONFIGURATION_FILE = "config/access-control/access-control.xml"
049: .replace('/', File.separatorChar);
050: protected static final String TYPE_ATTRIBUTE = "type";
051:
052: /**
053: * This implementation uses the publication ID in combination with the context path as cache
054: * key.
055: * @see org.apache.lenya.ac.impl.AbstractAccessControllerResolver#generateCacheKey(java.lang.String,
056: * org.apache.excalibur.source.SourceResolver)
057: */
058: protected Object generateCacheKey(String webappUrl,
059: SourceResolver resolver) throws AccessControlException {
060:
061: URLInformation info = new URLInformation(webappUrl);
062:
063: String publicationId = info.getPublicationId();
064: if (getLogger().isDebugEnabled()) {
065: getLogger().debug(
066: "Using first URL step (might be publication ID) as cache key: ["
067: + publicationId + "]");
068: }
069:
070: return super .generateCacheKey(publicationId, resolver);
071: }
072:
073: /**
074: * @see org.apache.lenya.ac.impl.AbstractAccessControllerResolver#doResolveAccessController(java.lang.String)
075: */
076: public AccessController doResolveAccessController(String webappUrl)
077: throws AccessControlException {
078: getLogger().debug(
079: "Resolving controller for URL [" + webappUrl + "]");
080:
081: AccessController controller = null;
082: Publication publication = getPublication(webappUrl);
083:
084: if (publication != null) {
085: String publicationUrl = webappUrl
086: .substring(("/" + publication.getId()).length());
087: controller = resolveAccessController(publication,
088: publicationUrl);
089: }
090: return controller;
091: }
092:
093: /**
094: * Returns the publication for the webapp URL or null if the URL is not included in a
095: * publication.
096: * @param webappUrl The webapp URL.
097: * @return A publication.
098: * @throws AccessControlException when something went wrong.
099: */
100: protected Publication getPublication(String webappUrl)
101: throws AccessControlException {
102: Publication publication = null;
103:
104: assert webappUrl.startsWith("/");
105: // remove leading slash
106: String url = webappUrl.substring(1);
107:
108: if (url.length() > 0) {
109:
110: URLInformation info = new URLInformation(webappUrl);
111: String pubId = info.getPublicationId();
112:
113: ContextUtility util = null;
114: try {
115: util = (ContextUtility) this .manager
116: .lookup(ContextUtility.ROLE);
117: Request request = util.getRequest();
118: DocumentFactory factory = DocumentUtil
119: .getDocumentFactory(manager, request);
120: if (pubId != null && factory.existsPublication(pubId)) {
121: publication = factory.getPublication(pubId);
122: }
123: } catch (Exception e) {
124: throw new AccessControlException(e);
125: } finally {
126: if (util != null) {
127: this .manager.release(util);
128: }
129: }
130: if (publication != null) {
131: getLogger()
132: .debug("Publication [" + pubId + "] exists.");
133: }
134: }
135: return publication;
136: }
137:
138: /**
139: * Returns the servlet context.
140: * @return A file.
141: */
142: protected File getContext() {
143: return this .context;
144: }
145:
146: /**
147: * Retrieves access control configuration of a specific publication.
148: * @param publication The publication.
149: * @return Configuration
150: * @throws AccessControlException when something went wrong.
151: */
152: public Configuration getConfiguration(Publication publication)
153: throws AccessControlException {
154: File configurationFile = new File(publication.getDirectory(),
155: AC_CONFIGURATION_FILE);
156:
157: if (configurationFile.isFile()) {
158: try {
159: Configuration configuration = new DefaultConfigurationBuilder()
160: .buildFromFile(configurationFile);
161: return configuration;
162: } catch (Exception e) {
163: throw new AccessControlException(e);
164: }
165: } else {
166: throw new AccessControlException(
167: "No such file or directory: " + configurationFile);
168: }
169: }
170:
171: private File context;
172:
173: /**
174: * Resolves an access controller for a certain URL within a publication.
175: * @param publication The publication.
176: * @param url The url within the publication.
177: * @return An access controller.
178: * @throws AccessControlException when something went wrong.
179: */
180: public AccessController resolveAccessController(
181: Publication publication, String url)
182: throws AccessControlException {
183:
184: assert publication != null;
185:
186: AccessController accessController = null;
187:
188: try {
189: Configuration configuration = getConfiguration(publication);
190: String type = configuration.getAttribute(TYPE_ATTRIBUTE);
191:
192: accessController = (AccessController) getManager().lookup(
193: AccessController.ROLE + "/" + type);
194:
195: if (accessController instanceof Configurable) {
196: ((Configurable) accessController)
197: .configure(configuration);
198: }
199:
200: } catch (Exception e) {
201: throw new AccessControlException(e);
202: }
203:
204: return accessController;
205: }
206:
207: /**
208: * @see org.apache.avalon.framework.activity.Initializable#initialize()
209: */
210: public void initialize() throws Exception {
211: SourceResolver resolver = null;
212: Source contextSource = null;
213: File contextDir;
214: try {
215: resolver = (SourceResolver) getManager().lookup(
216: SourceResolver.ROLE);
217: contextSource = resolver.resolveURI("context:///");
218: contextDir = SourceUtil.getFile(contextSource);
219:
220: if (contextDir == null || !contextDir.isDirectory()) {
221: throw new AccessControlException(
222: "The servlet context is not a directory!");
223: }
224:
225: } finally {
226: if (resolver != null) {
227: if (contextSource != null) {
228: resolver.release(contextSource);
229: }
230: getManager().release(resolver);
231: }
232: }
233: this.context = contextDir;
234: }
235:
236: }
|