Index: src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiRightServiceImpl.java =================================================================== --- src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiRightServiceImpl.java (revision 4066) +++ src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiRightServiceImpl.java (working copy) @@ -1,782 +1,795 @@ -/* - * Copyright 2006-2007, XpertNet SARL, and individual contributors as indicated - * by the contributors.txt. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ - -package com.xpn.xwiki.user.impl.xwiki; - -import com.xpn.xwiki.XWikiContext; -import com.xpn.xwiki.XWikiException; -import com.xpn.xwiki.doc.XWikiDocument; -import com.xpn.xwiki.objects.BaseObject; -import com.xpn.xwiki.user.api.XWikiGroupService; -import com.xpn.xwiki.user.api.XWikiRightNotFoundException; -import com.xpn.xwiki.user.api.XWikiRightService; -import com.xpn.xwiki.user.api.XWikiUser; -import com.xpn.xwiki.util.Util; -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.*; - -public class XWikiRightServiceImpl implements XWikiRightService { - private static final Log log = LogFactory.getLog(XWikiRightServiceImpl.class); - private static Map actionMap; - private static List allLevels = Arrays.asList( - new String[] {"admin","view","edit","comment","delete","register","programming"}); - - protected void logAllow(String username, String page, String action, String info) { - if (log.isDebugEnabled()) - log.debug("Access has been granted for (" + username + "," + page + "," + action + "): " + info); - } - - protected void logDeny(String username, String page, String action, String info) { - if (log.isInfoEnabled()) - log.info("Access has been denied for (" + username + "," + page + "," + action + "): " + info); - } - - protected void logDeny(String name, String resourceKey, String accessLevel, String info, Exception e) { - if (log.isDebugEnabled()) - log.debug("Access has been denied for (" + name + "," + resourceKey + "," + accessLevel + ") at " + info, e); - } - - public List listAllLevels(XWikiContext context) throws XWikiException { - List list = new ArrayList(); - list.addAll(allLevels); - return list; - } - - public String getRight(String action) { - if (actionMap == null) { - actionMap = new HashMap(); - actionMap.put("login", "login"); - actionMap.put("logout", "login"); - actionMap.put("loginerror", "login"); - actionMap.put("loginsubmit", "login"); - actionMap.put("view", "view"); - actionMap.put("viewrev", "view"); - actionMap.put("downloadrev", "download"); - actionMap.put("plain", "view"); - actionMap.put("raw", "view"); - actionMap.put("attach", "view"); - actionMap.put("charting", "view"); - actionMap.put("skin", "view"); - actionMap.put("download", "view"); - actionMap.put("dot", "view"); - actionMap.put("svg", "view"); - actionMap.put("pdf", "view"); - actionMap.put("delete", "delete"); - actionMap.put("reset", "delete"); - actionMap.put("commentadd", "comment"); - actionMap.put("register", "register"); - actionMap.put("redirect", "view"); - actionMap.put("admin", "admin"); - actionMap.put("export", "view"); - actionMap.put("import", "admin"); - actionMap.put("unknown", "view"); - } - - String right = (String) actionMap.get(action); - if (right == null) { - return "edit"; - } else - return right; - } - - public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException { - String username = null; - XWikiUser user = null; - boolean needsAuth = false; - String right = getRight(action); - - if (right.equals("login")) { - user = context.getWiki().checkAuth(context); - if (user == null) - username = "XWiki.XWikiGuest"; - else - username = user.getUser(); - - // Save the user - context.setUser(username); - logAllow(username, doc.getFullName(), action, "login/logout pages"); - return true; - } - - if (right.equals("delete")) { - user = context.getWiki().checkAuth(context); - String creator = doc.getCreator(); - if ((user != null) && (user.getUser() != null) && (creator != null)) { - if (user.getUser().equals(creator)) { - context.setUser(user.getUser()); - return true; - } - } - right = "admin"; - } - - // We do not need to authenticate twice - // This seems to cause a problem in virtual wikis - user = context.getXWikiUser(); - if (user == null) { - needsAuth = needsAuth(right, context); - try { - if (context.getMode() != XWikiContext.MODE_XMLRPC) - user = context.getWiki().checkAuth(context); - else - user = new XWikiUser(context.getUser()); - - if ((user == null) && (needsAuth)) { - if (context.getRequest() != null) - context.getWiki().getAuthService().showLogin(context); - logDeny("unauthentified", doc.getFullName(), action, "Authentication needed"); - return false; - } - } catch (XWikiException e) { - if (needsAuth) - throw e; - } - - if (user == null) - username = "XWiki.XWikiGuest"; - else - username = user.getUser(); - - // Save the user - context.setUser(username); - } else { - username = user.getUser(); - } - -// Check Rights - try { -// Verify access rights and return if ok - String docname; - if (context.getDatabase() != null) { - docname = context.getDatabase() + ":" + doc.getFullName(); - if (username.indexOf(":") == -1) - username = context.getDatabase() + ":" + username; - } else - docname = doc.getFullName(); - - if (context.getWiki().getRightService().hasAccessLevel(right, username, docname, context)) { - logAllow(username, docname, action, "access manager granted right"); - return true; - } - } catch (Exception e) { -// This should not happen.. - logDeny(username, (doc==null) ? "" : doc.getFullName(), action, "access manager exception " + e.getMessage()); - e.printStackTrace(); - return false; - } - - if (user == null) { -// Denied Guest need to be authenticated - logDeny("unauthentified", (doc==null) ? "" : doc.getFullName(), action, "Guest has been denied - Redirecting to authentication"); - if (context.getRequest() != null) - context.getWiki().getAuthService().showLogin(context); - return false; - } else { - logDeny(username, doc.getFullName(), action, "access manager denied right"); - return false; - } - } - - private boolean needsAuth(String right, XWikiContext context) { - boolean needsAuth = false; - try { - needsAuth = context.getWiki().getXWikiPreference("authenticate_" + right, "", context).toLowerCase().equals("yes"); - } catch (Exception e) { - } - try { - needsAuth |= (context.getWiki().getXWikiPreferenceAsInt("authenticate_" + right, 0, context) == 1); - } catch (Exception e) { - } - try { - needsAuth |= context.getWiki().getWebPreference("authenticate_" + right, "", context).toLowerCase().equals("yes"); - } catch (Exception e) { - } - try { - needsAuth |= (context.getWiki().getWebPreferenceAsInt("authenticate_" + right, 0, context) == 1); - } catch (Exception e) { - } - return needsAuth; - } - - public boolean hasAccessLevel(String right, String username, String docname, XWikiContext context) throws XWikiException { - try { - return hasAccessLevel(right, username, docname, true, context); - } catch (XWikiException e) { - return false; - } - } - - public boolean checkRight(String name, XWikiDocument doc, String accessLevel, - boolean user, boolean allow, boolean global, XWikiContext context) throws XWikiRightNotFoundException, XWikiException { - String className = global ? "XWiki.XWikiGlobalRights" : "XWiki.XWikiRights"; - String fieldName = user ? "users" : "groups"; - boolean found = false; - - // Get the userdb and the shortname - String userdatabase = null; - String shortname = name; - int i0 = name.indexOf(":"); - if (i0 != -1) { - userdatabase = name.substring(0, i0); - shortname = name.substring(i0 + 1); - } - - if (log.isDebugEnabled()) - log.debug("Checking right: " + name + "," + doc.getFullName() + "," + accessLevel - + "," + user + "," + allow + "," + global); - - Vector vobj = doc.getObjects(className); - if (vobj != null) { - if (log.isDebugEnabled()) - log.debug("Checking objects " + vobj.size()); - for (int i = 0; i < vobj.size(); i++) { - if (log.isDebugEnabled()) - log.debug("Checking object " + i); - - BaseObject bobj = (BaseObject) vobj.get(i); - - if (bobj == null) { - if (log.isDebugEnabled()) - log.debug("Bypass object " + i); - continue; - } - String users = bobj.getStringValue(fieldName); - String levels = bobj.getStringValue("levels"); - boolean allowdeny = (bobj.getIntValue("allow") == 1); - - if (allowdeny == allow) { - if (log.isDebugEnabled()) - log.debug("Checking match: " + accessLevel + " in " + levels); - - String[] levelsarray = StringUtils.split(levels, " ,|"); - if (ArrayUtils.contains(levelsarray, accessLevel)) { - if (log.isDebugEnabled()) - log.debug("Found a right for " + allow); - found = true; - - if (log.isDebugEnabled()) - log.debug("Checking match: " + name + " in " + users); - - String[] userarray = StringUtils.split(users, " ,|"); - - for (int ii = 0; ii < userarray.length; ii++) { - String value = userarray[ii]; - if (value.indexOf(".") == -1) - userarray[ii] = "XWiki." + value; - } - - if (log.isDebugEnabled()) - log.debug("Checking match: " + name + " in " + StringUtils.join(userarray, ",")); - - // In the case where the document database and the user database is the same - // then we allow the usage of the short name, otherwise the fully qualified name is requested - if (context.getDatabase().equals(userdatabase)) { - if (ArrayUtils.contains(userarray, shortname)) { - if (log.isDebugEnabled()) - log.debug("Found matching right in " + users + " for " + shortname); - return true; - } - // We should also allow to skip "XWiki." from the usernames and group lists - String veryshortname = shortname.substring(shortname.indexOf(".") + 1); - if (ArrayUtils.contains(userarray, veryshortname)) { - if (log.isDebugEnabled()) - log.debug("Found matching right in " + users + " for " + shortname); - return true; - } - } - - if ((context.getDatabase() != null) && - (ArrayUtils.contains(userarray, name))) { - if (log.isDebugEnabled()) - log.debug("Found matching right in " + users + " for " + name); - return true; - } - - if (log.isDebugEnabled()) - log.debug("Failed match: " + name + " in " + users); - } - } else { - if (log.isDebugEnabled()) - log.debug("Bypass object because wrong allow/deny" + i); - } - } - } - - if (log.isDebugEnabled()) - log.debug("Searching for matching rights at group level"); - -// Didn't found right at this level.. Let's go to group level - Map grouplistcache = (Map) context.get("grouplist"); - if (grouplistcache == null) { - grouplistcache = new HashMap(); - context.put("grouplist", grouplistcache); - } - - Collection grouplist = new ArrayList(); - XWikiGroupService groupService = context.getWiki().getGroupService(context); - String key = context.getDatabase() + ":" + name; - Collection grouplist1 = (Collection) grouplistcache.get(key); - - if (grouplist1 == null) { - grouplist1 = new ArrayList(); - try { - Collection glist = groupService.listGroupsForUser(name, context); - Iterator it = glist.iterator(); - - while (it.hasNext()) { - grouplist1.add(context.getDatabase() + ":" + it.next()); - } - } catch (Exception e) { - - } - - if (grouplist1 != null) - grouplistcache.put(key, grouplist1); - else - grouplistcache.put(key, new ArrayList()); - } - - if (grouplist1 != null) - grouplist.addAll(grouplist1); - - if (context.isVirtual()) { - String database = context.getDatabase(); - try { - shortname = Util.getName(name, context); - - if (!database.equals(context.getDatabase())) { - String key2 = context.getDatabase() + ":" + name; - Collection grouplist2 = (Collection) grouplistcache.get(key2); - - if (grouplist2 == null) { - Collection glist = groupService.listGroupsForUser(shortname, context); - Iterator it = glist.iterator(); - while (it.hasNext()) { - grouplist2.add(context.getDatabase() + ":" + it.next()); - } - if (grouplist2 != null) - grouplistcache.put(key2, grouplist2); - else - grouplistcache.put(key2, new ArrayList()); - } - - if (grouplist2 != null) - grouplist.addAll(grouplist2); - } - } catch (Exception e) { - } finally { - context.setDatabase(database); - } - } - - if (log.isDebugEnabled()) - log.debug("Searching for matching rights for " + ((grouplist == null) ? "0" : "" + grouplist.size()) - + " groups: " + grouplist); - - if (grouplist != null) { - Iterator groupit = grouplist.iterator(); - while (groupit.hasNext()) { - String group = (String) groupit.next(); - try { - // We need to construct the full group name to make sure the groups are - // handled separately - boolean result = checkRight(group, doc, accessLevel, false, allow, global, context); - if (result) - return true; - } catch (XWikiRightNotFoundException e) { - } - catch (Exception e) { - // This should not happen - e.printStackTrace(); - } - } - } - - if (log.isDebugEnabled()) - log.debug("Finished searching for rights for " + name + ": " + found); - - if (found) - return false; - else - throw new XWikiRightNotFoundException(); - } - - public boolean hasAccessLevel(String accessLevel, String name, String resourceKey, - boolean user, XWikiContext context) throws XWikiException { - boolean deny = false; - boolean allow = false; - boolean allow_found = false; - boolean deny_found = false; - boolean isReadOnly = context.getWiki().isReadOnly(); - String database = context.getDatabase(); - XWikiDocument currentdoc = null; - - if (isReadOnly) { - - if ("edit".equals(accessLevel) || - "delete".equals(accessLevel) || - "comment".equals(accessLevel) || - "register".equals(accessLevel)) { - logDeny(name, resourceKey, accessLevel, "server in read-only mode"); - return false; - } - } - - if (name.equals("XWiki.XWikiGuest") || name.endsWith(":XWiki.XWikiGuest")) { - if (needsAuth(accessLevel, context)) - return false; - } - - allow = isSuperAdminOrProgramming(name, resourceKey, accessLevel, user, context); - if ((allow==true)||(accessLevel.equals("programming"))) { - return allow; - } - - try { - // Verify Wiki Owner - String wikiOwner = context.getWikiOwner(); - if (wikiOwner != null) { - if (wikiOwner.equals(name)) { - logAllow(name, resourceKey, accessLevel, "admin level from wiki ownership"); - return true; - } - } - - XWikiDocument xwikidoc = context.getWiki().getDocument("XWiki.XWikiPreferences", context); - - // Verify XWiki register right - if (accessLevel.equals("register")) { - try { - allow = checkRight(name, xwikidoc, "register", user, true, true, context); - if (allow) { - logAllow(name, resourceKey, accessLevel, "register level"); - return true; - } else { - logDeny(name, resourceKey, accessLevel, "register level"); - return false; - } - } catch (XWikiRightNotFoundException e) { - } - logDeny(name, resourceKey, accessLevel, "register level (no right found)"); - return false; - } - - int maxRecursiveSpaceChecks = context.getWiki().getMaxRecursiveSpaceChecks(context); - boolean isSuperUser = isSuperUser(accessLevel, name, resourceKey, user, xwikidoc, maxRecursiveSpaceChecks, context); - if (isSuperUser) { - logAllow(name, resourceKey, accessLevel, "admin level"); - return true; - } - - // check has deny rights - if (hasDenyRights()) { - // First check if this document is denied to the specific user - resourceKey = Util.getName(resourceKey, context); - try { - currentdoc = (currentdoc==null) ? context.getWiki().getDocument(resourceKey, context) : currentdoc; - deny = checkRight(name, currentdoc, accessLevel, user, false, false, context); - deny_found = true; - if (deny) { - logDeny(name, resourceKey, accessLevel, "document level"); - return false; - } - } catch (XWikiRightNotFoundException e) { - } - } - - try { - currentdoc = (currentdoc==null) ? context.getWiki().getDocument(resourceKey, context) : currentdoc; - allow = checkRight(name, currentdoc, accessLevel, user, true, false, context); - allow_found = true; - if (allow) { - logAllow(name, resourceKey, accessLevel, "document level"); - return true; - } - } catch (XWikiRightNotFoundException e) { - } - - // Check if this document is denied/allowed - // through the web WebPreferences Global Rights - - String web = Util.getWeb(resourceKey); - ArrayList spacesChecked = new ArrayList(); - int recursiveSpaceChecks = 0; - while ((web!=null)&&(recursiveSpaceChecks<=maxRecursiveSpaceChecks)) { - // Add one to the recursive space checks - recursiveSpaceChecks++; - // add to list of spaces already checked - spacesChecked.add(web); - XWikiDocument webdoc = context.getWiki().getDocument(web, "WebPreferences", context); - if (!webdoc.isNew()) { - if (hasDenyRights()) { - try { - deny = checkRight(name, webdoc, accessLevel, user, false, true, context); - deny_found = true; - if (deny) { - logDeny(name, resourceKey, accessLevel, "web level"); - return false; - } - } catch (XWikiRightNotFoundException e) { - } - } - - // If a right was found at the previous level - // then we cannot check the web rights anymore - if (!allow_found) { - try { - allow = checkRight(name, webdoc, accessLevel, user, true, true, context); - allow_found = true; - if (allow) { - logAllow(name, resourceKey, accessLevel, "web level"); - return true; - } - } catch (XWikiRightNotFoundException e) { - } - } - - // find the parent web to check rights on it - web = webdoc.getStringValue("XWiki.XWikiPreferences", "parent"); - if ((web==null)||(web.trim().equals(""))||spacesChecked.contains(web)) { - // no parent space or space already checked (recursive loop). let's finish the loop - web = null; - } - } else { - // let's finish the loop - web = null; - } - } - - // Check if this document is denied/allowed - // through the XWiki.XWikiPreferences Global Rights - if (hasDenyRights()) { - try { - deny = checkRight(name, xwikidoc, accessLevel, user, false, true, context); - deny_found = true; - if (deny) { - logDeny(name, resourceKey, accessLevel, "xwiki level"); - return false; - } - } catch (XWikiRightNotFoundException e) { - } - } - - // If a right was found at the document or web level - // then we cannot check the web rights anymore - if (!allow_found) { - try { - allow = checkRight(name, xwikidoc, accessLevel, user, true, true, context); - allow_found = true; - if (allow) { - logAllow(name, resourceKey, accessLevel, "xwiki level"); - return true; - } - } catch (XWikiRightNotFoundException e) { - } - } - -// If neither doc, web or topic had any allowed ACL -// and that all users that were not denied -// should be allowed. - if (!allow_found) { - if (accessLevel.equals("register")) { - logDeny(name, resourceKey, accessLevel, "global level (register right must be explicit)"); - return false; - } else { - logAllow(name, resourceKey, accessLevel, "global level (no restricting right)"); - return true; - } - } else { - logDeny(name, resourceKey, accessLevel, "global level (restricting right was found)"); - return false; - } - - } catch (XWikiException e) { - logDeny(name, resourceKey, accessLevel, "global level (exception)", e); - e.printStackTrace(); - return false; - } - finally { - context.setDatabase(database); - } - } - - private boolean hasDenyRights() { - return true; - } - - private boolean isSuperAdminOrProgramming(String name, String resourceKey, String accessLevel, boolean user, XWikiContext context) throws XWikiException { - String database = context.getDatabase(); - boolean allow; - if (name.equals("XWiki.superadmin") || name.endsWith(":XWiki.superadmin")) { - logAllow(name, resourceKey, accessLevel, "super admin level"); - return true; - } - - try { - // The master user and programming rights are checked in the main wiki - context.setDatabase(context.getWiki().getDatabase()); - XWikiDocument xwikimasterdoc = context.getWiki().getDocument("XWiki.XWikiPreferences", context); -// Verify XWiki Master super user - try { - allow = checkRight(name, xwikimasterdoc, "admin", true, true, true, context); - if (allow) { - logAllow(name, resourceKey, accessLevel, "master admin level"); - return true; - } - } catch (XWikiRightNotFoundException e) { - } - -// Verify XWiki programming right - if (accessLevel.equals("programming")) { - // Programming right can only been given if user is from main wiki - if (!name.startsWith(context.getWiki().getDatabase() + ":")) - return false; - - try { - allow = checkRight(name, xwikimasterdoc, "programming", user, true, true, context); - if (allow) { - logAllow(name, resourceKey, accessLevel, "programming level"); - return true; - } else { - logDeny(name, resourceKey, accessLevel, "programming level"); - return false; - } - } catch (XWikiRightNotFoundException e) { - } - logDeny(name, resourceKey, accessLevel, "programming level (no right found)"); - return false; - } - } finally { - // The next rights are checked in the virtual wiki - context.setDatabase(database); - } - - return false; - } - - private boolean isSuperUser(String accessLevel, String name, String resourceKey, boolean user, XWikiDocument xwikidoc, int maxRecursiveSpaceChecks, XWikiContext context) throws XWikiException { - boolean allow; - - // Verify XWiki super user - try { - allow = checkRight(name, xwikidoc, "admin", user, true, true, context); - if (allow) { - logAllow(name, resourceKey, accessLevel, "admin level"); - return true; - } - } catch (XWikiRightNotFoundException e) { - } - - // Verify Web super user - String web = Util.getWeb(resourceKey); - ArrayList spacesChecked = new ArrayList(); - int recursiveSpaceChecks = 0; - while ((web!=null)&&(recursiveSpaceChecks<=maxRecursiveSpaceChecks)) { - // Add one to the recursive space checks - recursiveSpaceChecks++; - // add to list of spaces already checked - spacesChecked.add(web); - XWikiDocument webdoc = context.getWiki().getDocument(web, "WebPreferences", context); - if (!webdoc.isNew()) { - try { - allow = checkRight(name, webdoc, "admin", user, true, true, context); - if (allow) { - logAllow(name, resourceKey, accessLevel, "web admin level"); - return true; - } - } catch (XWikiRightNotFoundException e) { - } - // find the parent web to check rights on it - web = webdoc.getStringValue("XWiki.XWikiPreferences", "parent"); - if ((web==null)||(web.trim().equals(""))||spacesChecked.contains(web)) { - // no parent space or space already checked (recursive loop). let's finish the loop - web = null; - } - } else { - web = null; - } - } - return false; - } - - public boolean hasProgrammingRights(XWikiContext context) { - XWikiDocument sdoc = (XWikiDocument) context.get("sdoc"); - if (sdoc == null) - sdoc = context.getDoc(); - return hasProgrammingRights(sdoc, context); - } - - public boolean hasProgrammingRights(XWikiDocument doc, XWikiContext context) { - try { - if (doc == null) - return false; - - String username = doc.getAuthor(); - - if (username == null) - return false; - - String docname; - if (doc.getDatabase() != null) { - docname = doc.getDatabase() + ":" + doc.getFullName(); - if (username.indexOf(":") == -1) - username = doc.getDatabase() + ":" + username; - } else - docname = doc.getFullName(); - - // programming rights can only been given for user of the main wiki - if (context.getWiki().isVirtual()) { - String maindb = context.getWiki().getDatabase(); - if ((maindb == null) || (!username.startsWith(maindb))) - return false; - } - - return hasAccessLevel("programming", username, docname, context); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public boolean hasAdminRights(XWikiContext context) { - boolean hasAdmin = false; - try { - hasAdmin = hasAccessLevel("admin", context.getUser(), - "XWiki.XWikiPreferences", context); - } catch (Exception e) { - e.printStackTrace(); - } - if (!hasAdmin) { - try { - hasAdmin = hasAccessLevel("admin", context.getUser(), - context.getDoc().getSpace() + ".WebPreferences", context); - } catch (Exception e) { - e.printStackTrace(); - } - } - return hasAdmin; - } - -} +/* + * Copyright 2006-2007, XpertNet SARL, and individual contributors as indicated + * by the contributors.txt. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +package com.xpn.xwiki.user.impl.xwiki; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiInterface; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.objects.BaseObject; +import com.xpn.xwiki.user.api.XWikiGroupService; +import com.xpn.xwiki.user.api.XWikiRightNotFoundException; +import com.xpn.xwiki.user.api.XWikiRightService; +import com.xpn.xwiki.user.api.XWikiUser; +import com.xpn.xwiki.util.Util; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.*; + +public class XWikiRightServiceImpl implements XWikiRightService +{ + private static final Log log = LogFactory.getLog(XWikiRightServiceImpl.class); + private static Map actionMap; + private static List allLevels = Arrays.asList( + new String[] {"admin","view","edit","comment","delete","register","programming"}); + + protected void logAllow(String username, String page, String action, String info) { + if (log.isDebugEnabled()) + log.debug("Access has been granted for (" + username + "," + page + "," + action + "): " + info); + } + + protected void logDeny(String username, String page, String action, String info) { + if (log.isInfoEnabled()) + log.info("Access has been denied for (" + username + "," + page + "," + action + "): " + info); + } + + protected void logDeny(String name, String resourceKey, String accessLevel, String info, Exception e) { + if (log.isDebugEnabled()) + log.debug("Access has been denied for (" + name + "," + resourceKey + "," + accessLevel + ") at " + info, e); + } + + public List listAllLevels(XWikiContext context) throws XWikiException { + List list = new ArrayList(); + list.addAll(allLevels); + return list; + } + + public String getRight(String action) { + if (actionMap == null) { + actionMap = new HashMap(); + actionMap.put("login", "login"); + actionMap.put("logout", "login"); + actionMap.put("loginerror", "login"); + actionMap.put("loginsubmit", "login"); + actionMap.put("view", "view"); + actionMap.put("viewrev", "view"); + actionMap.put("downloadrev", "download"); + actionMap.put("plain", "view"); + actionMap.put("raw", "view"); + actionMap.put("attach", "view"); + actionMap.put("charting", "view"); + actionMap.put("skin", "view"); + actionMap.put("download", "view"); + actionMap.put("dot", "view"); + actionMap.put("svg", "view"); + actionMap.put("pdf", "view"); + actionMap.put("delete", "delete"); + actionMap.put("reset", "delete"); + actionMap.put("commentadd", "comment"); + actionMap.put("register", "register"); + actionMap.put("redirect", "view"); + actionMap.put("admin", "admin"); + actionMap.put("export", "view"); + actionMap.put("import", "admin"); + actionMap.put("unknown", "view"); + } + + String right = (String) actionMap.get(action); + if (right == null) { + return "edit"; + } else + return right; + } + + public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException { + String username = null; + XWikiUser user = null; + boolean needsAuth = false; + String right = getRight(action); + + if (right.equals("login")) { + user = context.getWiki().checkAuth(context); + if (user == null) + username = "XWiki.XWikiGuest"; + else + username = user.getUser(); + + // Save the user + context.setUser(username); + logAllow(username, doc.getFullName(), action, "login/logout pages"); + return true; + } + + if (right.equals("delete")) { + user = context.getWiki().checkAuth(context); + String creator = doc.getCreator(); + if ((user != null) && (user.getUser() != null) && (creator != null)) { + if (user.getUser().equals(creator)) { + context.setUser(user.getUser()); + return true; + } + } + right = "admin"; + } + + // We do not need to authenticate twice + // This seems to cause a problem in virtual wikis + user = context.getXWikiUser(); + if (user == null) { + needsAuth = needsAuth(right, context); + try { + if (context.getMode() != XWikiContext.MODE_XMLRPC) + user = context.getWiki().checkAuth(context); + else + user = new XWikiUser(context.getUser()); + + if ((user == null) && (needsAuth)) { + if (context.getRequest() != null){ + if (!context.getWiki().Param("xwiki.hidelogin", "false").equalsIgnoreCase("true")) { + context.getWiki().getAuthService().showLogin(context); + } + } + logDeny("unauthentified", doc.getFullName(), action, "Authentication needed"); + return false; + } + } catch (XWikiException e) { + if (needsAuth) + throw e; + } + + if (user == null) + username = "XWiki.XWikiGuest"; + else + username = user.getUser(); + + // Save the user + context.setUser(username); + } else { + username = user.getUser(); + } + +// Check Rights + try { +// Verify access rights and return if ok + String docname; + if (context.getDatabase() != null) { + docname = context.getDatabase() + ":" + doc.getFullName(); + if (username.indexOf(":") == -1) + username = context.getDatabase() + ":" + username; + } else + docname = doc.getFullName(); + + if (context.getWiki().getRightService().hasAccessLevel(right, username, docname, context)) { + logAllow(username, docname, action, "access manager granted right"); + return true; + } + } catch (Exception e) { +// This should not happen.. + logDeny(username, (doc==null) ? "" : doc.getFullName(), action, "access manager exception " + e.getMessage()); + e.printStackTrace(); + return false; + } + + if (user == null) { +// Denied Guest need to be authenticated + /*logDeny("unauthentified", (doc==null) ? "" : doc.getFullName(), action, "Guest has been denied - Redirecting to authentication"); + if (context.getRequest() != null) + context.getWiki().getAuthService().showLogin(context); + return false;*/ + + if (!context.getWiki().Param("xwiki.hidelogin", "false").equalsIgnoreCase("true")) { + context.getWiki().getAuthService().showLogin(context); + } + return false; + } else { + logDeny(username, doc.getFullName(), action, "access manager denied right"); + return false; + } + } + + private boolean needsAuth(String right, XWikiContext context) { + boolean needsAuth = false; + try { + needsAuth = context.getWiki().getXWikiPreference("authenticate_" + right, "", context).toLowerCase().equals("yes"); + } catch (Exception e) { + } + try { + needsAuth |= (context.getWiki().getXWikiPreferenceAsInt("authenticate_" + right, 0, context) == 1); + } catch (Exception e) { + } + try { + needsAuth |= context.getWiki().getWebPreference("authenticate_" + right, "", context).toLowerCase().equals("yes"); + } catch (Exception e) { + } + try { + needsAuth |= (context.getWiki().getWebPreferenceAsInt("authenticate_" + right, 0, context) == 1); + } catch (Exception e) { + } + return needsAuth; + } + + public boolean hasAccessLevel(String right, String username, String docname, XWikiContext context) throws XWikiException { + try { + return hasAccessLevel(right, username, docname, true, context); + } catch (XWikiException e) { + return false; + } + } + + public boolean checkRight(String name, XWikiDocument doc, String accessLevel, + boolean user, boolean allow, boolean global, XWikiContext context) throws XWikiRightNotFoundException, XWikiException { + String className = global ? "XWiki.XWikiGlobalRights" : "XWiki.XWikiRights"; + String fieldName = user ? "users" : "groups"; + boolean found = false; + + // Get the userdb and the shortname + String userdatabase = null; + String shortname = name; + int i0 = name.indexOf(":"); + if (i0 != -1) { + userdatabase = name.substring(0, i0); + shortname = name.substring(i0 + 1); + } + + if (log.isDebugEnabled()) + log.debug("Checking right: " + name + "," + doc.getFullName() + "," + accessLevel + + "," + user + "," + allow + "," + global); + + Vector vobj = doc.getObjects(className); + if (vobj != null) { + if (log.isDebugEnabled()) + log.debug("Checking objects " + vobj.size()); + for (int i = 0; i < vobj.size(); i++) { + if (log.isDebugEnabled()) + log.debug("Checking object " + i); + + BaseObject bobj = (BaseObject) vobj.get(i); + + if (bobj == null) { + if (log.isDebugEnabled()) + log.debug("Bypass object " + i); + continue; + } + String users = bobj.getStringValue(fieldName); + String levels = bobj.getStringValue("levels"); + boolean allowdeny = (bobj.getIntValue("allow") == 1); + + if (allowdeny == allow) { + if (log.isDebugEnabled()) + log.debug("Checking match: " + accessLevel + " in " + levels); + + String[] levelsarray = StringUtils.split(levels, " ,|"); + if (ArrayUtils.contains(levelsarray, accessLevel)) { + if (log.isDebugEnabled()) + log.debug("Found a right for " + allow); + found = true; + + if (log.isDebugEnabled()) + log.debug("Checking match: " + name + " in " + users); + + String[] userarray = StringUtils.split(users, " ,|"); + + for (int ii = 0; ii < userarray.length; ii++) { + String value = userarray[ii]; + if (value.indexOf(".") == -1) + userarray[ii] = "XWiki." + value; + } + + if (log.isDebugEnabled()) + log.debug("Checking match: " + name + " in " + StringUtils.join(userarray, ",")); + + // In the case where the document database and the user database is the same + // then we allow the usage of the short name, otherwise the fully qualified name is requested + if (context.getDatabase().equals(userdatabase)) { + if (ArrayUtils.contains(userarray, shortname)) { + if (log.isDebugEnabled()) + log.debug("Found matching right in " + users + " for " + shortname); + return true; + } + // We should also allow to skip "XWiki." from the usernames and group lists + String veryshortname = shortname.substring(shortname.indexOf(".") + 1); + if (ArrayUtils.contains(userarray, veryshortname)) { + if (log.isDebugEnabled()) + log.debug("Found matching right in " + users + " for " + shortname); + return true; + } + } + + if ((context.getDatabase() != null) && + (ArrayUtils.contains(userarray, name))) { + if (log.isDebugEnabled()) + log.debug("Found matching right in " + users + " for " + name); + return true; + } + + if (log.isDebugEnabled()) + log.debug("Failed match: " + name + " in " + users); + } + } else { + if (log.isDebugEnabled()) + log.debug("Bypass object because wrong allow/deny" + i); + } + } + } + + if (log.isDebugEnabled()) + log.debug("Searching for matching rights at group level"); + +// Didn't found right at this level.. Let's go to group level + Map grouplistcache = (Map) context.get("grouplist"); + if (grouplistcache == null) { + grouplistcache = new HashMap(); + context.put("grouplist", grouplistcache); + } + + Collection grouplist = new ArrayList(); + XWikiGroupService groupService = context.getWiki().getGroupService(context); + String key = context.getDatabase() + ":" + name; + Collection grouplist1 = (Collection) grouplistcache.get(key); + + if (grouplist1 == null) { + grouplist1 = new ArrayList(); + try { + Collection glist = groupService.listGroupsForUser(name, context); + Iterator it = glist.iterator(); + + while (it.hasNext()) { + grouplist1.add(context.getDatabase() + ":" + it.next()); + } + } catch (Exception e) { + + } + + if (grouplist1 != null) + grouplistcache.put(key, grouplist1); + else + grouplistcache.put(key, new ArrayList()); + } + + if (grouplist1 != null) + grouplist.addAll(grouplist1); + + if (context.isVirtual()) { + String database = context.getDatabase(); + try { + shortname = Util.getName(name, context); + + if (!database.equals(context.getDatabase())) { + String key2 = context.getDatabase() + ":" + name; + Collection grouplist2 = (Collection) grouplistcache.get(key2); + + if (grouplist2 == null) { + Collection glist = groupService.listGroupsForUser(shortname, context); + Iterator it = glist.iterator(); + while (it.hasNext()) { + grouplist2.add(context.getDatabase() + ":" + it.next()); + } + if (grouplist2 != null) + grouplistcache.put(key2, grouplist2); + else + grouplistcache.put(key2, new ArrayList()); + } + + if (grouplist2 != null) + grouplist.addAll(grouplist2); + } + } catch (Exception e) { + } finally { + context.setDatabase(database); + } + } + + if (log.isDebugEnabled()) + log.debug("Searching for matching rights for " + ((grouplist == null) ? "0" : "" + grouplist.size()) + + " groups: " + grouplist); + + if (grouplist != null) { + Iterator groupit = grouplist.iterator(); + while (groupit.hasNext()) { + String group = (String) groupit.next(); + try { + // We need to construct the full group name to make sure the groups are + // handled separately + boolean result = checkRight(group, doc, accessLevel, false, allow, global, context); + if (result) + return true; + } catch (XWikiRightNotFoundException e) { + } + catch (Exception e) { + // This should not happen + e.printStackTrace(); + } + } + } + + if (log.isDebugEnabled()) + log.debug("Finished searching for rights for " + name + ": " + found); + + if (found) + return false; + else + throw new XWikiRightNotFoundException(); + } + + public boolean hasAccessLevel(String accessLevel, String name, String resourceKey, + boolean user, XWikiContext context) throws XWikiException { + boolean deny = false; + boolean allow = false; + boolean allow_found = false; + boolean deny_found = false; + boolean isReadOnly = context.getWiki().isReadOnly(); + String database = context.getDatabase(); + XWikiDocument currentdoc = null; + + if (isReadOnly) { + + if ("edit".equals(accessLevel) || + "delete".equals(accessLevel) || + "comment".equals(accessLevel) || + "register".equals(accessLevel)) { + logDeny(name, resourceKey, accessLevel, "server in read-only mode"); + return false; + } + } + + if (name.equals("XWiki.XWikiGuest") || name.endsWith(":XWiki.XWikiGuest")) { + if (needsAuth(accessLevel, context)) + return false; + } + + allow = isSuperAdminOrProgramming(name, resourceKey, accessLevel, user, context); + if ((allow==true)||(accessLevel.equals("programming"))) { + return allow; + } + + try { + // Verify Wiki Owner + String wikiOwner = context.getWikiOwner(); + if (wikiOwner != null) { + if (wikiOwner.equals(name)) { + logAllow(name, resourceKey, accessLevel, "admin level from wiki ownership"); + return true; + } + } + + XWikiDocument xwikidoc = context.getWiki().getDocument("XWiki.XWikiPreferences", context); + + // Verify XWiki register right + if (accessLevel.equals("register")) { + try { + allow = checkRight(name, xwikidoc, "register", user, true, true, context); + if (allow) { + logAllow(name, resourceKey, accessLevel, "register level"); + return true; + } else { + logDeny(name, resourceKey, accessLevel, "register level"); + return false; + } + } catch (XWikiRightNotFoundException e) { + } + logDeny(name, resourceKey, accessLevel, "register level (no right found)"); + return false; + } + + int maxRecursiveSpaceChecks = context.getWiki().getMaxRecursiveSpaceChecks(context); + boolean isSuperUser = isSuperUser(accessLevel, name, resourceKey, user, xwikidoc, maxRecursiveSpaceChecks, context); + if (isSuperUser) { + logAllow(name, resourceKey, accessLevel, "admin level"); + return true; + } + + // check has deny rights + if (hasDenyRights()) { + // First check if this document is denied to the specific user + resourceKey = Util.getName(resourceKey, context); + try { + currentdoc = (currentdoc==null) ? context.getWiki().getDocument(resourceKey, context) : currentdoc; + deny = checkRight(name, currentdoc, accessLevel, user, false, false, context); + deny_found = true; + if (deny) { + logDeny(name, resourceKey, accessLevel, "document level"); + return false; + } + } catch (XWikiRightNotFoundException e) { + } + } + + try { + currentdoc = (currentdoc==null) ? context.getWiki().getDocument(resourceKey, context) : currentdoc; + allow = checkRight(name, currentdoc, accessLevel, user, true, false, context); + allow_found = true; + if (allow) { + logAllow(name, resourceKey, accessLevel, "document level"); + return true; + } + } catch (XWikiRightNotFoundException e) { + } + + // Check if this document is denied/allowed + // through the web WebPreferences Global Rights + + String web = Util.getWeb(resourceKey); + ArrayList spacesChecked = new ArrayList(); + int recursiveSpaceChecks = 0; + while ((web!=null)&&(recursiveSpaceChecks<=maxRecursiveSpaceChecks)) { + // Add one to the recursive space checks + recursiveSpaceChecks++; + // add to list of spaces already checked + spacesChecked.add(web); + XWikiDocument webdoc = context.getWiki().getDocument(web, "WebPreferences", context); + if (!webdoc.isNew()) { + if (hasDenyRights()) { + try { + deny = checkRight(name, webdoc, accessLevel, user, false, true, context); + deny_found = true; + if (deny) { + logDeny(name, resourceKey, accessLevel, "web level"); + return false; + } + } catch (XWikiRightNotFoundException e) { + } + } + + // If a right was found at the previous level + // then we cannot check the web rights anymore + if (!allow_found) { + try { + allow = checkRight(name, webdoc, accessLevel, user, true, true, context); + allow_found = true; + if (allow) { + logAllow(name, resourceKey, accessLevel, "web level"); + return true; + } + } catch (XWikiRightNotFoundException e) { + } + } + + // find the parent web to check rights on it + web = webdoc.getStringValue("XWiki.XWikiPreferences", "parent"); + if ((web==null)||(web.trim().equals(""))||spacesChecked.contains(web)) { + // no parent space or space already checked (recursive loop). let's finish the loop + web = null; + } + } else { + // let's finish the loop + web = null; + } + } + + // Check if this document is denied/allowed + // through the XWiki.XWikiPreferences Global Rights + if (hasDenyRights()) { + try { + deny = checkRight(name, xwikidoc, accessLevel, user, false, true, context); + deny_found = true; + if (deny) { + logDeny(name, resourceKey, accessLevel, "xwiki level"); + return false; + } + } catch (XWikiRightNotFoundException e) { + } + } + + // If a right was found at the document or web level + // then we cannot check the web rights anymore + if (!allow_found) { + try { + allow = checkRight(name, xwikidoc, accessLevel, user, true, true, context); + allow_found = true; + if (allow) { + logAllow(name, resourceKey, accessLevel, "xwiki level"); + return true; + } + } catch (XWikiRightNotFoundException e) { + } + } + +// If neither doc, web or topic had any allowed ACL +// and that all users that were not denied +// should be allowed. + if (!allow_found) { + if (accessLevel.equals("register")) { + logDeny(name, resourceKey, accessLevel, "global level (register right must be explicit)"); + return false; + } else { + logAllow(name, resourceKey, accessLevel, "global level (no restricting right)"); + return true; + } + } else { + logDeny(name, resourceKey, accessLevel, "global level (restricting right was found)"); + return false; + } + + } catch (XWikiException e) { + logDeny(name, resourceKey, accessLevel, "global level (exception)", e); + e.printStackTrace(); + return false; + } + finally { + context.setDatabase(database); + } + } + + private boolean hasDenyRights() { + return true; + } + + private boolean isSuperAdminOrProgramming(String name, String resourceKey, String accessLevel, boolean user, XWikiContext context) throws XWikiException { + String database = context.getDatabase(); + boolean allow; + if (name.equals("XWiki.superadmin") || name.endsWith(":XWiki.superadmin")) { + logAllow(name, resourceKey, accessLevel, "super admin level"); + return true; + } + + try { + // The master user and programming rights are checked in the main wiki + context.setDatabase(context.getWiki().getDatabase()); + XWikiDocument xwikimasterdoc = context.getWiki().getDocument("XWiki.XWikiPreferences", context); +// Verify XWiki Master super user + try { + allow = checkRight(name, xwikimasterdoc, "admin", true, true, true, context); + if (allow) { + logAllow(name, resourceKey, accessLevel, "master admin level"); + return true; + } + } catch (XWikiRightNotFoundException e) { + } + +// Verify XWiki programming right + if (accessLevel.equals("programming")) { + // Programming right can only been given if user is from main wiki + if (!name.startsWith(context.getWiki().getDatabase() + ":")) + return false; + + try { + allow = checkRight(name, xwikimasterdoc, "programming", user, true, true, context); + if (allow) { + logAllow(name, resourceKey, accessLevel, "programming level"); + return true; + } else { + logDeny(name, resourceKey, accessLevel, "programming level"); + return false; + } + } catch (XWikiRightNotFoundException e) { + } + logDeny(name, resourceKey, accessLevel, "programming level (no right found)"); + return false; + } + } finally { + // The next rights are checked in the virtual wiki + context.setDatabase(database); + } + + return false; + } + + private boolean isSuperUser(String accessLevel, String name, String resourceKey, boolean user, XWikiDocument xwikidoc, int maxRecursiveSpaceChecks, XWikiContext context) throws XWikiException { + boolean allow; + + // Verify XWiki super user + try { + allow = checkRight(name, xwikidoc, "admin", user, true, true, context); + if (allow) { + logAllow(name, resourceKey, accessLevel, "admin level"); + return true; + } + } catch (XWikiRightNotFoundException e) { + } + + // Verify Web super user + String web = Util.getWeb(resourceKey); + ArrayList spacesChecked = new ArrayList(); + int recursiveSpaceChecks = 0; + while ((web!=null)&&(recursiveSpaceChecks<=maxRecursiveSpaceChecks)) { + // Add one to the recursive space checks + recursiveSpaceChecks++; + // add to list of spaces already checked + spacesChecked.add(web); + XWikiDocument webdoc = context.getWiki().getDocument(web, "WebPreferences", context); + if (!webdoc.isNew()) { + try { + allow = checkRight(name, webdoc, "admin", user, true, true, context); + if (allow) { + logAllow(name, resourceKey, accessLevel, "web admin level"); + return true; + } + } catch (XWikiRightNotFoundException e) { + } + // find the parent web to check rights on it + web = webdoc.getStringValue("XWiki.XWikiPreferences", "parent"); + if ((web==null)||(web.trim().equals(""))||spacesChecked.contains(web)) { + // no parent space or space already checked (recursive loop). let's finish the loop + web = null; + } + } else { + web = null; + } + } + return false; + } + + public boolean hasProgrammingRights(XWikiContext context) { + XWikiDocument sdoc = (XWikiDocument) context.get("sdoc"); + if (sdoc == null) + sdoc = context.getDoc(); + return hasProgrammingRights(sdoc, context); + } + + public boolean hasProgrammingRights(XWikiDocument doc, XWikiContext context) { + try { + if (doc == null) + return false; + + String username = doc.getAuthor(); + + if (username == null) + return false; + + String docname; + if (doc.getDatabase() != null) { + docname = doc.getDatabase() + ":" + doc.getFullName(); + if (username.indexOf(":") == -1) + username = doc.getDatabase() + ":" + username; + } else + docname = doc.getFullName(); + + // programming rights can only been given for user of the main wiki + if (context.getWiki().isVirtual()) { + String maindb = context.getWiki().getDatabase(); + if ((maindb == null) || (!username.startsWith(maindb))) + return false; + } + + return hasAccessLevel("programming", username, docname, context); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public boolean hasAdminRights(XWikiContext context) { + boolean hasAdmin = false; + try { + hasAdmin = hasAccessLevel("admin", context.getUser(), + "XWiki.XWikiPreferences", context); + } catch (Exception e) { + e.printStackTrace(); + } + if (!hasAdmin) { + try { + hasAdmin = hasAccessLevel("admin", context.getUser(), + context.getDoc().getSpace() + ".WebPreferences", context); + } catch (Exception e) { + e.printStackTrace(); + } + } + return hasAdmin; + } + + + + +} Index: src/main/java/com/xpn/xwiki/web/XWikiAction.java =================================================================== --- src/main/java/com/xpn/xwiki/web/XWikiAction.java (revision 4066) +++ src/main/java/com/xpn/xwiki/web/XWikiAction.java (working copy) @@ -1,280 +1,281 @@ -/* - * Copyright 2006-2007, XpertNet SARL, and individual contributors as indicated - * by the contributors.txt. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ - - -package com.xpn.xwiki.web; - -import com.xpn.xwiki.XWiki; -import com.xpn.xwiki.XWikiContext; -import com.xpn.xwiki.XWikiException; -import com.xpn.xwiki.doc.XWikiDocument; -import com.xpn.xwiki.monitor.api.MonitorPlugin; -import com.xpn.xwiki.plugin.fileupload.FileUploadPlugin; -import com.xpn.xwiki.render.XWikiVelocityRenderer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.log4j.MDC; -import org.apache.struts.action.Action; -import org.apache.struts.action.ActionForm; -import org.apache.struts.action.ActionForward; -import org.apache.struts.action.ActionMapping; -import org.apache.velocity.VelocityContext; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - *

A simple action that handles the display and editing of an - * wiki page..

- *

- *

The action support an action URL. The action in the URL - * controls what this action class does. The following values are supported:

- * - */ -public abstract class XWikiAction extends Action { - - // --------------------------------------------------------- Public Methods - - /** - * Handle server requests. - * - * @param mapping The ActionMapping used to select this instance - * @param form The optional ActionForm bean for this request (if any) - * @param req The HTTP request we are processing - * @param resp The HTTP response we are creating - * @throws IOException if an input/output error occurs - * @throws ServletException if a servlet exception occurs - */ - public ActionForward execute(ActionMapping mapping, - ActionForm form, - HttpServletRequest req, - HttpServletResponse resp) - throws Exception, ServletException { - String action = mapping.getName(); - - MonitorPlugin monitor = null; - FileUploadPlugin fileupload = null; - XWikiContext context = null; - - try { - XWikiRequest request = new XWikiServletRequest(req); - XWikiResponse response = new XWikiServletResponse(resp); - context = Utils.prepareContext(mapping.getName(), request, response, - new XWikiServletContext(servlet.getServletContext())); - - // Add the form to the context - context.setForm((XWikiForm) form); - XWiki xwiki = null; - try { - xwiki = XWiki.getXWiki(context); - } catch (XWikiException e) { - if (e.getCode() == XWikiException.ERROR_XWIKI_DOES_NOT_EXIST) { - // redirect - String redirect = context.getWiki().Param("xwiki.virtual.redirect"); - response.sendRedirect(redirect); - return null; - } else - throw e; - } - - // Parses multipart so that parms in multipart are available for all actions - fileupload = Utils.handleMultipart(req, context); - - XWikiURLFactory urlf = xwiki.getURLFactoryService().createURLFactory(context.getMode(), context); - context.setURLFactory(urlf); - String sajax = request.get("ajax"); - boolean ajax = false; - if (sajax != null && !sajax.trim().equals("") && !sajax.equals("0")) { - ajax = true; - } - context.put("ajax", new Boolean(ajax)); - - // Any error before this will be treated using a redirection to an error page - - // Start monitoring timer - monitor = (MonitorPlugin) xwiki.getPlugin("monitor", context); - if (monitor != null) - monitor.startRequest("", mapping.getName(), context.getURL()); - if (monitor != null) - monitor.startTimer("request"); - - VelocityContext vcontext = null; - // Prepare velocity context - vcontext = XWikiVelocityRenderer.prepareContext(context); - - try { - // Prepare documents and put them in the context - if (xwiki.prepareDocuments(request, context, vcontext) == false) - return null; - - // Let's handle the notification and make sure it never fails - try { - xwiki.getNotificationManager().preverify(context.getDoc(), mapping.getName(), context); - } - catch (Throwable e) { - e.printStackTrace(); - } - if (monitor != null) - monitor.setWikiPage(context.getDoc().getFullName()); - - String renderResult = null; - XWikiDocument doc = context.getDoc(); - if (action(context)) { - renderResult = render(context); - } - - if (renderResult != null) { - if ((doc.isNew() && ("view".equals(action) || "delete".equals(action)))) { - String page = Utils.getPage(request, "docdoesnotexist"); - Utils.parseTemplate(page, context); - } else { - String page = Utils.getPage(request, renderResult); - Utils.parseTemplate(page, !page.equals("direct"), context); - } - } - return null; - } catch (Throwable e) { - if (!(e instanceof XWikiException)) { - e = new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_UNKNOWN, - "Uncaught exception", e); - } - - try { - XWikiException xex = (XWikiException) e; - if (xex.getCode() == XWikiException.ERROR_XWIKI_ACCESS_DENIED) { - Utils.parseTemplate("accessdenied", context); - return null; - } else if (xex.getCode() == XWikiException.ERROR_XWIKI_USER_INACTIVE) { - Utils.parseTemplate("userinactive", context); - return null; - }else if(xex.getCode() == XWikiException.ERROR_XWIKI_APP_ATTACHMENT_NOT_FOUND){ - context.put("message","attachmentdoesnotexist"); - Utils.parseTemplate("exception", context); - return null; - } - vcontext.put("exp", e); - Log log = LogFactory.getLog(XWikiAction.class); - if (log.isWarnEnabled()) { - log.warn("Uncaught exception: " + e.getMessage(), e); - } - Utils.parseTemplate(Utils.getPage(request, "exception"), context); - return null; - } catch (Exception e2) { - // I hope this never happens - e.printStackTrace(); - e2.printStackTrace(); - return null; - } - } - finally { - - // Let's make sure we have flushed content and closed - try { - response.getWriter().flush(); - } catch (Throwable e) { - } - - if (monitor != null) - monitor.endTimer("request"); - - if (monitor != null) - monitor.startTimer("notify"); - - // Let's handle the notification and make sure it never fails - try { - xwiki.getNotificationManager().verify(context.getDoc(), mapping.getName(), context); - } catch (Throwable e) { - e.printStackTrace(); - } - - if (monitor != null) - monitor.endTimer("notify"); - - // Make sure we cleanup database connections - // There could be cases where we have some - if ((context != null) && (xwiki != null)) { - xwiki.getStore().cleanUp(context); - } - } - } - finally { - // End request - if (monitor != null) - monitor.endRequest(); - if (fileupload != null) - fileupload.cleanFileList(context); - - MDC.remove("url"); - } - } - - public String getRealPath(String path) { - return servlet.getServletContext().getRealPath(path); - } - - // hook - public boolean action(XWikiContext context) throws XWikiException { - return true; - } - - // hook - public String render(XWikiContext context) throws XWikiException { - return null; - } - - protected void handleRevision(XWikiContext context) throws XWikiException { - String rev = context.getRequest().getParameter("rev"); - if (rev != null) { - context.put("rev", rev); - XWikiDocument doc = (XWikiDocument) context.get("doc"); - XWikiDocument tdoc = (XWikiDocument) context.get("tdoc"); - XWikiDocument rdoc = context.getWiki().getDocument(doc, rev, context); - XWikiDocument rtdoc = context.getWiki().getDocument(tdoc, rev, context); - context.put("tdoc", rtdoc); - context.put("cdoc", rdoc); - context.put("doc", rdoc); - VelocityContext vcontext = (VelocityContext) context.get("vcontext"); - vcontext.put("doc", rdoc.newDocument(context)); - vcontext.put("cdoc", vcontext.get("doc")); - vcontext.put("tdoc", rtdoc.newDocument(context)); - } - } - - protected void sendRedirect(XWikiResponse response, String page) throws XWikiException { - try { - if (page != null) { - response.sendRedirect(page); - } - } catch (IOException e) { - Object[] args = {page}; - throw new XWikiException(XWikiException.MODULE_XWIKI_APP, - XWikiException.ERROR_XWIKI_APP_REDIRECT_EXCEPTION, - "Exception while sending redirect to page {0}", e, args); - } - } +/* + * Copyright 2006-2007, XpertNet SARL, and individual contributors as indicated + * by the contributors.txt. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +package com.xpn.xwiki.web; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.XWikiInterface; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.monitor.api.MonitorPlugin; +import com.xpn.xwiki.plugin.fileupload.FileUploadPlugin; +import com.xpn.xwiki.render.XWikiVelocityRenderer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.log4j.MDC; +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.velocity.VelocityContext; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + *

A simple action that handles the display and editing of an + * wiki page..

+ *

+ *

The action support an action URL. The action in the URL + * controls what this action class does. The following values are supported:

+ * + */ +public abstract class XWikiAction extends Action { + + // --------------------------------------------------------- Public Methods + + /** + * Handle server requests. + * + * @param mapping The ActionMapping used to select this instance + * @param form The optional ActionForm bean for this request (if any) + * @param req The HTTP request we are processing + * @param resp The HTTP response we are creating + * @throws IOException if an input/output error occurs + * @throws ServletException if a servlet exception occurs + */ + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest req, + HttpServletResponse resp) + throws Exception, ServletException { + String action = mapping.getName(); + + MonitorPlugin monitor = null; + FileUploadPlugin fileupload = null; + XWikiContext context = null; + + try { + XWikiRequest request = new XWikiServletRequest(req); + XWikiResponse response = new XWikiServletResponse(resp); + context = Utils.prepareContext(mapping.getName(), request, response, + new XWikiServletContext(servlet.getServletContext())); + + // Add the form to the context + context.setForm((XWikiForm) form); + XWiki xwiki = null; + try { + xwiki = XWiki.getXWiki(context); + } catch (XWikiException e) { + if (e.getCode() == XWikiException.ERROR_XWIKI_DOES_NOT_EXIST) { + // redirect + String redirect = context.getWiki().Param("xwiki.virtual.redirect"); + response.sendRedirect(redirect); + return null; + } else + throw e; + } + + // Parses multipart so that parms in multipart are available for all actions + fileupload = Utils.handleMultipart(req, context); + + XWikiURLFactory urlf = xwiki.getURLFactoryService().createURLFactory(context.getMode(), context); + context.setURLFactory(urlf); + String sajax = request.get("ajax"); + boolean ajax = false; + if (sajax != null && !sajax.trim().equals("") && !sajax.equals("0")) { + ajax = true; + } + context.put("ajax", new Boolean(ajax)); + + // Any error before this will be treated using a redirection to an error page + + // Start monitoring timer + monitor = (MonitorPlugin) xwiki.getPlugin("monitor", context); + if (monitor != null) + monitor.startRequest("", mapping.getName(), context.getURL()); + if (monitor != null) + monitor.startTimer("request"); + + VelocityContext vcontext = null; + // Prepare velocity context + vcontext = XWikiVelocityRenderer.prepareContext(context); + + try { + // Prepare documents and put them in the context + if (xwiki.prepareDocuments(request, context, vcontext) == false) + return null; + + // Let's handle the notification and make sure it never fails + try { + xwiki.getNotificationManager().preverify(context.getDoc(), mapping.getName(), context); + } + catch (Throwable e) { + e.printStackTrace(); + } + if (monitor != null) + monitor.setWikiPage(context.getDoc().getFullName()); + + String renderResult = null; + XWikiDocument doc = context.getDoc(); + if (action(context)) { + renderResult = render(context); + } + + if (renderResult != null) { + if ((doc.isNew() && ("view".equals(action) || "delete".equals(action)))) { + String page = Utils.getPage(request, "docdoesnotexist"); + Utils.parseTemplate(page, context); + } else { + String page = Utils.getPage(request, renderResult); + Utils.parseTemplate(page, !page.equals("direct"), context); + } + } + return null; + } catch (Throwable e) { + if (!(e instanceof XWikiException)) { + e = new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_UNKNOWN, + "Uncaught exception", e); + } + + try { + XWikiException xex = (XWikiException) e; + if (xex.getCode() == XWikiException.ERROR_XWIKI_ACCESS_DENIED) { + Utils.parseTemplate(context.getWiki().Param("xwiki.access_exception", "accessdenied"), context); + return null; + } else if (xex.getCode() == XWikiException.ERROR_XWIKI_USER_INACTIVE) { + Utils.parseTemplate(context.getWiki().Param("xwiki.user_exception", "userinactive"), context); + return null; + }else if(xex.getCode() == XWikiException.ERROR_XWIKI_APP_ATTACHMENT_NOT_FOUND){ + context.put("message","attachmentdoesnotexist"); + Utils.parseTemplate(context.getWiki().Param("xwiki.attachment_exception", "attachmentdoesnotexist"), context); + return null; + } + vcontext.put("exp", e); + Log log = LogFactory.getLog(XWikiAction.class); + if (log.isWarnEnabled()) { + log.warn("Uncaught exception: " + e.getMessage(), e); + } + Utils.parseTemplate(Utils.getPage(request, "exception"), context); + return null; + } catch (Exception e2) { + // I hope this never happens + e.printStackTrace(); + e2.printStackTrace(); + return null; + } + } + finally { + + // Let's make sure we have flushed content and closed + try { + response.getWriter().flush(); + } catch (Throwable e) { + } + + if (monitor != null) + monitor.endTimer("request"); + + if (monitor != null) + monitor.startTimer("notify"); + + // Let's handle the notification and make sure it never fails + try { + xwiki.getNotificationManager().verify(context.getDoc(), mapping.getName(), context); + } catch (Throwable e) { + e.printStackTrace(); + } + + if (monitor != null) + monitor.endTimer("notify"); + + // Make sure we cleanup database connections + // There could be cases where we have some + if ((context != null) && (xwiki != null)) { + xwiki.getStore().cleanUp(context); + } + } + } + finally { + // End request + if (monitor != null) + monitor.endRequest(); + if (fileupload != null) + fileupload.cleanFileList(context); + + MDC.remove("url"); + } + } + + public String getRealPath(String path) { + return servlet.getServletContext().getRealPath(path); + } + + // hook + public boolean action(XWikiContext context) throws XWikiException { + return true; + } + + // hook + public String render(XWikiContext context) throws XWikiException { + return null; + } + + protected void handleRevision(XWikiContext context) throws XWikiException { + String rev = context.getRequest().getParameter("rev"); + if (rev != null) { + context.put("rev", rev); + XWikiDocument doc = (XWikiDocument) context.get("doc"); + XWikiDocument tdoc = (XWikiDocument) context.get("tdoc"); + XWikiDocument rdoc = context.getWiki().getDocument(doc, rev, context); + XWikiDocument rtdoc = context.getWiki().getDocument(tdoc, rev, context); + context.put("tdoc", rtdoc); + context.put("cdoc", rdoc); + context.put("doc", rdoc); + VelocityContext vcontext = (VelocityContext) context.get("vcontext"); + vcontext.put("doc", rdoc.newDocument(context)); + vcontext.put("cdoc", vcontext.get("doc")); + vcontext.put("tdoc", rtdoc.newDocument(context)); + } + } + + protected void sendRedirect(XWikiResponse response, String page) throws XWikiException { + try { + if (page != null) { + response.sendRedirect(page); + } + } catch (IOException e) { + Object[] args = {page}; + throw new XWikiException(XWikiException.MODULE_XWIKI_APP, + XWikiException.ERROR_XWIKI_APP_REDIRECT_EXCEPTION, + "Exception while sending redirect to page {0}", e, args); + } + } } \ No newline at end of file