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: FilePolicyManager.java 487256 2006-12-14 16:59:12Z andreas $ */
020:
021: package org.apache.lenya.ac.file;
022:
023: import java.io.File;
024: import java.io.FileFilter;
025: import java.io.FileInputStream;
026: import java.io.FileNotFoundException;
027: import java.io.InputStream;
028: import java.net.URI;
029: import java.util.HashMap;
030: import java.util.HashSet;
031: import java.util.LinkedHashMap;
032: import java.util.LinkedList;
033: import java.util.List;
034: import java.util.Set;
035:
036: import org.apache.avalon.framework.activity.Disposable;
037: import org.apache.avalon.framework.logger.AbstractLogEnabled;
038: import org.apache.avalon.framework.parameters.ParameterException;
039: import org.apache.avalon.framework.parameters.Parameterizable;
040: import org.apache.avalon.framework.parameters.Parameters;
041: import org.apache.avalon.framework.service.ServiceException;
042: import org.apache.avalon.framework.service.ServiceManager;
043: import org.apache.avalon.framework.service.Serviceable;
044: import org.apache.cocoon.util.NetUtils;
045: import org.apache.excalibur.source.Source;
046: import org.apache.excalibur.source.SourceResolver;
047: import org.apache.excalibur.source.SourceUtil;
048: import org.apache.lenya.ac.AccessControlException;
049: import org.apache.lenya.ac.Accreditable;
050: import org.apache.lenya.ac.AccreditableManager;
051: import org.apache.lenya.ac.Credential;
052: import org.apache.lenya.ac.Identity;
053: import org.apache.lenya.ac.InheritingPolicyManager;
054: import org.apache.lenya.ac.ModifiablePolicy;
055: import org.apache.lenya.ac.Policy;
056: import org.apache.lenya.ac.Role;
057: import org.apache.lenya.ac.cache.CachingException;
058: import org.apache.lenya.ac.cache.SourceCache;
059: import org.apache.lenya.ac.impl.CredentialImpl;
060: import org.apache.lenya.ac.impl.DefaultPolicy;
061: import org.apache.lenya.ac.impl.PolicyBuilder;
062: import org.apache.lenya.ac.impl.RemovedAccreditablePolicyBuilder;
063: import org.apache.lenya.ac.impl.URLPolicy;
064: import org.apache.lenya.xml.DocumentHelper;
065: import org.w3c.dom.Document;
066:
067: /**
068: * A PolicyBuilder is used to build policies.
069: */
070: public class FilePolicyManager extends AbstractLogEnabled implements
071: InheritingPolicyManager, Parameterizable, Disposable,
072: Serviceable {
073:
074: private static final class SubtreeFileFilter implements FileFilter {
075:
076: private final String subtree;
077:
078: private SubtreeFileFilter(String _subtree) {
079: super ();
080: this .subtree = _subtree;
081: }
082:
083: /**
084: * @see java.io.FileFilter#accept(java.io.File)
085: */
086: public boolean accept(File file) {
087: return file.getName().equals(this .subtree);
088: }
089: }
090:
091: private static final class IsDirectoryFileFilter implements
092: FileFilter {
093: /**
094: * @see java.io.FileFilter#accept(java.io.File)
095: */
096: public boolean accept(File file) {
097: return file.isDirectory();
098: }
099: }
100:
101: /**
102: * Creates a new FilePolicyManager.
103: */
104: public FilePolicyManager() {
105: // do nothing
106: }
107:
108: /**
109: * Returns the source cache.
110: *
111: * @return A source cache.
112: */
113: protected SourceCache getCache() {
114: return this .cache;
115: }
116:
117: private SourceCache cache;
118:
119: protected static final String SUBTREE_FILENAME = "subtree-policy.acml";
120:
121: /**
122: * Builds a subtree policy from a file. When the file is not present, an
123: * empty policy is returned.
124: *
125: * @param controller The access controller to use.
126: * @param url The URL inside the web application.
127: * @return A policy.
128: * @throws AccessControlException when something went wrong.
129: */
130: public Policy buildSubtreePolicy(AccreditableManager controller,
131: String url) throws AccessControlException {
132: return buildPolicy(controller, url, SUBTREE_FILENAME);
133: }
134:
135: /**
136: * Builds a policy from a file. When the file is not present, an empty
137: * policy is returned.
138: *
139: * @param controller The access controller to use.
140: * @param url The url.
141: * @param policyFilename The policy filename.
142: * @return A policy.
143: * @throws AccessControlException when something went wrong.
144: */
145: protected DefaultPolicy buildPolicy(AccreditableManager controller,
146: String url, String policyFilename)
147: throws AccessControlException {
148:
149: if (getLogger().isDebugEnabled()) {
150: getLogger().debug("Building policy for URL [" + url + "]");
151: }
152:
153: DefaultPolicy policy = null;
154:
155: String policyUri = getPolicySourceURI(url, policyFilename);
156: if (getLogger().isDebugEnabled()) {
157: getLogger().debug(
158: "Policy source URI resolved to: " + policyUri);
159: }
160:
161: try {
162: PolicyBuilder builder = new PolicyBuilder(controller);
163: policy = (DefaultPolicy) getCache().get(policyUri, builder);
164: } catch (CachingException e) {
165: throw new AccessControlException(e);
166: }
167:
168: if (getLogger().isDebugEnabled()) {
169: getLogger().debug(
170: "Policy exists: [" + (policy != null) + "]");
171: }
172:
173: if (policy == null) {
174: policy = new DefaultPolicy();
175: }
176: return policy;
177: }
178:
179: /**
180: * Returns the policy file URI for a URL and a policy filename.
181: *
182: * @param url The url to get the file for.
183: * @param policyFilename The name of the policy file.
184: * @return A String.
185: * @throws AccessControlException if an error occurs
186: */
187: protected String getPolicySourceURI(String url,
188: String policyFilename) throws AccessControlException {
189: if (url.startsWith("/")) {
190: url = url.substring(1);
191: }
192:
193: // remove publication ID
194: if (url.indexOf("/") > -1) {
195: url = url.substring(url.indexOf("/") + 1);
196: } else {
197: url = "";
198: }
199:
200: final String policyUri = this .policiesDirectoryUri + "/" + url
201: + "/" + policyFilename;
202: if (getLogger().isDebugEnabled()) {
203: getLogger().debug(
204: "Computing policy URI [" + policyUri + "]");
205: }
206: return policyUri;
207: }
208:
209: /**
210: * Returns the policy file for a certain URL.
211: *
212: * @param url The URL to get the policy for.
213: * @param policyFilename The policy filename.
214: * @return A file.
215: * @throws AccessControlException when an error occurs.
216: */
217: protected File getPolicyFile(String url, String policyFilename)
218: throws AccessControlException {
219: String fileUri = getPolicySourceURI(url, policyFilename);
220: SourceResolver resolver = null;
221: Source source = null;
222: try {
223: resolver = (SourceResolver) this .serviceManager
224: .lookup(SourceResolver.ROLE);
225: source = resolver.resolveURI(fileUri);
226: return SourceUtil.getFile(source);
227: } catch (final Exception e) {
228: throw new AccessControlException(e);
229: } finally {
230: if (resolver != null) {
231: if (source != null) {
232: resolver.release(source);
233: }
234: this .serviceManager.release(resolver);
235: }
236: }
237: }
238:
239: /**
240: * Saves a Subtree policy.
241: *
242: * @param url The url to save the policy for.
243: * @param policy The policy to save.
244: * @throws AccessControlException when something went wrong.
245: */
246: public void saveSubtreePolicy(String url, Policy policy)
247: throws AccessControlException {
248: getLogger()
249: .debug("Saving subtree policy for URL [" + url + "]");
250: savePolicy(url, policy, SUBTREE_FILENAME);
251: }
252:
253: /**
254: * Saves a policy to a file.
255: *
256: * @param url The URL to save the policy for.
257: * @param policy The policy.
258: * @param filename The file.
259: * @throws AccessControlException if something goes wrong.
260: */
261: protected void savePolicy(String url, Policy policy, String filename)
262: throws AccessControlException {
263:
264: File file = getPolicyFile(url, filename);
265: savePolicy(policy, file);
266: }
267:
268: /**
269: * Saves a policy to a file.
270: *
271: * @param policy The policy to save.
272: * @param file The file.
273: * @throws AccessControlException when an error occurs.
274: */
275: protected void savePolicy(Policy policy, File file)
276: throws AccessControlException {
277: Document document = PolicyBuilder.savePolicy(policy);
278:
279: try {
280: if (!file.exists()) {
281: file.getParentFile().mkdirs();
282: if (!file.createNewFile()) {
283: throw new AccessControlException("File [" + file
284: + "] could not be created.");
285: }
286: }
287: DocumentHelper.writeDocument(document, file);
288: } catch (AccessControlException e) {
289: throw e;
290: } catch (Exception e) {
291: throw new AccessControlException("Path: ["
292: + file.getAbsolutePath() + "]", e);
293: }
294: }
295:
296: /**
297: * @see org.apache.lenya.ac.PolicyManager#getPolicy(org.apache.lenya.ac.AccreditableManager,
298: * java.lang.String)
299: */
300: public Policy getPolicy(AccreditableManager controller, String url)
301: throws AccessControlException {
302:
303: return new URLPolicy(controller, url, this );
304: }
305:
306: protected static final String DIRECTORY_PARAMETER = "directory";
307:
308: private String policiesDirectoryUri;
309:
310: private File policiesDirectory;
311:
312: /**
313: * @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(org.apache.avalon.framework.parameters.Parameters)
314: */
315: public void parameterize(Parameters parameters)
316: throws ParameterException {
317: if (parameters.isParameter(DIRECTORY_PARAMETER)) {
318: this .policiesDirectoryUri = parameters
319: .getParameter(DIRECTORY_PARAMETER);
320: if (getLogger().isDebugEnabled()) {
321: getLogger().debug(
322: "Policies directory URI: "
323: + this .policiesDirectoryUri);
324: }
325: }
326: }
327:
328: /**
329: * Get the path to the policies directory.
330: *
331: * @return the path to the policies directory
332: * @throws AccessControlException if an error occurs
333: */
334: public File getPoliciesDirectory() throws AccessControlException {
335:
336: if (this .policiesDirectory == null) {
337: SourceResolver resolver = null;
338: Source source = null;
339: File directory;
340:
341: try {
342: resolver = (SourceResolver) getServiceManager().lookup(
343: SourceResolver.ROLE);
344: source = resolver.resolveURI(this .policiesDirectoryUri);
345: getLogger().debug(
346: "Policies directory source: ["
347: + source.getURI() + "]");
348: directory = new File(new URI(NetUtils.encodePath(source
349: .getURI())));
350: } catch (final Exception e) {
351: throw new AccessControlException(
352: "Resolving policies directory failed: ", e);
353: } finally {
354: if (resolver != null) {
355: if (source != null) {
356: resolver.release(source);
357: }
358: getServiceManager().release(resolver);
359: }
360: }
361:
362: getLogger().debug(
363: "Policies directory resolved to ["
364: + directory.getAbsolutePath() + "]");
365: setPoliciesDirectory(directory);
366: }
367:
368: return this .policiesDirectory;
369: }
370:
371: /**
372: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
373: */
374: public void service(ServiceManager manager) throws ServiceException {
375: this .serviceManager = manager;
376: this .cache = (SourceCache) manager.lookup(SourceCache.ROLE);
377: }
378:
379: /**
380: * Sets the policies directory.
381: *
382: * @param directory The directory.
383: * @throws AccessControlException if the directory is not a directory
384: */
385: public void setPoliciesDirectory(File directory)
386: throws AccessControlException {
387: getLogger().debug(
388: "Setting policies directory ["
389: + directory.getAbsolutePath() + "]");
390: if (!directory.isDirectory()) {
391: throw new AccessControlException(
392: "Policies directory invalid: ["
393: + directory.getAbsolutePath() + "]");
394: }
395: this .policiesDirectory = directory;
396: }
397:
398: /**
399: * @see org.apache.lenya.ac.InheritingPolicyManager#getPolicies(org.apache.lenya.ac.AccreditableManager,
400: * java.lang.String)
401: */
402: public Policy[] getPolicies(AccreditableManager controller,
403: String url) throws AccessControlException {
404:
405: if (!url.startsWith("/")) {
406: throw new IllegalArgumentException("The URL [" + url
407: + "] doesn't start with a slash!");
408: }
409:
410: url = url.substring(1);
411:
412: List policies = new LinkedList();
413: HashMap orderedPolicies = new LinkedHashMap();
414: int position = 1;
415: Policy policy;
416: String[] directories = url.split("/");
417: url = directories[0] + "/";
418:
419: for (int i = 1; i < directories.length; i++) {
420: url += directories[i] + "/";
421: policy = buildSubtreePolicy(controller, url);
422: orderedPolicies.put(String.valueOf(position), policy);
423: position++;
424: }
425: for (int i = orderedPolicies.size(); i > 0; i--) {
426: policies.add(orderedPolicies.get(String.valueOf(i)));
427: }
428: return (DefaultPolicy[]) policies
429: .toArray(new DefaultPolicy[policies.size()]);
430: }
431:
432: /**
433: * @see org.apache.avalon.framework.activity.Disposable#dispose()
434: */
435: public void dispose() {
436:
437: if (getCache() != null) {
438: getServiceManager().release(getCache());
439: }
440:
441: if (getLogger().isDebugEnabled()) {
442: getLogger().debug("Disposing [" + this + "]");
443: }
444: }
445:
446: /**
447: * Removes an accreditable from all policies within a certain directory
448: * tree.
449: *
450: * @param manager The accreditable manager which owns the accreditable.
451: * @param accreditable The accreditable to remove.
452: * @param policyDirectory The directory where the policies are located.
453: * @throws AccessControlException when an error occurs.
454: */
455: protected void removeAccreditable(AccreditableManager manager,
456: Accreditable accreditable, File policyDirectory)
457: throws AccessControlException {
458:
459: File[] policyFiles = policyDirectory
460: .listFiles(new SubtreeFileFilter(SUBTREE_FILENAME));
461:
462: try {
463: RemovedAccreditablePolicyBuilder builder = new RemovedAccreditablePolicyBuilder(
464: manager);
465: builder.setRemovedAccreditable(accreditable);
466: for (int i = 0; i < policyFiles.length; i++) {
467:
468: if (getLogger().isDebugEnabled()) {
469: getLogger().debug("Removing roles");
470: getLogger().debug(
471: " Accreditable: [" + accreditable + "]");
472: getLogger().debug(
473: " File: ["
474: + policyFiles[i].getAbsolutePath()
475: + "]");
476: }
477:
478: InputStream stream = new FileInputStream(policyFiles[i]);
479: ModifiablePolicy policy = builder.buildPolicy(stream);
480: policy.removeRoles(accreditable);
481: savePolicy(policy, policyFiles[i]);
482: }
483: } catch (final FileNotFoundException e1) {
484: throw new AccessControlException(e1);
485: }
486:
487: File[] directories = policyDirectory
488: .listFiles(new IsDirectoryFileFilter());
489:
490: for (int i = 0; i < directories.length; i++) {
491: removeAccreditable(manager, accreditable, directories[i]);
492: }
493:
494: }
495:
496: /**
497: * @see org.apache.lenya.ac.PolicyManager#accreditableRemoved(org.apache.lenya.ac.AccreditableManager,
498: * org.apache.lenya.ac.Accreditable)
499: */
500: public void accreditableRemoved(AccreditableManager manager,
501: Accreditable accreditable) throws AccessControlException {
502:
503: if (getLogger().isDebugEnabled()) {
504: getLogger().debug(
505: "An accreditable was removed: [" + accreditable
506: + "]");
507: }
508:
509: removeAccreditable(manager, accreditable,
510: getPoliciesDirectory());
511: }
512:
513: private ServiceManager serviceManager;
514:
515: /**
516: * Returns the service manager.
517: *
518: * @return A service manager.
519: */
520: protected ServiceManager getServiceManager() {
521: return this .serviceManager;
522: }
523:
524: /**
525: * @see org.apache.lenya.ac.PolicyManager#accreditableAdded(org.apache.lenya.ac.AccreditableManager,
526: * org.apache.lenya.ac.Accreditable)
527: */
528: public void accreditableAdded(AccreditableManager manager,
529: Accreditable accreditable) throws AccessControlException {
530: }
531:
532: public Credential[] getCredentials(AccreditableManager controller,
533: String url) throws AccessControlException {
534:
535: if (!url.startsWith("/")) {
536: throw new IllegalArgumentException("The URL [" + url
537: + "] doesn't start with a slash!");
538: }
539:
540: url = url.substring(1);
541:
542: HashMap orderedCredential = new LinkedHashMap();
543: int position = 1;
544:
545: String[] directories = url.split("/");
546: url = directories[0] + "/";
547:
548: for (int i = 1; i < directories.length; i++) {
549: url += directories[i] + "/";
550: Policy policy = buildSubtreePolicy(controller, url);
551: Credential[] tmp = policy.getCredentials();
552: // we need to revert the order of the credentials
553: // to keep the most important policy on top
554: for (int j = tmp.length - 1; j >= 0; j--) {
555: Credential credential = tmp[j];
556: orderedCredential.put(String.valueOf(position),
557: credential);
558: position++;
559: }
560: }
561: Credential[] returnCredential = new CredentialImpl[orderedCredential
562: .size()];
563: int y = 0;
564: for (int i = orderedCredential.size(); i > 0; i--) {
565: returnCredential[y] = (Credential) orderedCredential
566: .get(String.valueOf(i));
567: y++;
568: }
569:
570: return returnCredential;
571: }
572:
573: public Role[] getGrantedRoles(
574: AccreditableManager accreditableManager, Identity identity,
575: String url) throws AccessControlException {
576: Role[] roles = accreditableManager.getRoleManager().getRoles();
577: Set grantedRoles = new HashSet();
578: Policy policy = getPolicy(accreditableManager, url);
579: for (int i = 0; i < roles.length; i++) {
580: if (policy.check(identity, roles[i]) == Policy.RESULT_GRANTED) {
581: grantedRoles.add(roles[i]);
582: }
583: }
584: return (Role[]) grantedRoles.toArray(new Role[grantedRoles
585: .size()]);
586: }
587:
588: }
|