/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program 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 General Public License for more details. * * Copyright 2006 - 2008 Pentaho Corporation. All rights reserved. * */ package org.pentaho.platform.engine.security; import java.security.Principal; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.platform.api.engine.IAclHolder; import org.pentaho.platform.api.engine.IAclSolutionFile; import org.pentaho.platform.api.engine.IAclVoter; import org.pentaho.platform.api.engine.IPentahoAclEntry; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.ISolutionFile; import org.pentaho.platform.api.engine.IUserDetailsRoleListService; import org.pentaho.platform.api.repository.ISolutionRepository; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.springframework.security.Authentication; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; /** * A utility class with several static methods that are used to * either bind the <tt>Authentication</tt> to the <tt>IPentahoSession</tt>, retrieve * the <tt>Authentication</tt> from the <tt>IPentahoSession</tt>, and other various helper * functions. * @author mbatchel * */ public class SecurityHelper { private static final Log logger = LogFactory.getLog(SecurityHelper.class); public static final String SESSION_PRINCIPAL = "SECURITY_PRINCIPAL"; //$NON-NLS-1$ public static final String DefaultAnonymousRole = PentahoSystem.getSystemSetting( "anonymous-authentication/anonymous-role", "Anonymous"); //$NON-NLS-1$ //$NON-NLS-2$ public static final String DefaultAnonymousUser = PentahoSystem.getSystemSetting( "anonymous-authentication/anonymous-user", "anonymous"); //$NON-NLS-1$ //$NON-NLS-2$ /** * Looks in the provided session to get the Spring Security Authentication object out. * Optionally returns an "anonymous" Authentication if desired. * @param session Users' IPentahoSession object * @param allowAnonymous If true, will return an anonymous Authentication object. * @return the Authentication object from the session */ public static Authentication getAuthentication(final IPentahoSession session, final boolean allowAnonymous) { Principal principal = (Principal) session.getAttribute(SecurityHelper.SESSION_PRINCIPAL); if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("principal from IPentahoSession: " + principal); //$NON-NLS-1$ if (null != principal) { SecurityHelper.logger.debug("principal class: " + principal.getClass().getName()); //$NON-NLS-1$ } } if (principal instanceof Authentication) { if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("principal is an instance of Authentication"); //$NON-NLS-1$ } return (Authentication) principal; } else if (principal != null) { if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("principal is not an instance of Authentication"); //$NON-NLS-1$ SecurityHelper.logger.debug("attempting role fetch with username"); //$NON-NLS-1$ } // OK - Not Spring Security somehow. // However, since the principal interface doesn't specify the // roles a user is in, we need to dispatch a call to the // UserRoleListProvider to get that information from there. IUserDetailsRoleListService roleListService = PentahoSystem.get(IUserDetailsRoleListService.class); List roles = roleListService.getRolesForUser(principal.getName()); if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("rolesForUser from roleListService:" + roles); //$NON-NLS-1$ } if (!roles.isEmpty()) { GrantedAuthority[] grantedAuthorities = new GrantedAuthority[roles.size()]; for (int i = 0; i < roles.size(); i++) { grantedAuthorities[i] = new GrantedAuthorityImpl((String) roles.get(i)); } Authentication auth = new UsernamePasswordAuthenticationToken(principal.getName(), null, grantedAuthorities); return auth; } } if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("either principal is null or user has no roles"); //$NON-NLS-1$ } if (allowAnonymous) { if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("there is no principal in IPentahoSession"); //$NON-NLS-1$ SecurityHelper.logger.debug("creating token with username anonymous and role Anonymous"); //$NON-NLS-1$ } // Hmmm - at this point, we're being asked for an authentication on // an un-authenticated user. For now, we'll default to returning // an authentication that has the user as anonymous. Authentication auth = new UsernamePasswordAuthenticationToken(SecurityHelper.DefaultAnonymousUser, null, new GrantedAuthorityImpl[] { new GrantedAuthorityImpl(SecurityHelper.DefaultAnonymousRole) }); return auth; } else { if (SecurityHelper.logger.isDebugEnabled()) { SecurityHelper.logger.debug("there is no principal in IPentahoSession"); //$NON-NLS-1$ SecurityHelper.logger.debug("and allowAnonymous is false"); //$NON-NLS-1$ } // If we're here - we require a properly authenticated user and // there's nothing // else we can do aside from returning null. return null; } } /** * Gets the java.security.principal object from the IPentahoSession object * @param session The users' session * @return The bound Principal */ public static Principal getPrincipal(final IPentahoSession session) { Principal principal = (Principal) session.getAttribute(SecurityHelper.SESSION_PRINCIPAL); return principal; } /** * Sets the java.security.principal object into the IPentahoSession object. * @param principal The principal from the servlet context * @param session The users' IPentahoSession object */ public static void setPrincipal(final Principal principal, final IPentahoSession session) { session.setAttribute(SecurityHelper.SESSION_PRINCIPAL, principal); } /** * Utility method that communicates with the installed ACLVoter to determine * administrator status * @param session The users IPentahoSession object * @return true if the user is considered a Pentaho administrator */ public static boolean isPentahoAdministrator(final IPentahoSession session) { IAclVoter voter = PentahoSystem.get(IAclVoter.class, session); return voter.isPentahoAdministrator(session); } /** * Utility method that communicates with the installed ACLVoter to determine * whether a particular role is granted to the specified user. * @param session The users' IPentahoSession * @param role The role to look for * @return true if the user is granted the specified role. */ public static boolean isGranted(final IPentahoSession session, final GrantedAuthority role) { IAclVoter voter = PentahoSystem.get(IAclVoter.class, session); return voter.isGranted(session, role); } /** * @param aFile * @return a boolean that indicates if this file can have ACLS placed on it. */ public static boolean canHaveACLS(final ISolutionFile aFile) { if (aFile.isDirectory()) { // All Directories can have ACLS return true; } // Otherwise anything in the PentahoSystem extension list. return PentahoSystem.getACLFileExtensionList().contains(aFile.getExtension()); } public static boolean hasAccess(final IAclHolder aHolder, final int actionOperation, final IPentahoSession session) { IAclVoter voter = PentahoSystem.get(IAclVoter.class, session); int aclMask = -1; switch (actionOperation) { case (IAclHolder.ACCESS_TYPE_READ): { aclMask = IPentahoAclEntry.PERM_EXECUTE; break; } case IAclHolder.ACCESS_TYPE_WRITE: case IAclHolder.ACCESS_TYPE_UPDATE: { aclMask = IPentahoAclEntry.PERM_UPDATE; break; } case IAclHolder.ACCESS_TYPE_DELETE: { aclMask = IPentahoAclEntry.PERM_DELETE; break; } case IAclHolder.ACCESS_TYPE_ADMIN: { aclMask = IPentahoAclEntry.PERM_ADMINISTRATION; break; } default: { aclMask = IPentahoAclEntry.PERM_EXECUTE; break; } } return voter.hasAccess(session, aHolder, aclMask); } /** * Utility method for access negotiation. For performance, not all files will * be checked against the supplied voter. * @param aFile * @param actionOperation * @param session * @return */ public static boolean hasAccess(final IAclSolutionFile aFile, final int actionOperation, final IPentahoSession session) { if (aFile == null) { return false; } if (!aFile.isDirectory()) { List extensionList = PentahoSystem.getACLFileExtensionList(); String fName = aFile.getFileName(); int posn = fName.lastIndexOf('.'); if (posn >= 0) { if (extensionList.indexOf(fName.substring(posn)) < 0) { // Non-acl'd file. Return true. return true; } } else { // Untyped file. Allow access. return true; } } IAclVoter voter = PentahoSystem.get(IAclVoter.class, session); int aclMask = -1; switch (actionOperation) { case ISolutionRepository.ACTION_EXECUTE: { aclMask = IPentahoAclEntry.PERM_EXECUTE; break; } case ISolutionRepository.ACTION_ADMIN: { // aclMask = PentahoAclEntry.ADMINISTRATION; // break; return SecurityHelper.isPentahoAdministrator(session); } case ISolutionRepository.ACTION_SUBSCRIBE: { aclMask = IPentahoAclEntry.PERM_SUBSCRIBE; break; } case ISolutionRepository.ACTION_CREATE: { aclMask = IPentahoAclEntry.PERM_CREATE; break; } case ISolutionRepository.ACTION_UPDATE: { aclMask = IPentahoAclEntry.PERM_UPDATE; break; } case ISolutionRepository.ACTION_DELETE: { aclMask = IPentahoAclEntry.PERM_DELETE; break; } case ISolutionRepository.ACTION_SHARE: { aclMask = IPentahoAclEntry.PERM_UPDATE_PERMS; break; } default: { aclMask = IPentahoAclEntry.PERM_EXECUTE; break; } } return voter.hasAccess(session, aFile, aclMask); } }