001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2003 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.auth;
021:
022: import java.util.Properties;
023: import java.util.List;
024: import java.util.Iterator;
025: import java.security.acl.NotOwnerException;
026: import java.security.Principal;
027:
028: import org.apache.log4j.Logger;
029:
030: import com.ecyrd.jspwiki.WikiPage;
031: import com.ecyrd.jspwiki.WikiEngine;
032: import com.ecyrd.jspwiki.WikiContext;
033: import com.ecyrd.jspwiki.WikiException;
034: import com.ecyrd.jspwiki.NoRequiredPropertyException;
035: import com.ecyrd.jspwiki.TextUtil;
036: import com.ecyrd.jspwiki.InternalWikiException;
037: import com.ecyrd.jspwiki.acl.AccessControlList;
038: import com.ecyrd.jspwiki.acl.AclEntryImpl;
039: import com.ecyrd.jspwiki.acl.AclImpl;
040: import com.ecyrd.jspwiki.auth.permissions.*;
041: import com.ecyrd.jspwiki.util.ClassUtil;
042: import com.ecyrd.jspwiki.attachment.Attachment;
043:
044: import com.sun.jspwiki.community.CommunityContext;
045:
046: /**
047: * Manages all access control and authorization.
048: *
049: * @see UserManager
050: */
051: public class AuthorizationManager {
052: public static final String PROP_STRICTLOGINS = "jspwiki.policy.strictLogins";
053: public static final String PROP_AUTHORIZER = "jspwiki.authorizer";
054: public static final String DEFAULT_AUTHORIZER = "com.ecyrd.jspwiki.auth.modules.PageAuthorizer";
055:
056: protected static final String PROP_USEOLDAUTH = "jspwiki.auth.useOldAuth";
057:
058: static Logger log = Logger.getLogger(AuthorizationManager.class);
059:
060: private WikiAuthorizer m_authorizer;
061: private AccessControlList m_defaultPermissions;
062:
063: private boolean m_strictLogins = false;
064:
065: /** If true, allows the old auth system to be used. */
066: private boolean m_useAuth = false;
067:
068: private WikiEngine m_engine;
069:
070: /**
071: * Creates a new AuthorizationManager, owned by engine and initialized
072: * according to the settings in properties. Expects to find property
073: * 'jspwiki.authorizer' with a valid WikiAuthorizer implementation name
074: * to take care of authorization.
075: */
076: public AuthorizationManager(WikiEngine engine, Properties properties)
077: throws WikiException {
078: m_engine = engine;
079:
080: m_useAuth = TextUtil.getBooleanProperty(properties,
081: PROP_USEOLDAUTH, false);
082:
083: m_strictLogins = TextUtil.getBooleanProperty(properties,
084: PROP_STRICTLOGINS, false);
085:
086: if (!m_useAuth)
087: return;
088:
089: m_authorizer = getAuthorizerImplementation(properties);
090: m_authorizer.initialize(engine, properties);
091:
092: AclEntryImpl ae = new AclEntryImpl();
093:
094: //
095: // Default set of permissions for everyone:
096: // ALLOW: View, Edit
097: // DENY: Delete
098: //
099:
100: WikiGroup allGroup = new AllGroup();
101: allGroup.setName("All");
102: ae.setPrincipal(allGroup);
103: ae.addPermission(new ViewPermission());
104: ae.addPermission(new EditPermission());
105:
106: AclEntryImpl aeneg = new AclEntryImpl();
107: aeneg.setPrincipal(allGroup);
108: aeneg.setNegativePermissions();
109: aeneg.addPermission(new DeletePermission());
110:
111: try {
112: m_defaultPermissions = new AclImpl();
113: m_defaultPermissions.addEntry(null, ae);
114: m_defaultPermissions.addEntry(null, aeneg);
115: } catch (NotOwnerException e) {
116: throw new InternalWikiException(
117: "Nobody told me that owners were in use");
118: }
119:
120: }
121:
122: /**
123: * Returns true, if strict logins are required. Strict logins
124: * mean that all pages are accessible only to users who have logged in.
125: */
126: public boolean strictLogins() {
127: return m_strictLogins;
128: }
129:
130: /**
131: * Attempts to find the ACL of a page.
132: * If the page has a parent page, then that is tried also.
133: */
134: private AccessControlList getAcl(WikiPage page) {
135: //
136: // Does the page already have cached ACLs?
137: //
138: AccessControlList acl = page.getAcl();
139:
140: if (acl == null) {
141: //
142: // Nope, check if we can get them from the authorizer
143: //
144:
145: acl = m_authorizer.getPermissions(page);
146:
147: //
148: // If still no go, try the parent.
149: //
150: if (acl == null && page instanceof Attachment) {
151: WikiPage parent = m_engine.getPage(((Attachment) page)
152: .getParentName());
153:
154: acl = getAcl(parent);
155: }
156: }
157:
158: return acl;
159: }
160:
161: /**
162: * Attempts to locate and initialize a WikiAuthorizer to use with this manager.
163: * Throws a WikiException if no entry is found, or if one fails to initialize.
164: *
165: * @param props jspwiki.properties, containing a 'jpswiki.authorizer' class name
166: * @return a WikiAuthorizer used to get page authorization information
167: * @throws WikiException
168: */
169: private WikiAuthorizer getAuthorizerImplementation(Properties props)
170: throws WikiException {
171: String authClassName = props.getProperty(PROP_AUTHORIZER,
172: DEFAULT_AUTHORIZER);
173: WikiAuthorizer impl = null;
174:
175: if (authClassName != null) {
176: try {
177: // TODO: this should probably look in package ...modules
178: Class authClass = ClassUtil
179: .findClass("com.ecyrd.jspwiki.auth.modules",
180: authClassName);
181: impl = (WikiAuthorizer) authClass.newInstance();
182: return (impl);
183: } catch (ClassNotFoundException e) {
184: log.fatal("WikiAuthorizer " + authClassName
185: + " cannot be found", e);
186: throw new WikiException("WikiAuthorizer "
187: + authClassName + " cannot be found");
188: } catch (InstantiationException e) {
189: log.fatal("Authorizer " + authClassName
190: + " cannot be created", e);
191: throw new WikiException("Authorizer " + authClassName
192: + " cannot be created");
193: } catch (IllegalAccessException e) {
194: log
195: .fatal(
196: "You are not allowed to access this authorizer class",
197: e);
198: throw new WikiException(
199: "You are not allowed to access this authorizer class");
200: }
201: } else {
202: throw new NoRequiredPropertyException("Unable to find a "
203: + PROP_AUTHORIZER + " entry in the properties.",
204: PROP_AUTHORIZER);
205: }
206: }
207:
208: /**
209: * Returns true or false, depending on whether this action
210: * is allowed for this WikiPage.
211: *
212: * @param permission Any of the available permissions "view", "edit, "comment", etc.
213: */
214: public boolean checkPermission(WikiPage page, UserProfile wup,
215: String permission) {
216: return checkPermission(page, wup, WikiPermission
217: .newInstance(permission));
218: }
219:
220: /**
221: * Returns true or false, depending on whether this action
222: * is allowed. This method returns true for 2.2.
223: */
224: public boolean oldcheckPermission(WikiPage page, UserProfile wup,
225: WikiPermission permission) {
226: int res = AccessControlList.NONE;
227: UserManager userManager = m_engine.getUserManager();
228:
229: //
230: // A slight sanity check.
231: //
232: if (wup == null)
233: return false;
234:
235: //
236: // Honor strict login requirements. Weak code - should not be permanent.
237: //
238: if (wup.isAuthenticated() == false && m_strictLogins)
239: return false;
240:
241: //
242: // If auth is turned off, return immediately for speed
243: //
244: if (!m_useAuth)
245: return true;
246:
247: //
248: // Yup, superusers can do anything.
249: //
250: if (wup.isAuthenticated() && userManager.isAdministrator(wup)) {
251: return true;
252: }
253:
254: AccessControlList acl = getAcl(page);
255:
256: //
257: // Does the page in question have an access control list?
258: //
259: if (acl != null) {
260: log.debug("ACL for this page is: " + acl);
261: log.debug("Checking for wup: " + wup);
262: log.debug("Permission: " + permission);
263:
264: if (wup.isAuthenticated()) {
265: res = acl.findPermission(wup, permission);
266: }
267:
268: //
269: // If there as no entry for the user, then try all of his groups
270: //
271:
272: if (res == AccessControlList.NONE) {
273: log.debug("Checking groups...");
274:
275: try {
276: List list = userManager.getGroupsForPrincipal(wup);
277:
278: for (Iterator i = list.iterator(); i.hasNext();) {
279: res = acl.findPermission((Principal) i.next(),
280: permission);
281:
282: if (res != AccessControlList.NONE)
283: break;
284: }
285: } catch (NoSuchPrincipalException e) {
286: log
287: .warn(
288: "Internal trouble: No principal defined for requested user.",
289: e);
290: }
291: }
292: }
293:
294: //
295: // If there was no result, then query from the default
296: // permission set of the authorizer.
297: //
298:
299: if (res == AccessControlList.NONE) {
300: log.debug("Page defines no permissions for "
301: + wup.getName() + ", checking defaults.");
302:
303: acl = m_authorizer.getDefaultPermissions();
304:
305: if (acl != null) {
306: res = acl.findPermission(wup, permission);
307: }
308: }
309:
310: //
311: // If there still is nothing, then query from the Wiki default
312: // set of permissions.
313: //
314:
315: if (res == AccessControlList.NONE) {
316: log
317: .debug("No defaults exist, falling back to hardcoded permissions.");
318: res = m_defaultPermissions.findPermission(wup, permission);
319: }
320:
321: log.debug("Permission " + permission + " for user " + wup
322: + " is " + res);
323:
324: if (res == AccessControlList.NONE) {
325: throw new InternalWikiException(
326: "No default policy has been defined!");
327: }
328:
329: return res == AccessControlList.ALLOW;
330: }
331:
332: /**
333: * Returns true or false, depending on whether this action
334: * is allowed. This method returns true for 2.2.
335: */
336: public boolean checkPermission(WikiPage page, UserProfile wup,
337: WikiPermission permission) {
338: UserManager userManager = m_engine.getUserManager();
339:
340: //
341: // A slight sanity check.
342: //
343: if (wup == null)
344: return false;
345:
346: //
347: // Honor strict login requirements. Weak code - should not be permanent.
348: //
349: if (wup.isAuthenticated() == false && m_strictLogins)
350: return false;
351:
352: //
353: // If auth is turned off, return immediately for speed
354: //
355: if (!m_useAuth)
356: return true;
357:
358: //
359: // Yup, superusers can do anything.
360: //
361: if (wup.isAuthenticated() && userManager.isAdministrator(wup)) {
362: return true;
363: }
364:
365: return m_engine.getCommunityContext().checkPermission(page,
366: wup, permission);
367: }
368: }
|