libreccm-legacy/ccm-cms/src/com/arsdigita/cms/SecurityManager.java

509 lines
18 KiB
Java
Executable File

/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.cms;
import com.arsdigita.cms.dispatcher.SimpleCache;
import com.arsdigita.cms.publishToFile.LocalRequestPassword;
import com.arsdigita.cms.util.SecurityConstants;
import com.arsdigita.cms.workflow.CMSEngine;
import com.arsdigita.cms.workflow.CMSTask;
import com.arsdigita.cms.workflow.CMSTaskType;
import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.Party;
import com.arsdigita.kernel.User;
import com.arsdigita.kernel.permissions.PermissionDescriptor;
import com.arsdigita.kernel.permissions.PermissionService;
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
import com.arsdigita.kernel.security.UserContext;
import com.arsdigita.toolbox.Security;
import com.arsdigita.ui.login.LoginHelper;
import com.arsdigita.util.Assert;
import com.arsdigita.workflow.simple.Engine;
import com.arsdigita.workflow.simple.Workflow;
import java.io.IOException;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
/**
* <p>Security class used for checking and granting privileges in CMS.</p>
*
* @author Michael Pih
* @version $Id: SecurityManager.java 2280 2012-03-10 23:55:04Z pboy $
*/
public class SecurityManager implements Security, SecurityConstants {
private static final Logger s_log = Logger.getLogger
(SecurityManager.class);
public static final PrivilegeDescriptor CMS_PREVIEW_ITEM_DESCRIPTOR =
new PrivilegeDescriptor(CMS_PREVIEW_ITEM);
private ContentSection m_section;
// MP: Use this.
private SimpleCache m_cache;
public SecurityManager(ContentSection section) {
m_section = section;
m_cache = new SimpleCache();
}
public final boolean canAccess(final String action) {
return canAccess(Kernel.getContext().getParty(), action);
}
/**
* Determine whether a party has access to a particular action.
*
* @param party The party
* @param action The action
* @return true if the party has access, false otherwise
* @pre (action != null)
*/
public boolean canAccess(final Party party, final String action) {
if (s_log.isDebugEnabled()) {
s_log.debug("Access check: party " + party + ", action " + action);
}
if (action.equals(WORKFLOW_ADMIN)) {
return canAdministerWorkflow(party);
} else if (action.equals(LIFECYCLE_ADMIN)) {
return canAdministerLifecycles(party);
} else if (action.equals(STAFF_ADMIN)) {
return canAdministerRoles(party);
} else if (action.equals(CONTENT_TYPE_ADMIN)) {
return canAdministerContentTypes(party);
} else if (action.equals(CATEGORY_ADMIN)) {
return canAdministerCategories(party);
} else if (action.equals(PUBLISH)) {
return canPublishItems(party);
} else if (action.equals(NEW_ITEM)) {
return canCreateItems(party);
} else if (action.equals(ADMIN_PAGES)) {
return canViewAdminPages(party);
} else if (action.equals(PUBLIC_PAGES)) {
return canViewPublicPages(party);
} else if (action.equals(PREVIEW_PAGES)) {
return canViewPreviewPages(party);
} else if (action.equals(DELETE_IMAGES)) {
return canDeleteImages(party);
} else if (action.equals(APPLY_ALTERNATE_WORKFLOWS)) {
return canApplyAlternateWorkflows(party);
} else {
throw new IllegalArgumentException
("Unknown action for access check: " + action);
}
}
/**
* Determine whether the current user has access to a particular action.
*
* @param request The HTTP request
* @param action The action
* @return true if the logged-in user has access, false otherwise
*/
public boolean canAccess(final HttpServletRequest request,
final String action) {
final Party party = Kernel.getContext().getParty();
boolean canAccess = canAccess(party, action);
if (!canAccess) {
canAccess = LocalRequestPassword.validLocalRequest(request);
}
return canAccess;
}
public boolean canAccess(final User user,
final String action,
final ContentItem item) {
if (s_log.isDebugEnabled()) {
s_log.debug("Access check: user " + user + ", object " +
item + ", action " + action);
}
if (action.equals(EDIT_ITEM)) {
return canEditItem(user, item);
} else if (action.equals(APPLY_WORKFLOW)) {
return canApplyWorkflow(user, item);
} else if (action.equals(DELETE_ITEM)) {
return canDeleteItem(user, item);
} else if (action.equals(SCHEDULE_PUBLICATION)) {
return canSchedulePublication(user, item);
} else if (action.equals(PUBLISH)) {
return canPublishItems(user, item);
} else if (action.equals(PUBLIC_PAGES)) {
return canViewPublicPages(user, item);
} else if (action.equals(PREVIEW_PAGES)) {
return canViewPreviewPages(user, item);
} else if (action.equals(NEW_ITEM)) {
// this should really only be called if the ContentItem is
// a folder...
return canCreateItems(user, item);
} else if (action.equals(APPLY_ALTERNATE_WORKFLOWS)) {
return canApplyAlternateWorkflows(user, item);
} else if (action.equals(STAFF_ADMIN)) {
// this should really only be called if the ContentItem is
// a folder...
return canAdministerRoles(user, item);
// section levels -- call non-item-specific version
} else if (action.equals(WORKFLOW_ADMIN)) {
return canAdministerWorkflow(user);
} else if (action.equals(LIFECYCLE_ADMIN)) {
return canAdministerLifecycles(user);
} else if (action.equals(STAFF_ADMIN)) {
return canAdministerRoles(user);
} else if (action.equals(CONTENT_TYPE_ADMIN)) {
return canAdministerContentTypes(user);
} else if (action.equals(ADMIN_PAGES)) {
return canViewAdminPages(user);
} else {
throw new IllegalArgumentException
("Unknown action for access check: " + action);
}
}
public boolean canAccess(HttpServletRequest request, String action,
ContentItem item) {
User user = (User)Kernel.getContext().getParty();
boolean canAccess = canAccess(user, action, item);
if (!canAccess) {
canAccess = LocalRequestPassword.validLocalRequest(request);
}
return canAccess;
}
/**
* Checking privileges.
**/
protected boolean canAdministerLifecycles(Party party) {
return (hasPermission(party, CMS_LIFECYCLE_ADMIN));
}
protected boolean canAdministerWorkflow(Party party) {
return (hasPermission(party, CMS_WORKFLOW_ADMIN));
}
protected boolean canAdministerRoles(Party party) {
return (hasPermission(party, CMS_STAFF_ADMIN));
}
protected boolean canAdministerRoles(Party party, ContentItem item) {
return (hasPermission(party, CMS_STAFF_ADMIN, item));
}
protected boolean canAdministerContentTypes(Party party) {
return (hasPermission(party, CMS_CONTENT_TYPE_ADMIN));
}
protected boolean canAdministerCategories(Party party) {
return (hasPermission(party, CMS_CATEGORY_ADMIN));
}
protected boolean canPublishItems(Party party) {
return (hasPermission(party, CMS_PUBLISH));
}
protected boolean canPublishItems(Party party, ContentItem item) {
return (hasPermission(party, CMS_PUBLISH, item));
}
protected boolean canCreateItems(Party party) {
return (hasPermission(party, CMS_NEW_ITEM));
}
protected boolean canCreateItems(User user, ContentItem item) {
return (hasPermission(user, CMS_NEW_ITEM, item));
}
protected boolean canApplyAlternateWorkflows(Party party) {
return (hasPermission(party, CMS_APPLY_ALTERNATE_WORKFLOWS));
}
protected boolean canApplyAlternateWorkflows(User user, ContentItem item) {
return (hasPermission(user, CMS_APPLY_ALTERNATE_WORKFLOWS, item));
}
/**
* Returns true if the specified user has the CMS_READ_ITEM permission on the
* current content section. False otherwise.
*
* @pre m_section != null
**/
protected boolean canViewPublicPages(Party party) {
return (hasPermission(party, CMS_READ_ITEM));
// return true;
}
/**
* Returns true if the specified user has the CMS_READ_ITEM permission on the
* current content item. False otherwise.
*
* For now, just call the section-specific version. Must modify when we
* implement folder-level permissions.
*
* @pre m_section != null
**/
protected boolean canViewPublicPages(User user, ContentItem item) {
return (hasPermission(user, CMS_READ_ITEM, item));
}
/**
* Returns true if the specified user has the CMS_PREVIEW_ITEM permission on the
* current content section. False otherwise.
*
* @pre m_section != null
**/
protected boolean canViewPreviewPages(Party party) {
return (hasPermission(party, CMS_PREVIEW_ITEM) ||
hasPermission(party, CMS_EDIT_ITEM));
// return true;
}
/**
* Returns true if the specified user has the CMS_PREVIEW_ITEM permission on the
* current content item. False otherwise.
*
* For now, just call the section-specific version. Must modify when we
* implement folder-level permissions.
*
* @pre m_section != null
**/
protected boolean canViewPreviewPages(User user, ContentItem item) {
return (hasPermission(user, CMS_PREVIEW_ITEM, item) ||
hasPermission(user, CMS_EDIT_ITEM, item));
}
/**
* Returns true if the specified party can access authoring UI in the
* current content section. False otherwise.
*
* @pre m_section != null
**/
protected boolean canViewAdminPages(Party party) {
return (hasPermission(party, CMS_PREVIEW_ITEM));
}
/**
* Returns true if the specified user has the CMS_ITEM_ADMIN permission on the
* current content item. False otherwise.
*
*
* @pre m_section != null
**/
protected boolean canDeleteImages(Party party) {
return (hasPermission(party, CMS_ITEM_ADMIN));
}
/**
* <p>Check if:</p>
* <ul>
* <li>User is logged in</li>
* <li>User has the "edit items" privilege OR
* <li>User is assigned to and owns the lock on an active task in the
* workflow applied to the item.</li>
* </ul>
*
* @param user The user
* @param item The content item
* @return true if the user is allowed to edit an item, false otherwise
* @pre (item != null)
*/
protected boolean canEditItem(User user, ContentItem item) {
if (user == null) {
return false;
}
// If the user does not have the edit items permission, then there is no
// need to check for workflow task assignments.
if (!hasPermission(user, CMS_EDIT_ITEM, item)) {
return false;
}
Workflow wf = Workflow.getObjectWorkflow(item);
if (wf == null) {
return hasPermission(user, CMS_ITEM_ADMIN, item);
} else {
if (wf.isFinished() || wf.getProcessState() == Workflow.STOPPED) {
return hasPermission(user, CMS_ITEM_ADMIN, item);
}
Engine engine = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE);
Iterator i = engine.getEnabledTasks(user, wf.getID()).iterator();
while (i.hasNext()) {
CMSTask t = (CMSTask) i.next();
if (t.isLocked() && user.equals(t.getLockedUser())) {
// The user owns the lock on the task.
return true;
}
}
// The user does not own the lock on any tasks.
return false;
}
}
/**
* <p>Check if:</p>
* <ul>
* <li>User is logged in</li>
* <li>If the user has publish privileges, verify the current
* workflow is null, stopped or finished
* <li>If the user is assigned a task of type schedule/deploy
* </ul>
*
* @param user The user
* @param item The content item
* @return true if the user is allowed to edit an item, false otherwise
* @pre (item != null) */
protected boolean canSchedulePublication(User user, ContentItem item) {
// If the user does not have the publish items permission, then there is no
// need to check for workflow task assignments.
if (user != null && canPublishItems(user, item)) {
Workflow wf = Workflow.getObjectWorkflow(item);
if (wf == null || wf.getProcessState() == Workflow.STOPPED ||
wf.isFinished()) {
return true;
} else {
Engine engine = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE);
Iterator i = engine.getEnabledTasks(user, wf.getID()).iterator();
int j =0;
while (i.hasNext()) {
CMSTask t = (CMSTask) i.next();
if (t.getTaskType().getID().equals(CMSTaskType.DEPLOY)) {
User lockingUser = t.getLockedUser();
if (lockingUser == null || user.equals(lockingUser)) {
return true;
}
}
}
}
}
return false;
}
/**
* Check if the user has CMS_DELETE_ITEM privelege.
*
* @param user The user
* @param item The content item
* @return true if the user is allowed to edit an item, false otherwise
* @pre (item != null)
*/
protected boolean canDeleteItem(User user, ContentItem item) {
return (hasPermission(user, CMS_DELETE_ITEM, item));
}
/**
* <p>Check if:</p>
* <ul>
* <li>User is logged in</li>
* <li>User has "edit items" permission on the item (or section) OR</li>
* <li>User has cms_new_item or cms_workflow_admin on the item (or
* section)</li>
* </ul>
*
* @param user The user
* @param item The content item
* @return true if the user is allowed to apply a workflow to the item,
* false otherwise
* @pre (item != null)
*/
protected boolean canApplyWorkflow(User user, ContentItem item) {
if (user == null) {
return false;
}
if (!hasPermission(user, CMS_EDIT_ITEM)) {
return true;
}
if (Workflow.getObjectWorkflowID(item) != null) {
return false;
}
return (hasPermission(user, CMS_NEW_ITEM, item) ||
hasPermission(user, CMS_WORKFLOW_ADMIN));
}
/**
* Helper method for checking permissions within a content section.
*/
private boolean hasPermission(Party party, String privilege) {
PrivilegeDescriptor pd = PrivilegeDescriptor.get(privilege);
Assert.exists(pd, "PrivilegeDescriptor.get(\"" + privilege + "\")");
return hasPermission(party, pd);
}
/**
* Helper method for checking permissions within a content section.
*/
private boolean hasPermission(Party party, PrivilegeDescriptor pd) {
PermissionDescriptor perm = new PermissionDescriptor(pd, m_section, party);
return PermissionService.checkPermission(perm);
}
/**
* Helper method for checking permissions on a content item.
*/
private boolean hasPermission(Party party, String privilege,
ContentItem item) {
PrivilegeDescriptor pd = PrivilegeDescriptor.get(privilege);
Assert.exists(pd, "PrivilegeDescriptor.get(\"" + privilege + "\")");
return hasPermission(party, pd, item);
}
/**
* Helper method for checking permissions on a content item.
* @pre pd != null
*/
private boolean hasPermission(Party party, PrivilegeDescriptor pd,
ContentItem item) {
Assert.exists(pd, "PrivilegeDescriptor");
PermissionDescriptor perm = new PermissionDescriptor(pd, item, party);
return (PermissionService.checkPermission(perm));
}
/**
* Redirects the user to the login page if not already signed in,
* setting the return url to the current request URI.
*
* @exception ServletException If there is an exception thrown while
* trying to redirect, wrap that exception in a ServletException
**/
public static void requireSignIn(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
if (Kernel.getContext().getParty() != null) { return; }
String url = com.arsdigita.kernel.security.Util
.getSecurityHelper().getLoginURL(request)
+ "?" + LoginHelper.RETURN_URL_PARAM_NAME
+ "=" + UserContext.encodeReturnURL(request);
LoginHelper.sendRedirect(request, response, url);
}
}